`
7 | 2. cd into your new project folder and run `npm i`
8 | 3. Create a new `.env` file and add the `MONGODB_URI`
9 | 4. Run the app with: `npm run dev`
--------------------------------------------------------------------------------
/frontend/src/api/api.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | const API = axios.create({
4 | baseURL: "http://localhost:4000/api", // make sure this matches your Express server URL
5 | withCredentials: true, // optional: only needed if you're dealing with cookies
6 | });
7 |
8 | export default API;
--------------------------------------------------------------------------------
/frontend/src/redux/store.js:
--------------------------------------------------------------------------------
1 | import { configureStore } from "@reduxjs/toolkit";
2 | import authReducer from "./authSlice";
3 | import postReducer from "./postSlice";
4 |
5 | const store = configureStore({
6 | reducer: {
7 | auth: authReducer,
8 | posts: postReducer,
9 | },
10 | });
11 |
12 | export default store;
13 |
--------------------------------------------------------------------------------
/frontend/src/api/comments.js:
--------------------------------------------------------------------------------
1 | import API from "./axios";
2 |
3 | const commentsAPI = {
4 | addComment: (postId, data) => API.post(`/comment/${postId}`, data),
5 | deleteComment: (commentId) => API.delete(`/comment/${commentId}`),
6 | updateComment: (commentId, data) => API.put(`/comment/${commentId}`, data),
7 | };
8 |
9 | export default commentsAPI;
10 |
--------------------------------------------------------------------------------
/frontend/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Creatify
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/frontend/src/redux/postSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from '@reduxjs/toolkit';
2 |
3 | const postSlice = createSlice({
4 | name: 'posts',
5 | initialState: [],
6 | reducers: {
7 | addPost: (state, action) => {
8 | state.push(action.payload);
9 | },
10 | // add more reducers as needed
11 | },
12 | });
13 |
14 | // ✅ Export the actions
15 | export const { addPost } = postSlice.actions;
16 |
17 | // ✅ Export reducer as default
18 | export default postSlice.reducer;
--------------------------------------------------------------------------------
/frontend/src/components/ImageUpload.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const ImageUpload = ({ onImageChange }) => {
4 | return (
5 |
6 | Upload Image
7 |
13 |
14 | );
15 | };
16 |
17 | export default ImageUpload;
--------------------------------------------------------------------------------
/frontend/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: [
4 | "./index.html",
5 | "./src/**/*.{js,jsx,ts,tsx}",
6 | ],
7 | theme: {
8 | extend: {
9 | colors: {
10 | primary: "#7e22ce",
11 | secondary: "#f3f4f6",
12 | accent: "#e879f9",
13 | },
14 | fontFamily: {
15 | sans: ["Inter", "ui-sans-serif", "system-ui"],
16 | },
17 | },
18 | },
19 | plugins: [],
20 | };
21 |
--------------------------------------------------------------------------------
/backend/middleware/authMiddleware.js:
--------------------------------------------------------------------------------
1 | import jwt from "jsonwebtoken"
2 |
3 | const authMiddleware = (req, res, next) => {
4 | const token = req.header("Authorization");
5 |
6 | if (!token) return res.status(401).json({ message: "Access denied" });
7 |
8 | try {
9 | const verified = jwt.verify(token, process.env.JWT_SECRET);
10 | req.user = verified;
11 | next();
12 | } catch (err) {
13 | res.status(401).json({ message: "Invalid token" });
14 | }
15 | };
16 |
17 | export default authMiddleware;
18 |
--------------------------------------------------------------------------------
/frontend/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import App from './App';
4 | import './index.css';
5 | import "@fontsource/inter/400.css";
6 | import "@fontsource/inter/600.css";
7 | import "@fontsource/inter/700.css";
8 |
9 |
10 | import { Provider } from 'react-redux';
11 | import store from './redux/store';
12 |
13 | ReactDOM.createRoot(document.getElementById('root')).render(
14 |
15 |
16 |
17 |
18 |
19 | );
20 |
--------------------------------------------------------------------------------
/frontend/src/components/FollowButton.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 |
3 | const FollowButton = () => {
4 | const [isFollowing, setIsFollowing] = useState(false);
5 | return (
6 | setIsFollowing(!isFollowing)}
8 | className={`px-4 py-1 rounded-full font-medium transition ${
9 | isFollowing ? "bg-gray-300 text-gray-800" : "bg-purple-600 text-white hover:bg-purple-700"
10 | }`}
11 | >
12 | {isFollowing ? "Following" : "Follow"}
13 |
14 | );
15 | };
16 |
17 | export default FollowButton;
--------------------------------------------------------------------------------
/backend/models/user.js:
--------------------------------------------------------------------------------
1 | import mongoose from "mongoose";
2 |
3 | const userSchema = new mongoose.Schema({
4 | username: { type: String, required: true, unique: true },
5 | email: { type: String, required: true, unique: true },
6 | password: { type: String, required: true },
7 | profilePic: { type: String, default: "" },
8 | followers: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
9 | following: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
10 | }, { timestamps: true });
11 |
12 | const User = mongoose.models.User || mongoose.model("User", userSchema);
13 | export default User; // ✅ safe and re-usable
14 |
--------------------------------------------------------------------------------
/backend/models/post.js:
--------------------------------------------------------------------------------
1 | import mongoose from "mongoose"
2 |
3 | const postSchema = new mongoose.Schema({
4 | user: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true },
5 | imageUrl: { type: String, required: true },
6 | caption: { type: String },
7 | likes: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
8 | comments: [
9 | {
10 | user: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
11 | text: { type: String },
12 | createdAt: { type: Date, default: Date.now }
13 | }
14 | ]
15 | }, { timestamps: true });
16 |
17 | export default mongoose.model("Post", postSchema);
18 |
--------------------------------------------------------------------------------
/frontend/src/components/Layout.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Navbar from "./Navbar";
3 | import Sidebar from "./Sidebar";
4 |
5 | const Layout = ({ children }) => {
6 | return (
7 |
8 |
9 |
10 | {/* Sidebar */}
11 |
14 |
15 | {/* Main Content */}
16 |
17 | {children}
18 |
19 |
20 |
21 | );
22 | };
23 |
24 | export default Layout;
25 |
--------------------------------------------------------------------------------
/backend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "backend-template",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "type": "module",
7 | "scripts": {
8 | "dev": "nodemon index.js",
9 | "start": "node index.js"
10 | },
11 | "keywords": [],
12 | "author": "Abe Tavarez",
13 | "license": "ISC",
14 | "dependencies": {
15 | "bcryptjs": "^3.0.2",
16 | "cors": "^2.8.5",
17 | "dotenv": "^16.4.7",
18 | "express": "^4.21.2",
19 | "helmet": "^8.0.0",
20 | "jsonwebtoken": "^9.0.2",
21 | "mongoose": "^8.12.1",
22 | "multer": "^1.4.5-lts.2",
23 | "pug": "^3.0.3"
24 | },
25 | "devDependencies": {
26 | "morgan": "^1.10.0",
27 | "nodemon": "^3.1.9"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/frontend/src/components/ProfileHeader.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const ProfileHeader = ({ user }) => {
4 | return (
5 |
6 |
11 |
12 |
{user.username}
13 |
{user.bio}
14 |
15 | {user.followers} Followers
16 | {user.following} Following
17 |
18 |
19 |
20 | );
21 | };
22 |
23 | export default ProfileHeader;
24 |
--------------------------------------------------------------------------------
/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/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-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 and enable type-aware lint rules. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
13 |
--------------------------------------------------------------------------------
/frontend/src/components/Sidebar.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link } from "react-router-dom";
3 |
4 | const Sidebar = () => {
5 | return (
6 |
7 |
Navigation
8 |
9 | 🏠 Home
10 | 📸 Create Post
11 | 👤 My Profile
12 | 🔐 Login
13 | ✍️ Register
14 |
15 |
16 | );
17 | };
18 |
19 | export default Sidebar;
--------------------------------------------------------------------------------
/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 |
6 | export default [
7 | { ignores: ['dist'] },
8 | {
9 | files: ['**/*.{js,jsx}'],
10 | languageOptions: {
11 | ecmaVersion: 2020,
12 | globals: globals.browser,
13 | parserOptions: {
14 | ecmaVersion: 'latest',
15 | ecmaFeatures: { jsx: true },
16 | sourceType: 'module',
17 | },
18 | },
19 | plugins: {
20 | 'react-hooks': reactHooks,
21 | 'react-refresh': reactRefresh,
22 | },
23 | rules: {
24 | ...js.configs.recommended.rules,
25 | ...reactHooks.configs.recommended.rules,
26 | 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
27 | 'react-refresh/only-export-components': [
28 | 'warn',
29 | { allowConstantExport: true },
30 | ],
31 | },
32 | },
33 | ]
34 |
--------------------------------------------------------------------------------
/backend/public/js/main.js:
--------------------------------------------------------------------------------
1 | document.addEventListener("DOMContentLoaded", () => {
2 | // Add copy functionality to code blocks
3 | document.querySelectorAll("pre code").forEach((block) => {
4 | block.addEventListener("click", () => {
5 | const text = block.textContent;
6 | navigator.clipboard.writeText(text).then(() => {
7 | // Show a brief "Copied!" message
8 | const message = document.createElement("div");
9 | message.textContent = "Copied!";
10 | message.style.cssText = `
11 | position: fixed;
12 | top: 20px;
13 | right: 20px;
14 | background: #28a745;
15 | color: white;
16 | padding: 10px 20px;
17 | border-radius: 5px;
18 | transition: opacity 0.3s;
19 | `;
20 | document.body.appendChild(message);
21 | setTimeout(() => {
22 | message.style.opacity = "0";
23 | setTimeout(() => message.remove(), 300);
24 | }, 2000);
25 | });
26 | });
27 | });
28 | });
--------------------------------------------------------------------------------
/frontend/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
3 | import Home from "./pages/Home";
4 | import Login from "./pages/Login";
5 | import Register from "./pages/Register";
6 | import Profile from "./pages/Profile";
7 | import CreatePost from "./pages/CreatePost";
8 | import Comments from "./pages/Comment"; // ✅ Add this line!
9 | import Layout from "./components/Layout";
10 |
11 | const App = () => {
12 | return (
13 |
14 |
15 | } />
16 | } />
17 | } />
18 | } />
19 |
20 | {/* Login & Register don't use the main layout */}
21 | } />
22 | } />
23 |
24 |
25 | );
26 | };
27 |
28 | export default App;
29 |
--------------------------------------------------------------------------------
/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 | "@fontsource/inter": "^5.2.5",
14 | "@reduxjs/toolkit": "^2.6.1",
15 | "axios": "^1.8.4",
16 | "lucide-react": "^0.484.0",
17 | "react": "^19.0.0",
18 | "react-dom": "^19.0.0",
19 | "react-icons": "^5.5.0",
20 | "react-redux": "^9.2.0",
21 | "react-router-dom": "^7.4.0"
22 | },
23 | "devDependencies": {
24 | "@eslint/js": "^9.21.0",
25 | "@tailwindcss/postcss": "^4.0.17",
26 | "@types/react": "^19.0.10",
27 | "@types/react-dom": "^19.0.4",
28 | "@vitejs/plugin-react": "^4.3.4",
29 | "autoprefixer": "^10.4.21",
30 | "eslint": "^9.21.0",
31 | "eslint-plugin-react-hooks": "^5.1.0",
32 | "eslint-plugin-react-refresh": "^0.4.19",
33 | "globals": "^15.15.0",
34 | "postcss": "^8.5.3",
35 | "tailwindcss": "^3.4.17",
36 | "vite": "^6.2.0"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/backend/public/css/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
3 | "Helvetica Neue", Arial, sans-serif;
4 | line-height: 1.6;
5 | max-width: 1000px;
6 | margin: 0 auto;
7 | padding: 20px;
8 | }
9 |
10 | .api-title {
11 | color: #2c3e50;
12 | border-bottom: 2px solid #3498db;
13 | padding-bottom: 10px;
14 | }
15 |
16 | .endpoint {
17 | background: #f8f9fa;
18 | padding: 15px;
19 | margin: 10px 0;
20 | border-radius: 5px;
21 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
22 | }
23 |
24 | .method {
25 | display: inline-block;
26 | padding: 4px 8px;
27 | border-radius: 4px;
28 | color: white;
29 | font-weight: bold;
30 | margin-right: 10px;
31 | }
32 |
33 | .get {
34 | background: #28a745;
35 | }
36 | .post {
37 | background: #007bff;
38 | }
39 | .put {
40 | background: #ffc107;
41 | color: #000;
42 | }
43 | .delete {
44 | background: #dc3545;
45 | }
46 |
47 | code {
48 | background: #e9ecef;
49 | padding: 2px 5px;
50 | border-radius: 3px;
51 | font-family: "Courier New", Courier, monospace;
52 | }
53 |
54 | pre {
55 | background: #f8f9fa;
56 | padding: 15px;
57 | border-radius: 5px;
58 | overflow-x: auto;
59 | }
60 |
61 | pre:hover {
62 | cursor: pointer;
63 | }
--------------------------------------------------------------------------------
/frontend/src/components/Navbar.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link, useLocation } from "react-router-dom";
3 | import { Home, PlusCircle, User, LogIn } from "lucide-react";
4 |
5 | const Navbar = () => {
6 | const location = useLocation();
7 |
8 | const navItems = [
9 | { to: "/", icon: , label: "Home" },
10 | { to: "/create", icon: , label: "Create" },
11 | { to: "/profile/1", icon: , label: "Profile" },
12 | { to: "/login", icon: , label: "Login" },
13 | ];
14 |
15 | return (
16 |
17 |
18 | {navItems.map((item) => (
19 |
26 | {item.icon}
27 |
28 | ))}
29 |
30 |
31 | );
32 | };
33 |
34 | export default Navbar;
35 |
--------------------------------------------------------------------------------
/frontend/src/pages/Home.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import PostCard from "../components/PostCard";
3 | import API from "../api/axios";
4 |
5 | const Home = () => {
6 | const [posts, setPosts] = useState([]);
7 | const [loading, setLoading] = useState(true);
8 |
9 | useEffect(() => {
10 | const fetchPosts = async () => {
11 | try {
12 | const res = await API.get("/post");
13 | setPosts(Array.isArray(res.data) ? res.data : []);
14 | } catch (err) {
15 | console.error("Error fetching posts:", err);
16 | } finally {
17 | setLoading(false);
18 | }
19 | };
20 |
21 | fetchPosts();
22 | }, []);
23 |
24 | return (
25 |
26 |
27 | Explore Creatify Feed
28 |
29 |
30 | {loading ? (
31 |
Loading posts...
32 | ) : posts.length === 0 ? (
33 |
No posts available.
34 | ) : (
35 |
36 | {posts.map((post) => (
37 |
38 | ))}
39 |
40 | )}
41 |
42 | );
43 | };
44 |
45 | export default Home;
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🎨 Creatify - Social Media App
2 |
3 | Creatify is a full-stack social media web application — built for creators and visionaries. With a sleek modern UI and intuitive experience, users can share visual stories, like and comment on posts, and build their own digital presence.
4 |
5 | ## ✨ Features
6 |
7 | - 🏠 **Home Feed** – Scroll through all posts from users.
8 | - 🖼️ **Create & Upload Posts** – Share your creativity with captions and images.
9 | - ❤️ **Like Posts** – Includes toggle with heart animation.
10 | - 💬 **Comment System** – Add, edit, and delete comments.
11 | - ➕ **Follow/Unfollow** – Build and grow your audience.
12 | - ✏️ **Edit Captions** – Update or delete your own post captions.
13 | - 👤 **Profile Page** – View user details, avatar, bio, and their posts.
14 | - 📱 **Responsive Design** – Optimized for desktop-first; mobile ready.
15 | - ⚡ **Smooth UX** – Fast transitions and interactive feedback.
16 |
17 | ## 🛠️ Tech Stack
18 |
19 | ### 💻 Frontend
20 | - **React.js** with **React Router**
21 | - **Redux Toolkit** – Global state management
22 | - **Tailwind CSS** – Utility-first styling
23 | - **Axios** – API communication
24 | - **Lucide React** – Modern, lightweight UI icons
25 |
26 | ### 🔧 Backend
27 | - **Node.js** + **Express.js** – REST API
28 | - **MongoDB** with **Mongoose** – Database
29 | - **Firebase** – Image storage and retrieval
30 |
31 | ## 📁 Folder Structure (Simplified)
32 |
--------------------------------------------------------------------------------
/frontend/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backend/index.js:
--------------------------------------------------------------------------------
1 | import express from "express";
2 | import morgan from "morgan";
3 | import helmet from "helmet";
4 | import dotenv from "dotenv";
5 | import cors from "cors";
6 | import mongoose from "mongoose";
7 |
8 | // Routers
9 | import { healthRouter } from "./routes/health.js";
10 | import authRouter from "./routes/auth.js";
11 | import postRouter from "./routes/post.js";
12 | import userRouter from "./routes/user.js";
13 |
14 |
15 | const app = express();
16 |
17 | dotenv.config();
18 | // console.log(process.env.MONGODB_URI);
19 |
20 | // Connect to MongoDB
21 | await mongoose
22 | .connect(process.env.MONGODB_URI)
23 | .then(() => console.log("Connected to MongoDB"))
24 | .catch((e) => console.error(e));
25 |
26 | const PORT = process.env.PORT || 4000;
27 |
28 |
29 |
30 | // View Engine
31 | app.set("views", "./views");
32 | app.set("view engine", "pug");
33 |
34 | // Middlewares
35 | app.use(express.static("./public"));
36 | app.use(express.json());
37 | app.use(express.urlencoded({ extended: true }));
38 | app.use(morgan("dev"));
39 | app.use(helmet());
40 | app.use(cors());
41 |
42 | // Routes
43 | app.get("/", (req, res) => {
44 | res.render("index");
45 | });
46 |
47 | // API Routes
48 | app.use("/api/health", healthRouter);
49 | app.use("/api/auth", authRouter);
50 | app.use("/api/post", postRouter);
51 | app.use("/api/user", userRouter);
52 |
53 |
54 | // Global error handling
55 | app.use((err, req, res, next) => {
56 | console.error(err);
57 | res.status(500).send("Seems like we messed up somewhere...");
58 | });
59 |
60 | app.listen(PORT, () => console.log(`Server is running on port: ${PORT}`));
61 |
--------------------------------------------------------------------------------
/backend/routes/auth.js:
--------------------------------------------------------------------------------
1 | import express from "express";
2 | import bcrypt from "bcryptjs";
3 | import jwt from "jsonwebtoken"
4 | import user from "../models/user.js"
5 |
6 |
7 | const router = express.Router();
8 |
9 | // Register
10 | router.post("/register", async (req, res) => {
11 | try {
12 | const { username, email, password } = req.body;
13 |
14 | // Check if user exists
15 | const existingUser = await user.findOne({ email });
16 | if (existingUser) return res.status(400).json({ message: "Email already exists" });
17 |
18 | // Hash password
19 | const salt = await bcrypt.genSalt(10);
20 | const hashedPassword = await bcrypt.hash(password, salt);
21 |
22 | // Create new user
23 | const newUser = new user({ username, email, password: hashedPassword });
24 | await newUser.save();
25 |
26 | res.status(201).json({ message: "User registered successfully!" });
27 | } catch (error) {
28 | res.status(500).json({ message: "Server error" });
29 | }
30 | });
31 |
32 | // Login
33 | router.post("/login", async (req, res) => {
34 | try {
35 | const { email, password } = req.body;
36 |
37 | const user = await user.findOne({ email });
38 | if (!user) return res.status(400).json({ message: "Invalid credentials" });
39 |
40 | const isMatch = await bcrypt.compare(password, user.password);
41 | if (!isMatch) return res.status(400).json({ message: "Invalid credentials" });
42 |
43 | // Generate JWT Token
44 | const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: "7d" });
45 |
46 | res.json({ token, user });
47 | } catch (error) {
48 | res.status(500).json({ message: "Server error" });
49 | }
50 | });
51 |
52 | export default router;
--------------------------------------------------------------------------------
/backend/controllers/authController.js:
--------------------------------------------------------------------------------
1 | import bcrypt from ("bcryptjs");
2 | import jwt from ("jsonwebtoken");
3 | import User from ("../models/user");
4 |
5 | // Register User
6 | exports.registerUser = async (req, res) => {
7 | try {
8 | const { username, email, password } = req.body;
9 |
10 | // Check if user already exists
11 | let user = await User.findOne({ email });
12 | if (user) return res.status(400).json({ message: "User already exists" });
13 |
14 | // Hash password
15 | const salt = await bcrypt.genSalt(10);
16 | const hashedPassword = await bcrypt.hash(password, salt);
17 |
18 | // Create new user
19 | user = new User({ username, email, password: hashedPassword });
20 | await user.save();
21 |
22 | // Generate JWT token
23 | const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: "7d" });
24 |
25 | res.status(201).json({ token, user });
26 | } catch (error) {
27 | res.status(500).json({ message: "Server error" });
28 | }
29 | };
30 |
31 | // Login User
32 | exports.loginUser = async (req, res) => {
33 | try {
34 | const { email, password } = req.body;
35 |
36 | // Check if user exists
37 | const user = await User.findOne({ email });
38 | if (!user) return res.status(400).json({ message: "Invalid credentials" });
39 |
40 | // Validate password
41 | const isMatch = await bcrypt.compare(password, user.password);
42 | if (!isMatch) return res.status(400).json({ message: "Invalid credentials" });
43 |
44 | // Generate token
45 | const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: "7d" });
46 |
47 | res.status(200).json({ token, user });
48 | } catch (error) {
49 | res.status(500).json({ message: "Server error" });
50 | }
51 | };
52 |
--------------------------------------------------------------------------------
/frontend/src/components/PostCard.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { Heart, MessageCircle } from "lucide-react";
3 | import CommentBox from "./CommentBox";
4 |
5 | const PostCard = ({ post }) => {
6 | const { userAvatar, username, image, caption, likes: initialLikes, comments } = post;
7 |
8 | const [likes, setLikes] = useState(initialLikes);
9 | const [liked, setLiked] = useState(false);
10 | const [showComments, setShowComments] = useState(false);
11 |
12 | const toggleLike = () => {
13 | setLiked(!liked);
14 | setLikes((prev) => (liked ? prev - 1 : prev + 1));
15 | };
16 |
17 | return (
18 |
19 |
20 |
21 |
{username}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 | setShowComments((prev) => !prev)} className="hover:scale-110 transition-transform">
33 |
34 |
35 |
36 |
37 |
38 | {username} {caption}
39 |
40 |
{likes} likes
41 |
42 | {showComments && (
43 |
44 |
45 |
46 | )}
47 |
48 |
49 | );
50 | };
51 |
52 | export default PostCard;
53 |
--------------------------------------------------------------------------------
/backend/controllers/postController.js:
--------------------------------------------------------------------------------
1 | import Post from "../models/post";
2 |
3 | // Create Post
4 | exports.createPost = async (req, res) => {
5 | try {
6 | const { caption, imageUrl } = req.body;
7 | const newPost = new Post({
8 | user: req.user.id,
9 | caption,
10 | imageUrl,
11 | });
12 |
13 | await newPost.save();
14 | res.status(201).json(newPost);
15 | } catch (error) {
16 | res.status(500).json({ message: "Server error" });
17 | }
18 | };
19 |
20 | // Get All Posts
21 | exports.getPosts = async (req, res) => {
22 | try {
23 | const posts = await Post.find().populate("user", "username profilePic").sort({ createdAt: -1 });
24 | res.status(200).json(posts);
25 | } catch (error) {
26 | res.status(500).json({ message: "Server error" });
27 | }
28 | };
29 |
30 | // Like a Post
31 | exports.likePost = async (req, res) => {
32 | try {
33 | const post = await Post.findById(req.params.id);
34 | if (!post) return res.status(404).json({ message: "Post not found" });
35 |
36 | if (post.likes.includes(req.user.id)) {
37 | post.likes = post.likes.filter(id => id.toString() !== req.user.id.toString());
38 | } else {
39 | post.likes.push(req.user.id);
40 | }
41 |
42 | await post.save();
43 | res.status(200).json(post);
44 | } catch (error) {
45 | res.status(500).json({ message: "Server error" });
46 | }
47 | };
48 |
49 | // Comment on a Post
50 | exports.commentOnPost = async (req, res) => {
51 | try {
52 | const { text } = req.body;
53 | const post = await Post.findById(req.params.id);
54 | if (!post) return res.status(404).json({ message: "Post not found" });
55 |
56 | const comment = { user: req.user.id, text, createdAt: new Date() };
57 | post.comments.push(comment);
58 |
59 | await post.save();
60 | res.status(200).json(post);
61 | } catch (error) {
62 | res.status(500).json({ message: "Server error" });
63 | }
64 | };
65 |
--------------------------------------------------------------------------------
/backend/controllers/userController.js:
--------------------------------------------------------------------------------
1 | import User from ("../models/user");
2 |
3 | // Get User Profile
4 | exports.getUserProfile = async (req, res) => {
5 | try {
6 | const user = await User.findById(req.params.id).select("-password");
7 | if (!user) return res.status(404).json({ message: "User not found" });
8 |
9 | res.status(200).json(user);
10 | } catch (error) {
11 | res.status(500).json({ message: "Server error" });
12 | }
13 | };
14 |
15 | // Follow a User
16 | exports.followUser = async (req, res) => {
17 | try {
18 | const user = await User.findById(req.params.id);
19 | const currentUser = await User.findById(req.user.id);
20 |
21 | if (!user || !currentUser) return res.status(404).json({ message: "User not found" });
22 | if (currentUser.following.includes(user._id)) return res.status(400).json({ message: "Already following" });
23 |
24 | currentUser.following.push(user._id);
25 | user.followers.push(currentUser._id);
26 |
27 | await currentUser.save();
28 | await user.save();
29 |
30 | res.status(200).json({ message: "Followed successfully" });
31 | } catch (error) {
32 | res.status(500).json({ message: "Server error" });
33 | }
34 | };
35 |
36 | // Unfollow a User
37 | exports.unfollowUser = async (req, res) => {
38 | try {
39 | const user = await User.findById(req.params.id);
40 | const currentUser = await User.findById(req.user.id);
41 |
42 | if (!user || !currentUser) return res.status(404).json({ message: "User not found" });
43 | if (!currentUser.following.includes(user._id)) return res.status(400).json({ message: "Not following this user" });
44 |
45 | currentUser.following = currentUser.following.filter(id => id.toString() !== user._id.toString());
46 | user.followers = user.followers.filter(id => id.toString() !== currentUser._id.toString());
47 |
48 | await currentUser.save();
49 | await user.save();
50 |
51 | res.status(200).json({ message: "Unfollowed successfully" });
52 | } catch (error) {
53 | res.status(500).json({ message: "Server error" });
54 | }
55 | };
56 |
--------------------------------------------------------------------------------
/frontend/src/pages/CreatePost.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { useNavigate } from "react-router-dom";
3 |
4 | const CreatePost = () => {
5 | const navigate = useNavigate();
6 | const [formData, setFormData] = useState({
7 | caption: "",
8 | image: null,
9 | });
10 |
11 | const handleChange = (e) => {
12 | const { name, value, files } = e.target;
13 | if (name === "image") {
14 | setFormData({ ...formData, image: files[0] });
15 | } else {
16 | setFormData({ ...formData, [name]: value });
17 | }
18 | };
19 |
20 | const handleSubmit = (e) => {
21 | e.preventDefault();
22 | // Here you'd send to backend, or Firebase, etc.
23 | console.log("New Post Submitted:", formData);
24 | navigate("/"); // go back to home/feed
25 | };
26 |
27 | return (
28 |
29 |
30 |
31 | Create a New Post 🖼️
32 |
33 |
63 |
64 |
65 | );
66 | };
67 |
68 | export default CreatePost;
69 |
--------------------------------------------------------------------------------
/frontend/src/redux/authSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
2 | import axios from "../api/api";
3 |
4 | // Async Thunks
5 | export const registerUser = createAsyncThunk("auth/register", async (formData, thunkAPI) => {
6 | try {
7 | const res = await axios.post("/auth/register", formData);
8 | return res.data;
9 | } catch (err) {
10 | return thunkAPI.rejectWithValue(err.response.data);
11 | }
12 | });
13 |
14 | export const loginUser = createAsyncThunk("auth/login", async (formData, thunkAPI) => {
15 | try {
16 | const res = await axios.post("/auth/login", formData, {
17 | withCredentials: true,
18 | });
19 | localStorage.setItem("token", res.data.token); // Optional for now
20 | return res.data;
21 | } catch (err) {
22 | return thunkAPI.rejectWithValue(err.response?.data || { message: "Login failed" });
23 | }
24 | });
25 |
26 | // Slice
27 | const authSlice = createSlice({
28 | name: "auth",
29 | initialState: {
30 | user: null,
31 | token: localStorage.getItem("token") || null,
32 | loading: false,
33 | error: null,
34 | },
35 | reducers: {
36 | logout: (state) => {
37 | state.user = null;
38 | state.token = null;
39 | localStorage.removeItem("token");
40 | },
41 | },
42 | extraReducers: (builder) => {
43 | builder
44 | .addCase(registerUser.pending, (state) => {
45 | state.loading = true;
46 | state.error = null;
47 | })
48 | .addCase(registerUser.fulfilled, (state, action) => {
49 | state.loading = false;
50 | state.user = action.payload.user;
51 | state.token = action.payload.token;
52 | })
53 | .addCase(registerUser.rejected, (state, action) => {
54 | state.loading = false;
55 | state.error = action.payload?.message || "Registration failed";
56 | })
57 | .addCase(loginUser.pending, (state) => {
58 | state.loading = true;
59 | state.error = null;
60 | })
61 | .addCase(loginUser.fulfilled, (state, action) => {
62 | state.loading = false;
63 | state.user = action.payload.user;
64 | state.token = action.payload.token;
65 | })
66 | .addCase(loginUser.rejected, (state, action) => {
67 | state.loading = false;
68 | state.error = action.payload?.message || "Login failed";
69 | });
70 | },
71 | });
72 |
73 | export const { logout } = authSlice.actions;
74 | export default authSlice.reducer;
75 |
--------------------------------------------------------------------------------
/frontend/src/pages/Comment.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import { useParams } from "react-router-dom";
3 | import API from "../api/axios";
4 | import CommentBox from "../components/CommentBox";
5 |
6 |
7 |
8 | const Comments = () => {
9 | const { postId } = useParams(); // Grab post ID from route
10 | const [post, setPost] = useState(null);
11 | const [comments, setComments] = useState([]);
12 | const [newComment, setNewComment] = useState("");
13 |
14 | useEffect(() => {
15 | const fetchData = async () => {
16 | try {
17 | const res = await API.get(`/post/${postId}`);
18 | setPost(res.data.post);
19 | setComments(res.data.comments); // Adjust if your response structure differs
20 | } catch (err) {
21 | console.error("Error fetching post/comments", err);
22 | }
23 | };
24 | fetchData();
25 | }, [postId]);
26 |
27 | const handleCommentSubmit = async () => {
28 | try {
29 | const res = await API.post(`/comments`, {
30 | postId,
31 | text: newComment,
32 | });
33 | setComments((prev) => [...prev, res.data]);
34 | setNewComment("");
35 | } catch (err) {
36 | console.error("Error posting comment", err);
37 | }
38 | };
39 |
40 | if (!post) return Loading post...
;
41 |
42 | return (
43 |
44 |
45 |
46 |
47 | {post.caption}
48 |
49 |
50 |
51 |
52 |
Comments
53 |
54 | {comments.map((comment) => (
55 |
56 | ))}
57 |
58 |
59 |
60 | setNewComment(e.target.value)}
66 | />
67 |
71 | Post Comment
72 |
73 |
74 |
75 |
76 | );
77 | };
78 |
79 | export default Comments;
80 |
--------------------------------------------------------------------------------
/backend/routes/post.js:
--------------------------------------------------------------------------------
1 | import express from "express";
2 | import User from "../models/user.js";
3 | import Post from "../models/post.js"; // ✅ You forgot to import the Post model
4 | //import authMiddleware from "../middleware/authMiddleware.js";
5 |
6 | const router = express.Router();
7 |
8 | // ✅ Create a post
9 | router.post("/", async (req, res) => {
10 | try {
11 | const { caption, imageUrl } = req.body;
12 | const newPost = new Post({
13 | user: req.user.id,
14 | caption,
15 | imageUrl,
16 | });
17 |
18 | await newPost.save();
19 | res.status(201).json(newPost);
20 | } catch (error) {
21 | console.error(error); // Helpful for debugging
22 | res.status(500).json({ message: "Server error" });
23 | }
24 | });
25 |
26 | // ✅ Get all posts
27 | router.get("/", async (req, res) => {
28 | try {
29 | const posts = await Post.find()
30 | .populate("user", "username profilePic")
31 | .sort({ createdAt: -1 });
32 | res.json(posts);
33 | } catch (error) {
34 | console.error(error);
35 | res.status(500).json({ message: "Server error" });
36 | }
37 | });
38 |
39 | // ✅ Like/unlike a post
40 | router.post("/:id/like", async (req, res) => {
41 | try {
42 | const foundPost = await Post.findById(req.params.id); // ✅ Changed variable name to avoid shadowing
43 | if (!foundPost) {
44 | return res.status(404).json({ message: "Post not found" });
45 | }
46 |
47 | const userId = req.user.id;
48 | const alreadyLiked = foundPost.likes.includes(userId);
49 |
50 | if (alreadyLiked) {
51 | // Remove like
52 | foundPost.likes = foundPost.likes.filter(id => id.toString() !== userId);
53 | } else {
54 | // Add like
55 | foundPost.likes.push(userId);
56 | }
57 |
58 | await foundPost.save();
59 | res.json(foundPost);
60 | } catch (error) {
61 | console.error(error);
62 | res.status(500).json({ message: "Server error" });
63 | }
64 | });
65 |
66 | // ✅ Comment on a post
67 | router.post("/:id/comment", async (req, res) => {
68 | try {
69 | const { text } = req.body;
70 | const foundPost = await Post.findById(req.params.id);
71 |
72 | if (!foundPost) {
73 | return res.status(404).json({ message: "Post not found" });
74 | }
75 |
76 | foundPost.comments.push({
77 | user: req.user.id,
78 | text,
79 | createdAt: new Date()
80 | });
81 |
82 | await foundPost.save();
83 | res.json(foundPost);
84 | } catch (error) {
85 | console.error(error);
86 | res.status(500).json({ message: "Server error" });
87 | }
88 | });
89 |
90 | export default router;
91 |
--------------------------------------------------------------------------------
/frontend/src/pages/Login.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { useDispatch, useSelector } from "react-redux";
3 | import { loginUser } from "../redux/authSlice";
4 | import { useNavigate } from "react-router-dom";
5 |
6 | const Login = () => {
7 | const dispatch = useDispatch();
8 | const navigate = useNavigate();
9 | const { loading, error } = useSelector((state) => state.auth);
10 | const [formData, setFormData] = useState({ email: "", password: "" });
11 |
12 | const handleChange = (e) =>
13 | setFormData({ ...formData, [e.target.name]: e.target.value });
14 |
15 | const handleSubmit = async (e) => {
16 | e.preventDefault();
17 | const result = await dispatch(loginUser(formData));
18 | if (result.type === "auth/login/fulfilled") {
19 | navigate("/");
20 | }
21 | };
22 |
23 | return (
24 |
25 |
26 |
27 | Login to Creatify
28 |
29 | {error && (
30 |
{error}
31 | )}
32 |
33 |
34 | Email
35 |
43 |
44 |
45 | Password
46 |
54 |
55 |
60 | {loading ? "Logging in..." : "Login"}
61 |
62 |
63 |
64 | Dont have an account?{" "}
65 | navigate("/register")}
68 | >
69 | Register
70 |
71 |
72 |
73 |
74 | );
75 | };
76 |
77 | export default Login;
78 |
--------------------------------------------------------------------------------
/frontend/src/pages/Profile.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Sidebar from "../components/Sidebar";
3 | import ProfileHeader from "../components/ProfileHeader";
4 | import PostCard from "../components/PostCard";
5 |
6 | // Avatar you provided
7 | const avatarURL =
8 | "https://scontent-dfw5-2.xx.fbcdn.net/v/t39.30808-6/464857778_1685821188629397_2485675738634627979_n.jpg?_nc_cat=108&ccb=1-7&_nc_sid=a5f93a&_nc_ohc=7F7zaQ3ylcQQ7kNvgGHz5Ho&_nc_oc=AdnGxIzaKl0u_1-SBi7EIMnE367aTnO4GRCTZdtT5PcA7NzQUN0TXdQ91qForFqUgjqlR5R6kAfSbjUUesP5id7g&_nc_zt=23&_nc_ht=scontent-dfw5-2.xx&_nc_gid=h519OxmAvhnM06c2jnXzWA&oh=00_AYEJsJYLxklF7Za2-B3jP_cyykq0xkD54OL8m8PodlDUtg&oe=67EB3464";
9 |
10 | const dummyUser = {
11 | avatar: avatarURL,
12 | username: "DigitalVisionary",
13 | bio: "|Creating Digital MasterPieces|",
14 | followers: 1200,
15 | following: 340,
16 | };
17 |
18 | // Post images you provided
19 | const posts = [
20 | {
21 | _id: "1",
22 | userAvatar: avatarURL,
23 | username: dummyUser.username,
24 | image:
25 | "https://scontent-dfw5-1.xx.fbcdn.net/v/t39.30808-6/480258617_1779981625880019_1287261705637954459_n.jpg?_nc_cat=105&ccb=1-7&_nc_sid=f727a1&_nc_ohc=Xh5vHJiT618Q7kNvgF8ys5R&_nc_oc=AdlfMr2vOmQZ_vcDszS-7dz7swq513plW9Ail6GRuVZbmnuhPxPfMASganBBZzaL_zdRCHGDRjVHt7D5Ky_VY09Y&_nc_zt=23&_nc_ht=scontent-dfw5-1.xx&_nc_gid=2v0F-Iqs3xpLCloZN3WtOQ&oh=00_AYHU2F1_CYFX2qVwXlI9c_Zbh0zNK22gPXWliaD72cAPKQ&oe=67EB23EF",
26 | caption: "DND🎧",
27 | likes: 210,
28 | comments: 18,
29 | },
30 | {
31 | _id: "2",
32 | userAvatar: avatarURL,
33 | username: dummyUser.username,
34 | image:
35 | "https://scontent-dfw5-2.xx.fbcdn.net/v/t39.30808-6/472843868_1733299927214856_6680476038779064540_n.jpg?_nc_cat=107&ccb=1-7&_nc_sid=6ee11a&_nc_ohc=5VD0f6JGz4EQ7kNvgGy5T1n&_nc_oc=Adn-wxBvbos2HWi_O-hvFAIGb-ZyY7XRFfIg076y-9PfFBpEzgYvSdoNj7IDUBc4SS_tZif00ZfsT5wkW1dxf48M&_nc_zt=23&_nc_ht=scontent-dfw5-2.xx&_nc_gid=eHAcTQliVM27QQrvzrWxHw&oh=00_AYEYhYPbynGN2RTTyO7ZotNRiTZxA2urq4NCA47LXW8w0Q&oe=67EB2687",
36 | caption: "His love rewrites my story, bringing healing to every chapter. #GodsGrace",
37 | likes: 154,
38 | comments: 12,
39 | },
40 | {
41 | _id: "3",
42 | userAvatar: avatarURL,
43 | username: dummyUser.username,
44 | image:
45 | "https://scontent-dfw5-2.xx.fbcdn.net/v/t39.30808-6/481015210_1764443634100485_2200052985729672030_n.jpg?_nc_cat=104&ccb=1-7&_nc_sid=833d8c&_nc_ohc=aUheaU38wXwQ7kNvgGr__Kx&_nc_oc=Adl5_B1I43waZ2OjhAYPBZnL0onpCCSyg2h8Y0PszFvrpRoeGTz5nPl5xsGvI0E-J2xsMboCrY9Jwdyh-jSTt3S6&_nc_zt=23&_nc_ht=scontent-dfw5-2.xx&_nc_gid=zVsSoZ9YPMPw_srUyx8-Zg&oh=00_AYGjyp5sBPDWtWpl1OC5KG1qrp7O2IxfiJXiBABWXs6pDA&oe=67EB3782",
46 | caption: "Living a life with purpose🖤",
47 | likes: 193,
48 | comments: 9,
49 | },
50 | ];
51 |
52 | const Profile = () => {
53 | return (
54 |
55 | {/* Sidebar */}
56 |
57 |
58 |
59 |
60 | {/* Main Content */}
61 |
62 |
63 |
64 |
65 | {posts.map((post) => (
66 |
67 | ))}
68 |
69 |
70 |
71 | );
72 | };
73 |
74 | export default Profile;
75 |
--------------------------------------------------------------------------------
/frontend/src/pages/Register.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { useDispatch, useSelector } from "react-redux";
3 | import { registerUser } from "../redux/authSlice";
4 | import { useNavigate } from "react-router-dom";
5 |
6 | const Register = () => {
7 | const dispatch = useDispatch();
8 | const navigate = useNavigate();
9 | const { loading, error } = useSelector((state) => state.auth);
10 | const [formData, setFormData] = useState({
11 | username: "",
12 | email: "",
13 | password: "",
14 | });
15 |
16 | const handleChange = (e) =>
17 | setFormData({ ...formData, [e.target.name]: e.target.value });
18 |
19 | const handleSubmit = async (e) => {
20 | e.preventDefault();
21 | const result = await dispatch(registerUser(formData));
22 | if (result.meta.requestStatus === "fulfilled") {
23 | navigate("/");
24 | }
25 | };
26 |
27 | return (
28 |
29 |
30 |
31 | Join Creatify
32 |
33 | {error && (
34 |
{error}
35 | )}
36 |
37 |
38 | Username
39 |
47 |
48 |
49 | Email
50 |
58 |
59 |
60 | Password
61 |
69 |
70 |
75 | {loading ? "Signing up..." : "Register"}
76 |
77 |
78 |
79 | Already have an account?{" "}
80 | navigate("/login")}
83 | >
84 | Log in
85 |
86 |
87 |
88 |
89 | );
90 | };
91 |
92 | export default Register;
93 |
--------------------------------------------------------------------------------
/backend/views/index.pug:
--------------------------------------------------------------------------------
1 | doctype html
2 | html(lang="en")
3 | head
4 | title API Documentation
5 | link(rel="stylesheet" href="/css/style.css")
6 |
7 | body
8 | h1.api-title API Documentation
9 |
10 | h2 Base URL
11 | p All endpoints are prefixed with:
12 | code http://localhost:4000/api
13 |
14 | h2 Authentication
15 | p Currently, no authentication is required for the API endpoints.
16 |
17 | h2 Endpoints
18 |
19 | h3 Health Check
20 | .endpoint
21 | span.method.get GET
22 | code /health
23 | p Returns the API health status.
24 | h4 Response
25 | pre
26 | code
27 | | {
28 | | "status": "OK"
29 | | }
30 |
31 | h3 Users
32 |
33 | .endpoint
34 | span.method.get GET
35 | code /users
36 | p Retrieve all users
37 | h4 Response
38 | pre
39 | code
40 | | [
41 | | {
42 | | "_id": "string",
43 | | "name": "string",
44 | | "email": "string",
45 | | "createdAt": "date"
46 | | }
47 | | ]
48 |
49 | .endpoint
50 | span.method.get GET
51 | code /users/:id
52 | p Retrieve a specific user by ID
53 | h4 Response
54 | pre
55 | code
56 | | {
57 | | "_id": "string",
58 | | "name": "string",
59 | | "email": "string",
60 | | "createdAt": "date"
61 | | }
62 |
63 | .endpoint
64 | span.method.post POST
65 | code /users
66 | p Create a new user
67 | h4 Request Body
68 | table
69 | tr
70 | th Field
71 | th Type
72 | th Required
73 | th Description
74 | tr
75 | td name
76 | td string
77 | td Yes
78 | td User's full name
79 | tr
80 | td email
81 | td string
82 | td Yes
83 | td User's email address
84 | h4 Response
85 | pre
86 | code
87 | | {
88 | | "_id": "string",
89 | | "name": "string",
90 | | "email": "string",
91 | | "createdAt": "date"
92 | | }
93 |
94 | .endpoint
95 | span.method.put PUT
96 | code /users/:id
97 | p Update an existing user
98 | h4 Request Body
99 | table
100 | tr
101 | th Field
102 | th Type
103 | th Required
104 | th Description
105 | tr
106 | td name
107 | td string
108 | td No
109 | td User's full name
110 | tr
111 | td email
112 | td string
113 | td No
114 | td User's email address
115 | h4 Response
116 | pre
117 | code
118 | | {
119 | | "_id": "string",
120 | | "name": "string",
121 | | "email": "string",
122 | | "createdAt": "date"
123 | | }
124 |
125 | .endpoint
126 | span.method.delete DELETE
127 | code /users/:id
128 | p Delete a user
129 | h4 Response
130 | p Returns status code 204 with no content on success.
131 |
132 | h2 Error Responses
133 | p The API returns standard HTTP status codes and JSON error messages:
134 | pre
135 | code
136 | | {
137 | | "error": "Error Type",
138 | | "message": "Error description"
139 | | }
140 |
141 | script(src="/js/main.js")
--------------------------------------------------------------------------------
/frontend/src/assets/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backend/routes/user.js:
--------------------------------------------------------------------------------
1 | import express from "express";
2 | import User from "../models/user.js";
3 | //import authMiddleware from "../middleware/authMiddleware.js";
4 |
5 | const router = express.Router();
6 |
7 | // Create User
8 | router.post("/", async (req, res) => {
9 | try {
10 | const user = new User(req.body);
11 | await user.save();
12 | res.status(201).json(user);
13 | } catch (e) {
14 | console.error(e);
15 | res.status(400).json({ message: e.message });
16 | }
17 | });
18 |
19 | // Get all users
20 | router.get("/", async (req, res) => {
21 | try {
22 | const users = await User.find().select("-password");
23 | res.json(users);
24 | } catch (error) {
25 | res.status(500).json({ message: "Server error" });
26 | }
27 | });
28 |
29 | // Get single user profile
30 | router.get("/:id", async (req, res) => {
31 | try {
32 | const user = await User.findById(req.params.id).select("-password");
33 | if (!user) return res.status(404).json({ message: "User not found" });
34 | res.json(user);
35 | } catch (error) {
36 | res.status(500).json({ message: "Server error" });
37 | }
38 | });
39 |
40 | // Follow a user
41 | router.post("/:id/follow", async (req, res) => {
42 | try {
43 | const userToFollow = await User.findById(req.params.id);
44 | const currentUser = await User.findById(req.user.id);
45 |
46 | if (!userToFollow || !currentUser)
47 | return res.status(404).json({ message: "User not found" });
48 |
49 | if (!currentUser.following.includes(userToFollow._id)) {
50 | currentUser.following.push(userToFollow._id);
51 | userToFollow.followers.push(currentUser._id);
52 | await currentUser.save();
53 | await userToFollow.save();
54 | }
55 |
56 | res.json({ message: "User followed" });
57 | } catch (error) {
58 | res.status(500).json({ message: "Server error" });
59 | }
60 | });
61 |
62 | // Unfollow a user
63 | router.post("/:id/unfollow", async (req, res) => {
64 | try {
65 | const userToUnfollow = await User.findById(req.params.id);
66 | const currentUser = await User.findById(req.user.id);
67 |
68 | if (!userToUnfollow || !currentUser)
69 | return res.status(404).json({ message: "User not found" });
70 |
71 | currentUser.following = currentUser.following.filter(
72 | (id) => id.toString() !== userToUnfollow._id.toString()
73 | );
74 | userToUnfollow.followers = userToUnfollow.followers.filter(
75 | (id) => id.toString() !== currentUser._id.toString()
76 | );
77 |
78 | await currentUser.save();
79 | await userToUnfollow.save();
80 |
81 | res.json({ message: "User unfollowed" });
82 | } catch (error) {
83 | res.status(500).json({ message: "Server error" });
84 | }
85 | });
86 |
87 | // ✅ Delete a user
88 | router.delete("/:id", async (req, res) => {
89 | try {
90 | // Optional: Only allow deleting your own account
91 | // if (req.user.id !== req.params.id) {
92 | // return res.status(403).json({ message: "You can only delete your own account." });
93 | // }
94 |
95 | const deletedUser = await User.findByIdAndDelete(req.params.id);
96 | if (!deletedUser) {
97 | return res.status(404).json({ message: "User not found" });
98 | }
99 |
100 | res.json({ message: "User deleted successfully" });
101 | } catch (error) {
102 | res.status(500).json({ message: "Server error" });
103 | }
104 | });
105 |
106 | // Update user
107 | router.patch("/:id", async (req, res) => {
108 | try {
109 | const updatedUser = await User.findByIdAndUpdate(
110 | req.params.id,
111 | { $set: req.body },
112 | { new: true }
113 | );
114 | if (!updatedUser) {
115 | return res.status(404).json({ message: "User not found" });
116 | }
117 | res.json(updatedUser);
118 | } catch (error) {
119 | res.status(500).json({ message: "Server error" });
120 | }
121 | });
122 |
123 |
124 | export default router;
125 |
--------------------------------------------------------------------------------
/frontend/src/components/CommentBox.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { useSelector } from "react-redux";
3 | import { Pencil, Trash2, Send } from "lucide-react";
4 | import commentsAPI from "../api/comments";
5 |
6 |
7 | const CommentBox = ({ postId, comments, setComments }) => {
8 | const { user } = useSelector((state) => state.auth);
9 | const [newComment, setNewComment] = useState("");
10 | const [editing, setEditing] = useState(null);
11 | const [editText, setEditText] = useState("");
12 |
13 | const handleAddComment = async () => {
14 | if (!newComment.trim()) return;
15 | try {
16 | const res = await addComment(postId, { text: newComment });
17 | setComments((prev) => [...prev, res.data]);
18 | setNewComment("");
19 | } catch (err) {
20 | console.error("Error adding comment:", err);
21 | }
22 | };
23 |
24 | const handleDelete = async (commentId) => {
25 | try {
26 | await deleteComment(commentId);
27 | setComments((prev) => prev.filter((c) => c._id !== commentId));
28 | } catch (err) {
29 | console.error("Error deleting:", err);
30 | }
31 | };
32 |
33 | const handleEdit = async (commentId) => {
34 | try {
35 | const res = await updateComment(commentId, { text: editText });
36 | setComments((prev) =>
37 | prev.map((c) => (c._id === commentId ? res.data : c))
38 | );
39 | setEditing(null);
40 | setEditText("");
41 | } catch (err) {
42 | console.error("Error updating:", err);
43 | }
44 | };
45 |
46 | return (
47 |
48 |
Comments
49 |
50 | {comments.map((c) => (
51 |
55 |
56 |
{c.user?.username}
57 | {editing === c._id ? (
58 |
59 | setEditText(e.target.value)}
64 | />
65 | handleEdit(c._id)}
68 | >
69 | Save
70 |
71 |
72 | ) : (
73 |
{c.text}
74 | )}
75 |
76 | {user && user._id === c.user?._id && (
77 |
78 |
{
81 | setEditing(c._id);
82 | setEditText(c.text);
83 | }}
84 | >
85 |
86 |
87 |
handleDelete(c._id)}
90 | >
91 |
92 |
93 |
94 | )}
95 |
96 | ))}
97 |
98 | {/* Add new comment */}
99 |
100 | setNewComment(e.target.value)}
106 | />
107 |
111 |
112 |
113 |
114 |
115 | );
116 | };
117 |
118 | export default CommentBox;
119 |
--------------------------------------------------------------------------------
/backend/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "backend-template",
3 | "version": "1.0.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "backend-template",
9 | "version": "1.0.0",
10 | "license": "ISC",
11 | "dependencies": {
12 | "bcryptjs": "^3.0.2",
13 | "cors": "^2.8.5",
14 | "dotenv": "^16.4.7",
15 | "express": "^4.21.2",
16 | "helmet": "^8.0.0",
17 | "jsonwebtoken": "^9.0.2",
18 | "mongoose": "^8.12.1",
19 | "multer": "^1.4.5-lts.2",
20 | "pug": "^3.0.3"
21 | },
22 | "devDependencies": {
23 | "morgan": "^1.10.0",
24 | "nodemon": "^3.1.9"
25 | }
26 | },
27 | "node_modules/@babel/helper-string-parser": {
28 | "version": "7.25.9",
29 | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
30 | "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
31 | "engines": {
32 | "node": ">=6.9.0"
33 | }
34 | },
35 | "node_modules/@babel/helper-validator-identifier": {
36 | "version": "7.25.9",
37 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
38 | "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
39 | "engines": {
40 | "node": ">=6.9.0"
41 | }
42 | },
43 | "node_modules/@babel/parser": {
44 | "version": "7.26.10",
45 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz",
46 | "integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==",
47 | "dependencies": {
48 | "@babel/types": "^7.26.10"
49 | },
50 | "bin": {
51 | "parser": "bin/babel-parser.js"
52 | },
53 | "engines": {
54 | "node": ">=6.0.0"
55 | }
56 | },
57 | "node_modules/@babel/types": {
58 | "version": "7.26.10",
59 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz",
60 | "integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==",
61 | "dependencies": {
62 | "@babel/helper-string-parser": "^7.25.9",
63 | "@babel/helper-validator-identifier": "^7.25.9"
64 | },
65 | "engines": {
66 | "node": ">=6.9.0"
67 | }
68 | },
69 | "node_modules/@mongodb-js/saslprep": {
70 | "version": "1.2.0",
71 | "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.2.0.tgz",
72 | "integrity": "sha512-+ywrb0AqkfaYuhHs6LxKWgqbh3I72EpEgESCw37o+9qPx9WTCkgDm2B+eMrwehGtHBWHFU4GXvnSCNiFhhausg==",
73 | "dependencies": {
74 | "sparse-bitfield": "^3.0.3"
75 | }
76 | },
77 | "node_modules/@types/webidl-conversions": {
78 | "version": "7.0.3",
79 | "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
80 | "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA=="
81 | },
82 | "node_modules/@types/whatwg-url": {
83 | "version": "11.0.5",
84 | "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz",
85 | "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==",
86 | "dependencies": {
87 | "@types/webidl-conversions": "*"
88 | }
89 | },
90 | "node_modules/accepts": {
91 | "version": "1.3.8",
92 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
93 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
94 | "dependencies": {
95 | "mime-types": "~2.1.34",
96 | "negotiator": "0.6.3"
97 | },
98 | "engines": {
99 | "node": ">= 0.6"
100 | }
101 | },
102 | "node_modules/acorn": {
103 | "version": "7.4.1",
104 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
105 | "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
106 | "bin": {
107 | "acorn": "bin/acorn"
108 | },
109 | "engines": {
110 | "node": ">=0.4.0"
111 | }
112 | },
113 | "node_modules/anymatch": {
114 | "version": "3.1.3",
115 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
116 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
117 | "dev": true,
118 | "dependencies": {
119 | "normalize-path": "^3.0.0",
120 | "picomatch": "^2.0.4"
121 | },
122 | "engines": {
123 | "node": ">= 8"
124 | }
125 | },
126 | "node_modules/append-field": {
127 | "version": "1.0.0",
128 | "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
129 | "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==",
130 | "license": "MIT"
131 | },
132 | "node_modules/array-flatten": {
133 | "version": "1.1.1",
134 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
135 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
136 | },
137 | "node_modules/asap": {
138 | "version": "2.0.6",
139 | "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
140 | "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
141 | },
142 | "node_modules/assert-never": {
143 | "version": "1.4.0",
144 | "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.4.0.tgz",
145 | "integrity": "sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA=="
146 | },
147 | "node_modules/babel-walk": {
148 | "version": "3.0.0-canary-5",
149 | "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz",
150 | "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==",
151 | "dependencies": {
152 | "@babel/types": "^7.9.6"
153 | },
154 | "engines": {
155 | "node": ">= 10.0.0"
156 | }
157 | },
158 | "node_modules/balanced-match": {
159 | "version": "1.0.2",
160 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
161 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
162 | "dev": true
163 | },
164 | "node_modules/basic-auth": {
165 | "version": "2.0.1",
166 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
167 | "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
168 | "dev": true,
169 | "dependencies": {
170 | "safe-buffer": "5.1.2"
171 | },
172 | "engines": {
173 | "node": ">= 0.8"
174 | }
175 | },
176 | "node_modules/basic-auth/node_modules/safe-buffer": {
177 | "version": "5.1.2",
178 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
179 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
180 | "dev": true
181 | },
182 | "node_modules/bcryptjs": {
183 | "version": "3.0.2",
184 | "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz",
185 | "integrity": "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==",
186 | "license": "BSD-3-Clause",
187 | "bin": {
188 | "bcrypt": "bin/bcrypt"
189 | }
190 | },
191 | "node_modules/binary-extensions": {
192 | "version": "2.3.0",
193 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
194 | "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
195 | "dev": true,
196 | "engines": {
197 | "node": ">=8"
198 | },
199 | "funding": {
200 | "url": "https://github.com/sponsors/sindresorhus"
201 | }
202 | },
203 | "node_modules/body-parser": {
204 | "version": "1.20.3",
205 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
206 | "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
207 | "dependencies": {
208 | "bytes": "3.1.2",
209 | "content-type": "~1.0.5",
210 | "debug": "2.6.9",
211 | "depd": "2.0.0",
212 | "destroy": "1.2.0",
213 | "http-errors": "2.0.0",
214 | "iconv-lite": "0.4.24",
215 | "on-finished": "2.4.1",
216 | "qs": "6.13.0",
217 | "raw-body": "2.5.2",
218 | "type-is": "~1.6.18",
219 | "unpipe": "1.0.0"
220 | },
221 | "engines": {
222 | "node": ">= 0.8",
223 | "npm": "1.2.8000 || >= 1.4.16"
224 | }
225 | },
226 | "node_modules/brace-expansion": {
227 | "version": "1.1.11",
228 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
229 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
230 | "dev": true,
231 | "dependencies": {
232 | "balanced-match": "^1.0.0",
233 | "concat-map": "0.0.1"
234 | }
235 | },
236 | "node_modules/braces": {
237 | "version": "3.0.3",
238 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
239 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
240 | "dev": true,
241 | "dependencies": {
242 | "fill-range": "^7.1.1"
243 | },
244 | "engines": {
245 | "node": ">=8"
246 | }
247 | },
248 | "node_modules/bson": {
249 | "version": "6.10.3",
250 | "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.3.tgz",
251 | "integrity": "sha512-MTxGsqgYTwfshYWTRdmZRC+M7FnG1b4y7RO7p2k3X24Wq0yv1m77Wsj0BzlPzd/IowgESfsruQCUToa7vbOpPQ==",
252 | "engines": {
253 | "node": ">=16.20.1"
254 | }
255 | },
256 | "node_modules/buffer-equal-constant-time": {
257 | "version": "1.0.1",
258 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
259 | "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
260 | "license": "BSD-3-Clause"
261 | },
262 | "node_modules/buffer-from": {
263 | "version": "1.1.2",
264 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
265 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
266 | "license": "MIT"
267 | },
268 | "node_modules/busboy": {
269 | "version": "1.6.0",
270 | "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
271 | "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
272 | "dependencies": {
273 | "streamsearch": "^1.1.0"
274 | },
275 | "engines": {
276 | "node": ">=10.16.0"
277 | }
278 | },
279 | "node_modules/bytes": {
280 | "version": "3.1.2",
281 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
282 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
283 | "engines": {
284 | "node": ">= 0.8"
285 | }
286 | },
287 | "node_modules/call-bind-apply-helpers": {
288 | "version": "1.0.2",
289 | "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
290 | "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
291 | "dependencies": {
292 | "es-errors": "^1.3.0",
293 | "function-bind": "^1.1.2"
294 | },
295 | "engines": {
296 | "node": ">= 0.4"
297 | }
298 | },
299 | "node_modules/call-bound": {
300 | "version": "1.0.4",
301 | "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
302 | "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
303 | "dependencies": {
304 | "call-bind-apply-helpers": "^1.0.2",
305 | "get-intrinsic": "^1.3.0"
306 | },
307 | "engines": {
308 | "node": ">= 0.4"
309 | },
310 | "funding": {
311 | "url": "https://github.com/sponsors/ljharb"
312 | }
313 | },
314 | "node_modules/character-parser": {
315 | "version": "2.2.0",
316 | "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz",
317 | "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==",
318 | "dependencies": {
319 | "is-regex": "^1.0.3"
320 | }
321 | },
322 | "node_modules/chokidar": {
323 | "version": "3.6.0",
324 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
325 | "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
326 | "dev": true,
327 | "dependencies": {
328 | "anymatch": "~3.1.2",
329 | "braces": "~3.0.2",
330 | "glob-parent": "~5.1.2",
331 | "is-binary-path": "~2.1.0",
332 | "is-glob": "~4.0.1",
333 | "normalize-path": "~3.0.0",
334 | "readdirp": "~3.6.0"
335 | },
336 | "engines": {
337 | "node": ">= 8.10.0"
338 | },
339 | "funding": {
340 | "url": "https://paulmillr.com/funding/"
341 | },
342 | "optionalDependencies": {
343 | "fsevents": "~2.3.2"
344 | }
345 | },
346 | "node_modules/concat-map": {
347 | "version": "0.0.1",
348 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
349 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
350 | "dev": true
351 | },
352 | "node_modules/concat-stream": {
353 | "version": "1.6.2",
354 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
355 | "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
356 | "engines": [
357 | "node >= 0.8"
358 | ],
359 | "license": "MIT",
360 | "dependencies": {
361 | "buffer-from": "^1.0.0",
362 | "inherits": "^2.0.3",
363 | "readable-stream": "^2.2.2",
364 | "typedarray": "^0.0.6"
365 | }
366 | },
367 | "node_modules/constantinople": {
368 | "version": "4.0.1",
369 | "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz",
370 | "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==",
371 | "dependencies": {
372 | "@babel/parser": "^7.6.0",
373 | "@babel/types": "^7.6.1"
374 | }
375 | },
376 | "node_modules/content-disposition": {
377 | "version": "0.5.4",
378 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
379 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
380 | "dependencies": {
381 | "safe-buffer": "5.2.1"
382 | },
383 | "engines": {
384 | "node": ">= 0.6"
385 | }
386 | },
387 | "node_modules/content-type": {
388 | "version": "1.0.5",
389 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
390 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
391 | "engines": {
392 | "node": ">= 0.6"
393 | }
394 | },
395 | "node_modules/cookie": {
396 | "version": "0.7.1",
397 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
398 | "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
399 | "engines": {
400 | "node": ">= 0.6"
401 | }
402 | },
403 | "node_modules/cookie-signature": {
404 | "version": "1.0.6",
405 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
406 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
407 | },
408 | "node_modules/core-util-is": {
409 | "version": "1.0.3",
410 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
411 | "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
412 | "license": "MIT"
413 | },
414 | "node_modules/cors": {
415 | "version": "2.8.5",
416 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
417 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
418 | "dependencies": {
419 | "object-assign": "^4",
420 | "vary": "^1"
421 | },
422 | "engines": {
423 | "node": ">= 0.10"
424 | }
425 | },
426 | "node_modules/debug": {
427 | "version": "2.6.9",
428 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
429 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
430 | "dependencies": {
431 | "ms": "2.0.0"
432 | }
433 | },
434 | "node_modules/depd": {
435 | "version": "2.0.0",
436 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
437 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
438 | "engines": {
439 | "node": ">= 0.8"
440 | }
441 | },
442 | "node_modules/destroy": {
443 | "version": "1.2.0",
444 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
445 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
446 | "engines": {
447 | "node": ">= 0.8",
448 | "npm": "1.2.8000 || >= 1.4.16"
449 | }
450 | },
451 | "node_modules/doctypes": {
452 | "version": "1.1.0",
453 | "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz",
454 | "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ=="
455 | },
456 | "node_modules/dotenv": {
457 | "version": "16.4.7",
458 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
459 | "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
460 | "engines": {
461 | "node": ">=12"
462 | },
463 | "funding": {
464 | "url": "https://dotenvx.com"
465 | }
466 | },
467 | "node_modules/dunder-proto": {
468 | "version": "1.0.1",
469 | "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
470 | "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
471 | "dependencies": {
472 | "call-bind-apply-helpers": "^1.0.1",
473 | "es-errors": "^1.3.0",
474 | "gopd": "^1.2.0"
475 | },
476 | "engines": {
477 | "node": ">= 0.4"
478 | }
479 | },
480 | "node_modules/ecdsa-sig-formatter": {
481 | "version": "1.0.11",
482 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
483 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
484 | "license": "Apache-2.0",
485 | "dependencies": {
486 | "safe-buffer": "^5.0.1"
487 | }
488 | },
489 | "node_modules/ee-first": {
490 | "version": "1.1.1",
491 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
492 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
493 | },
494 | "node_modules/encodeurl": {
495 | "version": "2.0.0",
496 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
497 | "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
498 | "engines": {
499 | "node": ">= 0.8"
500 | }
501 | },
502 | "node_modules/es-define-property": {
503 | "version": "1.0.1",
504 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
505 | "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
506 | "engines": {
507 | "node": ">= 0.4"
508 | }
509 | },
510 | "node_modules/es-errors": {
511 | "version": "1.3.0",
512 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
513 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
514 | "engines": {
515 | "node": ">= 0.4"
516 | }
517 | },
518 | "node_modules/es-object-atoms": {
519 | "version": "1.1.1",
520 | "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
521 | "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
522 | "dependencies": {
523 | "es-errors": "^1.3.0"
524 | },
525 | "engines": {
526 | "node": ">= 0.4"
527 | }
528 | },
529 | "node_modules/escape-html": {
530 | "version": "1.0.3",
531 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
532 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
533 | },
534 | "node_modules/etag": {
535 | "version": "1.8.1",
536 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
537 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
538 | "engines": {
539 | "node": ">= 0.6"
540 | }
541 | },
542 | "node_modules/express": {
543 | "version": "4.21.2",
544 | "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
545 | "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
546 | "dependencies": {
547 | "accepts": "~1.3.8",
548 | "array-flatten": "1.1.1",
549 | "body-parser": "1.20.3",
550 | "content-disposition": "0.5.4",
551 | "content-type": "~1.0.4",
552 | "cookie": "0.7.1",
553 | "cookie-signature": "1.0.6",
554 | "debug": "2.6.9",
555 | "depd": "2.0.0",
556 | "encodeurl": "~2.0.0",
557 | "escape-html": "~1.0.3",
558 | "etag": "~1.8.1",
559 | "finalhandler": "1.3.1",
560 | "fresh": "0.5.2",
561 | "http-errors": "2.0.0",
562 | "merge-descriptors": "1.0.3",
563 | "methods": "~1.1.2",
564 | "on-finished": "2.4.1",
565 | "parseurl": "~1.3.3",
566 | "path-to-regexp": "0.1.12",
567 | "proxy-addr": "~2.0.7",
568 | "qs": "6.13.0",
569 | "range-parser": "~1.2.1",
570 | "safe-buffer": "5.2.1",
571 | "send": "0.19.0",
572 | "serve-static": "1.16.2",
573 | "setprototypeof": "1.2.0",
574 | "statuses": "2.0.1",
575 | "type-is": "~1.6.18",
576 | "utils-merge": "1.0.1",
577 | "vary": "~1.1.2"
578 | },
579 | "engines": {
580 | "node": ">= 0.10.0"
581 | },
582 | "funding": {
583 | "type": "opencollective",
584 | "url": "https://opencollective.com/express"
585 | }
586 | },
587 | "node_modules/fill-range": {
588 | "version": "7.1.1",
589 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
590 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
591 | "dev": true,
592 | "dependencies": {
593 | "to-regex-range": "^5.0.1"
594 | },
595 | "engines": {
596 | "node": ">=8"
597 | }
598 | },
599 | "node_modules/finalhandler": {
600 | "version": "1.3.1",
601 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
602 | "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
603 | "dependencies": {
604 | "debug": "2.6.9",
605 | "encodeurl": "~2.0.0",
606 | "escape-html": "~1.0.3",
607 | "on-finished": "2.4.1",
608 | "parseurl": "~1.3.3",
609 | "statuses": "2.0.1",
610 | "unpipe": "~1.0.0"
611 | },
612 | "engines": {
613 | "node": ">= 0.8"
614 | }
615 | },
616 | "node_modules/forwarded": {
617 | "version": "0.2.0",
618 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
619 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
620 | "engines": {
621 | "node": ">= 0.6"
622 | }
623 | },
624 | "node_modules/fresh": {
625 | "version": "0.5.2",
626 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
627 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
628 | "engines": {
629 | "node": ">= 0.6"
630 | }
631 | },
632 | "node_modules/fsevents": {
633 | "version": "2.3.3",
634 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
635 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
636 | "dev": true,
637 | "hasInstallScript": true,
638 | "optional": true,
639 | "os": [
640 | "darwin"
641 | ],
642 | "engines": {
643 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
644 | }
645 | },
646 | "node_modules/function-bind": {
647 | "version": "1.1.2",
648 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
649 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
650 | "funding": {
651 | "url": "https://github.com/sponsors/ljharb"
652 | }
653 | },
654 | "node_modules/get-intrinsic": {
655 | "version": "1.3.0",
656 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
657 | "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
658 | "dependencies": {
659 | "call-bind-apply-helpers": "^1.0.2",
660 | "es-define-property": "^1.0.1",
661 | "es-errors": "^1.3.0",
662 | "es-object-atoms": "^1.1.1",
663 | "function-bind": "^1.1.2",
664 | "get-proto": "^1.0.1",
665 | "gopd": "^1.2.0",
666 | "has-symbols": "^1.1.0",
667 | "hasown": "^2.0.2",
668 | "math-intrinsics": "^1.1.0"
669 | },
670 | "engines": {
671 | "node": ">= 0.4"
672 | },
673 | "funding": {
674 | "url": "https://github.com/sponsors/ljharb"
675 | }
676 | },
677 | "node_modules/get-proto": {
678 | "version": "1.0.1",
679 | "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
680 | "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
681 | "dependencies": {
682 | "dunder-proto": "^1.0.1",
683 | "es-object-atoms": "^1.0.0"
684 | },
685 | "engines": {
686 | "node": ">= 0.4"
687 | }
688 | },
689 | "node_modules/glob-parent": {
690 | "version": "5.1.2",
691 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
692 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
693 | "dev": true,
694 | "dependencies": {
695 | "is-glob": "^4.0.1"
696 | },
697 | "engines": {
698 | "node": ">= 6"
699 | }
700 | },
701 | "node_modules/gopd": {
702 | "version": "1.2.0",
703 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
704 | "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
705 | "engines": {
706 | "node": ">= 0.4"
707 | },
708 | "funding": {
709 | "url": "https://github.com/sponsors/ljharb"
710 | }
711 | },
712 | "node_modules/has-flag": {
713 | "version": "3.0.0",
714 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
715 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
716 | "dev": true,
717 | "engines": {
718 | "node": ">=4"
719 | }
720 | },
721 | "node_modules/has-symbols": {
722 | "version": "1.1.0",
723 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
724 | "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
725 | "engines": {
726 | "node": ">= 0.4"
727 | },
728 | "funding": {
729 | "url": "https://github.com/sponsors/ljharb"
730 | }
731 | },
732 | "node_modules/has-tostringtag": {
733 | "version": "1.0.2",
734 | "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
735 | "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
736 | "dependencies": {
737 | "has-symbols": "^1.0.3"
738 | },
739 | "engines": {
740 | "node": ">= 0.4"
741 | },
742 | "funding": {
743 | "url": "https://github.com/sponsors/ljharb"
744 | }
745 | },
746 | "node_modules/hasown": {
747 | "version": "2.0.2",
748 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
749 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
750 | "dependencies": {
751 | "function-bind": "^1.1.2"
752 | },
753 | "engines": {
754 | "node": ">= 0.4"
755 | }
756 | },
757 | "node_modules/helmet": {
758 | "version": "8.0.0",
759 | "resolved": "https://registry.npmjs.org/helmet/-/helmet-8.0.0.tgz",
760 | "integrity": "sha512-VyusHLEIIO5mjQPUI1wpOAEu+wl6Q0998jzTxqUYGE45xCIcAxy3MsbEK/yyJUJ3ADeMoB6MornPH6GMWAf+Pw==",
761 | "engines": {
762 | "node": ">=18.0.0"
763 | }
764 | },
765 | "node_modules/http-errors": {
766 | "version": "2.0.0",
767 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
768 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
769 | "dependencies": {
770 | "depd": "2.0.0",
771 | "inherits": "2.0.4",
772 | "setprototypeof": "1.2.0",
773 | "statuses": "2.0.1",
774 | "toidentifier": "1.0.1"
775 | },
776 | "engines": {
777 | "node": ">= 0.8"
778 | }
779 | },
780 | "node_modules/iconv-lite": {
781 | "version": "0.4.24",
782 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
783 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
784 | "dependencies": {
785 | "safer-buffer": ">= 2.1.2 < 3"
786 | },
787 | "engines": {
788 | "node": ">=0.10.0"
789 | }
790 | },
791 | "node_modules/ignore-by-default": {
792 | "version": "1.0.1",
793 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
794 | "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
795 | "dev": true
796 | },
797 | "node_modules/inherits": {
798 | "version": "2.0.4",
799 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
800 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
801 | },
802 | "node_modules/ipaddr.js": {
803 | "version": "1.9.1",
804 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
805 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
806 | "engines": {
807 | "node": ">= 0.10"
808 | }
809 | },
810 | "node_modules/is-binary-path": {
811 | "version": "2.1.0",
812 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
813 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
814 | "dev": true,
815 | "dependencies": {
816 | "binary-extensions": "^2.0.0"
817 | },
818 | "engines": {
819 | "node": ">=8"
820 | }
821 | },
822 | "node_modules/is-core-module": {
823 | "version": "2.16.1",
824 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
825 | "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
826 | "dependencies": {
827 | "hasown": "^2.0.2"
828 | },
829 | "engines": {
830 | "node": ">= 0.4"
831 | },
832 | "funding": {
833 | "url": "https://github.com/sponsors/ljharb"
834 | }
835 | },
836 | "node_modules/is-expression": {
837 | "version": "4.0.0",
838 | "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz",
839 | "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==",
840 | "dependencies": {
841 | "acorn": "^7.1.1",
842 | "object-assign": "^4.1.1"
843 | }
844 | },
845 | "node_modules/is-extglob": {
846 | "version": "2.1.1",
847 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
848 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
849 | "dev": true,
850 | "engines": {
851 | "node": ">=0.10.0"
852 | }
853 | },
854 | "node_modules/is-glob": {
855 | "version": "4.0.3",
856 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
857 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
858 | "dev": true,
859 | "dependencies": {
860 | "is-extglob": "^2.1.1"
861 | },
862 | "engines": {
863 | "node": ">=0.10.0"
864 | }
865 | },
866 | "node_modules/is-number": {
867 | "version": "7.0.0",
868 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
869 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
870 | "dev": true,
871 | "engines": {
872 | "node": ">=0.12.0"
873 | }
874 | },
875 | "node_modules/is-promise": {
876 | "version": "2.2.2",
877 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
878 | "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="
879 | },
880 | "node_modules/is-regex": {
881 | "version": "1.2.1",
882 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
883 | "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
884 | "dependencies": {
885 | "call-bound": "^1.0.2",
886 | "gopd": "^1.2.0",
887 | "has-tostringtag": "^1.0.2",
888 | "hasown": "^2.0.2"
889 | },
890 | "engines": {
891 | "node": ">= 0.4"
892 | },
893 | "funding": {
894 | "url": "https://github.com/sponsors/ljharb"
895 | }
896 | },
897 | "node_modules/isarray": {
898 | "version": "1.0.0",
899 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
900 | "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
901 | "license": "MIT"
902 | },
903 | "node_modules/js-stringify": {
904 | "version": "1.0.2",
905 | "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz",
906 | "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g=="
907 | },
908 | "node_modules/jsonwebtoken": {
909 | "version": "9.0.2",
910 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
911 | "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
912 | "license": "MIT",
913 | "dependencies": {
914 | "jws": "^3.2.2",
915 | "lodash.includes": "^4.3.0",
916 | "lodash.isboolean": "^3.0.3",
917 | "lodash.isinteger": "^4.0.4",
918 | "lodash.isnumber": "^3.0.3",
919 | "lodash.isplainobject": "^4.0.6",
920 | "lodash.isstring": "^4.0.1",
921 | "lodash.once": "^4.0.0",
922 | "ms": "^2.1.1",
923 | "semver": "^7.5.4"
924 | },
925 | "engines": {
926 | "node": ">=12",
927 | "npm": ">=6"
928 | }
929 | },
930 | "node_modules/jsonwebtoken/node_modules/ms": {
931 | "version": "2.1.3",
932 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
933 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
934 | "license": "MIT"
935 | },
936 | "node_modules/jstransformer": {
937 | "version": "1.0.0",
938 | "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz",
939 | "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==",
940 | "dependencies": {
941 | "is-promise": "^2.0.0",
942 | "promise": "^7.0.1"
943 | }
944 | },
945 | "node_modules/jwa": {
946 | "version": "1.4.1",
947 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
948 | "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
949 | "license": "MIT",
950 | "dependencies": {
951 | "buffer-equal-constant-time": "1.0.1",
952 | "ecdsa-sig-formatter": "1.0.11",
953 | "safe-buffer": "^5.0.1"
954 | }
955 | },
956 | "node_modules/jws": {
957 | "version": "3.2.2",
958 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
959 | "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
960 | "license": "MIT",
961 | "dependencies": {
962 | "jwa": "^1.4.1",
963 | "safe-buffer": "^5.0.1"
964 | }
965 | },
966 | "node_modules/kareem": {
967 | "version": "2.6.3",
968 | "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
969 | "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==",
970 | "engines": {
971 | "node": ">=12.0.0"
972 | }
973 | },
974 | "node_modules/lodash.includes": {
975 | "version": "4.3.0",
976 | "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
977 | "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
978 | "license": "MIT"
979 | },
980 | "node_modules/lodash.isboolean": {
981 | "version": "3.0.3",
982 | "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
983 | "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
984 | "license": "MIT"
985 | },
986 | "node_modules/lodash.isinteger": {
987 | "version": "4.0.4",
988 | "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
989 | "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
990 | "license": "MIT"
991 | },
992 | "node_modules/lodash.isnumber": {
993 | "version": "3.0.3",
994 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
995 | "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
996 | "license": "MIT"
997 | },
998 | "node_modules/lodash.isplainobject": {
999 | "version": "4.0.6",
1000 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
1001 | "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
1002 | "license": "MIT"
1003 | },
1004 | "node_modules/lodash.isstring": {
1005 | "version": "4.0.1",
1006 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
1007 | "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
1008 | "license": "MIT"
1009 | },
1010 | "node_modules/lodash.once": {
1011 | "version": "4.1.1",
1012 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
1013 | "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
1014 | "license": "MIT"
1015 | },
1016 | "node_modules/math-intrinsics": {
1017 | "version": "1.1.0",
1018 | "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
1019 | "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
1020 | "engines": {
1021 | "node": ">= 0.4"
1022 | }
1023 | },
1024 | "node_modules/media-typer": {
1025 | "version": "0.3.0",
1026 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
1027 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
1028 | "engines": {
1029 | "node": ">= 0.6"
1030 | }
1031 | },
1032 | "node_modules/memory-pager": {
1033 | "version": "1.5.0",
1034 | "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
1035 | "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg=="
1036 | },
1037 | "node_modules/merge-descriptors": {
1038 | "version": "1.0.3",
1039 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
1040 | "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
1041 | "funding": {
1042 | "url": "https://github.com/sponsors/sindresorhus"
1043 | }
1044 | },
1045 | "node_modules/methods": {
1046 | "version": "1.1.2",
1047 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
1048 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
1049 | "engines": {
1050 | "node": ">= 0.6"
1051 | }
1052 | },
1053 | "node_modules/mime": {
1054 | "version": "1.6.0",
1055 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
1056 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
1057 | "bin": {
1058 | "mime": "cli.js"
1059 | },
1060 | "engines": {
1061 | "node": ">=4"
1062 | }
1063 | },
1064 | "node_modules/mime-db": {
1065 | "version": "1.52.0",
1066 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
1067 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
1068 | "engines": {
1069 | "node": ">= 0.6"
1070 | }
1071 | },
1072 | "node_modules/mime-types": {
1073 | "version": "2.1.35",
1074 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
1075 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
1076 | "dependencies": {
1077 | "mime-db": "1.52.0"
1078 | },
1079 | "engines": {
1080 | "node": ">= 0.6"
1081 | }
1082 | },
1083 | "node_modules/minimatch": {
1084 | "version": "3.1.2",
1085 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
1086 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
1087 | "dev": true,
1088 | "dependencies": {
1089 | "brace-expansion": "^1.1.7"
1090 | },
1091 | "engines": {
1092 | "node": "*"
1093 | }
1094 | },
1095 | "node_modules/minimist": {
1096 | "version": "1.2.8",
1097 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
1098 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
1099 | "license": "MIT",
1100 | "funding": {
1101 | "url": "https://github.com/sponsors/ljharb"
1102 | }
1103 | },
1104 | "node_modules/mkdirp": {
1105 | "version": "0.5.6",
1106 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
1107 | "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
1108 | "license": "MIT",
1109 | "dependencies": {
1110 | "minimist": "^1.2.6"
1111 | },
1112 | "bin": {
1113 | "mkdirp": "bin/cmd.js"
1114 | }
1115 | },
1116 | "node_modules/mongodb": {
1117 | "version": "6.14.2",
1118 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.14.2.tgz",
1119 | "integrity": "sha512-kMEHNo0F3P6QKDq17zcDuPeaywK/YaJVCEQRzPF3TOM/Bl9MFg64YE5Tu7ifj37qZJMhwU1tl2Ioivws5gRG5Q==",
1120 | "dependencies": {
1121 | "@mongodb-js/saslprep": "^1.1.9",
1122 | "bson": "^6.10.3",
1123 | "mongodb-connection-string-url": "^3.0.0"
1124 | },
1125 | "engines": {
1126 | "node": ">=16.20.1"
1127 | },
1128 | "peerDependencies": {
1129 | "@aws-sdk/credential-providers": "^3.188.0",
1130 | "@mongodb-js/zstd": "^1.1.0 || ^2.0.0",
1131 | "gcp-metadata": "^5.2.0",
1132 | "kerberos": "^2.0.1",
1133 | "mongodb-client-encryption": ">=6.0.0 <7",
1134 | "snappy": "^7.2.2",
1135 | "socks": "^2.7.1"
1136 | },
1137 | "peerDependenciesMeta": {
1138 | "@aws-sdk/credential-providers": {
1139 | "optional": true
1140 | },
1141 | "@mongodb-js/zstd": {
1142 | "optional": true
1143 | },
1144 | "gcp-metadata": {
1145 | "optional": true
1146 | },
1147 | "kerberos": {
1148 | "optional": true
1149 | },
1150 | "mongodb-client-encryption": {
1151 | "optional": true
1152 | },
1153 | "snappy": {
1154 | "optional": true
1155 | },
1156 | "socks": {
1157 | "optional": true
1158 | }
1159 | }
1160 | },
1161 | "node_modules/mongodb-connection-string-url": {
1162 | "version": "3.0.2",
1163 | "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz",
1164 | "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==",
1165 | "dependencies": {
1166 | "@types/whatwg-url": "^11.0.2",
1167 | "whatwg-url": "^14.1.0 || ^13.0.0"
1168 | }
1169 | },
1170 | "node_modules/mongoose": {
1171 | "version": "8.12.1",
1172 | "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.12.1.tgz",
1173 | "integrity": "sha512-UW22y8QFVYmrb36hm8cGncfn4ARc/XsYWQwRTaj0gxtQk1rDuhzDO1eBantS+hTTatfAIS96LlRCJrcNHvW5+Q==",
1174 | "dependencies": {
1175 | "bson": "^6.10.3",
1176 | "kareem": "2.6.3",
1177 | "mongodb": "~6.14.0",
1178 | "mpath": "0.9.0",
1179 | "mquery": "5.0.0",
1180 | "ms": "2.1.3",
1181 | "sift": "17.1.3"
1182 | },
1183 | "engines": {
1184 | "node": ">=16.20.1"
1185 | },
1186 | "funding": {
1187 | "type": "opencollective",
1188 | "url": "https://opencollective.com/mongoose"
1189 | }
1190 | },
1191 | "node_modules/mongoose/node_modules/ms": {
1192 | "version": "2.1.3",
1193 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1194 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
1195 | },
1196 | "node_modules/morgan": {
1197 | "version": "1.10.0",
1198 | "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
1199 | "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==",
1200 | "dev": true,
1201 | "dependencies": {
1202 | "basic-auth": "~2.0.1",
1203 | "debug": "2.6.9",
1204 | "depd": "~2.0.0",
1205 | "on-finished": "~2.3.0",
1206 | "on-headers": "~1.0.2"
1207 | },
1208 | "engines": {
1209 | "node": ">= 0.8.0"
1210 | }
1211 | },
1212 | "node_modules/morgan/node_modules/on-finished": {
1213 | "version": "2.3.0",
1214 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
1215 | "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
1216 | "dev": true,
1217 | "dependencies": {
1218 | "ee-first": "1.1.1"
1219 | },
1220 | "engines": {
1221 | "node": ">= 0.8"
1222 | }
1223 | },
1224 | "node_modules/mpath": {
1225 | "version": "0.9.0",
1226 | "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
1227 | "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==",
1228 | "engines": {
1229 | "node": ">=4.0.0"
1230 | }
1231 | },
1232 | "node_modules/mquery": {
1233 | "version": "5.0.0",
1234 | "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz",
1235 | "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==",
1236 | "dependencies": {
1237 | "debug": "4.x"
1238 | },
1239 | "engines": {
1240 | "node": ">=14.0.0"
1241 | }
1242 | },
1243 | "node_modules/mquery/node_modules/debug": {
1244 | "version": "4.4.0",
1245 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
1246 | "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
1247 | "dependencies": {
1248 | "ms": "^2.1.3"
1249 | },
1250 | "engines": {
1251 | "node": ">=6.0"
1252 | },
1253 | "peerDependenciesMeta": {
1254 | "supports-color": {
1255 | "optional": true
1256 | }
1257 | }
1258 | },
1259 | "node_modules/mquery/node_modules/ms": {
1260 | "version": "2.1.3",
1261 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1262 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
1263 | },
1264 | "node_modules/ms": {
1265 | "version": "2.0.0",
1266 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
1267 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
1268 | },
1269 | "node_modules/multer": {
1270 | "version": "1.4.5-lts.2",
1271 | "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.2.tgz",
1272 | "integrity": "sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==",
1273 | "license": "MIT",
1274 | "dependencies": {
1275 | "append-field": "^1.0.0",
1276 | "busboy": "^1.0.0",
1277 | "concat-stream": "^1.5.2",
1278 | "mkdirp": "^0.5.4",
1279 | "object-assign": "^4.1.1",
1280 | "type-is": "^1.6.4",
1281 | "xtend": "^4.0.0"
1282 | },
1283 | "engines": {
1284 | "node": ">= 6.0.0"
1285 | }
1286 | },
1287 | "node_modules/negotiator": {
1288 | "version": "0.6.3",
1289 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
1290 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
1291 | "engines": {
1292 | "node": ">= 0.6"
1293 | }
1294 | },
1295 | "node_modules/nodemon": {
1296 | "version": "3.1.9",
1297 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz",
1298 | "integrity": "sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==",
1299 | "dev": true,
1300 | "dependencies": {
1301 | "chokidar": "^3.5.2",
1302 | "debug": "^4",
1303 | "ignore-by-default": "^1.0.1",
1304 | "minimatch": "^3.1.2",
1305 | "pstree.remy": "^1.1.8",
1306 | "semver": "^7.5.3",
1307 | "simple-update-notifier": "^2.0.0",
1308 | "supports-color": "^5.5.0",
1309 | "touch": "^3.1.0",
1310 | "undefsafe": "^2.0.5"
1311 | },
1312 | "bin": {
1313 | "nodemon": "bin/nodemon.js"
1314 | },
1315 | "engines": {
1316 | "node": ">=10"
1317 | },
1318 | "funding": {
1319 | "type": "opencollective",
1320 | "url": "https://opencollective.com/nodemon"
1321 | }
1322 | },
1323 | "node_modules/nodemon/node_modules/debug": {
1324 | "version": "4.4.0",
1325 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
1326 | "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
1327 | "dev": true,
1328 | "dependencies": {
1329 | "ms": "^2.1.3"
1330 | },
1331 | "engines": {
1332 | "node": ">=6.0"
1333 | },
1334 | "peerDependenciesMeta": {
1335 | "supports-color": {
1336 | "optional": true
1337 | }
1338 | }
1339 | },
1340 | "node_modules/nodemon/node_modules/ms": {
1341 | "version": "2.1.3",
1342 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1343 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1344 | "dev": true
1345 | },
1346 | "node_modules/normalize-path": {
1347 | "version": "3.0.0",
1348 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
1349 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
1350 | "dev": true,
1351 | "engines": {
1352 | "node": ">=0.10.0"
1353 | }
1354 | },
1355 | "node_modules/object-assign": {
1356 | "version": "4.1.1",
1357 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
1358 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
1359 | "engines": {
1360 | "node": ">=0.10.0"
1361 | }
1362 | },
1363 | "node_modules/object-inspect": {
1364 | "version": "1.13.4",
1365 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
1366 | "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
1367 | "engines": {
1368 | "node": ">= 0.4"
1369 | },
1370 | "funding": {
1371 | "url": "https://github.com/sponsors/ljharb"
1372 | }
1373 | },
1374 | "node_modules/on-finished": {
1375 | "version": "2.4.1",
1376 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
1377 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
1378 | "dependencies": {
1379 | "ee-first": "1.1.1"
1380 | },
1381 | "engines": {
1382 | "node": ">= 0.8"
1383 | }
1384 | },
1385 | "node_modules/on-headers": {
1386 | "version": "1.0.2",
1387 | "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
1388 | "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
1389 | "dev": true,
1390 | "engines": {
1391 | "node": ">= 0.8"
1392 | }
1393 | },
1394 | "node_modules/parseurl": {
1395 | "version": "1.3.3",
1396 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
1397 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
1398 | "engines": {
1399 | "node": ">= 0.8"
1400 | }
1401 | },
1402 | "node_modules/path-parse": {
1403 | "version": "1.0.7",
1404 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
1405 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
1406 | },
1407 | "node_modules/path-to-regexp": {
1408 | "version": "0.1.12",
1409 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
1410 | "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
1411 | },
1412 | "node_modules/picomatch": {
1413 | "version": "2.3.1",
1414 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
1415 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
1416 | "dev": true,
1417 | "engines": {
1418 | "node": ">=8.6"
1419 | },
1420 | "funding": {
1421 | "url": "https://github.com/sponsors/jonschlinkert"
1422 | }
1423 | },
1424 | "node_modules/process-nextick-args": {
1425 | "version": "2.0.1",
1426 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
1427 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
1428 | "license": "MIT"
1429 | },
1430 | "node_modules/promise": {
1431 | "version": "7.3.1",
1432 | "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
1433 | "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
1434 | "dependencies": {
1435 | "asap": "~2.0.3"
1436 | }
1437 | },
1438 | "node_modules/proxy-addr": {
1439 | "version": "2.0.7",
1440 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
1441 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
1442 | "dependencies": {
1443 | "forwarded": "0.2.0",
1444 | "ipaddr.js": "1.9.1"
1445 | },
1446 | "engines": {
1447 | "node": ">= 0.10"
1448 | }
1449 | },
1450 | "node_modules/pstree.remy": {
1451 | "version": "1.1.8",
1452 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
1453 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
1454 | "dev": true
1455 | },
1456 | "node_modules/pug": {
1457 | "version": "3.0.3",
1458 | "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.3.tgz",
1459 | "integrity": "sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==",
1460 | "dependencies": {
1461 | "pug-code-gen": "^3.0.3",
1462 | "pug-filters": "^4.0.0",
1463 | "pug-lexer": "^5.0.1",
1464 | "pug-linker": "^4.0.0",
1465 | "pug-load": "^3.0.0",
1466 | "pug-parser": "^6.0.0",
1467 | "pug-runtime": "^3.0.1",
1468 | "pug-strip-comments": "^2.0.0"
1469 | }
1470 | },
1471 | "node_modules/pug-attrs": {
1472 | "version": "3.0.0",
1473 | "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz",
1474 | "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==",
1475 | "dependencies": {
1476 | "constantinople": "^4.0.1",
1477 | "js-stringify": "^1.0.2",
1478 | "pug-runtime": "^3.0.0"
1479 | }
1480 | },
1481 | "node_modules/pug-code-gen": {
1482 | "version": "3.0.3",
1483 | "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.3.tgz",
1484 | "integrity": "sha512-cYQg0JW0w32Ux+XTeZnBEeuWrAY7/HNE6TWnhiHGnnRYlCgyAUPoyh9KzCMa9WhcJlJ1AtQqpEYHc+vbCzA+Aw==",
1485 | "dependencies": {
1486 | "constantinople": "^4.0.1",
1487 | "doctypes": "^1.1.0",
1488 | "js-stringify": "^1.0.2",
1489 | "pug-attrs": "^3.0.0",
1490 | "pug-error": "^2.1.0",
1491 | "pug-runtime": "^3.0.1",
1492 | "void-elements": "^3.1.0",
1493 | "with": "^7.0.0"
1494 | }
1495 | },
1496 | "node_modules/pug-error": {
1497 | "version": "2.1.0",
1498 | "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.1.0.tgz",
1499 | "integrity": "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg=="
1500 | },
1501 | "node_modules/pug-filters": {
1502 | "version": "4.0.0",
1503 | "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz",
1504 | "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==",
1505 | "dependencies": {
1506 | "constantinople": "^4.0.1",
1507 | "jstransformer": "1.0.0",
1508 | "pug-error": "^2.0.0",
1509 | "pug-walk": "^2.0.0",
1510 | "resolve": "^1.15.1"
1511 | }
1512 | },
1513 | "node_modules/pug-lexer": {
1514 | "version": "5.0.1",
1515 | "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz",
1516 | "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==",
1517 | "dependencies": {
1518 | "character-parser": "^2.2.0",
1519 | "is-expression": "^4.0.0",
1520 | "pug-error": "^2.0.0"
1521 | }
1522 | },
1523 | "node_modules/pug-linker": {
1524 | "version": "4.0.0",
1525 | "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz",
1526 | "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==",
1527 | "dependencies": {
1528 | "pug-error": "^2.0.0",
1529 | "pug-walk": "^2.0.0"
1530 | }
1531 | },
1532 | "node_modules/pug-load": {
1533 | "version": "3.0.0",
1534 | "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz",
1535 | "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==",
1536 | "dependencies": {
1537 | "object-assign": "^4.1.1",
1538 | "pug-walk": "^2.0.0"
1539 | }
1540 | },
1541 | "node_modules/pug-parser": {
1542 | "version": "6.0.0",
1543 | "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz",
1544 | "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==",
1545 | "dependencies": {
1546 | "pug-error": "^2.0.0",
1547 | "token-stream": "1.0.0"
1548 | }
1549 | },
1550 | "node_modules/pug-runtime": {
1551 | "version": "3.0.1",
1552 | "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz",
1553 | "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg=="
1554 | },
1555 | "node_modules/pug-strip-comments": {
1556 | "version": "2.0.0",
1557 | "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz",
1558 | "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==",
1559 | "dependencies": {
1560 | "pug-error": "^2.0.0"
1561 | }
1562 | },
1563 | "node_modules/pug-walk": {
1564 | "version": "2.0.0",
1565 | "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz",
1566 | "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ=="
1567 | },
1568 | "node_modules/punycode": {
1569 | "version": "2.3.1",
1570 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
1571 | "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
1572 | "engines": {
1573 | "node": ">=6"
1574 | }
1575 | },
1576 | "node_modules/qs": {
1577 | "version": "6.13.0",
1578 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
1579 | "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
1580 | "dependencies": {
1581 | "side-channel": "^1.0.6"
1582 | },
1583 | "engines": {
1584 | "node": ">=0.6"
1585 | },
1586 | "funding": {
1587 | "url": "https://github.com/sponsors/ljharb"
1588 | }
1589 | },
1590 | "node_modules/range-parser": {
1591 | "version": "1.2.1",
1592 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
1593 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
1594 | "engines": {
1595 | "node": ">= 0.6"
1596 | }
1597 | },
1598 | "node_modules/raw-body": {
1599 | "version": "2.5.2",
1600 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
1601 | "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
1602 | "dependencies": {
1603 | "bytes": "3.1.2",
1604 | "http-errors": "2.0.0",
1605 | "iconv-lite": "0.4.24",
1606 | "unpipe": "1.0.0"
1607 | },
1608 | "engines": {
1609 | "node": ">= 0.8"
1610 | }
1611 | },
1612 | "node_modules/readable-stream": {
1613 | "version": "2.3.8",
1614 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
1615 | "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
1616 | "license": "MIT",
1617 | "dependencies": {
1618 | "core-util-is": "~1.0.0",
1619 | "inherits": "~2.0.3",
1620 | "isarray": "~1.0.0",
1621 | "process-nextick-args": "~2.0.0",
1622 | "safe-buffer": "~5.1.1",
1623 | "string_decoder": "~1.1.1",
1624 | "util-deprecate": "~1.0.1"
1625 | }
1626 | },
1627 | "node_modules/readable-stream/node_modules/safe-buffer": {
1628 | "version": "5.1.2",
1629 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
1630 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
1631 | "license": "MIT"
1632 | },
1633 | "node_modules/readdirp": {
1634 | "version": "3.6.0",
1635 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
1636 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
1637 | "dev": true,
1638 | "dependencies": {
1639 | "picomatch": "^2.2.1"
1640 | },
1641 | "engines": {
1642 | "node": ">=8.10.0"
1643 | }
1644 | },
1645 | "node_modules/resolve": {
1646 | "version": "1.22.10",
1647 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
1648 | "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
1649 | "dependencies": {
1650 | "is-core-module": "^2.16.0",
1651 | "path-parse": "^1.0.7",
1652 | "supports-preserve-symlinks-flag": "^1.0.0"
1653 | },
1654 | "bin": {
1655 | "resolve": "bin/resolve"
1656 | },
1657 | "engines": {
1658 | "node": ">= 0.4"
1659 | },
1660 | "funding": {
1661 | "url": "https://github.com/sponsors/ljharb"
1662 | }
1663 | },
1664 | "node_modules/safe-buffer": {
1665 | "version": "5.2.1",
1666 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1667 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
1668 | "funding": [
1669 | {
1670 | "type": "github",
1671 | "url": "https://github.com/sponsors/feross"
1672 | },
1673 | {
1674 | "type": "patreon",
1675 | "url": "https://www.patreon.com/feross"
1676 | },
1677 | {
1678 | "type": "consulting",
1679 | "url": "https://feross.org/support"
1680 | }
1681 | ]
1682 | },
1683 | "node_modules/safer-buffer": {
1684 | "version": "2.1.2",
1685 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1686 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
1687 | },
1688 | "node_modules/semver": {
1689 | "version": "7.7.1",
1690 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
1691 | "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
1692 | "bin": {
1693 | "semver": "bin/semver.js"
1694 | },
1695 | "engines": {
1696 | "node": ">=10"
1697 | }
1698 | },
1699 | "node_modules/send": {
1700 | "version": "0.19.0",
1701 | "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
1702 | "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
1703 | "dependencies": {
1704 | "debug": "2.6.9",
1705 | "depd": "2.0.0",
1706 | "destroy": "1.2.0",
1707 | "encodeurl": "~1.0.2",
1708 | "escape-html": "~1.0.3",
1709 | "etag": "~1.8.1",
1710 | "fresh": "0.5.2",
1711 | "http-errors": "2.0.0",
1712 | "mime": "1.6.0",
1713 | "ms": "2.1.3",
1714 | "on-finished": "2.4.1",
1715 | "range-parser": "~1.2.1",
1716 | "statuses": "2.0.1"
1717 | },
1718 | "engines": {
1719 | "node": ">= 0.8.0"
1720 | }
1721 | },
1722 | "node_modules/send/node_modules/encodeurl": {
1723 | "version": "1.0.2",
1724 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
1725 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
1726 | "engines": {
1727 | "node": ">= 0.8"
1728 | }
1729 | },
1730 | "node_modules/send/node_modules/ms": {
1731 | "version": "2.1.3",
1732 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1733 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
1734 | },
1735 | "node_modules/serve-static": {
1736 | "version": "1.16.2",
1737 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
1738 | "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
1739 | "dependencies": {
1740 | "encodeurl": "~2.0.0",
1741 | "escape-html": "~1.0.3",
1742 | "parseurl": "~1.3.3",
1743 | "send": "0.19.0"
1744 | },
1745 | "engines": {
1746 | "node": ">= 0.8.0"
1747 | }
1748 | },
1749 | "node_modules/setprototypeof": {
1750 | "version": "1.2.0",
1751 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
1752 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
1753 | },
1754 | "node_modules/side-channel": {
1755 | "version": "1.1.0",
1756 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
1757 | "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
1758 | "dependencies": {
1759 | "es-errors": "^1.3.0",
1760 | "object-inspect": "^1.13.3",
1761 | "side-channel-list": "^1.0.0",
1762 | "side-channel-map": "^1.0.1",
1763 | "side-channel-weakmap": "^1.0.2"
1764 | },
1765 | "engines": {
1766 | "node": ">= 0.4"
1767 | },
1768 | "funding": {
1769 | "url": "https://github.com/sponsors/ljharb"
1770 | }
1771 | },
1772 | "node_modules/side-channel-list": {
1773 | "version": "1.0.0",
1774 | "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
1775 | "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
1776 | "dependencies": {
1777 | "es-errors": "^1.3.0",
1778 | "object-inspect": "^1.13.3"
1779 | },
1780 | "engines": {
1781 | "node": ">= 0.4"
1782 | },
1783 | "funding": {
1784 | "url": "https://github.com/sponsors/ljharb"
1785 | }
1786 | },
1787 | "node_modules/side-channel-map": {
1788 | "version": "1.0.1",
1789 | "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
1790 | "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
1791 | "dependencies": {
1792 | "call-bound": "^1.0.2",
1793 | "es-errors": "^1.3.0",
1794 | "get-intrinsic": "^1.2.5",
1795 | "object-inspect": "^1.13.3"
1796 | },
1797 | "engines": {
1798 | "node": ">= 0.4"
1799 | },
1800 | "funding": {
1801 | "url": "https://github.com/sponsors/ljharb"
1802 | }
1803 | },
1804 | "node_modules/side-channel-weakmap": {
1805 | "version": "1.0.2",
1806 | "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
1807 | "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
1808 | "dependencies": {
1809 | "call-bound": "^1.0.2",
1810 | "es-errors": "^1.3.0",
1811 | "get-intrinsic": "^1.2.5",
1812 | "object-inspect": "^1.13.3",
1813 | "side-channel-map": "^1.0.1"
1814 | },
1815 | "engines": {
1816 | "node": ">= 0.4"
1817 | },
1818 | "funding": {
1819 | "url": "https://github.com/sponsors/ljharb"
1820 | }
1821 | },
1822 | "node_modules/sift": {
1823 | "version": "17.1.3",
1824 | "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz",
1825 | "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ=="
1826 | },
1827 | "node_modules/simple-update-notifier": {
1828 | "version": "2.0.0",
1829 | "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
1830 | "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
1831 | "dev": true,
1832 | "dependencies": {
1833 | "semver": "^7.5.3"
1834 | },
1835 | "engines": {
1836 | "node": ">=10"
1837 | }
1838 | },
1839 | "node_modules/sparse-bitfield": {
1840 | "version": "3.0.3",
1841 | "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
1842 | "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
1843 | "dependencies": {
1844 | "memory-pager": "^1.0.2"
1845 | }
1846 | },
1847 | "node_modules/statuses": {
1848 | "version": "2.0.1",
1849 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
1850 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
1851 | "engines": {
1852 | "node": ">= 0.8"
1853 | }
1854 | },
1855 | "node_modules/streamsearch": {
1856 | "version": "1.1.0",
1857 | "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
1858 | "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
1859 | "engines": {
1860 | "node": ">=10.0.0"
1861 | }
1862 | },
1863 | "node_modules/string_decoder": {
1864 | "version": "1.1.1",
1865 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
1866 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
1867 | "license": "MIT",
1868 | "dependencies": {
1869 | "safe-buffer": "~5.1.0"
1870 | }
1871 | },
1872 | "node_modules/string_decoder/node_modules/safe-buffer": {
1873 | "version": "5.1.2",
1874 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
1875 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
1876 | "license": "MIT"
1877 | },
1878 | "node_modules/supports-color": {
1879 | "version": "5.5.0",
1880 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
1881 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
1882 | "dev": true,
1883 | "dependencies": {
1884 | "has-flag": "^3.0.0"
1885 | },
1886 | "engines": {
1887 | "node": ">=4"
1888 | }
1889 | },
1890 | "node_modules/supports-preserve-symlinks-flag": {
1891 | "version": "1.0.0",
1892 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
1893 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
1894 | "engines": {
1895 | "node": ">= 0.4"
1896 | },
1897 | "funding": {
1898 | "url": "https://github.com/sponsors/ljharb"
1899 | }
1900 | },
1901 | "node_modules/to-regex-range": {
1902 | "version": "5.0.1",
1903 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
1904 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
1905 | "dev": true,
1906 | "dependencies": {
1907 | "is-number": "^7.0.0"
1908 | },
1909 | "engines": {
1910 | "node": ">=8.0"
1911 | }
1912 | },
1913 | "node_modules/toidentifier": {
1914 | "version": "1.0.1",
1915 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
1916 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
1917 | "engines": {
1918 | "node": ">=0.6"
1919 | }
1920 | },
1921 | "node_modules/token-stream": {
1922 | "version": "1.0.0",
1923 | "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz",
1924 | "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg=="
1925 | },
1926 | "node_modules/touch": {
1927 | "version": "3.1.1",
1928 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
1929 | "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
1930 | "dev": true,
1931 | "bin": {
1932 | "nodetouch": "bin/nodetouch.js"
1933 | }
1934 | },
1935 | "node_modules/tr46": {
1936 | "version": "5.1.0",
1937 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.0.tgz",
1938 | "integrity": "sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==",
1939 | "dependencies": {
1940 | "punycode": "^2.3.1"
1941 | },
1942 | "engines": {
1943 | "node": ">=18"
1944 | }
1945 | },
1946 | "node_modules/type-is": {
1947 | "version": "1.6.18",
1948 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
1949 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
1950 | "dependencies": {
1951 | "media-typer": "0.3.0",
1952 | "mime-types": "~2.1.24"
1953 | },
1954 | "engines": {
1955 | "node": ">= 0.6"
1956 | }
1957 | },
1958 | "node_modules/typedarray": {
1959 | "version": "0.0.6",
1960 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
1961 | "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
1962 | "license": "MIT"
1963 | },
1964 | "node_modules/undefsafe": {
1965 | "version": "2.0.5",
1966 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
1967 | "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
1968 | "dev": true
1969 | },
1970 | "node_modules/unpipe": {
1971 | "version": "1.0.0",
1972 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
1973 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
1974 | "engines": {
1975 | "node": ">= 0.8"
1976 | }
1977 | },
1978 | "node_modules/util-deprecate": {
1979 | "version": "1.0.2",
1980 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
1981 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
1982 | "license": "MIT"
1983 | },
1984 | "node_modules/utils-merge": {
1985 | "version": "1.0.1",
1986 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
1987 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
1988 | "engines": {
1989 | "node": ">= 0.4.0"
1990 | }
1991 | },
1992 | "node_modules/vary": {
1993 | "version": "1.1.2",
1994 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
1995 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
1996 | "engines": {
1997 | "node": ">= 0.8"
1998 | }
1999 | },
2000 | "node_modules/void-elements": {
2001 | "version": "3.1.0",
2002 | "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
2003 | "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
2004 | "engines": {
2005 | "node": ">=0.10.0"
2006 | }
2007 | },
2008 | "node_modules/webidl-conversions": {
2009 | "version": "7.0.0",
2010 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
2011 | "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
2012 | "engines": {
2013 | "node": ">=12"
2014 | }
2015 | },
2016 | "node_modules/whatwg-url": {
2017 | "version": "14.2.0",
2018 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz",
2019 | "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==",
2020 | "dependencies": {
2021 | "tr46": "^5.1.0",
2022 | "webidl-conversions": "^7.0.0"
2023 | },
2024 | "engines": {
2025 | "node": ">=18"
2026 | }
2027 | },
2028 | "node_modules/with": {
2029 | "version": "7.0.2",
2030 | "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz",
2031 | "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==",
2032 | "dependencies": {
2033 | "@babel/parser": "^7.9.6",
2034 | "@babel/types": "^7.9.6",
2035 | "assert-never": "^1.2.1",
2036 | "babel-walk": "3.0.0-canary-5"
2037 | },
2038 | "engines": {
2039 | "node": ">= 10.0.0"
2040 | }
2041 | },
2042 | "node_modules/xtend": {
2043 | "version": "4.0.2",
2044 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
2045 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
2046 | "license": "MIT",
2047 | "engines": {
2048 | "node": ">=0.4"
2049 | }
2050 | }
2051 | }
2052 | }
2053 |
--------------------------------------------------------------------------------