├── Backend
├── .gitignore
├── src
│ ├── routes
│ │ ├── auth.routes.js
│ │ └── chat.routes.js
│ ├── db
│ │ └── db.js
│ ├── models
│ │ ├── chat.model.js
│ │ ├── user.model.js
│ │ └── message.model.js
│ ├── middlewares
│ │ └── auth.middleware.js
│ ├── app.js
│ ├── services
│ │ ├── vector.service.js
│ │ └── ai.service.js
│ ├── controllers
│ │ ├── chat.controller.js
│ │ └── auth.controller.js
│ └── sockets
│ │ └── socket.server.js
├── server.js
├── public
│ ├── index.html
│ ├── vite.svg
│ └── assets
│ │ └── index-DEPrTWc_.css
├── package.json
└── package-lock.json
└── Frontend
├── vite.config.js
├── src
├── App.jsx
├── components
│ ├── chat
│ │ ├── aiClient.js
│ │ ├── ChatMobileBar.jsx
│ │ ├── ChatSidebar.jsx
│ │ ├── ChatMobileBar.css
│ │ ├── ChatSidebar.css
│ │ ├── ChatComposer.jsx
│ │ ├── ChatMessages.jsx
│ │ ├── ChatComposer.css
│ │ ├── ChatMessages.css
│ │ └── ChatLayout.css
│ └── ThemeToggle.jsx
├── store
│ ├── store.js
│ └── chatSlice.js
├── main.jsx
├── AppRoutes.jsx
├── styles
│ └── theme.css
├── pages
│ ├── Login.jsx
│ ├── Register.jsx
│ └── Home.jsx
├── assets
│ └── react.svg
└── App.css
├── .gitignore
├── index.html
├── README.md
├── eslint.config.js
├── package.json
└── public
└── vite.svg
/Backend/.gitignore:
--------------------------------------------------------------------------------
1 | .env
2 | node_modules
--------------------------------------------------------------------------------
/Frontend/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 |
--------------------------------------------------------------------------------
/Frontend/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react'
2 |
3 | import './App.css'
4 | import AppRoutes from './AppRoutes'
5 |
6 | function App() {
7 |
8 |
9 | return (
10 | <>
11 |
12 | >
13 | )
14 | }
15 |
16 | export default App
17 |
--------------------------------------------------------------------------------
/Frontend/src/components/chat/aiClient.js:
--------------------------------------------------------------------------------
1 | // Placeholder AI client; replace with real API integration.
2 | export async function fakeAIReply(prompt) {
3 | await new Promise(r => setTimeout(r, 600 + Math.random() * 800));
4 | return `Echo: ${prompt.slice(0, 400)}`;
5 | }
6 |
--------------------------------------------------------------------------------
/Frontend/src/store/store.js:
--------------------------------------------------------------------------------
1 | import { configureStore } from '@reduxjs/toolkit';
2 | import chatReducer from './chatSlice.js';
3 |
4 | export const store = configureStore({
5 | reducer: {
6 | chat: chatReducer
7 | }
8 | });
9 |
10 | export default store;
11 |
--------------------------------------------------------------------------------
/Backend/src/routes/auth.routes.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const authControllers = require("../controllers/auth.controller")
3 | const router = express.Router();
4 |
5 |
6 |
7 | router.post("/register", authControllers.registerUser)
8 | router.post("/login", authControllers.loginUser)
9 |
10 |
11 |
12 | module.exports = router;
--------------------------------------------------------------------------------
/Backend/src/db/db.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 |
3 |
4 | async function connectDb() {
5 | try {
6 | await mongoose.connect(process.env.MONGO_URI)
7 | console.log("Connected to MongoDB")
8 | } catch (err) {
9 | console.error("Error connecting to MongoDB:", err)
10 | }
11 |
12 | }
13 |
14 |
15 | module.exports = connectDb;
--------------------------------------------------------------------------------
/Frontend/.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 |
--------------------------------------------------------------------------------
/Backend/server.js:
--------------------------------------------------------------------------------
1 | require("dotenv").config();
2 | const app = require("./src/app")
3 | const connectDb = require("./src/db/db");
4 | const initSocketServer = require("./src/sockets/socket.server");
5 | const httpServer = require("http").createServer(app);
6 |
7 |
8 |
9 | connectDb()
10 | initSocketServer(httpServer);
11 |
12 |
13 | httpServer.listen(3000, () => {
14 | console.log("Server is running on port 3000");
15 | })
--------------------------------------------------------------------------------
/Frontend/src/main.jsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react'
2 | import { createRoot } from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './App.css'
5 | import { Provider } from 'react-redux'
6 | import store from './store/store.js'
7 |
8 | createRoot(document.getElementById('root')).render(
9 |
10 |
11 |
12 |
13 |
14 | )
15 |
--------------------------------------------------------------------------------
/Frontend/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Backend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Backend/src/models/chat.model.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 |
3 |
4 | const chatSchema = new mongoose.Schema({
5 | user: {
6 | type: mongoose.Schema.Types.ObjectId,
7 | ref: 'user',
8 | required: true
9 | },
10 | title: {
11 | type: String,
12 | required: true
13 | },
14 | lastActivity: {
15 | type: Date,
16 | default: Date.now
17 | }
18 | }, {
19 | timestamps: true
20 | })
21 |
22 | const chatModel = mongoose.model("chat", chatSchema)
23 |
24 |
25 | module.exports = chatModel;
--------------------------------------------------------------------------------
/Frontend/src/components/chat/ChatMobileBar.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './ChatMobileBar.css';
3 | import './ChatLayout.css';
4 |
5 |
6 | const ChatMobileBar = ({ onToggleSidebar, onNewChat }) => (
7 |
8 |
9 | Chat
10 |
11 |
12 | );
13 |
14 | export default ChatMobileBar;
15 |
--------------------------------------------------------------------------------
/Backend/src/routes/chat.routes.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const authMiddleware = require("../middlewares/auth.middleware")
3 | const chatController = require("../controllers/chat.controller")
4 |
5 |
6 | const router = express.Router();
7 |
8 | /* POST /api/chat/ */
9 | router.post('/', authMiddleware.authUser, chatController.createChat)
10 |
11 |
12 | /* GET /api/chat/ */
13 | router.get('/', authMiddleware.authUser, chatController.getChats)
14 |
15 |
16 | /* GET /api/chat/messages/:id */
17 | router.get('/messages/:id', authMiddleware.authUser, chatController.getMessages)
18 |
19 |
20 | module.exports = router;
--------------------------------------------------------------------------------
/Frontend/src/AppRoutes.jsx:
--------------------------------------------------------------------------------
1 | import { BrowserRouter, Routes, Route } from 'react-router-dom'
2 | import React from 'react'
3 | import Home from './pages/Home'
4 | import Register from './pages/Register'
5 | import Login from './pages/Login'
6 |
7 | const AppRoutes = () => {
8 | return (
9 |
10 |
11 |
12 | } />
13 | } />
14 | } />
15 |
16 |
17 | )
18 | }
19 |
20 | export default AppRoutes
--------------------------------------------------------------------------------
/Backend/src/models/user.model.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 |
3 |
4 |
5 | const userSchema = new mongoose.Schema({
6 | email: {
7 | type: String,
8 | required: true,
9 | unique: true,
10 | },
11 | fullName: {
12 | firstName: {
13 | type: String,
14 | required: true
15 | },
16 | lastName: {
17 | type: String,
18 | required: true
19 | }
20 | },
21 | password: {
22 | type: String,
23 | }
24 | },
25 | {
26 | timestamps: true
27 | }
28 | )
29 |
30 | const userModel = mongoose.model("user", userSchema)
31 |
32 |
33 | module.exports = userModel
--------------------------------------------------------------------------------
/Backend/src/models/message.model.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 |
4 | const messageSchema = new mongoose.Schema({
5 | user: {
6 | type: mongoose.Schema.Types.ObjectId,
7 | ref: "user"
8 | },
9 | chat: {
10 | type: mongoose.Schema.Types.ObjectId,
11 | ref: "chat"
12 | },
13 | content: {
14 | type: String,
15 | required: true
16 | },
17 | role: {
18 | type: String,
19 | enum: [ "user", "model", "system" ],
20 | default: "user"
21 | }
22 | }, {
23 | timestamps: true
24 | })
25 |
26 | const messageModel = mongoose.model("message", messageSchema);
27 |
28 | module.exports = messageModel;
--------------------------------------------------------------------------------
/Backend/src/middlewares/auth.middleware.js:
--------------------------------------------------------------------------------
1 | const userModel = require('../models/user.model');
2 | const jwt = require('jsonwebtoken');
3 |
4 |
5 |
6 | async function authUser(req, res, next) {
7 |
8 | const { token } = req.cookies;
9 |
10 | if (!token) {
11 | return res.status(401).json({ message: 'Unauthorized' });
12 | }
13 |
14 | try {
15 |
16 | const decoded = jwt.verify(token, process.env.JWT_SECRET);
17 |
18 | const user = await userModel.findById(decoded.id)
19 |
20 | req.user = user;
21 |
22 | next()
23 |
24 | } catch (err) {
25 | res.status(401).json({ message: 'Unauthorized' });
26 | }
27 |
28 | }
29 |
30 | module.exports = {
31 | authUser
32 | }
--------------------------------------------------------------------------------
/Backend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cohort-1-project-chat-gpt",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "dev": "npx nodemon server.js"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC",
13 | "type": "commonjs",
14 | "dependencies": {
15 | "@google/genai": "^1.14.0",
16 | "@pinecone-database/pinecone": "^6.1.2",
17 | "bcryptjs": "^3.0.2",
18 | "cookie": "^1.0.2",
19 | "cookie-parser": "^1.4.7",
20 | "cors": "^2.8.5",
21 | "dotenv": "^17.2.1",
22 | "express": "^5.1.0",
23 | "jsonwebtoken": "^9.0.2",
24 | "mongoose": "^8.17.1",
25 | "socket.io": "^4.8.1"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Frontend/src/components/ThemeToggle.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 |
3 | const ThemeToggle = () => {
4 | const [theme, setTheme] = useState(() => {
5 | return localStorage.getItem('theme') || 'light';
6 | });
7 |
8 | useEffect(() => {
9 | document.documentElement.setAttribute('data-theme', theme);
10 | localStorage.setItem('theme', theme);
11 | }, [theme]);
12 |
13 | function toggleTheme() {
14 | setTheme(t => (t === 'light' ? 'dark' : 'light'));
15 | }
16 |
17 | return (
18 |
26 | );
27 | };
28 |
29 | export default ThemeToggle;
30 |
--------------------------------------------------------------------------------
/Backend/src/app.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const cookieParser = require('cookie-parser');
3 | const cors = require('cors');
4 | const path = require('path');
5 |
6 |
7 | /* Routes */
8 | const authRoutes = require('./routes/auth.routes');
9 | const chatRoutes = require("./routes/chat.routes");
10 |
11 |
12 | const app = express();
13 |
14 |
15 |
16 | /* using middlewares */
17 | app.use(cors({
18 | origin: 'http://localhost:5173',
19 | credentials: true
20 | }))
21 | app.use(express.json());
22 | app.use(cookieParser());
23 | app.use(express.static(path.join(__dirname, '../public')));
24 |
25 |
26 |
27 | /* Using Routes */
28 | app.use('/api/auth', authRoutes);
29 | app.use('/api/chat', chatRoutes);
30 |
31 |
32 | app.get("*name", (req, res) => {
33 | res.sendFile(path.join(__dirname, '../public/index.html'));
34 | });
35 |
36 | module.exports = app;
--------------------------------------------------------------------------------
/Frontend/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 |
--------------------------------------------------------------------------------
/Frontend/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 |
--------------------------------------------------------------------------------
/Frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frontend",
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 | "@reduxjs/toolkit": "^2.2.7",
14 | "axios": "^1.11.0",
15 | "react": "^19.1.1",
16 | "react-dom": "^19.1.1",
17 | "react-redux": "^9.1.2",
18 | "react-router-dom": "^7.8.1",
19 | "socket.io-client": "^4.8.1"
20 | },
21 | "devDependencies": {
22 | "@eslint/js": "^9.33.0",
23 | "@types/react": "^19.1.10",
24 | "@types/react-dom": "^19.1.7",
25 | "@vitejs/plugin-react": "^5.0.0",
26 | "eslint": "^9.33.0",
27 | "eslint-plugin-react-hooks": "^5.2.0",
28 | "eslint-plugin-react-refresh": "^0.4.20",
29 | "globals": "^16.3.0",
30 | "vite": "^7.1.2"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Backend/src/services/vector.service.js:
--------------------------------------------------------------------------------
1 | // Import the Pinecone library
2 | const { Pinecone } = require('@pinecone-database/pinecone')
3 |
4 | // Initialize a Pinecone client with your API key
5 | const pc = new Pinecone({ apiKey: process.env.PINECONE_API_KEY });
6 |
7 | const cohortChatGptIndex = pc.Index('cohort-chat-gpt');
8 |
9 | async function createMemory({ vectors, metadata, messageId }) {
10 | await cohortChatGptIndex.upsert([ {
11 | id: messageId,
12 | values: vectors,
13 | metadata
14 | } ])
15 | }
16 |
17 |
18 | async function queryMemory({ queryVector, limit = 5, metadata }) {
19 |
20 | const data = await cohortChatGptIndex.query({
21 | vector: queryVector,
22 | topK: limit,
23 | filter: metadata ? metadata : undefined,
24 | includeMetadata: true
25 | })
26 |
27 | return data.matches
28 |
29 | }
30 |
31 | module.exports = { createMemory, queryMemory }
--------------------------------------------------------------------------------
/Frontend/src/components/chat/ChatSidebar.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './ChatSidebar.css';
3 |
4 |
5 | const ChatSidebar = ({ chats, activeChatId, onSelectChat, onNewChat, open }) => {
6 |
7 |
8 |
9 | return (
10 |
28 | );
29 | };
30 |
31 | export default ChatSidebar;
32 |
--------------------------------------------------------------------------------
/Backend/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Frontend/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Backend/src/controllers/chat.controller.js:
--------------------------------------------------------------------------------
1 | const chatModel = require('../models/chat.model');
2 | const messageModel = require('../models/message.model');
3 |
4 |
5 | async function createChat(req, res) {
6 |
7 | const { title } = req.body;
8 | const user = req.user;
9 |
10 | const chat = await chatModel.create({
11 | user: user._id,
12 | title
13 | });
14 |
15 | res.status(201).json({
16 | message: "Chat created successfully",
17 | chat: {
18 | _id: chat._id,
19 | title: chat.title,
20 | lastActivity: chat.lastActivity,
21 | user: chat.user
22 | }
23 | });
24 |
25 | }
26 |
27 | async function getChats(req, res) {
28 | const user = req.user;
29 |
30 | const chats = await chatModel.find({ user: user._id });
31 |
32 | res.status(200).json({
33 | message: "Chats retrieved successfully",
34 | chats: chats.map(chat => ({
35 | _id: chat._id,
36 | title: chat.title,
37 | lastActivity: chat.lastActivity,
38 | user: chat.user
39 | }))
40 | });
41 | }
42 |
43 | async function getMessages(req, res) {
44 |
45 | const chatId = req.params.id;
46 |
47 | const messages = await messageModel.find({ chat: chatId }).sort({ createdAt: 1 });
48 |
49 | res.status(200).json({
50 | message: "Messages retrieved successfully",
51 | messages: messages
52 | })
53 |
54 | }
55 |
56 | module.exports = {
57 | createChat,
58 | getChats,
59 | getMessages
60 | };
--------------------------------------------------------------------------------
/Frontend/src/components/chat/ChatMobileBar.css:
--------------------------------------------------------------------------------
1 | /* Mobile top bar (hidden on desktop) */
2 | .chat-mobile-bar {
3 | position: fixed;
4 | top: 0;
5 | left: 0;
6 | right: 0;
7 | min-height: 52px;
8 | display: flex;
9 | align-items: center;
10 | gap: var(--space-4);
11 | padding: env(safe-area-inset-top, 0) var(--space-4) 0 var(--space-4);
12 | border-bottom: 1px solid var(--color-border);
13 | background: rgba(5, 5, 5, 0.9);
14 | backdrop-filter: blur(10px);
15 | z-index: 30;
16 | box-sizing: border-box;
17 | }
18 |
19 | .chat-app-title {
20 | margin: 0;
21 | font-size: 1.1rem;
22 | font-weight: var(--font-weight-medium);
23 | flex: 1;
24 | text-align: center;
25 | pointer-events: none;
26 | }
27 |
28 | .chat-icon-btn {
29 | background: #0d0d0d;
30 | border: 1px solid #1e1e1e;
31 | padding: 8px 14px;
32 | border-radius: 10px;
33 | font: inherit;
34 | cursor: pointer;
35 | display: inline-flex;
36 | align-items: center;
37 | justify-content: center;
38 | gap: 6px;
39 | color: #d0d0d0;
40 | flex-shrink: 0;
41 | }
42 |
43 | .chat-icon-btn:hover {
44 | background: #181818;
45 | color: #ffffff;
46 | }
47 |
48 | /* Very small widths: reduce horizontal padding to avoid wrapping/overflow */
49 | @media (max-width:480px) {
50 | .chat-mobile-bar {
51 | gap: 8px;
52 | padding: env(safe-area-inset-top, 0) 10px 0 10px;
53 | }
54 |
55 | .chat-icon-btn {
56 | padding: 8px 10px;
57 | }
58 |
59 | .chat-app-title {
60 | font-size: 1rem;
61 | }
62 | }
63 |
64 | /* Hide on desktop */
65 | @media (min-width:960px) {
66 | .chat-mobile-bar {
67 | display: none;
68 | }
69 | }
--------------------------------------------------------------------------------
/Frontend/src/styles/theme.css:
--------------------------------------------------------------------------------
1 | /* CSS Variable Theme Tokens (light + dark) */
2 | /* Keep ONLY variables here; structural styles go elsewhere */
3 |
4 | :root {
5 | /* Palette */
6 | --color-bg: #ffffff;
7 | --color-bg-alt: #f5f7fa;
8 | --color-surface: #ffffff;
9 | --color-border: #d0d7de;
10 | --color-text: #111827;
11 | --color-text-muted: #5f6b7a;
12 | --color-primary: #2563eb;
13 | --color-primary-hover: #1d4ed8;
14 | --color-danger: #dc2626;
15 | --color-focus-ring: 0 0 0 3px rgba(37, 99, 235, 0.4);
16 |
17 | /* Elevation */
18 | --shadow-xs: 0 1px 2px rgba(0,0,0,0.04);
19 | --shadow-sm: 0 1px 3px rgba(0,0,0,0.08), 0 1px 2px rgba(0,0,0,0.04);
20 |
21 | /* Typography */
22 | --font-sans: system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif;
23 | --text-sm: 0.875rem;
24 | --text-base: 1rem;
25 | --text-lg: 1.125rem;
26 | --font-weight-normal: 400;
27 | --font-weight-medium: 500;
28 | --font-weight-semibold: 600;
29 |
30 | /* Sizing & Layout */
31 | --radius-sm: 4px;
32 | --radius-md: 8px;
33 | --radius-full: 999px;
34 | --space-1: 0.25rem;
35 | --space-2: 0.5rem;
36 | --space-3: 0.75rem;
37 | --space-4: 1rem;
38 | --space-5: 1.25rem;
39 | --space-6: 1.5rem;
40 | --space-8: 2rem;
41 | --transition-fast: 120ms cubic-bezier(.4,0,.2,1);
42 | }
43 |
44 | /* Dark Theme (system preference) */
45 | @media (prefers-color-scheme: dark) {
46 | :root {
47 | --color-bg: #0f172a;
48 | --color-bg-alt: #1e293b;
49 | --color-surface: #1e293b;
50 | --color-border: #334155;
51 | --color-text: #f1f5f9;
52 | --color-text-muted: #94a3b8;
53 | --color-primary: #3b82f6;
54 | --color-primary-hover: #2563eb;
55 | --color-danger: #f87171;
56 | --color-focus-ring: 0 0 0 3px rgba(59,130,246,0.45);
57 | --shadow-xs: 0 1px 2px rgba(0,0,0,0.6);
58 | --shadow-sm: 0 1px 3px rgba(0,0,0,0.7), 0 1px 2px rgba(0,0,0,0.5);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Backend/src/controllers/auth.controller.js:
--------------------------------------------------------------------------------
1 | const userModel = require('../models/user.model');
2 | const bcrypt = require('bcryptjs');
3 | const jwt = require('jsonwebtoken');
4 |
5 |
6 | async function registerUser(req, res) {
7 |
8 | const { fullName: { firstName, lastName }, email, password } = req.body;
9 |
10 | const isUserAlreadyExists = await userModel.findOne({ email })
11 |
12 | if (isUserAlreadyExists) {
13 | res.status(400).json({ message: "User already exists" });
14 | }
15 |
16 |
17 | const hashPassword = await bcrypt.hash(password, 10);
18 |
19 |
20 | const user = await userModel.create({
21 | fullName: {
22 | firstName, lastName
23 | },
24 | email,
25 | password: hashPassword
26 | })
27 |
28 | const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET)
29 |
30 |
31 | res.cookie("token", token)
32 |
33 |
34 | res.status(201).json({
35 | message: "User registered successfully",
36 | user: {
37 | email: user.email,
38 | _id: user._id,
39 | fullName: user.fullName
40 | }
41 | })
42 | }
43 |
44 | async function loginUser(req, res) {
45 |
46 | const { email, password } = req.body;
47 |
48 | const user = await userModel.findOne({
49 | email
50 | })
51 |
52 | if (!user) {
53 | return res.status(400).json({ message: "Invalid email or password" });
54 | }
55 |
56 | const isPasswordValid = await bcrypt.compare(password, user.password);
57 |
58 |
59 | if (!isPasswordValid) {
60 | return res.status(400).json({ message: "Invalid email or password" });
61 | }
62 |
63 | const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET);
64 |
65 |
66 | res.cookie("token", token);
67 |
68 |
69 | res.status(200).json({
70 | message: "user logged in successfully",
71 | user: {
72 | email: user.email,
73 | _id: user._id,
74 | fullName: user.fullName
75 | }
76 | })
77 |
78 | }
79 |
80 |
81 | module.exports = {
82 | registerUser,
83 | loginUser
84 | }
--------------------------------------------------------------------------------
/Frontend/src/components/chat/ChatSidebar.css:
--------------------------------------------------------------------------------
1 | /* Sidebar */
2 | .chat-sidebar { width:250px; flex-shrink:0; border-right:1px solid var(--color-border); background: var(--color-surface); display:flex; flex-direction:column; position:fixed; top:0; bottom:0; left:-270px; z-index:40; transition: transform var(--transition-fast); padding-top:52px; backdrop-filter: blur(10px); }
3 | .chat-sidebar.open { transform: translateX(270px); }
4 | @media (min-width:960px) { .chat-sidebar { position:static; transform:none; left:0; padding-top:0; } }
5 | .sidebar-header { display:flex; align-items:center; justify-content:space-between; padding: var(--space-4); border-bottom:1px solid var(--color-border); gap:8px; }
6 | .sidebar-header h2 { margin:0; font-size:1rem; font-weight: var(--font-weight-medium); }
7 | .small-btn { font: inherit; background:#111; color:#fafafa; border:1px solid #252525; border-radius:8px; padding:6px 12px; cursor:pointer; display:inline-flex; align-items:center; gap:6px; font-size:0.75rem; font-weight:500; letter-spacing:0.05em; text-transform:uppercase; }
8 | .small-btn:hover { background:#181818; }
9 | .chat-list { display:flex; flex-direction:column; gap:2px; padding: var(--space-3); overflow-y:auto; }
10 | .chat-list-item { text-align:left; background:#0d0d0d; border:1px solid #1c1c1c; padding: var(--space-3) var(--space-4); border-radius:12px; cursor:pointer; display:flex; flex-direction:column; gap:2px; font: inherit; position:relative; transition: background var(--transition-fast), border-color var(--transition-fast); }
11 | .chat-list-item.active { border-color:#ffffff; box-shadow:0 0 0 1px #ffffff; }
12 | .chat-list-item:hover { background:#151515; }
13 | .chat-list-item .title-line { font-size: var(--text-sm); font-weight: var(--font-weight-medium); line-height:1.3; }
14 | .chat-list-item .meta-line { font-size:0.65rem; color: var(--color-text-muted); }
15 | .empty-hint { margin: var(--space-4); font-size: var(--text-sm); color: var(--color-text-muted); }
16 | /* Sidebar backdrop */
17 | .sidebar-backdrop { position:fixed; inset:0; background: rgba(0,0,0,0.35); border:none; padding:0; margin:0; cursor:pointer; z-index:35; }
18 | @media (min-width:960px) { .sidebar-backdrop { display:none; } }
19 |
--------------------------------------------------------------------------------
/Frontend/src/components/chat/ChatComposer.jsx:
--------------------------------------------------------------------------------
1 | import React, { useCallback, useRef, useLayoutEffect } from 'react';
2 | import './ChatComposer.css';
3 |
4 | // NOTE: Public API (props) kept identical for drop-in upgrade
5 | const ChatComposer = ({ input, setInput, onSend, isSending }) => {
6 | const textareaRef = useRef(null);
7 |
8 | // Auto-grow textarea height up to max-height
9 | useLayoutEffect(() => {
10 | const el = textareaRef.current;
11 | if (!el) return;
12 | el.style.height = 'auto';
13 | el.style.height = Math.min(el.scrollHeight, 320) + 'px';
14 | }, [input]);
15 |
16 | const handleKeyDown = useCallback((e) => {
17 | if (e.key === 'Enter' && !e.shiftKey) {
18 | e.preventDefault();
19 | if (input.trim()) onSend();
20 | }
21 | }, [onSend, input]);
22 |
23 | return (
24 |
56 | );
57 | };
58 |
59 | export default ChatComposer;
60 |
--------------------------------------------------------------------------------
/Frontend/src/pages/Login.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { Link,useNavigate } from 'react-router-dom';
3 | import axios from 'axios';
4 |
5 |
6 | const Login = () => {
7 | const [ form, setForm ] = useState({ email: '', password: '' });
8 | const [ submitting, setSubmitting ] = useState(false);
9 | const navigate = useNavigate();
10 |
11 |
12 | function handleChange(e) {
13 | const { name, value } = e.target;
14 | setForm({ ...form, [name]: value });
15 | }
16 |
17 | async function handleSubmit(e) {
18 | e.preventDefault();
19 | setSubmitting(true);
20 |
21 |
22 | console.log(form);
23 |
24 | axios.post("https://cohort-1-project-chat-gpt.onrender.com/api/auth/login", {
25 | email: form.email,
26 | password: form.password
27 | },
28 | {
29 | withCredentials: true
30 | }
31 | ).then((res) => {
32 | console.log(res);
33 | navigate("/");
34 | }).catch((err) => {
35 | console.error(err);
36 | }).finally(() => {
37 | setSubmitting(false);
38 | });
39 |
40 | }
41 |
42 | return (
43 |
44 |
45 |
49 |
62 |
Need an account? Create one
63 |
64 |
65 | );
66 | };
67 |
68 | export default Login;
69 |
70 |
--------------------------------------------------------------------------------
/Frontend/src/store/chatSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice, nanoid } from '@reduxjs/toolkit';
2 |
3 | // helpers
4 | const createEmptyChat = (title) => ({ id: nanoid(), title: title || 'New Chat', messages: [] });
5 |
6 | const chatSlice = createSlice({
7 | name: 'chat',
8 | initialState: {
9 | chats: [],
10 | activeChatId: null,
11 | isSending: false,
12 | input: ''
13 | },
14 | reducers: {
15 | ensureInitialChat(state) {
16 | if (state.chats.length === 0) {
17 | const chat = createEmptyChat();
18 | state.chats.unshift(chat);
19 | state.activeChatId = chat.id;
20 | }
21 | },
22 | startNewChat: {
23 | reducer(state, action) {
24 | const { _id, title } = action.payload;
25 | state.chats.unshift({ _id, title: title || 'New Chat', messages: [] });
26 | state.activeChatId = _id;
27 | }
28 | },
29 | selectChat(state, action) {
30 | state.activeChatId = action.payload;
31 | },
32 | setInput(state, action) {
33 | state.input = action.payload;
34 | },
35 | sendingStarted(state) {
36 | state.isSending = true;
37 | },
38 | sendingFinished(state) {
39 | state.isSending = false;
40 | },
41 | setChats(state, action) {
42 | state.chats = action.payload;
43 | },
44 | addUserMessage: {
45 | reducer(state, action) {
46 | const { chatId, message } = action.payload;
47 | const chat = state.chats.find(c => c.id === chatId);
48 | if (!chat) return;
49 | if (chat.messages.length === 0) {
50 | chat.title = message.content.slice(0, 40) + (message.content.length > 40 ? '…' : '');
51 | }
52 | chat.messages.push(message);
53 | },
54 | prepare(chatId, content) {
55 | return { payload: { chatId, message: { id: nanoid(), role: 'user', content, ts: Date.now() } } };
56 | }
57 | },
58 | addAIMessage: {
59 | reducer(state, action) {
60 | const { chatId, message } = action.payload;
61 | const chat = state.chats.find(c => c.id === chatId);
62 | if (!chat) return;
63 | chat.messages.push(message);
64 | },
65 | prepare(chatId, content, error = false) {
66 | return { payload: { chatId, message: { id: nanoid(), role: 'ai', content, ts: Date.now(), ...(error ? { error: true } : {}) } } };
67 | }
68 | }
69 | }
70 | });
71 |
72 | export const {
73 | ensureInitialChat,
74 | startNewChat,
75 | selectChat,
76 | setInput,
77 | sendingStarted,
78 | sendingFinished,
79 | addUserMessage,
80 | addAIMessage,
81 | setChats
82 | } = chatSlice.actions;
83 |
84 | export default chatSlice.reducer;
85 |
--------------------------------------------------------------------------------
/Frontend/src/components/chat/ChatMessages.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef } from 'react';
2 | import './ChatMessages.css';
3 |
4 |
5 | const ChatMessages = ({ messages, isSending }) => {
6 | const bottomRef = useRef(null);
7 | useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages.length, isSending]);
8 | return (
9 |
10 | {messages.map((m,index) => (
11 |
12 |
{m.type === 'user' ? 'You' : 'AI'}
13 |
{m.content}
14 |
15 |
18 | {m.role === 'ai' && (
19 | <>
20 |
23 |
26 |
29 |
32 | >
33 | )}
34 |
35 |
36 | ))}
37 | {isSending && (
38 |
39 |
AI
40 |
41 |
42 |
43 |
44 | )}
45 |
46 |
47 | );
48 | };
49 |
50 | export default ChatMessages;
51 |
--------------------------------------------------------------------------------
/Frontend/src/components/chat/ChatComposer.css:
--------------------------------------------------------------------------------
1 | /* === ChatGPT-like bottom composer === */
2 | /* Centered, max-width column, floating pill with subtle border */
3 |
4 | .composer {
5 | position: sticky; /* stays above scroll end */
6 | bottom: 0;
7 | width: 100%;
8 | padding: 24px 0 32px; /* vertical breathing room */
9 | display: flex;
10 | justify-content: center;
11 | background: linear-gradient(to top, rgba(0,0,0,.85), rgba(0,0,0,0));
12 | backdrop-filter: blur(12px);
13 | }
14 |
15 | .composer-surface {
16 | display: flex;
17 | align-items: flex-end;
18 | gap: 8px;
19 | max-width: 820px; /* ChatGPT input width vibes */
20 | width: 100%;
21 | margin: 0 32px;
22 | background: #1f1f20;
23 | border: 1px solid #3a3a3c;
24 | border-radius: 24px;
25 | padding: 12px 14px 14px 18px; /* top tighter than bottom for hint room */
26 | position: relative;
27 | transition: border-color .15s, background-color .15s, box-shadow .15s;
28 | }
29 |
30 | .composer-surface:focus-within {
31 | background: #232324;
32 | border-color: #565759;
33 | box-shadow: 0 0 0 1px #565759, 0 0 0 4px rgba(86,87,89,.25);
34 | }
35 |
36 | .composer-field { flex: 1; position: relative; }
37 |
38 | .composer-input {
39 | width: 100%;
40 | resize: none;
41 | border: 0;
42 | outline: none;
43 | background: transparent;
44 | color: #f5f5f5;
45 | font: inherit;
46 | line-height: 1.5;
47 | max-height: 260px;
48 | padding: 0 0 18px 0; /* space for hint overlay */
49 | }
50 |
51 | .composer-input::placeholder { color: #8d8d91; }
52 |
53 | .composer-hint {
54 | position: absolute;
55 | left: 2px;
56 | bottom: 2px;
57 | font-size: 11px;
58 | color: #5f6165;
59 | pointer-events: none;
60 | user-select: none;
61 | line-height: 1.1;
62 | font-weight: 500;
63 | }
64 |
65 | /* Icon-only circular send button */
66 | .send-btn.icon-btn {
67 | --size: 40px;
68 | width: var(--size);
69 | height: var(--size);
70 | border-radius: 50%;
71 | display: inline-flex;
72 | align-items: center;
73 | justify-content: center;
74 | background: #3a3a3c;
75 | border: 1px solid #525255;
76 | color: #f1f1f2;
77 | cursor: pointer;
78 | transition: background-color .15s, border-color .15s, transform .15s;
79 | flex-shrink: 0;
80 | }
81 |
82 | .send-btn.icon-btn:hover:not(:disabled) { background:#4a4a4d; }
83 | .send-btn.icon-btn:active:not(:disabled) { background:#343436; transform:translateY(1px); }
84 | .send-btn.icon-btn:disabled { opacity:.35; cursor: default; }
85 | .send-btn.icon-btn:focus-visible { outline:none; box-shadow:0 0 0 2px #fff,0 0 0 4px #000; }
86 |
87 | .send-icon { display:inline-flex; }
88 |
89 | /* Slide arrow a tad */
90 | .send-btn.icon-btn:hover:not(:disabled) .send-icon { transform: translateX(1px); }
91 | .send-icon svg { transition: transform .15s; }
92 |
93 | /* Compact adjustments for very narrow screens */
94 | @media (max-width:600px) {
95 | .composer { padding: 16px 0 26px; }
96 | .composer-surface { margin:0 12px; border-radius:20px; padding:10px 12px 12px 16px; }
97 | .send-btn.icon-btn { --size:36px; }
98 | }
99 |
100 | @media (max-width:420px) {
101 | .composer-hint { display:none; }
102 | .composer-input { padding-bottom:0; }
103 | }
104 |
105 | @media (prefers-reduced-motion: reduce) {
106 | .send-btn.icon-btn, .send-icon svg { transition: none; }
107 | }
--------------------------------------------------------------------------------
/Frontend/src/components/chat/ChatMessages.css:
--------------------------------------------------------------------------------
1 | /* Container & flow */
2 | .messages {
3 | flex: 1;
4 | width: 100%;
5 | overflow-y: auto;
6 | display: flex;
7 | flex-direction: column;
8 | gap: var(--space-5);
9 | max-width: 820px;
10 | }
11 |
12 | .messages::-webkit-scrollbar{
13 | display: none;
14 | }
15 |
16 | .msg {
17 | display: flex;
18 | flex-direction: column;
19 | max-width: 780px;
20 | position: relative;
21 | }
22 |
23 | .msg-user {
24 | align-self: flex-end;
25 | }
26 |
27 | .msg-role {
28 | font-size: 0.65rem;
29 | text-transform: uppercase;
30 | letter-spacing: 0.05em;
31 | color: var(--color-text-muted);
32 | margin-bottom: 4px;
33 | font-weight: 600;
34 | }
35 |
36 | /* Bubble styling refined */
37 | .msg-bubble {
38 | padding: var(--space-4) var(--space-5);
39 | border: 1px solid var(--color-border);
40 | background: var(--color-bg-alt);
41 | border-radius: 14px;
42 | line-height: 1.5;
43 | white-space: pre-wrap;
44 | word-wrap: break-word;
45 | font-size: var(--text-sm);
46 | }
47 |
48 | .msg-user .msg-bubble {
49 | background: linear-gradient(180deg, #1f1f1f, #161616);
50 | color: #fafafa;
51 | border: 1px solid #2a2a2a;
52 | }
53 |
54 | .minimal .msg-user .msg-bubble {
55 | background: #111;
56 | border-color: #2a2a2a;
57 | }
58 |
59 | .msg-ai .msg-bubble {
60 | background: #0d0d0d;
61 | border-color: #1e1e1e;
62 | }
63 |
64 | .msg-ai.pending .msg-bubble {
65 | display: inline-flex;
66 | gap: 6px;
67 | }
68 |
69 | .msg-error .msg-bubble {
70 | border-color: var(--color-danger);
71 | color: var(--color-danger);
72 | }
73 |
74 | /* Actions bar shown on hover / focus */
75 | .msg-actions {
76 | display: flex;
77 | align-items: center;
78 | gap: 6px;
79 | margin-top: 8px;
80 | opacity: 0;
81 | pointer-events: none;
82 | transition: opacity var(--transition-fast);
83 | }
84 |
85 | .msg:hover .msg-actions,
86 | .msg:focus-within .msg-actions {
87 | opacity: 1;
88 | pointer-events: auto;
89 | }
90 |
91 | .msg-actions button {
92 | width: 30px;
93 | height: 30px;
94 | background: #0d0d0d;
95 | border: 1px solid #1e1e1e;
96 | display: inline-flex;
97 | align-items: center;
98 | justify-content: center;
99 | border-radius: 8px;
100 | cursor: pointer;
101 | color: #6a6a6a;
102 | padding: 0;
103 | }
104 |
105 | .msg-actions button:hover {
106 | background: #151515;
107 | color: #ffffff;
108 | }
109 |
110 | .msg-actions button:focus-visible {
111 | outline: 2px solid #ffffff;
112 | outline-offset: 2px;
113 | }
114 |
115 | .msg-actions svg {
116 | width: 16px;
117 | height: 16px;
118 | stroke-width: 1.75;
119 | }
120 |
121 | /* Subtle fade in for new AI messages */
122 | .msg-ai .msg-bubble {
123 | animation: fadeIn .25s ease;
124 | }
125 |
126 | @keyframes fadeIn {
127 | from {
128 | opacity: 0;
129 | transform: translateY(4px);
130 | }
131 |
132 | to {
133 | opacity: 1;
134 | transform: translateY(0);
135 | }
136 | }
137 |
138 | /* Typing dots */
139 | .typing-dots span {
140 | width: 6px;
141 | height: 6px;
142 | background: currentColor;
143 | opacity: .6;
144 | border-radius: 50%;
145 | animation: blink 1s infinite ease-in-out;
146 | }
147 |
148 | .typing-dots span:nth-child(2) {
149 | animation-delay: .2s;
150 | }
151 |
152 | .typing-dots span:nth-child(3) {
153 | animation-delay: .4s;
154 | }
155 |
156 | @keyframes blink {
157 |
158 | 0%,
159 | 80%,
160 | 100% {
161 | opacity: .2;
162 | }
163 |
164 | 40% {
165 | opacity: 1;
166 | }
167 | }
--------------------------------------------------------------------------------
/Frontend/src/pages/Register.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { Link, useNavigate } from 'react-router-dom';
3 | import axios from 'axios';
4 |
5 | const Register = () => {
6 | const [ form, setForm ] = useState({ email: '', firstname: '', lastname: '', password: '' });
7 | const [ submitting, setSubmitting ] = useState(false);
8 | const navigate = useNavigate();
9 |
10 |
11 | function handleChange(e) {
12 | const { name, value } = e.target;
13 | setForm(f => ({ ...f, [ name ]: value }));
14 | }
15 |
16 | async function handleSubmit(e) {
17 | e.preventDefault();
18 | setSubmitting(true);
19 | console.log(form);
20 |
21 | axios.post("https://cohort-1-project-chat-gpt.onrender.com/api/auth/register", {
22 | email: form.email,
23 | fullName: {
24 | firstName: form.firstname,
25 | lastName: form.lastname
26 | },
27 | password: form.password
28 | }, {
29 | withCredentials: true
30 | }).then((res) => {
31 | console.log(res);
32 | navigate("/");
33 | }).catch((err) => {
34 | console.error(err);
35 | alert('Registration failed (placeholder)');
36 | })
37 |
38 | try {
39 | // Placeholder: integrate real registration logic / API call.
40 |
41 | } catch (err) {
42 | console.error(err);
43 | } finally {
44 | setSubmitting(false);
45 | }
46 | }
47 |
48 | return (
49 |
50 |
51 |
55 |
78 |
Already have an account? Sign in
79 |
80 |
81 | );
82 | };
83 |
84 | export default Register;
85 |
86 |
--------------------------------------------------------------------------------
/Frontend/src/assets/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Frontend/src/components/chat/ChatLayout.css:
--------------------------------------------------------------------------------
1 | /* Base layout */
2 | .chat-layout {
3 | display: flex;
4 | height: 100dvh;
5 | background: var(--color-bg);
6 | font-size: var(--text-base);
7 | }
8 |
9 | .chat-main {
10 | flex: 1;
11 | display: flex;
12 | flex-direction: column;
13 | align-items: center;
14 | height: 100dvh;
15 | padding-top: calc(52px + env(safe-area-inset-top, 0));
16 | position: relative;
17 | }
18 |
19 | @media (min-width: 960px) {
20 | .chat-main {
21 | padding-top: 0;
22 | }
23 | }
24 |
25 | @media (min-width: 960px) {
26 | .chat-layout {
27 | flex-direction: row;
28 | }
29 | }
30 |
31 | @media (max-width: 959px) {
32 | .chat-layout {
33 | flex-direction: column;
34 | }
35 | }
36 |
37 | /* Minimal monochrome variant (applied when parent has .minimal) */
38 | .chat-layout.minimal {
39 | --color-bg: #000;
40 | --color-bg-alt: #0d0d0d;
41 | --color-surface: #050505;
42 | --color-border: #1e1e1e;
43 | --color-text: #f5f5f5;
44 | --color-text-muted: #7a7a7a;
45 | --color-accent: #fff;
46 | }
47 |
48 | .chat-layout.minimal {
49 | background: linear-gradient(180deg, #000 0%, #050505 60%, #050505 100%);
50 | color: var(--color-text);
51 | }
52 |
53 | .chat-layout.minimal .chat-main {
54 | background: transparent;
55 | }
56 |
57 | .chat-layout.minimal .chat-mobile-bar {
58 | background: #000;
59 | border-color: #1e1e1e;
60 | }
61 |
62 | .chat-layout.minimal .chat-icon-btn {
63 | background: #0d0d0d;
64 | border-color: #1f1f1f;
65 | color: var(--color-text);
66 | }
67 |
68 | .chat-layout.minimal .chat-icon-btn:hover {
69 | background: #141414;
70 | }
71 |
72 | .chat-layout.minimal .chat-sidebar {
73 | background: #000;
74 | border-color: #1e1e1e;
75 | }
76 |
77 | .chat-layout.minimal .sidebar-header {
78 | border-color: #1e1e1e;
79 | }
80 |
81 | .chat-layout.minimal .small-btn {
82 | background: #111;
83 | border-color: #2a2a2a;
84 | }
85 |
86 | .chat-layout.minimal .small-btn:hover {
87 | background: #181818;
88 | }
89 |
90 | .chat-layout.minimal .chat-list-item {
91 | background: #0d0d0d;
92 | border-color: #1a1a1a;
93 | }
94 |
95 | .chat-layout.minimal .chat-list-item:hover {
96 | background: #141414;
97 | }
98 |
99 | .chat-layout.minimal .chat-list-item.active {
100 | border-color: #fff;
101 | box-shadow: 0 0 0 1px #fff;
102 | }
103 |
104 | .chat-layout.minimal .msg-bubble {
105 | background: #0d0d0d;
106 | border-color: #1e1e1e;
107 | color: var(--color-text);
108 | }
109 |
110 | .chat-layout.minimal .msg-user .msg-bubble {
111 | background: #111;
112 | border-color: #2a2a2a;
113 | color: #f8f8f8;
114 | }
115 |
116 | .chat-layout.minimal .msg-role {
117 | color: #5a5a5a;
118 | }
119 |
120 | .chat-layout.minimal .msg-error .msg-bubble {
121 | border-color: #ff4d4d;
122 | color: #ff4d4d;
123 | }
124 |
125 | /* Welcome (empty state) */
126 | .chat-welcome {
127 | position: absolute;
128 | inset: 0;
129 | display: flex;
130 | flex-direction: column;
131 | align-items: center;
132 | justify-content: center;
133 | gap: 18px;
134 | pointer-events: none;
135 | text-align: center;
136 | }
137 |
138 | .chat-welcome h1 {
139 | font-size: 2.75rem;
140 | font-weight: 600;
141 | letter-spacing: -0.02em;
142 | margin: 0;
143 | background: linear-gradient(90deg, #fafafa, #5a5a5a);
144 | -webkit-background-clip: text;
145 | background-clip: text;
146 | color: transparent;
147 | }
148 |
149 | .chat-welcome p {
150 | margin: 0;
151 | font-size: 0.95rem;
152 | color: #6a6a6a;
153 | max-width: 420px;
154 | line-height: 1.4;
155 | }
156 |
157 | .chat-welcome .chip {
158 | background: #111;
159 | border: 1px solid #1f1f1f;
160 | padding: 6px 14px;
161 | border-radius: 999px;
162 | font-size: 0.75rem;
163 | font-weight: 500;
164 | color: #b5b5b5;
165 | }
166 |
167 | /* Scrollbar minimal styling (webkit) */
168 | .chat-layout.minimal .messages::-webkit-scrollbar {
169 | width: 10px;
170 | }
171 |
172 | .chat-layout.minimal .messages::-webkit-scrollbar-track {
173 | background: #000;
174 | }
175 |
176 | .chat-layout.minimal .messages::-webkit-scrollbar-thumb {
177 | background: #1e1e1e;
178 | border-radius: 6px;
179 | }
180 |
181 | .chat-layout.minimal .messages::-webkit-scrollbar-thumb:hover {
182 | background: #2a2a2a;
183 | }
--------------------------------------------------------------------------------
/Frontend/src/App.css:
--------------------------------------------------------------------------------
1 | @import url('./styles/theme.css');
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | html,
8 | body {
9 | height: 100%;
10 | }
11 |
12 | body {
13 | margin: 0;
14 | font-family: var(--font-sans);
15 | background: var(--color-bg);
16 | color: var(--color-text);
17 | -webkit-font-smoothing: antialiased;
18 | line-height: 1.5;
19 | color-scheme: light dark;
20 | /* hint native UI */
21 | }
22 |
23 | a {
24 | color: var(--color-primary);
25 | text-decoration: none;
26 | }
27 |
28 | a:hover {
29 | text-decoration: underline;
30 | }
31 |
32 | /* Layout helpers */
33 | .center-min-h-screen {
34 | min-height: 100dvh;
35 | display: flex;
36 | align-items: center;
37 | justify-content: center;
38 | padding: var(--space-6) var(--space-4);
39 | }
40 |
41 | .auth-card {
42 | width: 100%;
43 | max-width: 420px;
44 | background: var(--color-surface);
45 | border: 1px solid var(--color-border);
46 | border-radius: var(--radius-md);
47 | padding: clamp(var(--space-5), 5vw, var(--space-8));
48 | box-shadow: var(--shadow-sm);
49 | display: flex;
50 | flex-direction: column;
51 | gap: var(--space-5);
52 | }
53 |
54 | .auth-header {
55 | text-align: center;
56 | }
57 |
58 | .auth-header h1 {
59 | margin: 0 0 var(--space-2);
60 | font-size: 1.75rem;
61 | font-weight: var(--font-weight-semibold);
62 | }
63 |
64 | .auth-sub {
65 | margin: 0;
66 | font-size: var(--text-sm);
67 | color: var(--color-text-muted);
68 | }
69 |
70 | form.auth-form {
71 | display: flex;
72 | flex-direction: column;
73 | gap: var(--space-4);
74 | }
75 |
76 | form.auth-form .field-group {
77 | display: flex;
78 | flex-direction: column;
79 | gap: var(--space-2);
80 | }
81 |
82 | form.auth-form label {
83 | font-size: var(--text-sm);
84 | font-weight: var(--font-weight-medium);
85 | }
86 |
87 | form.auth-form input {
88 | font: inherit;
89 | padding: var(--space-3) var(--space-4);
90 | border: 1px solid var(--color-border);
91 | border-radius: var(--radius-sm);
92 | background: var(--color-bg-alt);
93 | color: var(--color-text);
94 | transition: border-color var(--transition-fast), background var(--transition-fast);
95 | }
96 |
97 | form.auth-form input:focus {
98 | outline: none;
99 | border-color: var(--color-primary);
100 | box-shadow: var(--color-focus-ring);
101 | background: var(--color-bg);
102 | }
103 |
104 | .grid-2 {
105 | display: grid;
106 | grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
107 | gap: var(--space-4);
108 | width: 100%;
109 | }
110 |
111 | form.auth-form .field-group input {
112 | width: 100%;
113 | }
114 |
115 | /* Ensure long placeholder / values don't overflow */
116 | .auth-card input {
117 | min-width: 0;
118 | }
119 |
120 | /* Tighten vertical rhythm slightly on narrow screens */
121 | @media (max-width: 380px) {
122 | .auth-card {
123 | padding: var(--space-6) var(--space-5);
124 | }
125 | }
126 |
127 | @media (max-width: 520px) {
128 | .grid-2 {
129 | grid-template-columns: 1fr;
130 | }
131 | }
132 |
133 | button.primary-btn {
134 | appearance: none;
135 | cursor: pointer;
136 | border: 1px solid var(--color-primary);
137 | background: var(--color-primary);
138 | color: #fff;
139 | font: inherit;
140 | font-weight: var(--font-weight-medium);
141 | padding: var(--space-3) var(--space-5);
142 | border-radius: var(--radius-sm);
143 | display: inline-flex;
144 | align-items: center;
145 | justify-content: center;
146 | gap: var(--space-2);
147 | transition: background var(--transition-fast), box-shadow var(--transition-fast);
148 | }
149 |
150 | button.primary-btn:hover {
151 | background: var(--color-primary-hover);
152 | }
153 |
154 | button.primary-btn:focus {
155 | outline: none;
156 | box-shadow: var(--color-focus-ring);
157 | }
158 |
159 | button.primary-btn:active {
160 | transform: translateY(1px);
161 | }
162 |
163 | button.primary-btn:disabled {
164 | opacity: .6;
165 | cursor: not-allowed;
166 | }
167 |
168 | .auth-alt {
169 | text-align: center;
170 | font-size: var(--text-sm);
171 | color: var(--color-text-muted);
172 | }
173 |
174 | .auth-alt a {
175 | font-weight: var(--font-weight-medium);
176 | }
177 |
178 | /* Theme toggle removed since system preference is used */
179 |
180 | /* Smooth theme transition */
181 | html {
182 | transition: background-color .3s, color .3s;
183 | }
184 |
185 | body,
186 | .auth-card,
187 | input,
188 | button {
189 | transition: background-color .3s, color .3s, border-color .3s;
190 | }
191 |
--------------------------------------------------------------------------------
/Backend/src/sockets/socket.server.js:
--------------------------------------------------------------------------------
1 | const { Server } = require("socket.io");
2 | const cookie = require("cookie")
3 | const jwt = require("jsonwebtoken");
4 | const userModel = require("../models/user.model");
5 | const aiService = require("../services/ai.service")
6 | const messageModel = require("../models/message.model");
7 | const { createMemory, queryMemory } = require("../services/vector.service")
8 |
9 |
10 | function initSocketServer(httpServer) {
11 |
12 | const io = new Server(httpServer, {
13 | cors: {
14 | origin: "http://localhost:5173",
15 | allowedHeaders: [ "Content-Type", "Authorization" ],
16 | credentials: true
17 | }
18 | })
19 |
20 | io.use(async (socket, next) => {
21 |
22 | const cookies = cookie.parse(socket.handshake.headers?.cookie || "");
23 |
24 | if (!cookies.token) {
25 | next(new Error("Authentication error: No token provided"));
26 | }
27 |
28 | try {
29 |
30 | const decoded = jwt.verify(cookies.token, process.env.JWT_SECRET);
31 |
32 | const user = await userModel.findById(decoded.id);
33 |
34 | socket.user = user
35 |
36 | next()
37 |
38 | } catch (err) {
39 | next(new Error("Authentication error: Invalid token"));
40 | }
41 |
42 | })
43 |
44 | io.on("connection", (socket) => {
45 | socket.on("ai-message", async (messagePayload) => {
46 | /* messagePayload = { chat:chatId,content:message text } */
47 | const [ message, vectors ] = await Promise.all([
48 | messageModel.create({
49 | chat: messagePayload.chat,
50 | user: socket.user._id,
51 | content: messagePayload.content,
52 | role: "user"
53 | }),
54 | aiService.generateVector(messagePayload.content),
55 | ])
56 |
57 | await createMemory({
58 | vectors,
59 | messageId: message._id,
60 | metadata: {
61 | chat: messagePayload.chat,
62 | user: socket.user._id,
63 | text: messagePayload.content
64 | }
65 | })
66 |
67 |
68 | const [ memory, chatHistory ] = await Promise.all([
69 |
70 | queryMemory({
71 | queryVector: vectors,
72 | limit: 3,
73 | metadata: {
74 | user: socket.user._id
75 | }
76 | }),
77 |
78 | messageModel.find({
79 | chat: messagePayload.chat
80 | }).sort({ createdAt: -1 }).limit(20).lean().then(messages => messages.reverse())
81 | ])
82 |
83 | const stm = chatHistory.map(item => {
84 | return {
85 | role: item.role,
86 | parts: [ { text: item.content } ]
87 | }
88 | })
89 |
90 | const ltm = [
91 | {
92 | role: "user",
93 | parts: [ {
94 | text: `
95 |
96 | these are some previous messages from the chat, use them to generate a response
97 |
98 | ${memory.map(item => item.metadata.text).join("\n")}
99 |
100 | ` } ]
101 | }
102 | ]
103 |
104 |
105 | const response = await aiService.generateResponse([ ...ltm, ...stm ])
106 |
107 |
108 |
109 |
110 | socket.emit('ai-response', {
111 | content: response,
112 | chat: messagePayload.chat
113 | })
114 |
115 | const [ responseMessage, responseVectors ] = await Promise.all([
116 | messageModel.create({
117 | chat: messagePayload.chat,
118 | user: socket.user._id,
119 | content: response,
120 | role: "model"
121 | }),
122 | aiService.generateVector(response)
123 | ])
124 |
125 | await createMemory({
126 | vectors: responseVectors,
127 | messageId: responseMessage._id,
128 | metadata: {
129 | chat: messagePayload.chat,
130 | user: socket.user._id,
131 | text: response
132 | }
133 | })
134 |
135 | })
136 |
137 | })
138 | }
139 |
140 |
141 | module.exports = initSocketServer;
--------------------------------------------------------------------------------
/Backend/src/services/ai.service.js:
--------------------------------------------------------------------------------
1 | const { GoogleGenAI } = require("@google/genai")
2 |
3 |
4 | const ai = new GoogleGenAI({})
5 |
6 |
7 | async function generateResponse(content) {
8 |
9 | const response = await ai.models.generateContent({
10 | model: "gemini-2.0-flash",
11 | contents: content,
12 | config: {
13 | temperature: 0.7,
14 | systemInstruction: `
15 | Aurora Be a helpful, accurate AI assistant with a playful, upbeat vibe. Empower users to build, learn, and create fast. Friendly, concise, Gen-Z energy without slang overload. Use plain language. Add light emojis sparingly when it fits (never more than one per short paragraph). Honesty, clarity, practicality, user-first. Admit limits. Prefer actionable steps over theory. Playful but professional. Supportive, never condescending. Default to clear headings, short paragraphs, and minimal lists. Keep answers tight by default; expand only when asked. If the request is ambiguous, briefly state assumptions and proceed. Offer a one-line clarifying question only when necessary. Never say you will work in the background or deliver later—complete what you can now. Do not provide disallowed, harmful, or private information. Refuse clearly and offer safer alternatives. If unsure, say so and provide best-effort guidance or vetted sources. Do not invent facts, code, APIs, or prices. Think step-by-step internally; share only the useful outcome. Show calculations or assumptions when it helps the user. Start with a quick answer or summary. Follow with steps, examples, or code. End with a brief “Next steps” when relevant. Provide runnable, minimal code. Include file names when relevant. Explain key decisions with one-line comments. Prefer modern best practices. Use concrete examples tailored to the user’s context when known. Avoid generic filler. Never request or store sensitive personal data beyond what’s required. Avoid sharing credentials, tokens, or secrets. Don’t guarantee outcomes or timelines. No “I’ll keep working” statements. No purple prose. No excessive emojis. No walls of text unless explicitly requested. Use web browsing only when the answer likely changes over time (news, prices, laws, APIs, versions) or when citations are requested. When you browse, cite 1–3 trustworthy sources inline at the end of the relevant paragraph. If executing or generating files, include clear run instructions and dependencies. Provide download links when a file is produced.
16 |
17 |
18 | 1) State goal, 2) List prerequisites, 3) Give step-by-step commands/snippets, 4) Add a quick verification check, 5) Provide common pitfalls.
19 |
20 |
21 | Ask for minimal reproducible details (env, versions, error text). Offer a hypothesis → test → fix plan with one or two variants.
22 |
23 |
24 | Propose a lightweight plan with milestones and rough effort levels. Offer an MVP path first, then nice-to-haves.
25 |
26 |
27 | If a request is unsafe or disallowed: - Briefly explain why, - Offer a safe, closest-possible alternative, - Keep tone kind and neutral. Adapt examples, stack choices, and explanations to the user’s stated preferences and skill level. If unknown, default to modern, widely used tools.
28 |
29 | End with a small “Want me to tailor this further?” nudge when customization could help (e.g., specific stack, version, region).
30 |
31 |
32 | You are “Aurora”. Refer to yourself as Aurora when self-identifying. Do not claim real-world abilities or access you don’t have.
33 |
34 | `
35 | }
36 | })
37 |
38 | return response.text
39 |
40 | }
41 |
42 | async function generateVector(content) {
43 |
44 | const response = await ai.models.embedContent({
45 | model: "gemini-embedding-001",
46 | contents: content,
47 | config: {
48 | outputDimensionality: 768
49 | }
50 | })
51 |
52 | return response.embeddings[ 0 ].values
53 |
54 | }
55 |
56 |
57 | module.exports = {
58 | generateResponse,
59 | generateVector
60 | }
--------------------------------------------------------------------------------
/Frontend/src/pages/Home.jsx:
--------------------------------------------------------------------------------
1 | import React, { useCallback, useEffect, useState } from 'react';
2 | import { io } from "socket.io-client";
3 | import ChatMobileBar from '../components/chat/ChatMobileBar.jsx';
4 | import ChatSidebar from '../components/chat/ChatSidebar.jsx';
5 | import ChatMessages from '../components/chat/ChatMessages.jsx';
6 | import ChatComposer from '../components/chat/ChatComposer.jsx';
7 | import '../components/chat/ChatLayout.css';
8 | import { fakeAIReply } from '../components/chat/aiClient.js';
9 | import { useDispatch, useSelector } from 'react-redux';
10 | import axios from 'axios';
11 | import {
12 | ensureInitialChat,
13 | startNewChat,
14 | selectChat,
15 | setInput,
16 | sendingStarted,
17 | sendingFinished,
18 | addUserMessage,
19 | addAIMessage,
20 | setChats
21 | } from '../store/chatSlice.js';
22 |
23 | const Home = () => {
24 | const dispatch = useDispatch();
25 | const chats = useSelector(state => state.chat.chats);
26 | const activeChatId = useSelector(state => state.chat.activeChatId);
27 | const input = useSelector(state => state.chat.input);
28 | const isSending = useSelector(state => state.chat.isSending);
29 | const [ sidebarOpen, setSidebarOpen ] = React.useState(false);
30 | const [ socket, setSocket ] = useState(null);
31 |
32 | const activeChat = chats.find(c => c.id === activeChatId) || null;
33 |
34 | const [ messages, setMessages ] = useState([
35 | // {
36 | // type: 'user',
37 | // content: 'Hello, how can I help you today?'
38 | // },
39 | // {
40 | // type: 'ai',
41 | // content: 'Hi there! I need assistance with my account.'
42 | // }
43 | ]);
44 |
45 | const handleNewChat = async () => {
46 | // Prompt user for title of new chat, fallback to 'New Chat'
47 | let title = window.prompt('Enter a title for the new chat:', '');
48 | if (title) title = title.trim();
49 | if (!title) return
50 |
51 | const response = await axios.post("https://cohort-1-project-chat-gpt.onrender.com/api/chat", {
52 | title
53 | }, {
54 | withCredentials: true
55 | })
56 | getMessages(response.data.chat._id);
57 | dispatch(startNewChat(response.data.chat));
58 | setSidebarOpen(false);
59 | }
60 |
61 | // Ensure at least one chat exists initially
62 | useEffect(() => {
63 |
64 | axios.get("https://cohort-1-project-chat-gpt.onrender.com/api/chat", { withCredentials: true })
65 | .then(response => {
66 | dispatch(setChats(response.data.chats.reverse()));
67 | })
68 |
69 | const tempSocket = io("https://cohort-1-project-chat-gpt.onrender.com", {
70 | withCredentials: true,
71 | })
72 |
73 | tempSocket.on("ai-response", (messagePayload) => {
74 | console.log("Received AI response:", messagePayload);
75 |
76 | setMessages((prevMessages) => [ ...prevMessages, {
77 | type: 'ai',
78 | content: messagePayload.content
79 | } ]);
80 |
81 | dispatch(sendingFinished());
82 | });
83 |
84 | setSocket(tempSocket);
85 |
86 | }, []);
87 |
88 | const sendMessage = async () => {
89 |
90 | const trimmed = input.trim();
91 | console.log("Sending message:", trimmed);
92 | if (!trimmed || !activeChatId || isSending) return;
93 | dispatch(sendingStarted());
94 |
95 | const newMessages = [ ...messages, {
96 | type: 'user',
97 | content: trimmed
98 | } ];
99 |
100 | console.log("New messages:", newMessages);
101 |
102 | setMessages(newMessages);
103 | dispatch(setInput(''));
104 |
105 | socket.emit("ai-message", {
106 | chat: activeChatId,
107 | content: trimmed
108 | })
109 |
110 | // try {
111 | // const reply = await fakeAIReply(trimmed);
112 | // dispatch(addAIMessage(activeChatId, reply));
113 | // } catch {
114 | // dispatch(addAIMessage(activeChatId, 'Error fetching AI response.', true));
115 | // } finally {
116 | // dispatch(sendingFinished());
117 | // }
118 | }
119 |
120 | const getMessages = async (chatId) => {
121 |
122 | const response = await axios.get(`https://cohort-1-project-chat-gpt.onrender.com/api/chat/messages/${chatId}`, { withCredentials: true })
123 |
124 | console.log("Fetched messages:", response.data.messages);
125 |
126 | setMessages(response.data.messages.map(m => ({
127 | type: m.role === 'user' ? 'user' : 'ai',
128 | content: m.content
129 | })));
130 |
131 | }
132 |
133 |
134 | return (
135 |
136 |
setSidebarOpen(o => !o)}
138 | onNewChat={handleNewChat}
139 | />
140 | {
144 | dispatch(selectChat(id));
145 | setSidebarOpen(false);
146 | getMessages(id);
147 | }}
148 | onNewChat={handleNewChat}
149 | open={sidebarOpen}
150 | />
151 |
152 | {messages.length === 0 && (
153 |
154 |
Early Preview
155 |
ChatGPT Clone
156 |
Ask anything. Paste text, brainstorm ideas, or get quick explanations. Your chats stay in the sidebar so you can pick up where you left off.
157 |
158 | )}
159 |
160 | {
161 | activeChatId &&
162 | dispatch(setInput(v))}
165 | onSend={sendMessage}
166 | isSending={isSending}
167 | />}
168 |
169 | {sidebarOpen && (
170 |
177 | );
178 | };
179 |
180 | export default Home;
181 |
--------------------------------------------------------------------------------
/Backend/public/assets/index-DEPrTWc_.css:
--------------------------------------------------------------------------------
1 | :root{--color-bg: #ffffff;--color-bg-alt: #f5f7fa;--color-surface: #ffffff;--color-border: #d0d7de;--color-text: #111827;--color-text-muted: #5f6b7a;--color-primary: #2563eb;--color-primary-hover: #1d4ed8;--color-danger: #dc2626;--color-focus-ring: 0 0 0 3px rgba(37, 99, 235, .4);--shadow-xs: 0 1px 2px rgba(0,0,0,.04);--shadow-sm: 0 1px 3px rgba(0,0,0,.08), 0 1px 2px rgba(0,0,0,.04);--font-sans: system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif;--text-sm: .875rem;--text-base: 1rem;--text-lg: 1.125rem;--font-weight-normal: 400;--font-weight-medium: 500;--font-weight-semibold: 600;--radius-sm: 4px;--radius-md: 8px;--radius-full: 999px;--space-1: .25rem;--space-2: .5rem;--space-3: .75rem;--space-4: 1rem;--space-5: 1.25rem;--space-6: 1.5rem;--space-8: 2rem;--transition-fast: .12s cubic-bezier(.4,0,.2,1)}@media (prefers-color-scheme: dark){:root{--color-bg: #0f172a;--color-bg-alt: #1e293b;--color-surface: #1e293b;--color-border: #334155;--color-text: #f1f5f9;--color-text-muted: #94a3b8;--color-primary: #3b82f6;--color-primary-hover: #2563eb;--color-danger: #f87171;--color-focus-ring: 0 0 0 3px rgba(59,130,246,.45);--shadow-xs: 0 1px 2px rgba(0,0,0,.6);--shadow-sm: 0 1px 3px rgba(0,0,0,.7), 0 1px 2px rgba(0,0,0,.5)}}*{box-sizing:border-box}html,body{height:100%}body{margin:0;font-family:var(--font-sans);background:var(--color-bg);color:var(--color-text);-webkit-font-smoothing:antialiased;line-height:1.5;color-scheme:light dark}a{color:var(--color-primary);text-decoration:none}a:hover{text-decoration:underline}.center-min-h-screen{min-height:100dvh;display:flex;align-items:center;justify-content:center;padding:var(--space-6) var(--space-4)}.auth-card{width:100%;max-width:420px;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-md);padding:clamp(var(--space-5),5vw,var(--space-8));box-shadow:var(--shadow-sm);display:flex;flex-direction:column;gap:var(--space-5)}.auth-header{text-align:center}.auth-header h1{margin:0 0 var(--space-2);font-size:1.75rem;font-weight:var(--font-weight-semibold)}.auth-sub{margin:0;font-size:var(--text-sm);color:var(--color-text-muted)}form.auth-form{display:flex;flex-direction:column;gap:var(--space-4)}form.auth-form .field-group{display:flex;flex-direction:column;gap:var(--space-2)}form.auth-form label{font-size:var(--text-sm);font-weight:var(--font-weight-medium)}form.auth-form input{font:inherit;padding:var(--space-3) var(--space-4);border:1px solid var(--color-border);border-radius:var(--radius-sm);background:var(--color-bg-alt);color:var(--color-text);transition:border-color var(--transition-fast),background var(--transition-fast)}form.auth-form input:focus{outline:none;border-color:var(--color-primary);box-shadow:var(--color-focus-ring);background:var(--color-bg)}.grid-2{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--space-4);width:100%}form.auth-form .field-group input{width:100%}.auth-card input{min-width:0}@media (max-width: 380px){.auth-card{padding:var(--space-6) var(--space-5)}}@media (max-width: 520px){.grid-2{grid-template-columns:1fr}}button.primary-btn{appearance:none;cursor:pointer;border:1px solid var(--color-primary);background:var(--color-primary);color:#fff;font:inherit;font-weight:var(--font-weight-medium);padding:var(--space-3) var(--space-5);border-radius:var(--radius-sm);display:inline-flex;align-items:center;justify-content:center;gap:var(--space-2);transition:background var(--transition-fast),box-shadow var(--transition-fast)}button.primary-btn:hover{background:var(--color-primary-hover)}button.primary-btn:focus{outline:none;box-shadow:var(--color-focus-ring)}button.primary-btn:active{transform:translateY(1px)}button.primary-btn:disabled{opacity:.6;cursor:not-allowed}.auth-alt{text-align:center;font-size:var(--text-sm);color:var(--color-text-muted)}.auth-alt a{font-weight:var(--font-weight-medium)}html{transition:background-color .3s,color .3s}body,.auth-card,input,button{transition:background-color .3s,color .3s,border-color .3s}.chat-mobile-bar{position:fixed;top:0;left:0;right:0;min-height:52px;display:flex;align-items:center;gap:var(--space-4);padding:env(safe-area-inset-top,0) var(--space-4) 0 var(--space-4);border-bottom:1px solid var(--color-border);background:#050505e6;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);z-index:30;box-sizing:border-box}.chat-app-title{margin:0;font-size:1.1rem;font-weight:var(--font-weight-medium);flex:1;text-align:center;pointer-events:none}.chat-icon-btn{background:#0d0d0d;border:1px solid #1e1e1e;padding:8px 14px;border-radius:10px;font:inherit;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;gap:6px;color:#d0d0d0;flex-shrink:0}.chat-icon-btn:hover{background:#181818;color:#fff}@media (max-width:480px){.chat-mobile-bar{gap:8px;padding:env(safe-area-inset-top,0) 10px 0 10px}.chat-icon-btn{padding:8px 10px}.chat-app-title{font-size:1rem}}@media (min-width:960px){.chat-mobile-bar{display:none}}.chat-layout{display:flex;height:100dvh;background:var(--color-bg);font-size:var(--text-base)}.chat-main{flex:1;display:flex;flex-direction:column;align-items:center;height:100dvh;padding-top:calc(52px + env(safe-area-inset-top,0));position:relative}@media (min-width: 960px){.chat-main{padding-top:0}}@media (min-width: 960px){.chat-layout{flex-direction:row}}@media (max-width: 959px){.chat-layout{flex-direction:column}}.chat-layout.minimal{--color-bg: #000;--color-bg-alt: #0d0d0d;--color-surface: #050505;--color-border: #1e1e1e;--color-text: #f5f5f5;--color-text-muted: #7a7a7a;--color-accent: #fff}.chat-layout.minimal{background:linear-gradient(180deg,#000,#050505 60% 100%);color:var(--color-text)}.chat-layout.minimal .chat-main{background:transparent}.chat-layout.minimal .chat-mobile-bar{background:#000;border-color:#1e1e1e}.chat-layout.minimal .chat-icon-btn{background:#0d0d0d;border-color:#1f1f1f;color:var(--color-text)}.chat-layout.minimal .chat-icon-btn:hover{background:#141414}.chat-layout.minimal .chat-sidebar{background:#000;border-color:#1e1e1e}.chat-layout.minimal .sidebar-header{border-color:#1e1e1e}.chat-layout.minimal .small-btn{background:#111;border-color:#2a2a2a}.chat-layout.minimal .small-btn:hover{background:#181818}.chat-layout.minimal .chat-list-item{background:#0d0d0d;border-color:#1a1a1a}.chat-layout.minimal .chat-list-item:hover{background:#141414}.chat-layout.minimal .chat-list-item.active{border-color:#fff;box-shadow:0 0 0 1px #fff}.chat-layout.minimal .msg-bubble{background:#0d0d0d;border-color:#1e1e1e;color:var(--color-text)}.chat-layout.minimal .msg-user .msg-bubble{background:#111;border-color:#2a2a2a;color:#f8f8f8}.chat-layout.minimal .msg-role{color:#5a5a5a}.chat-layout.minimal .msg-error .msg-bubble{border-color:#ff4d4d;color:#ff4d4d}.chat-welcome{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:18px;pointer-events:none;text-align:center}.chat-welcome h1{font-size:2.75rem;font-weight:600;letter-spacing:-.02em;margin:0;background:linear-gradient(90deg,#fafafa,#5a5a5a);-webkit-background-clip:text;background-clip:text;color:transparent}.chat-welcome p{margin:0;font-size:.95rem;color:#6a6a6a;max-width:420px;line-height:1.4}.chat-welcome .chip{background:#111;border:1px solid #1f1f1f;padding:6px 14px;border-radius:999px;font-size:.75rem;font-weight:500;color:#b5b5b5}.chat-layout.minimal .messages::-webkit-scrollbar{width:10px}.chat-layout.minimal .messages::-webkit-scrollbar-track{background:#000}.chat-layout.minimal .messages::-webkit-scrollbar-thumb{background:#1e1e1e;border-radius:6px}.chat-layout.minimal .messages::-webkit-scrollbar-thumb:hover{background:#2a2a2a}.chat-sidebar{width:250px;flex-shrink:0;border-right:1px solid var(--color-border);background:var(--color-surface);display:flex;flex-direction:column;position:fixed;top:0;bottom:0;left:-270px;z-index:40;transition:transform var(--transition-fast);padding-top:52px;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.chat-sidebar.open{transform:translate(270px)}@media (min-width:960px){.chat-sidebar{position:static;transform:none;left:0;padding-top:0}}.sidebar-header{display:flex;align-items:center;justify-content:space-between;padding:var(--space-4);border-bottom:1px solid var(--color-border);gap:8px}.sidebar-header h2{margin:0;font-size:1rem;font-weight:var(--font-weight-medium)}.small-btn{font:inherit;background:#111;color:#fafafa;border:1px solid #252525;border-radius:8px;padding:6px 12px;cursor:pointer;display:inline-flex;align-items:center;gap:6px;font-size:.75rem;font-weight:500;letter-spacing:.05em;text-transform:uppercase}.small-btn:hover{background:#181818}.chat-list{display:flex;flex-direction:column;gap:2px;padding:var(--space-3);overflow-y:auto}.chat-list-item{text-align:left;background:#0d0d0d;border:1px solid #1c1c1c;padding:var(--space-3) var(--space-4);border-radius:12px;cursor:pointer;display:flex;flex-direction:column;gap:2px;font:inherit;position:relative;transition:background var(--transition-fast),border-color var(--transition-fast)}.chat-list-item.active{border-color:#fff;box-shadow:0 0 0 1px #fff}.chat-list-item:hover{background:#151515}.chat-list-item .title-line{font-size:var(--text-sm);font-weight:var(--font-weight-medium);line-height:1.3}.chat-list-item .meta-line{font-size:.65rem;color:var(--color-text-muted)}.empty-hint{margin:var(--space-4);font-size:var(--text-sm);color:var(--color-text-muted)}.sidebar-backdrop{position:fixed;inset:0;background:#00000059;border:none;padding:0;margin:0;cursor:pointer;z-index:35}@media (min-width:960px){.sidebar-backdrop{display:none}}.messages{flex:1;width:100%;overflow-y:auto;display:flex;flex-direction:column;gap:var(--space-5);max-width:820px}.messages::-webkit-scrollbar{display:none}.msg{display:flex;flex-direction:column;max-width:780px;position:relative}.msg-user{align-self:flex-end}.msg-role{font-size:.65rem;text-transform:uppercase;letter-spacing:.05em;color:var(--color-text-muted);margin-bottom:4px;font-weight:600}.msg-bubble{padding:var(--space-4) var(--space-5);border:1px solid var(--color-border);background:var(--color-bg-alt);border-radius:14px;line-height:1.5;white-space:pre-wrap;word-wrap:break-word;font-size:var(--text-sm)}.msg-user .msg-bubble{background:linear-gradient(180deg,#1f1f1f,#161616);color:#fafafa;border:1px solid #2a2a2a}.minimal .msg-user .msg-bubble{background:#111;border-color:#2a2a2a}.msg-ai .msg-bubble{background:#0d0d0d;border-color:#1e1e1e}.msg-ai.pending .msg-bubble{display:inline-flex;gap:6px}.msg-error .msg-bubble{border-color:var(--color-danger);color:var(--color-danger)}.msg-actions{display:flex;align-items:center;gap:6px;margin-top:8px;opacity:0;pointer-events:none;transition:opacity var(--transition-fast)}.msg:hover .msg-actions,.msg:focus-within .msg-actions{opacity:1;pointer-events:auto}.msg-actions button{width:30px;height:30px;background:#0d0d0d;border:1px solid #1e1e1e;display:inline-flex;align-items:center;justify-content:center;border-radius:8px;cursor:pointer;color:#6a6a6a;padding:0}.msg-actions button:hover{background:#151515;color:#fff}.msg-actions button:focus-visible{outline:2px solid #ffffff;outline-offset:2px}.msg-actions svg{width:16px;height:16px;stroke-width:1.75}.msg-ai .msg-bubble{animation:fadeIn .25s ease}@keyframes fadeIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.typing-dots span{width:6px;height:6px;background:currentColor;opacity:.6;border-radius:50%;animation:blink 1s infinite ease-in-out}.typing-dots span:nth-child(2){animation-delay:.2s}.typing-dots span:nth-child(3){animation-delay:.4s}@keyframes blink{0%,80%,to{opacity:.2}40%{opacity:1}}.composer{position:sticky;bottom:0;width:100%;padding:24px 0 32px;display:flex;justify-content:center;background:linear-gradient(to top,#000000d9,#0000);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}.composer-surface{display:flex;align-items:flex-end;gap:8px;max-width:820px;width:100%;margin:0 32px;background:#1f1f20;border:1px solid #3a3a3c;border-radius:24px;padding:12px 14px 14px 18px;position:relative;transition:border-color .15s,background-color .15s,box-shadow .15s}.composer-surface:focus-within{background:#232324;border-color:#565759;box-shadow:0 0 0 1px #565759,0 0 0 4px #56575940}.composer-field{flex:1;position:relative}.composer-input{width:100%;resize:none;border:0;outline:none;background:transparent;color:#f5f5f5;font:inherit;line-height:1.5;max-height:260px;padding:0 0 18px}.composer-input::placeholder{color:#8d8d91}.composer-hint{position:absolute;left:2px;bottom:2px;font-size:11px;color:#5f6165;pointer-events:none;-webkit-user-select:none;user-select:none;line-height:1.1;font-weight:500}.send-btn.icon-btn{--size: 40px;width:var(--size);height:var(--size);border-radius:50%;display:inline-flex;align-items:center;justify-content:center;background:#3a3a3c;border:1px solid #525255;color:#f1f1f2;cursor:pointer;transition:background-color .15s,border-color .15s,transform .15s;flex-shrink:0}.send-btn.icon-btn:hover:not(:disabled){background:#4a4a4d}.send-btn.icon-btn:active:not(:disabled){background:#343436;transform:translateY(1px)}.send-btn.icon-btn:disabled{opacity:.35;cursor:default}.send-btn.icon-btn:focus-visible{outline:none;box-shadow:0 0 0 2px #fff,0 0 0 4px #000}.send-icon{display:inline-flex}.send-btn.icon-btn:hover:not(:disabled) .send-icon{transform:translate(1px)}.send-icon svg{transition:transform .15s}@media (max-width:600px){.composer{padding:16px 0 26px}.composer-surface{margin:0 12px;border-radius:20px;padding:10px 12px 12px 16px}.send-btn.icon-btn{--size:36px}}@media (max-width:420px){.composer-hint{display:none}.composer-input{padding-bottom:0}}@media (prefers-reduced-motion: reduce){.send-btn.icon-btn,.send-icon svg{transition:none}}
2 |
--------------------------------------------------------------------------------
/Backend/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cohort-1-project-chat-gpt",
3 | "version": "1.0.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "cohort-1-project-chat-gpt",
9 | "version": "1.0.0",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@google/genai": "^1.14.0",
13 | "@pinecone-database/pinecone": "^6.1.2",
14 | "bcryptjs": "^3.0.2",
15 | "cookie": "^1.0.2",
16 | "cookie-parser": "^1.4.7",
17 | "cors": "^2.8.5",
18 | "dotenv": "^17.2.1",
19 | "express": "^5.1.0",
20 | "jsonwebtoken": "^9.0.2",
21 | "mongoose": "^8.17.1",
22 | "socket.io": "^4.8.1"
23 | }
24 | },
25 | "node_modules/@google/genai": {
26 | "version": "1.14.0",
27 | "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.14.0.tgz",
28 | "integrity": "sha512-jirYprAAJU1svjwSDVCzyVq+FrJpJd5CSxR/g2Ga/gZ0ZYZpcWjMS75KJl9y71K1mDN+tcx6s21CzCbB2R840g==",
29 | "license": "Apache-2.0",
30 | "dependencies": {
31 | "google-auth-library": "^9.14.2",
32 | "ws": "^8.18.0"
33 | },
34 | "engines": {
35 | "node": ">=20.0.0"
36 | },
37 | "peerDependencies": {
38 | "@modelcontextprotocol/sdk": "^1.11.0"
39 | },
40 | "peerDependenciesMeta": {
41 | "@modelcontextprotocol/sdk": {
42 | "optional": true
43 | }
44 | }
45 | },
46 | "node_modules/@google/genai/node_modules/ws": {
47 | "version": "8.18.3",
48 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
49 | "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
50 | "license": "MIT",
51 | "engines": {
52 | "node": ">=10.0.0"
53 | },
54 | "peerDependencies": {
55 | "bufferutil": "^4.0.1",
56 | "utf-8-validate": ">=5.0.2"
57 | },
58 | "peerDependenciesMeta": {
59 | "bufferutil": {
60 | "optional": true
61 | },
62 | "utf-8-validate": {
63 | "optional": true
64 | }
65 | }
66 | },
67 | "node_modules/@mongodb-js/saslprep": {
68 | "version": "1.3.0",
69 | "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.3.0.tgz",
70 | "integrity": "sha512-zlayKCsIjYb7/IdfqxorK5+xUMyi4vOKcFy10wKJYc63NSdKI8mNME+uJqfatkPmOSMMUiojrL58IePKBm3gvQ==",
71 | "license": "MIT",
72 | "dependencies": {
73 | "sparse-bitfield": "^3.0.3"
74 | }
75 | },
76 | "node_modules/@pinecone-database/pinecone": {
77 | "version": "6.1.2",
78 | "resolved": "https://registry.npmjs.org/@pinecone-database/pinecone/-/pinecone-6.1.2.tgz",
79 | "integrity": "sha512-ydIlbtgIIHFgBL08sPzua5ckmOgtjgDz8xg21CnP1fqnnEgDmOlnfd10MRKU+fvFRhDlh4Md37SwZDr0d4cBqg==",
80 | "license": "Apache-2.0",
81 | "engines": {
82 | "node": ">=18.0.0"
83 | }
84 | },
85 | "node_modules/@socket.io/component-emitter": {
86 | "version": "3.1.2",
87 | "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
88 | "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
89 | "license": "MIT"
90 | },
91 | "node_modules/@types/cors": {
92 | "version": "2.8.19",
93 | "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
94 | "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==",
95 | "license": "MIT",
96 | "dependencies": {
97 | "@types/node": "*"
98 | }
99 | },
100 | "node_modules/@types/node": {
101 | "version": "24.3.0",
102 | "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz",
103 | "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==",
104 | "license": "MIT",
105 | "dependencies": {
106 | "undici-types": "~7.10.0"
107 | }
108 | },
109 | "node_modules/@types/webidl-conversions": {
110 | "version": "7.0.3",
111 | "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
112 | "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==",
113 | "license": "MIT"
114 | },
115 | "node_modules/@types/whatwg-url": {
116 | "version": "11.0.5",
117 | "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz",
118 | "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==",
119 | "license": "MIT",
120 | "dependencies": {
121 | "@types/webidl-conversions": "*"
122 | }
123 | },
124 | "node_modules/accepts": {
125 | "version": "2.0.0",
126 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
127 | "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
128 | "license": "MIT",
129 | "dependencies": {
130 | "mime-types": "^3.0.0",
131 | "negotiator": "^1.0.0"
132 | },
133 | "engines": {
134 | "node": ">= 0.6"
135 | }
136 | },
137 | "node_modules/agent-base": {
138 | "version": "7.1.4",
139 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
140 | "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
141 | "license": "MIT",
142 | "engines": {
143 | "node": ">= 14"
144 | }
145 | },
146 | "node_modules/base64-js": {
147 | "version": "1.5.1",
148 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
149 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
150 | "funding": [
151 | {
152 | "type": "github",
153 | "url": "https://github.com/sponsors/feross"
154 | },
155 | {
156 | "type": "patreon",
157 | "url": "https://www.patreon.com/feross"
158 | },
159 | {
160 | "type": "consulting",
161 | "url": "https://feross.org/support"
162 | }
163 | ],
164 | "license": "MIT"
165 | },
166 | "node_modules/base64id": {
167 | "version": "2.0.0",
168 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
169 | "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
170 | "license": "MIT",
171 | "engines": {
172 | "node": "^4.5.0 || >= 5.9"
173 | }
174 | },
175 | "node_modules/bcryptjs": {
176 | "version": "3.0.2",
177 | "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz",
178 | "integrity": "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==",
179 | "license": "BSD-3-Clause",
180 | "bin": {
181 | "bcrypt": "bin/bcrypt"
182 | }
183 | },
184 | "node_modules/bignumber.js": {
185 | "version": "9.3.1",
186 | "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
187 | "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==",
188 | "license": "MIT",
189 | "engines": {
190 | "node": "*"
191 | }
192 | },
193 | "node_modules/body-parser": {
194 | "version": "2.2.0",
195 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
196 | "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
197 | "license": "MIT",
198 | "dependencies": {
199 | "bytes": "^3.1.2",
200 | "content-type": "^1.0.5",
201 | "debug": "^4.4.0",
202 | "http-errors": "^2.0.0",
203 | "iconv-lite": "^0.6.3",
204 | "on-finished": "^2.4.1",
205 | "qs": "^6.14.0",
206 | "raw-body": "^3.0.0",
207 | "type-is": "^2.0.0"
208 | },
209 | "engines": {
210 | "node": ">=18"
211 | }
212 | },
213 | "node_modules/bson": {
214 | "version": "6.10.4",
215 | "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz",
216 | "integrity": "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==",
217 | "license": "Apache-2.0",
218 | "engines": {
219 | "node": ">=16.20.1"
220 | }
221 | },
222 | "node_modules/buffer-equal-constant-time": {
223 | "version": "1.0.1",
224 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
225 | "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
226 | "license": "BSD-3-Clause"
227 | },
228 | "node_modules/bytes": {
229 | "version": "3.1.2",
230 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
231 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
232 | "license": "MIT",
233 | "engines": {
234 | "node": ">= 0.8"
235 | }
236 | },
237 | "node_modules/call-bind-apply-helpers": {
238 | "version": "1.0.2",
239 | "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
240 | "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
241 | "license": "MIT",
242 | "dependencies": {
243 | "es-errors": "^1.3.0",
244 | "function-bind": "^1.1.2"
245 | },
246 | "engines": {
247 | "node": ">= 0.4"
248 | }
249 | },
250 | "node_modules/call-bound": {
251 | "version": "1.0.4",
252 | "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
253 | "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
254 | "license": "MIT",
255 | "dependencies": {
256 | "call-bind-apply-helpers": "^1.0.2",
257 | "get-intrinsic": "^1.3.0"
258 | },
259 | "engines": {
260 | "node": ">= 0.4"
261 | },
262 | "funding": {
263 | "url": "https://github.com/sponsors/ljharb"
264 | }
265 | },
266 | "node_modules/content-disposition": {
267 | "version": "1.0.0",
268 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
269 | "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==",
270 | "license": "MIT",
271 | "dependencies": {
272 | "safe-buffer": "5.2.1"
273 | },
274 | "engines": {
275 | "node": ">= 0.6"
276 | }
277 | },
278 | "node_modules/content-type": {
279 | "version": "1.0.5",
280 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
281 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
282 | "license": "MIT",
283 | "engines": {
284 | "node": ">= 0.6"
285 | }
286 | },
287 | "node_modules/cookie": {
288 | "version": "1.0.2",
289 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
290 | "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
291 | "license": "MIT",
292 | "engines": {
293 | "node": ">=18"
294 | }
295 | },
296 | "node_modules/cookie-parser": {
297 | "version": "1.4.7",
298 | "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
299 | "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
300 | "license": "MIT",
301 | "dependencies": {
302 | "cookie": "0.7.2",
303 | "cookie-signature": "1.0.6"
304 | },
305 | "engines": {
306 | "node": ">= 0.8.0"
307 | }
308 | },
309 | "node_modules/cookie-parser/node_modules/cookie": {
310 | "version": "0.7.2",
311 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
312 | "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
313 | "license": "MIT",
314 | "engines": {
315 | "node": ">= 0.6"
316 | }
317 | },
318 | "node_modules/cookie-parser/node_modules/cookie-signature": {
319 | "version": "1.0.6",
320 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
321 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
322 | "license": "MIT"
323 | },
324 | "node_modules/cookie-signature": {
325 | "version": "1.2.2",
326 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
327 | "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
328 | "license": "MIT",
329 | "engines": {
330 | "node": ">=6.6.0"
331 | }
332 | },
333 | "node_modules/cors": {
334 | "version": "2.8.5",
335 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
336 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
337 | "license": "MIT",
338 | "dependencies": {
339 | "object-assign": "^4",
340 | "vary": "^1"
341 | },
342 | "engines": {
343 | "node": ">= 0.10"
344 | }
345 | },
346 | "node_modules/debug": {
347 | "version": "4.4.1",
348 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
349 | "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
350 | "license": "MIT",
351 | "dependencies": {
352 | "ms": "^2.1.3"
353 | },
354 | "engines": {
355 | "node": ">=6.0"
356 | },
357 | "peerDependenciesMeta": {
358 | "supports-color": {
359 | "optional": true
360 | }
361 | }
362 | },
363 | "node_modules/depd": {
364 | "version": "2.0.0",
365 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
366 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
367 | "license": "MIT",
368 | "engines": {
369 | "node": ">= 0.8"
370 | }
371 | },
372 | "node_modules/dotenv": {
373 | "version": "17.2.1",
374 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz",
375 | "integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==",
376 | "license": "BSD-2-Clause",
377 | "engines": {
378 | "node": ">=12"
379 | },
380 | "funding": {
381 | "url": "https://dotenvx.com"
382 | }
383 | },
384 | "node_modules/dunder-proto": {
385 | "version": "1.0.1",
386 | "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
387 | "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
388 | "license": "MIT",
389 | "dependencies": {
390 | "call-bind-apply-helpers": "^1.0.1",
391 | "es-errors": "^1.3.0",
392 | "gopd": "^1.2.0"
393 | },
394 | "engines": {
395 | "node": ">= 0.4"
396 | }
397 | },
398 | "node_modules/ecdsa-sig-formatter": {
399 | "version": "1.0.11",
400 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
401 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
402 | "license": "Apache-2.0",
403 | "dependencies": {
404 | "safe-buffer": "^5.0.1"
405 | }
406 | },
407 | "node_modules/ee-first": {
408 | "version": "1.1.1",
409 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
410 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
411 | "license": "MIT"
412 | },
413 | "node_modules/encodeurl": {
414 | "version": "2.0.0",
415 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
416 | "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
417 | "license": "MIT",
418 | "engines": {
419 | "node": ">= 0.8"
420 | }
421 | },
422 | "node_modules/engine.io": {
423 | "version": "6.6.4",
424 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz",
425 | "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==",
426 | "license": "MIT",
427 | "dependencies": {
428 | "@types/cors": "^2.8.12",
429 | "@types/node": ">=10.0.0",
430 | "accepts": "~1.3.4",
431 | "base64id": "2.0.0",
432 | "cookie": "~0.7.2",
433 | "cors": "~2.8.5",
434 | "debug": "~4.3.1",
435 | "engine.io-parser": "~5.2.1",
436 | "ws": "~8.17.1"
437 | },
438 | "engines": {
439 | "node": ">=10.2.0"
440 | }
441 | },
442 | "node_modules/engine.io-parser": {
443 | "version": "5.2.3",
444 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
445 | "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
446 | "license": "MIT",
447 | "engines": {
448 | "node": ">=10.0.0"
449 | }
450 | },
451 | "node_modules/engine.io/node_modules/accepts": {
452 | "version": "1.3.8",
453 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
454 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
455 | "license": "MIT",
456 | "dependencies": {
457 | "mime-types": "~2.1.34",
458 | "negotiator": "0.6.3"
459 | },
460 | "engines": {
461 | "node": ">= 0.6"
462 | }
463 | },
464 | "node_modules/engine.io/node_modules/cookie": {
465 | "version": "0.7.2",
466 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
467 | "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
468 | "license": "MIT",
469 | "engines": {
470 | "node": ">= 0.6"
471 | }
472 | },
473 | "node_modules/engine.io/node_modules/debug": {
474 | "version": "4.3.7",
475 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
476 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
477 | "license": "MIT",
478 | "dependencies": {
479 | "ms": "^2.1.3"
480 | },
481 | "engines": {
482 | "node": ">=6.0"
483 | },
484 | "peerDependenciesMeta": {
485 | "supports-color": {
486 | "optional": true
487 | }
488 | }
489 | },
490 | "node_modules/engine.io/node_modules/mime-db": {
491 | "version": "1.52.0",
492 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
493 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
494 | "license": "MIT",
495 | "engines": {
496 | "node": ">= 0.6"
497 | }
498 | },
499 | "node_modules/engine.io/node_modules/mime-types": {
500 | "version": "2.1.35",
501 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
502 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
503 | "license": "MIT",
504 | "dependencies": {
505 | "mime-db": "1.52.0"
506 | },
507 | "engines": {
508 | "node": ">= 0.6"
509 | }
510 | },
511 | "node_modules/engine.io/node_modules/negotiator": {
512 | "version": "0.6.3",
513 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
514 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
515 | "license": "MIT",
516 | "engines": {
517 | "node": ">= 0.6"
518 | }
519 | },
520 | "node_modules/es-define-property": {
521 | "version": "1.0.1",
522 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
523 | "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
524 | "license": "MIT",
525 | "engines": {
526 | "node": ">= 0.4"
527 | }
528 | },
529 | "node_modules/es-errors": {
530 | "version": "1.3.0",
531 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
532 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
533 | "license": "MIT",
534 | "engines": {
535 | "node": ">= 0.4"
536 | }
537 | },
538 | "node_modules/es-object-atoms": {
539 | "version": "1.1.1",
540 | "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
541 | "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
542 | "license": "MIT",
543 | "dependencies": {
544 | "es-errors": "^1.3.0"
545 | },
546 | "engines": {
547 | "node": ">= 0.4"
548 | }
549 | },
550 | "node_modules/escape-html": {
551 | "version": "1.0.3",
552 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
553 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
554 | "license": "MIT"
555 | },
556 | "node_modules/etag": {
557 | "version": "1.8.1",
558 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
559 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
560 | "license": "MIT",
561 | "engines": {
562 | "node": ">= 0.6"
563 | }
564 | },
565 | "node_modules/express": {
566 | "version": "5.1.0",
567 | "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
568 | "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
569 | "license": "MIT",
570 | "dependencies": {
571 | "accepts": "^2.0.0",
572 | "body-parser": "^2.2.0",
573 | "content-disposition": "^1.0.0",
574 | "content-type": "^1.0.5",
575 | "cookie": "^0.7.1",
576 | "cookie-signature": "^1.2.1",
577 | "debug": "^4.4.0",
578 | "encodeurl": "^2.0.0",
579 | "escape-html": "^1.0.3",
580 | "etag": "^1.8.1",
581 | "finalhandler": "^2.1.0",
582 | "fresh": "^2.0.0",
583 | "http-errors": "^2.0.0",
584 | "merge-descriptors": "^2.0.0",
585 | "mime-types": "^3.0.0",
586 | "on-finished": "^2.4.1",
587 | "once": "^1.4.0",
588 | "parseurl": "^1.3.3",
589 | "proxy-addr": "^2.0.7",
590 | "qs": "^6.14.0",
591 | "range-parser": "^1.2.1",
592 | "router": "^2.2.0",
593 | "send": "^1.1.0",
594 | "serve-static": "^2.2.0",
595 | "statuses": "^2.0.1",
596 | "type-is": "^2.0.1",
597 | "vary": "^1.1.2"
598 | },
599 | "engines": {
600 | "node": ">= 18"
601 | },
602 | "funding": {
603 | "type": "opencollective",
604 | "url": "https://opencollective.com/express"
605 | }
606 | },
607 | "node_modules/express/node_modules/cookie": {
608 | "version": "0.7.2",
609 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
610 | "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
611 | "license": "MIT",
612 | "engines": {
613 | "node": ">= 0.6"
614 | }
615 | },
616 | "node_modules/extend": {
617 | "version": "3.0.2",
618 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
619 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
620 | "license": "MIT"
621 | },
622 | "node_modules/finalhandler": {
623 | "version": "2.1.0",
624 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
625 | "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
626 | "license": "MIT",
627 | "dependencies": {
628 | "debug": "^4.4.0",
629 | "encodeurl": "^2.0.0",
630 | "escape-html": "^1.0.3",
631 | "on-finished": "^2.4.1",
632 | "parseurl": "^1.3.3",
633 | "statuses": "^2.0.1"
634 | },
635 | "engines": {
636 | "node": ">= 0.8"
637 | }
638 | },
639 | "node_modules/forwarded": {
640 | "version": "0.2.0",
641 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
642 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
643 | "license": "MIT",
644 | "engines": {
645 | "node": ">= 0.6"
646 | }
647 | },
648 | "node_modules/fresh": {
649 | "version": "2.0.0",
650 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
651 | "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
652 | "license": "MIT",
653 | "engines": {
654 | "node": ">= 0.8"
655 | }
656 | },
657 | "node_modules/function-bind": {
658 | "version": "1.1.2",
659 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
660 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
661 | "license": "MIT",
662 | "funding": {
663 | "url": "https://github.com/sponsors/ljharb"
664 | }
665 | },
666 | "node_modules/gaxios": {
667 | "version": "6.7.1",
668 | "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz",
669 | "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==",
670 | "license": "Apache-2.0",
671 | "dependencies": {
672 | "extend": "^3.0.2",
673 | "https-proxy-agent": "^7.0.1",
674 | "is-stream": "^2.0.0",
675 | "node-fetch": "^2.6.9",
676 | "uuid": "^9.0.1"
677 | },
678 | "engines": {
679 | "node": ">=14"
680 | }
681 | },
682 | "node_modules/gcp-metadata": {
683 | "version": "5.3.0",
684 | "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz",
685 | "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==",
686 | "license": "Apache-2.0",
687 | "optional": true,
688 | "peer": true,
689 | "dependencies": {
690 | "gaxios": "^5.0.0",
691 | "json-bigint": "^1.0.0"
692 | },
693 | "engines": {
694 | "node": ">=12"
695 | }
696 | },
697 | "node_modules/gcp-metadata/node_modules/agent-base": {
698 | "version": "6.0.2",
699 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
700 | "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
701 | "license": "MIT",
702 | "optional": true,
703 | "peer": true,
704 | "dependencies": {
705 | "debug": "4"
706 | },
707 | "engines": {
708 | "node": ">= 6.0.0"
709 | }
710 | },
711 | "node_modules/gcp-metadata/node_modules/gaxios": {
712 | "version": "5.1.3",
713 | "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz",
714 | "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==",
715 | "license": "Apache-2.0",
716 | "optional": true,
717 | "peer": true,
718 | "dependencies": {
719 | "extend": "^3.0.2",
720 | "https-proxy-agent": "^5.0.0",
721 | "is-stream": "^2.0.0",
722 | "node-fetch": "^2.6.9"
723 | },
724 | "engines": {
725 | "node": ">=12"
726 | }
727 | },
728 | "node_modules/gcp-metadata/node_modules/https-proxy-agent": {
729 | "version": "5.0.1",
730 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
731 | "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
732 | "license": "MIT",
733 | "optional": true,
734 | "peer": true,
735 | "dependencies": {
736 | "agent-base": "6",
737 | "debug": "4"
738 | },
739 | "engines": {
740 | "node": ">= 6"
741 | }
742 | },
743 | "node_modules/get-intrinsic": {
744 | "version": "1.3.0",
745 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
746 | "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
747 | "license": "MIT",
748 | "dependencies": {
749 | "call-bind-apply-helpers": "^1.0.2",
750 | "es-define-property": "^1.0.1",
751 | "es-errors": "^1.3.0",
752 | "es-object-atoms": "^1.1.1",
753 | "function-bind": "^1.1.2",
754 | "get-proto": "^1.0.1",
755 | "gopd": "^1.2.0",
756 | "has-symbols": "^1.1.0",
757 | "hasown": "^2.0.2",
758 | "math-intrinsics": "^1.1.0"
759 | },
760 | "engines": {
761 | "node": ">= 0.4"
762 | },
763 | "funding": {
764 | "url": "https://github.com/sponsors/ljharb"
765 | }
766 | },
767 | "node_modules/get-proto": {
768 | "version": "1.0.1",
769 | "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
770 | "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
771 | "license": "MIT",
772 | "dependencies": {
773 | "dunder-proto": "^1.0.1",
774 | "es-object-atoms": "^1.0.0"
775 | },
776 | "engines": {
777 | "node": ">= 0.4"
778 | }
779 | },
780 | "node_modules/google-auth-library": {
781 | "version": "9.15.1",
782 | "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz",
783 | "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==",
784 | "license": "Apache-2.0",
785 | "dependencies": {
786 | "base64-js": "^1.3.0",
787 | "ecdsa-sig-formatter": "^1.0.11",
788 | "gaxios": "^6.1.1",
789 | "gcp-metadata": "^6.1.0",
790 | "gtoken": "^7.0.0",
791 | "jws": "^4.0.0"
792 | },
793 | "engines": {
794 | "node": ">=14"
795 | }
796 | },
797 | "node_modules/google-auth-library/node_modules/gcp-metadata": {
798 | "version": "6.1.1",
799 | "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz",
800 | "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==",
801 | "license": "Apache-2.0",
802 | "dependencies": {
803 | "gaxios": "^6.1.1",
804 | "google-logging-utils": "^0.0.2",
805 | "json-bigint": "^1.0.0"
806 | },
807 | "engines": {
808 | "node": ">=14"
809 | }
810 | },
811 | "node_modules/google-auth-library/node_modules/jwa": {
812 | "version": "2.0.1",
813 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
814 | "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==",
815 | "license": "MIT",
816 | "dependencies": {
817 | "buffer-equal-constant-time": "^1.0.1",
818 | "ecdsa-sig-formatter": "1.0.11",
819 | "safe-buffer": "^5.0.1"
820 | }
821 | },
822 | "node_modules/google-auth-library/node_modules/jws": {
823 | "version": "4.0.0",
824 | "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
825 | "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
826 | "license": "MIT",
827 | "dependencies": {
828 | "jwa": "^2.0.0",
829 | "safe-buffer": "^5.0.1"
830 | }
831 | },
832 | "node_modules/google-logging-utils": {
833 | "version": "0.0.2",
834 | "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz",
835 | "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==",
836 | "license": "Apache-2.0",
837 | "engines": {
838 | "node": ">=14"
839 | }
840 | },
841 | "node_modules/gopd": {
842 | "version": "1.2.0",
843 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
844 | "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
845 | "license": "MIT",
846 | "engines": {
847 | "node": ">= 0.4"
848 | },
849 | "funding": {
850 | "url": "https://github.com/sponsors/ljharb"
851 | }
852 | },
853 | "node_modules/gtoken": {
854 | "version": "7.1.0",
855 | "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz",
856 | "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==",
857 | "license": "MIT",
858 | "dependencies": {
859 | "gaxios": "^6.0.0",
860 | "jws": "^4.0.0"
861 | },
862 | "engines": {
863 | "node": ">=14.0.0"
864 | }
865 | },
866 | "node_modules/gtoken/node_modules/jwa": {
867 | "version": "2.0.1",
868 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
869 | "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==",
870 | "license": "MIT",
871 | "dependencies": {
872 | "buffer-equal-constant-time": "^1.0.1",
873 | "ecdsa-sig-formatter": "1.0.11",
874 | "safe-buffer": "^5.0.1"
875 | }
876 | },
877 | "node_modules/gtoken/node_modules/jws": {
878 | "version": "4.0.0",
879 | "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
880 | "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
881 | "license": "MIT",
882 | "dependencies": {
883 | "jwa": "^2.0.0",
884 | "safe-buffer": "^5.0.1"
885 | }
886 | },
887 | "node_modules/has-symbols": {
888 | "version": "1.1.0",
889 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
890 | "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
891 | "license": "MIT",
892 | "engines": {
893 | "node": ">= 0.4"
894 | },
895 | "funding": {
896 | "url": "https://github.com/sponsors/ljharb"
897 | }
898 | },
899 | "node_modules/hasown": {
900 | "version": "2.0.2",
901 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
902 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
903 | "license": "MIT",
904 | "dependencies": {
905 | "function-bind": "^1.1.2"
906 | },
907 | "engines": {
908 | "node": ">= 0.4"
909 | }
910 | },
911 | "node_modules/http-errors": {
912 | "version": "2.0.0",
913 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
914 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
915 | "license": "MIT",
916 | "dependencies": {
917 | "depd": "2.0.0",
918 | "inherits": "2.0.4",
919 | "setprototypeof": "1.2.0",
920 | "statuses": "2.0.1",
921 | "toidentifier": "1.0.1"
922 | },
923 | "engines": {
924 | "node": ">= 0.8"
925 | }
926 | },
927 | "node_modules/http-errors/node_modules/statuses": {
928 | "version": "2.0.1",
929 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
930 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
931 | "license": "MIT",
932 | "engines": {
933 | "node": ">= 0.8"
934 | }
935 | },
936 | "node_modules/https-proxy-agent": {
937 | "version": "7.0.6",
938 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
939 | "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
940 | "license": "MIT",
941 | "dependencies": {
942 | "agent-base": "^7.1.2",
943 | "debug": "4"
944 | },
945 | "engines": {
946 | "node": ">= 14"
947 | }
948 | },
949 | "node_modules/iconv-lite": {
950 | "version": "0.6.3",
951 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
952 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
953 | "license": "MIT",
954 | "dependencies": {
955 | "safer-buffer": ">= 2.1.2 < 3.0.0"
956 | },
957 | "engines": {
958 | "node": ">=0.10.0"
959 | }
960 | },
961 | "node_modules/inherits": {
962 | "version": "2.0.4",
963 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
964 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
965 | "license": "ISC"
966 | },
967 | "node_modules/ipaddr.js": {
968 | "version": "1.9.1",
969 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
970 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
971 | "license": "MIT",
972 | "engines": {
973 | "node": ">= 0.10"
974 | }
975 | },
976 | "node_modules/is-promise": {
977 | "version": "4.0.0",
978 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
979 | "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
980 | "license": "MIT"
981 | },
982 | "node_modules/is-stream": {
983 | "version": "2.0.1",
984 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
985 | "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
986 | "license": "MIT",
987 | "engines": {
988 | "node": ">=8"
989 | },
990 | "funding": {
991 | "url": "https://github.com/sponsors/sindresorhus"
992 | }
993 | },
994 | "node_modules/json-bigint": {
995 | "version": "1.0.0",
996 | "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
997 | "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
998 | "license": "MIT",
999 | "dependencies": {
1000 | "bignumber.js": "^9.0.0"
1001 | }
1002 | },
1003 | "node_modules/jsonwebtoken": {
1004 | "version": "9.0.2",
1005 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
1006 | "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
1007 | "license": "MIT",
1008 | "dependencies": {
1009 | "jws": "^3.2.2",
1010 | "lodash.includes": "^4.3.0",
1011 | "lodash.isboolean": "^3.0.3",
1012 | "lodash.isinteger": "^4.0.4",
1013 | "lodash.isnumber": "^3.0.3",
1014 | "lodash.isplainobject": "^4.0.6",
1015 | "lodash.isstring": "^4.0.1",
1016 | "lodash.once": "^4.0.0",
1017 | "ms": "^2.1.1",
1018 | "semver": "^7.5.4"
1019 | },
1020 | "engines": {
1021 | "node": ">=12",
1022 | "npm": ">=6"
1023 | }
1024 | },
1025 | "node_modules/jwa": {
1026 | "version": "1.4.2",
1027 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
1028 | "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
1029 | "license": "MIT",
1030 | "dependencies": {
1031 | "buffer-equal-constant-time": "^1.0.1",
1032 | "ecdsa-sig-formatter": "1.0.11",
1033 | "safe-buffer": "^5.0.1"
1034 | }
1035 | },
1036 | "node_modules/jws": {
1037 | "version": "3.2.2",
1038 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
1039 | "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
1040 | "license": "MIT",
1041 | "dependencies": {
1042 | "jwa": "^1.4.1",
1043 | "safe-buffer": "^5.0.1"
1044 | }
1045 | },
1046 | "node_modules/kareem": {
1047 | "version": "2.6.3",
1048 | "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
1049 | "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==",
1050 | "license": "Apache-2.0",
1051 | "engines": {
1052 | "node": ">=12.0.0"
1053 | }
1054 | },
1055 | "node_modules/lodash.includes": {
1056 | "version": "4.3.0",
1057 | "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
1058 | "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
1059 | "license": "MIT"
1060 | },
1061 | "node_modules/lodash.isboolean": {
1062 | "version": "3.0.3",
1063 | "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
1064 | "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
1065 | "license": "MIT"
1066 | },
1067 | "node_modules/lodash.isinteger": {
1068 | "version": "4.0.4",
1069 | "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
1070 | "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
1071 | "license": "MIT"
1072 | },
1073 | "node_modules/lodash.isnumber": {
1074 | "version": "3.0.3",
1075 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
1076 | "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
1077 | "license": "MIT"
1078 | },
1079 | "node_modules/lodash.isplainobject": {
1080 | "version": "4.0.6",
1081 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
1082 | "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
1083 | "license": "MIT"
1084 | },
1085 | "node_modules/lodash.isstring": {
1086 | "version": "4.0.1",
1087 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
1088 | "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
1089 | "license": "MIT"
1090 | },
1091 | "node_modules/lodash.once": {
1092 | "version": "4.1.1",
1093 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
1094 | "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
1095 | "license": "MIT"
1096 | },
1097 | "node_modules/math-intrinsics": {
1098 | "version": "1.1.0",
1099 | "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
1100 | "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
1101 | "license": "MIT",
1102 | "engines": {
1103 | "node": ">= 0.4"
1104 | }
1105 | },
1106 | "node_modules/media-typer": {
1107 | "version": "1.1.0",
1108 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
1109 | "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
1110 | "license": "MIT",
1111 | "engines": {
1112 | "node": ">= 0.8"
1113 | }
1114 | },
1115 | "node_modules/memory-pager": {
1116 | "version": "1.5.0",
1117 | "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
1118 | "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
1119 | "license": "MIT"
1120 | },
1121 | "node_modules/merge-descriptors": {
1122 | "version": "2.0.0",
1123 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
1124 | "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
1125 | "license": "MIT",
1126 | "engines": {
1127 | "node": ">=18"
1128 | },
1129 | "funding": {
1130 | "url": "https://github.com/sponsors/sindresorhus"
1131 | }
1132 | },
1133 | "node_modules/mime-db": {
1134 | "version": "1.54.0",
1135 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
1136 | "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
1137 | "license": "MIT",
1138 | "engines": {
1139 | "node": ">= 0.6"
1140 | }
1141 | },
1142 | "node_modules/mime-types": {
1143 | "version": "3.0.1",
1144 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
1145 | "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
1146 | "license": "MIT",
1147 | "dependencies": {
1148 | "mime-db": "^1.54.0"
1149 | },
1150 | "engines": {
1151 | "node": ">= 0.6"
1152 | }
1153 | },
1154 | "node_modules/mongodb": {
1155 | "version": "6.18.0",
1156 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.18.0.tgz",
1157 | "integrity": "sha512-fO5ttN9VC8P0F5fqtQmclAkgXZxbIkYRTUi1j8JO6IYwvamkhtYDilJr35jOPELR49zqCJgXZWwCtW7B+TM8vQ==",
1158 | "license": "Apache-2.0",
1159 | "dependencies": {
1160 | "@mongodb-js/saslprep": "^1.1.9",
1161 | "bson": "^6.10.4",
1162 | "mongodb-connection-string-url": "^3.0.0"
1163 | },
1164 | "engines": {
1165 | "node": ">=16.20.1"
1166 | },
1167 | "peerDependencies": {
1168 | "@aws-sdk/credential-providers": "^3.188.0",
1169 | "@mongodb-js/zstd": "^1.1.0 || ^2.0.0",
1170 | "gcp-metadata": "^5.2.0",
1171 | "kerberos": "^2.0.1",
1172 | "mongodb-client-encryption": ">=6.0.0 <7",
1173 | "snappy": "^7.2.2",
1174 | "socks": "^2.7.1"
1175 | },
1176 | "peerDependenciesMeta": {
1177 | "@aws-sdk/credential-providers": {
1178 | "optional": true
1179 | },
1180 | "@mongodb-js/zstd": {
1181 | "optional": true
1182 | },
1183 | "gcp-metadata": {
1184 | "optional": true
1185 | },
1186 | "kerberos": {
1187 | "optional": true
1188 | },
1189 | "mongodb-client-encryption": {
1190 | "optional": true
1191 | },
1192 | "snappy": {
1193 | "optional": true
1194 | },
1195 | "socks": {
1196 | "optional": true
1197 | }
1198 | }
1199 | },
1200 | "node_modules/mongodb-connection-string-url": {
1201 | "version": "3.0.2",
1202 | "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz",
1203 | "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==",
1204 | "license": "Apache-2.0",
1205 | "dependencies": {
1206 | "@types/whatwg-url": "^11.0.2",
1207 | "whatwg-url": "^14.1.0 || ^13.0.0"
1208 | }
1209 | },
1210 | "node_modules/mongoose": {
1211 | "version": "8.17.1",
1212 | "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.17.1.tgz",
1213 | "integrity": "sha512-aodS4cacux5caoxB5ErEwRmrafIUsVRJxHnvP7URnSUnTenr32j1qBVV+KjYxryyLSisQkxglAFF69TNLeZTLg==",
1214 | "license": "MIT",
1215 | "dependencies": {
1216 | "bson": "^6.10.4",
1217 | "kareem": "2.6.3",
1218 | "mongodb": "~6.18.0",
1219 | "mpath": "0.9.0",
1220 | "mquery": "5.0.0",
1221 | "ms": "2.1.3",
1222 | "sift": "17.1.3"
1223 | },
1224 | "engines": {
1225 | "node": ">=16.20.1"
1226 | },
1227 | "funding": {
1228 | "type": "opencollective",
1229 | "url": "https://opencollective.com/mongoose"
1230 | }
1231 | },
1232 | "node_modules/mpath": {
1233 | "version": "0.9.0",
1234 | "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
1235 | "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==",
1236 | "license": "MIT",
1237 | "engines": {
1238 | "node": ">=4.0.0"
1239 | }
1240 | },
1241 | "node_modules/mquery": {
1242 | "version": "5.0.0",
1243 | "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz",
1244 | "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==",
1245 | "license": "MIT",
1246 | "dependencies": {
1247 | "debug": "4.x"
1248 | },
1249 | "engines": {
1250 | "node": ">=14.0.0"
1251 | }
1252 | },
1253 | "node_modules/ms": {
1254 | "version": "2.1.3",
1255 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1256 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1257 | "license": "MIT"
1258 | },
1259 | "node_modules/negotiator": {
1260 | "version": "1.0.0",
1261 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
1262 | "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
1263 | "license": "MIT",
1264 | "engines": {
1265 | "node": ">= 0.6"
1266 | }
1267 | },
1268 | "node_modules/node-fetch": {
1269 | "version": "2.7.0",
1270 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
1271 | "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
1272 | "license": "MIT",
1273 | "dependencies": {
1274 | "whatwg-url": "^5.0.0"
1275 | },
1276 | "engines": {
1277 | "node": "4.x || >=6.0.0"
1278 | },
1279 | "peerDependencies": {
1280 | "encoding": "^0.1.0"
1281 | },
1282 | "peerDependenciesMeta": {
1283 | "encoding": {
1284 | "optional": true
1285 | }
1286 | }
1287 | },
1288 | "node_modules/node-fetch/node_modules/tr46": {
1289 | "version": "0.0.3",
1290 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
1291 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
1292 | "license": "MIT"
1293 | },
1294 | "node_modules/node-fetch/node_modules/webidl-conversions": {
1295 | "version": "3.0.1",
1296 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
1297 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
1298 | "license": "BSD-2-Clause"
1299 | },
1300 | "node_modules/node-fetch/node_modules/whatwg-url": {
1301 | "version": "5.0.0",
1302 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
1303 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
1304 | "license": "MIT",
1305 | "dependencies": {
1306 | "tr46": "~0.0.3",
1307 | "webidl-conversions": "^3.0.0"
1308 | }
1309 | },
1310 | "node_modules/object-assign": {
1311 | "version": "4.1.1",
1312 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
1313 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
1314 | "license": "MIT",
1315 | "engines": {
1316 | "node": ">=0.10.0"
1317 | }
1318 | },
1319 | "node_modules/object-inspect": {
1320 | "version": "1.13.4",
1321 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
1322 | "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
1323 | "license": "MIT",
1324 | "engines": {
1325 | "node": ">= 0.4"
1326 | },
1327 | "funding": {
1328 | "url": "https://github.com/sponsors/ljharb"
1329 | }
1330 | },
1331 | "node_modules/on-finished": {
1332 | "version": "2.4.1",
1333 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
1334 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
1335 | "license": "MIT",
1336 | "dependencies": {
1337 | "ee-first": "1.1.1"
1338 | },
1339 | "engines": {
1340 | "node": ">= 0.8"
1341 | }
1342 | },
1343 | "node_modules/once": {
1344 | "version": "1.4.0",
1345 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1346 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
1347 | "license": "ISC",
1348 | "dependencies": {
1349 | "wrappy": "1"
1350 | }
1351 | },
1352 | "node_modules/parseurl": {
1353 | "version": "1.3.3",
1354 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
1355 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
1356 | "license": "MIT",
1357 | "engines": {
1358 | "node": ">= 0.8"
1359 | }
1360 | },
1361 | "node_modules/path-to-regexp": {
1362 | "version": "8.2.0",
1363 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz",
1364 | "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==",
1365 | "license": "MIT",
1366 | "engines": {
1367 | "node": ">=16"
1368 | }
1369 | },
1370 | "node_modules/proxy-addr": {
1371 | "version": "2.0.7",
1372 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
1373 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
1374 | "license": "MIT",
1375 | "dependencies": {
1376 | "forwarded": "0.2.0",
1377 | "ipaddr.js": "1.9.1"
1378 | },
1379 | "engines": {
1380 | "node": ">= 0.10"
1381 | }
1382 | },
1383 | "node_modules/punycode": {
1384 | "version": "2.3.1",
1385 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
1386 | "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
1387 | "license": "MIT",
1388 | "engines": {
1389 | "node": ">=6"
1390 | }
1391 | },
1392 | "node_modules/qs": {
1393 | "version": "6.14.0",
1394 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
1395 | "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
1396 | "license": "BSD-3-Clause",
1397 | "dependencies": {
1398 | "side-channel": "^1.1.0"
1399 | },
1400 | "engines": {
1401 | "node": ">=0.6"
1402 | },
1403 | "funding": {
1404 | "url": "https://github.com/sponsors/ljharb"
1405 | }
1406 | },
1407 | "node_modules/range-parser": {
1408 | "version": "1.2.1",
1409 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
1410 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
1411 | "license": "MIT",
1412 | "engines": {
1413 | "node": ">= 0.6"
1414 | }
1415 | },
1416 | "node_modules/raw-body": {
1417 | "version": "3.0.0",
1418 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
1419 | "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
1420 | "license": "MIT",
1421 | "dependencies": {
1422 | "bytes": "3.1.2",
1423 | "http-errors": "2.0.0",
1424 | "iconv-lite": "0.6.3",
1425 | "unpipe": "1.0.0"
1426 | },
1427 | "engines": {
1428 | "node": ">= 0.8"
1429 | }
1430 | },
1431 | "node_modules/router": {
1432 | "version": "2.2.0",
1433 | "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
1434 | "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
1435 | "license": "MIT",
1436 | "dependencies": {
1437 | "debug": "^4.4.0",
1438 | "depd": "^2.0.0",
1439 | "is-promise": "^4.0.0",
1440 | "parseurl": "^1.3.3",
1441 | "path-to-regexp": "^8.0.0"
1442 | },
1443 | "engines": {
1444 | "node": ">= 18"
1445 | }
1446 | },
1447 | "node_modules/safe-buffer": {
1448 | "version": "5.2.1",
1449 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1450 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
1451 | "funding": [
1452 | {
1453 | "type": "github",
1454 | "url": "https://github.com/sponsors/feross"
1455 | },
1456 | {
1457 | "type": "patreon",
1458 | "url": "https://www.patreon.com/feross"
1459 | },
1460 | {
1461 | "type": "consulting",
1462 | "url": "https://feross.org/support"
1463 | }
1464 | ],
1465 | "license": "MIT"
1466 | },
1467 | "node_modules/safer-buffer": {
1468 | "version": "2.1.2",
1469 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1470 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
1471 | "license": "MIT"
1472 | },
1473 | "node_modules/semver": {
1474 | "version": "7.7.2",
1475 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
1476 | "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
1477 | "license": "ISC",
1478 | "bin": {
1479 | "semver": "bin/semver.js"
1480 | },
1481 | "engines": {
1482 | "node": ">=10"
1483 | }
1484 | },
1485 | "node_modules/send": {
1486 | "version": "1.2.0",
1487 | "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
1488 | "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
1489 | "license": "MIT",
1490 | "dependencies": {
1491 | "debug": "^4.3.5",
1492 | "encodeurl": "^2.0.0",
1493 | "escape-html": "^1.0.3",
1494 | "etag": "^1.8.1",
1495 | "fresh": "^2.0.0",
1496 | "http-errors": "^2.0.0",
1497 | "mime-types": "^3.0.1",
1498 | "ms": "^2.1.3",
1499 | "on-finished": "^2.4.1",
1500 | "range-parser": "^1.2.1",
1501 | "statuses": "^2.0.1"
1502 | },
1503 | "engines": {
1504 | "node": ">= 18"
1505 | }
1506 | },
1507 | "node_modules/serve-static": {
1508 | "version": "2.2.0",
1509 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
1510 | "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
1511 | "license": "MIT",
1512 | "dependencies": {
1513 | "encodeurl": "^2.0.0",
1514 | "escape-html": "^1.0.3",
1515 | "parseurl": "^1.3.3",
1516 | "send": "^1.2.0"
1517 | },
1518 | "engines": {
1519 | "node": ">= 18"
1520 | }
1521 | },
1522 | "node_modules/setprototypeof": {
1523 | "version": "1.2.0",
1524 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
1525 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
1526 | "license": "ISC"
1527 | },
1528 | "node_modules/side-channel": {
1529 | "version": "1.1.0",
1530 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
1531 | "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
1532 | "license": "MIT",
1533 | "dependencies": {
1534 | "es-errors": "^1.3.0",
1535 | "object-inspect": "^1.13.3",
1536 | "side-channel-list": "^1.0.0",
1537 | "side-channel-map": "^1.0.1",
1538 | "side-channel-weakmap": "^1.0.2"
1539 | },
1540 | "engines": {
1541 | "node": ">= 0.4"
1542 | },
1543 | "funding": {
1544 | "url": "https://github.com/sponsors/ljharb"
1545 | }
1546 | },
1547 | "node_modules/side-channel-list": {
1548 | "version": "1.0.0",
1549 | "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
1550 | "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
1551 | "license": "MIT",
1552 | "dependencies": {
1553 | "es-errors": "^1.3.0",
1554 | "object-inspect": "^1.13.3"
1555 | },
1556 | "engines": {
1557 | "node": ">= 0.4"
1558 | },
1559 | "funding": {
1560 | "url": "https://github.com/sponsors/ljharb"
1561 | }
1562 | },
1563 | "node_modules/side-channel-map": {
1564 | "version": "1.0.1",
1565 | "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
1566 | "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
1567 | "license": "MIT",
1568 | "dependencies": {
1569 | "call-bound": "^1.0.2",
1570 | "es-errors": "^1.3.0",
1571 | "get-intrinsic": "^1.2.5",
1572 | "object-inspect": "^1.13.3"
1573 | },
1574 | "engines": {
1575 | "node": ">= 0.4"
1576 | },
1577 | "funding": {
1578 | "url": "https://github.com/sponsors/ljharb"
1579 | }
1580 | },
1581 | "node_modules/side-channel-weakmap": {
1582 | "version": "1.0.2",
1583 | "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
1584 | "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
1585 | "license": "MIT",
1586 | "dependencies": {
1587 | "call-bound": "^1.0.2",
1588 | "es-errors": "^1.3.0",
1589 | "get-intrinsic": "^1.2.5",
1590 | "object-inspect": "^1.13.3",
1591 | "side-channel-map": "^1.0.1"
1592 | },
1593 | "engines": {
1594 | "node": ">= 0.4"
1595 | },
1596 | "funding": {
1597 | "url": "https://github.com/sponsors/ljharb"
1598 | }
1599 | },
1600 | "node_modules/sift": {
1601 | "version": "17.1.3",
1602 | "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz",
1603 | "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==",
1604 | "license": "MIT"
1605 | },
1606 | "node_modules/socket.io": {
1607 | "version": "4.8.1",
1608 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
1609 | "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
1610 | "license": "MIT",
1611 | "dependencies": {
1612 | "accepts": "~1.3.4",
1613 | "base64id": "~2.0.0",
1614 | "cors": "~2.8.5",
1615 | "debug": "~4.3.2",
1616 | "engine.io": "~6.6.0",
1617 | "socket.io-adapter": "~2.5.2",
1618 | "socket.io-parser": "~4.2.4"
1619 | },
1620 | "engines": {
1621 | "node": ">=10.2.0"
1622 | }
1623 | },
1624 | "node_modules/socket.io-adapter": {
1625 | "version": "2.5.5",
1626 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
1627 | "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
1628 | "license": "MIT",
1629 | "dependencies": {
1630 | "debug": "~4.3.4",
1631 | "ws": "~8.17.1"
1632 | }
1633 | },
1634 | "node_modules/socket.io-adapter/node_modules/debug": {
1635 | "version": "4.3.7",
1636 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
1637 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
1638 | "license": "MIT",
1639 | "dependencies": {
1640 | "ms": "^2.1.3"
1641 | },
1642 | "engines": {
1643 | "node": ">=6.0"
1644 | },
1645 | "peerDependenciesMeta": {
1646 | "supports-color": {
1647 | "optional": true
1648 | }
1649 | }
1650 | },
1651 | "node_modules/socket.io-parser": {
1652 | "version": "4.2.4",
1653 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
1654 | "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
1655 | "license": "MIT",
1656 | "dependencies": {
1657 | "@socket.io/component-emitter": "~3.1.0",
1658 | "debug": "~4.3.1"
1659 | },
1660 | "engines": {
1661 | "node": ">=10.0.0"
1662 | }
1663 | },
1664 | "node_modules/socket.io-parser/node_modules/debug": {
1665 | "version": "4.3.7",
1666 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
1667 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
1668 | "license": "MIT",
1669 | "dependencies": {
1670 | "ms": "^2.1.3"
1671 | },
1672 | "engines": {
1673 | "node": ">=6.0"
1674 | },
1675 | "peerDependenciesMeta": {
1676 | "supports-color": {
1677 | "optional": true
1678 | }
1679 | }
1680 | },
1681 | "node_modules/socket.io/node_modules/accepts": {
1682 | "version": "1.3.8",
1683 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
1684 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
1685 | "license": "MIT",
1686 | "dependencies": {
1687 | "mime-types": "~2.1.34",
1688 | "negotiator": "0.6.3"
1689 | },
1690 | "engines": {
1691 | "node": ">= 0.6"
1692 | }
1693 | },
1694 | "node_modules/socket.io/node_modules/debug": {
1695 | "version": "4.3.7",
1696 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
1697 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
1698 | "license": "MIT",
1699 | "dependencies": {
1700 | "ms": "^2.1.3"
1701 | },
1702 | "engines": {
1703 | "node": ">=6.0"
1704 | },
1705 | "peerDependenciesMeta": {
1706 | "supports-color": {
1707 | "optional": true
1708 | }
1709 | }
1710 | },
1711 | "node_modules/socket.io/node_modules/mime-db": {
1712 | "version": "1.52.0",
1713 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
1714 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
1715 | "license": "MIT",
1716 | "engines": {
1717 | "node": ">= 0.6"
1718 | }
1719 | },
1720 | "node_modules/socket.io/node_modules/mime-types": {
1721 | "version": "2.1.35",
1722 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
1723 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
1724 | "license": "MIT",
1725 | "dependencies": {
1726 | "mime-db": "1.52.0"
1727 | },
1728 | "engines": {
1729 | "node": ">= 0.6"
1730 | }
1731 | },
1732 | "node_modules/socket.io/node_modules/negotiator": {
1733 | "version": "0.6.3",
1734 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
1735 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
1736 | "license": "MIT",
1737 | "engines": {
1738 | "node": ">= 0.6"
1739 | }
1740 | },
1741 | "node_modules/sparse-bitfield": {
1742 | "version": "3.0.3",
1743 | "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
1744 | "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
1745 | "license": "MIT",
1746 | "dependencies": {
1747 | "memory-pager": "^1.0.2"
1748 | }
1749 | },
1750 | "node_modules/statuses": {
1751 | "version": "2.0.2",
1752 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
1753 | "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
1754 | "license": "MIT",
1755 | "engines": {
1756 | "node": ">= 0.8"
1757 | }
1758 | },
1759 | "node_modules/toidentifier": {
1760 | "version": "1.0.1",
1761 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
1762 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
1763 | "license": "MIT",
1764 | "engines": {
1765 | "node": ">=0.6"
1766 | }
1767 | },
1768 | "node_modules/tr46": {
1769 | "version": "5.1.1",
1770 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz",
1771 | "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==",
1772 | "license": "MIT",
1773 | "dependencies": {
1774 | "punycode": "^2.3.1"
1775 | },
1776 | "engines": {
1777 | "node": ">=18"
1778 | }
1779 | },
1780 | "node_modules/type-is": {
1781 | "version": "2.0.1",
1782 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
1783 | "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
1784 | "license": "MIT",
1785 | "dependencies": {
1786 | "content-type": "^1.0.5",
1787 | "media-typer": "^1.1.0",
1788 | "mime-types": "^3.0.0"
1789 | },
1790 | "engines": {
1791 | "node": ">= 0.6"
1792 | }
1793 | },
1794 | "node_modules/undici-types": {
1795 | "version": "7.10.0",
1796 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
1797 | "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
1798 | "license": "MIT"
1799 | },
1800 | "node_modules/unpipe": {
1801 | "version": "1.0.0",
1802 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
1803 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
1804 | "license": "MIT",
1805 | "engines": {
1806 | "node": ">= 0.8"
1807 | }
1808 | },
1809 | "node_modules/uuid": {
1810 | "version": "9.0.1",
1811 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
1812 | "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
1813 | "funding": [
1814 | "https://github.com/sponsors/broofa",
1815 | "https://github.com/sponsors/ctavan"
1816 | ],
1817 | "license": "MIT",
1818 | "bin": {
1819 | "uuid": "dist/bin/uuid"
1820 | }
1821 | },
1822 | "node_modules/vary": {
1823 | "version": "1.1.2",
1824 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
1825 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
1826 | "license": "MIT",
1827 | "engines": {
1828 | "node": ">= 0.8"
1829 | }
1830 | },
1831 | "node_modules/webidl-conversions": {
1832 | "version": "7.0.0",
1833 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
1834 | "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
1835 | "license": "BSD-2-Clause",
1836 | "engines": {
1837 | "node": ">=12"
1838 | }
1839 | },
1840 | "node_modules/whatwg-url": {
1841 | "version": "14.2.0",
1842 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz",
1843 | "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==",
1844 | "license": "MIT",
1845 | "dependencies": {
1846 | "tr46": "^5.1.0",
1847 | "webidl-conversions": "^7.0.0"
1848 | },
1849 | "engines": {
1850 | "node": ">=18"
1851 | }
1852 | },
1853 | "node_modules/wrappy": {
1854 | "version": "1.0.2",
1855 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1856 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
1857 | "license": "ISC"
1858 | },
1859 | "node_modules/ws": {
1860 | "version": "8.17.1",
1861 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
1862 | "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
1863 | "license": "MIT",
1864 | "engines": {
1865 | "node": ">=10.0.0"
1866 | },
1867 | "peerDependencies": {
1868 | "bufferutil": "^4.0.1",
1869 | "utf-8-validate": ">=5.0.2"
1870 | },
1871 | "peerDependenciesMeta": {
1872 | "bufferutil": {
1873 | "optional": true
1874 | },
1875 | "utf-8-validate": {
1876 | "optional": true
1877 | }
1878 | }
1879 | }
1880 | }
1881 | }
1882 |
--------------------------------------------------------------------------------