├── backend ├── ArquitecturaAPI.png ├── src │ ├── constants │ │ └── roles.constants.js │ ├── config │ │ ├── .env.example │ │ ├── configEnv.js │ │ ├── configDB.js │ │ └── initialSetup.js │ ├── routes │ │ ├── auth.routes.js │ │ ├── index.routes.js │ │ └── user.routes.js │ ├── models │ │ ├── role.model.js │ │ └── user.model.js │ ├── utils │ │ ├── errorHandler.js │ │ └── resHandler.js │ ├── schema │ │ ├── auth.schema.js │ │ └── user.schema.js │ ├── middlewares │ │ ├── authorization.middleware.js │ │ └── authentication.middleware.js │ ├── server.js │ ├── controllers │ │ ├── auth.controller.js │ │ └── user.controller.js │ └── services │ │ ├── auth.service.js │ │ └── user.service.js ├── .prettierrc.json ├── package.json ├── .eslintrc.json ├── .gitignore ├── README.md └── package-lock.json ├── frontend ├── src │ ├── routes │ │ ├── App.jsx │ │ ├── Login.jsx │ │ ├── ErrorPage.jsx │ │ └── Root.jsx │ ├── services │ │ ├── root.service.js │ │ └── auth.service.js │ ├── index.css │ ├── main.jsx │ ├── context │ │ └── AuthContext.jsx │ ├── components │ │ └── LoginForm.jsx │ └── assets │ │ └── react.svg ├── vite.config.js ├── .gitignore ├── index.html ├── README.md ├── public │ ├── .eslintrc.cjs │ └── vite.svg └── package.json ├── README.md └── .gitignore /backend/ArquitecturaAPI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ubiobio/Template-ISW-Proyecto-2023/HEAD/backend/ArquitecturaAPI.png -------------------------------------------------------------------------------- /backend/src/constants/roles.constants.js: -------------------------------------------------------------------------------- 1 | /** Roles permitidos por la base de datos */ 2 | const ROLES = ["user", "admin"]; 3 | 4 | export default ROLES; 5 | -------------------------------------------------------------------------------- /backend/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": false, 3 | "trailingComma": "all", 4 | "tabWidth": 2, 5 | "semi": true, 6 | "arrowParens": "always" 7 | } 8 | -------------------------------------------------------------------------------- /frontend/src/routes/App.jsx: -------------------------------------------------------------------------------- 1 | function App() { 2 | return ( 3 | <> 4 |

Pagina principal

5 | 6 | ); 7 | } 8 | 9 | export default App; 10 | -------------------------------------------------------------------------------- /frontend/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /backend/src/config/.env.example: -------------------------------------------------------------------------------- 1 | PORT=Inserte el puerto de su servidor 2 | HOST=localhost 3 | DB_URL=Inserte su link de mongo Atlas 4 | ACCESS_JWT_SECRET=Inserte el secreto de su JWT 5 | REFRESH_JWT_SECRET=Inserte un secreto distinto de su JWT 6 | -------------------------------------------------------------------------------- /frontend/src/services/root.service.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | const API_URL = import.meta.env.VITE_BASE_URL || 'http://localhost:5000/api'; 4 | 5 | const instance = axios.create({ 6 | baseURL: API_URL, 7 | headers: { 8 | 'Content-Type': 'application/json', 9 | }, 10 | withCredentials: true, 11 | }); 12 | 13 | export default instance; 14 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Titulo 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /frontend/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | -webkit-text-size-adjust: 100%; 15 | } 16 | 17 | a { 18 | text-decoration: inherit; 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/routes/Login.jsx: -------------------------------------------------------------------------------- 1 | import LoginForm from '../components/LoginForm'; 2 | import { useNavigate } from 'react-router-dom'; 3 | 4 | function Login() { 5 | const navigate = useNavigate(); 6 | 7 | if (localStorage.getItem('user')) { 8 | return ( 9 | <> 10 |

Ya estas logeado!

11 | 12 | 13 | ); 14 | } 15 | 16 | return ( 17 |
18 |

Inicia sesion!

19 | 20 |
21 | ); 22 | } 23 | 24 | export default Login; 25 | -------------------------------------------------------------------------------- /backend/src/routes/auth.routes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Importa el modulo 'express' para crear las rutas 3 | import { Router } from "express"; 4 | 5 | /** Controlador de autenticación */ 6 | import authController from "../controllers/auth.controller.js"; 7 | 8 | /** Instancia del enrutador */ 9 | const router = Router(); 10 | 11 | // Define las rutas para la autenticación 12 | router.post("/login", authController.login); 13 | router.post("/logout", authController.logout); 14 | router.get("/refresh", authController.refresh); 15 | 16 | // Exporta el enrutador 17 | export default router; 18 | -------------------------------------------------------------------------------- /frontend/public/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:react/recommended', 7 | 'plugin:react/jsx-runtime', 8 | 'plugin:react-hooks/recommended', 9 | ], 10 | ignorePatterns: ['dist', '.eslintrc.cjs'], 11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 12 | settings: { react: { version: '18.2' } }, 13 | plugins: ['react-refresh'], 14 | rules: { 15 | 'react-refresh/only-export-components': [ 16 | 'warn', 17 | { allowConstantExport: true }, 18 | ], 19 | }, 20 | } 21 | -------------------------------------------------------------------------------- /backend/src/models/role.model.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Importa el modulo 'mongoose' para crear la conexion a la base de datos 3 | import { Schema, model } from "mongoose"; 4 | import ROLES from "../constants/roles.constants.js"; 5 | 6 | // Crea el esquema de la coleccion 'roles' 7 | const roleSchema = new Schema( 8 | { 9 | name: { 10 | type: String, 11 | enum: ROLES, 12 | required: true, 13 | }, 14 | }, 15 | { 16 | versionKey: false, 17 | }, 18 | ); 19 | 20 | // Crea el modelo de datos 'Role' a partir del esquema 'roleSchema' 21 | const Role = model("Role", roleSchema); 22 | 23 | export default Role; 24 | -------------------------------------------------------------------------------- /frontend/src/routes/ErrorPage.jsx: -------------------------------------------------------------------------------- 1 | import { useRouteError } from 'react-router-dom'; 2 | 3 | const ErrorPage = () => { 4 | const error = useRouteError(); 5 | 6 | /** 7 | * Este mensaje de error, está pensado para los desarrolladores. 8 | * En un entorno de producción, no se debería mostrar este mensaje o almenos 9 | * no de esta forma. 10 | */ 11 | console.error({ 12 | status: error.status, 13 | statusText: error.statusText, 14 | message: error.message ? error.message : 'No message', 15 | }); 16 | 17 | return ( 18 |
19 |

Oops!

20 |

Sorry, un error inesperado a ocurrido.

21 |
22 | ); 23 | }; 24 | 25 | export default ErrorPage; 26 | -------------------------------------------------------------------------------- /backend/src/utils/errorHandler.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** 4 | * Manejador de errores fatales 5 | * @param {Object} error Objecto con las especificaciones del error 6 | * @param {String} msg Mensaje para dar contexto al error 7 | */ 8 | function handleFatalError(error, msg) { 9 | console.log("[FATAL ERROR] Apagando servidor \n", msg); 10 | console.error(error); 11 | process.exit(1); 12 | } 13 | 14 | /** 15 | * Manejador de errores 16 | * @param {Object} error Objecto con las especificaciones del error 17 | * @param {String} msg Mensaje para dar contexto al error 18 | */ 19 | function handleError(error, msg) { 20 | console.log("❌ [ERROR] A ocurrido un error en: \n📁", msg); 21 | console.error("🗯 " + error.message); 22 | } 23 | 24 | export { handleFatalError, handleError }; 25 | -------------------------------------------------------------------------------- /backend/src/routes/index.routes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Importa el modulo 'express' para crear las rutas 3 | import { Router } from "express"; 4 | 5 | /** Enrutador de usuarios */ 6 | import userRoutes from "./user.routes.js"; 7 | 8 | /** Enrutador de autenticación */ 9 | import authRoutes from "./auth.routes.js"; 10 | 11 | /** Middleware de autenticación */ 12 | import authenticationMiddleware from "../middlewares/authentication.middleware.js"; 13 | 14 | /** Instancia del enrutador */ 15 | const router = Router(); 16 | 17 | // Define las rutas para los usuarios /api/usuarios 18 | router.use("/users", authenticationMiddleware, userRoutes); 19 | // Define las rutas para la autenticación /api/auth 20 | router.use("/auth", authRoutes); 21 | 22 | // Exporta el enrutador 23 | export default router; 24 | -------------------------------------------------------------------------------- /frontend/src/main.jsx: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom/client'; 2 | import App from './routes/App.jsx'; 3 | import './index.css'; 4 | import { createBrowserRouter, RouterProvider } from 'react-router-dom'; 5 | import Root from './routes/Root.jsx'; 6 | import ErrorPage from './routes/ErrorPage.jsx'; 7 | import Login from './routes/Login.jsx'; 8 | 9 | const router = createBrowserRouter([ 10 | { 11 | path: '/', 12 | element: , 13 | errorElement: , 14 | children: [ 15 | { 16 | path: '/', 17 | element: , 18 | }, 19 | ], 20 | }, 21 | { 22 | path: '/auth', 23 | element: , 24 | }, 25 | ]); 26 | 27 | ReactDOM.createRoot(document.getElementById('root')).render( 28 | 29 | ); 30 | -------------------------------------------------------------------------------- /backend/src/config/configEnv.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Import the 'path' module to get the absolute path of the .env file 3 | import path from "node:path"; 4 | const __dirname = import.meta.dirname; 5 | 6 | /** Get the absolute path of the .env file. */ 7 | const envFilePath = path.resolve(__dirname, ".env"); 8 | // Load environment variables from the .env file 9 | import dotenv from "dotenv"; 10 | dotenv.config({ path: envFilePath }); 11 | 12 | /** Server port */ 13 | export const PORT = process.env.PORT; 14 | /** Server host */ 15 | export const HOST = process.env.HOST; 16 | /** Database URL */ 17 | export const DB_URL = process.env.DB_URL; 18 | /** Access token secret */ 19 | export const ACCESS_JWT_SECRET = process.env.ACCESS_JWT_SECRET; 20 | /** Refresh token secret */ 21 | export const REFRESH_JWT_SECRET = process.env.REFRESH_JWT_SECRET; 22 | -------------------------------------------------------------------------------- /backend/src/config/configDB.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Importa el modulo 'mongoose' para crear la conexion a la base de datos 3 | import { connect } from "mongoose"; 4 | 5 | // Agregamos la configuracion de las variables de entorno 6 | import { DB_URL } from "./configEnv.js"; 7 | import { handleError } from "../utils/errorHandler.js"; 8 | 9 | /** 10 | * Establece la conexión con la base de datos. 11 | * @async 12 | * @function setupDB 13 | * @throws {Error} Si no se puede conectar a la base de datos. 14 | * @returns {Promise} Una promesa que se resuelve cuando se establece la conexión con la base de datos. 15 | */ 16 | 17 | async function setupDB() { 18 | try { 19 | await connect(DB_URL); 20 | console.log("=> Conectado a la base de datos"); 21 | } catch (err) { 22 | handleError(err, "/configDB.js -> setupDB"); 23 | } 24 | } 25 | 26 | export { setupDB }; 27 | -------------------------------------------------------------------------------- /frontend/src/context/AuthContext.jsx: -------------------------------------------------------------------------------- 1 | import { createContext, useContext, useEffect } from 'react'; 2 | import { useNavigate } from 'react-router-dom'; 3 | 4 | const AuthContext = createContext(); 5 | 6 | // eslint-disable-next-line react-refresh/only-export-components 7 | export const useAuth = () => useContext(AuthContext); 8 | 9 | // eslint-disable-next-line react/prop-types 10 | export function AuthProvider({ children }) { 11 | const navigate = useNavigate(); 12 | 13 | const user = JSON.parse(localStorage.getItem('user')) || ''; 14 | const isAuthenticated = user ? true : false; 15 | 16 | useEffect(() => { 17 | if (!isAuthenticated) { 18 | navigate('/auth'); 19 | } 20 | }, [isAuthenticated, navigate]); 21 | 22 | return ( 23 | 24 | {children} 25 | 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /frontend/src/routes/Root.jsx: -------------------------------------------------------------------------------- 1 | import { Outlet } from 'react-router-dom'; 2 | import { useNavigate } from 'react-router-dom'; 3 | import { logout } from '../services/auth.service'; 4 | import { AuthProvider, useAuth } from '../context/AuthContext'; 5 | 6 | function Root() { 7 | return ( 8 | 9 | 10 | 11 | ); 12 | } 13 | 14 | function PageRoot() { 15 | const navigate = useNavigate(); 16 | 17 | const handleLogout = () => { 18 | logout(); 19 | navigate('/auth'); 20 | }; 21 | 22 | const { user } = useAuth(); 23 | 24 | return ( 25 |
26 |
27 |

Aqui deberia ir un header

28 |

Estas logeado como: {user.email}

29 | 30 |
31 | 32 |
33 | ); 34 | } 35 | 36 | export default Root; 37 | -------------------------------------------------------------------------------- /backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api-node", 3 | "version": "1.0.0", 4 | "type": "module", 5 | "description": "Template backend", 6 | "main": "src/server.js", 7 | "scripts": { 8 | "start": "nodemon src/server.js", 9 | "dev": "nodemon src/server.js" 10 | }, 11 | "keywords": [ 12 | "node", 13 | "backend", 14 | "http" 15 | ], 16 | "author": "Camilo saez", 17 | "license": "MIT", 18 | "dependencies": { 19 | "bcryptjs": "2.4.3", 20 | "cookie-parser": "1.4.6", 21 | "cors": "2.8.5", 22 | "dotenv": "^16.4.4", 23 | "express": "4.18.2", 24 | "joi": "17.10.2", 25 | "jsonwebtoken": "9.0.2", 26 | "mongoose": "^8.1.0", 27 | "morgan": "1.10.0" 28 | }, 29 | "devDependencies": { 30 | "eslint": "^8.56.0", 31 | "eslint-config-google": "0.14.0", 32 | "jsdoc": "4.0.2", 33 | "nodemon": "^3.0.3", 34 | "prettier": "^3.2.5" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /backend/src/schema/auth.schema.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import Joi from "joi"; 4 | 5 | /** 6 | * Esquema de validación para el cuerpo de la solicitud de inicio de sesión. 7 | * @constant {Object} 8 | */ 9 | const authLoginBodySchema = Joi.object({ 10 | email: Joi.string().email().required().messages({ 11 | "string.empty": "El email no puede estar vacío.", 12 | "any.required": "El email es obligatorio.", 13 | "string.base": "El email debe ser de tipo string.", 14 | "string.email": "El email debe tener un formato válido.", 15 | }), 16 | password: Joi.string().required().messages({ 17 | "string.empty": "La contraseña no puede estar vacía.", 18 | "any.required": "La contraseña es obligatoria.", 19 | "string.base": "La contraseña debe ser de tipo string.", 20 | }), 21 | }).messages({ 22 | "object.unknown": "No se permiten propiedades adicionales.", 23 | }); 24 | 25 | export { authLoginBodySchema }; 26 | -------------------------------------------------------------------------------- /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 . --ext js,jsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "axios": "^1.5.1", 14 | "js-cookie": "^3.0.5", 15 | "jwt-decode": "^3.1.2", 16 | "react": "^18.2.0", 17 | "react-dom": "^18.2.0", 18 | "react-hook-form": "^7.47.0", 19 | "react-router-dom": "^6.17.0" 20 | }, 21 | "devDependencies": { 22 | "@types/react": "^18.2.15", 23 | "@types/react-dom": "^18.2.7", 24 | "@vitejs/plugin-react": "^4.0.3", 25 | "eslint": "^8.45.0", 26 | "eslint-plugin-react": "^7.32.2", 27 | "eslint-plugin-react-hooks": "^4.6.0", 28 | "eslint-plugin-react-refresh": "^0.4.3", 29 | "vite": "^4.4.5" 30 | } 31 | } -------------------------------------------------------------------------------- /frontend/src/components/LoginForm.jsx: -------------------------------------------------------------------------------- 1 | import { useNavigate } from 'react-router-dom'; 2 | import { useForm } from 'react-hook-form'; 3 | import { login } from '../services/auth.service'; 4 | 5 | function LoginForm() { 6 | const navigate = useNavigate(); 7 | 8 | const { 9 | register, 10 | handleSubmit, 11 | formState: { errors }, 12 | } = useForm(); 13 | 14 | const onSubmit = (data) => { 15 | login(data).then(() => { 16 | navigate('/'); 17 | }); 18 | }; 19 | 20 | return ( 21 |
22 | 27 | 32 | {errors.exampleRequired && This field is required} 33 | 34 |
35 | ); 36 | } 37 | 38 | export default LoginForm; 39 | -------------------------------------------------------------------------------- /backend/src/routes/user.routes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Importa el modulo 'express' para crear las rutas 3 | import { Router } from "express"; 4 | 5 | /** Controlador de usuarios */ 6 | import usuarioController from "../controllers/user.controller.js"; 7 | 8 | /** Middlewares de autorización */ 9 | import { isAdmin } from "../middlewares/authorization.middleware.js"; 10 | 11 | /** Middleware de autenticación */ 12 | import authenticationMiddleware from "../middlewares/authentication.middleware.js"; 13 | 14 | /** Instancia del enrutador */ 15 | const router = Router(); 16 | 17 | // Define el middleware de autenticación para todas las rutas 18 | router.use(authenticationMiddleware); 19 | // Define las rutas para los usuarios 20 | router.get("/", isAdmin, usuarioController.getUsers); 21 | router.post("/", isAdmin, usuarioController.createUser); 22 | router.get("/:id", usuarioController.getUserById); 23 | router.put("/:id", isAdmin, usuarioController.updateUser); 24 | router.delete("/:id", isAdmin, usuarioController.deleteUser); 25 | 26 | // Exporta el enrutador 27 | export default router; 28 | -------------------------------------------------------------------------------- /backend/src/middlewares/authorization.middleware.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Autorizacion - Comprobar el rol del usuario 3 | import User from "../models/user.model.js"; 4 | import Role from "../models/role.model.js"; 5 | import { respondError } from "../utils/resHandler.js"; 6 | import { handleError } from "../utils/errorHandler.js"; 7 | 8 | /** 9 | * Comprueba si el usuario es administrador 10 | * @param {Object} req - Objeto de petición 11 | * @param {Object} res - Objeto de respuesta 12 | * @param {Function} next - Función para continuar con la siguiente función 13 | */ 14 | async function isAdmin(req, res, next) { 15 | try { 16 | const user = await User.findOne({ email: req.email }); 17 | const roles = await Role.find({ _id: { $in: user.roles } }); 18 | for (let i = 0; i < roles.length; i++) { 19 | if (roles[i].name === "admin") { 20 | next(); 21 | return; 22 | } 23 | } 24 | return respondError( 25 | req, 26 | res, 27 | 401, 28 | "Se requiere un rol de administrador para realizar esta acción", 29 | ); 30 | } catch (error) { 31 | handleError(error, "authorization.middleware -> isAdmin"); 32 | } 33 | } 34 | 35 | export { isAdmin }; 36 | -------------------------------------------------------------------------------- /frontend/src/services/auth.service.js: -------------------------------------------------------------------------------- 1 | import axios from './root.service'; 2 | import cookies from 'js-cookie'; 3 | import jwtDecode from 'jwt-decode'; 4 | 5 | export const login = async ({ email, password }) => { 6 | try { 7 | const response = await axios.post('auth/login', { 8 | email, 9 | password, 10 | }); 11 | const { status, data } = response; 12 | if (status === 200) { 13 | const { email, roles } = await jwtDecode(data.data.accessToken); 14 | localStorage.setItem('user', JSON.stringify({ email, roles })); 15 | axios.defaults.headers.common[ 16 | 'Authorization' 17 | ] = `Bearer ${data.data.accessToken}`; 18 | } 19 | } catch (error) { 20 | console.log(error); 21 | } 22 | }; 23 | 24 | export const logout = () => { 25 | localStorage.removeItem('user'); 26 | delete axios.defaults.headers.common['Authorization']; 27 | cookies.remove('jwt'); 28 | }; 29 | 30 | export const test = async () => { 31 | try { 32 | const response = await axios.get('/users'); 33 | const { status, data } = response; 34 | if (status === 200) { 35 | console.log(data.data); 36 | } 37 | } catch (error) { 38 | console.log(error); 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /backend/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true 5 | }, 6 | "extends": ["google"], 7 | "parserOptions": { 8 | "ecmaVersion": "latest", 9 | "sourceType": "module" 10 | }, 11 | "rules": { 12 | "require-jsdoc": [ 13 | "warn", 14 | { 15 | "require": { 16 | "FunctionDeclaration": true, 17 | "MethodDefinition": true, 18 | "ClassDeclaration": true, 19 | "ArrowFunctionExpression": true, 20 | "FunctionExpression": true 21 | } 22 | } 23 | ], 24 | "indent": "off", 25 | "new-cap": "off", 26 | "object-curly-spacing": ["error", "always"], 27 | "array-bracket-spacing": "off", 28 | "max-len": [ 29 | "error", 30 | { 31 | "code": 100, 32 | "tabWidth": 2, 33 | "comments": 150 34 | } 35 | ], 36 | "valid-jsdoc": "off", 37 | "no-console": "warn", 38 | "quotes": ["error", "double"], 39 | "operator-linebreak": [ 40 | "warn", 41 | "before", 42 | { 43 | "overrides": { 44 | ":": "before", 45 | "=": "after" 46 | } 47 | } 48 | ], 49 | "no-trailing-spaces": "off", 50 | "linebreak-style": "off" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!TIP] 2 | > Recomiendo utilizar el template, ya que les ahorrará tiempo al tener la implementación del inicio de sesión lista. 3 | # Template Proyecto Ingenieria de Software 👨‍💻 4 | 5 | Este template está diseñado para proporcionar a los estudiantes del curso de Ingeniería de Software una base al iniciar su proyecto, incluyendo un backend con funcionalidad de inicio de sesión y un frontend correspondiente. 6 | 7 | ## Cosas a tener en cuenta 📚 8 | 9 | Este proyecto consta de dos componentes principales: 10 | 11 | #### Backend 🚀 12 | 13 | El backend del proyecto proporciona la lógica y funcionalidad del lado del servidor, incluyendo una implementación de inicio de sesión. Este inicio de sesión utiliza tokens y cookies para la autenticación. Los estudiantes pueden encontrar más información y acceder al código del backend en el siguiente enlace: 14 | 15 | - [Backend](./backend/) 16 | 17 | #### Frontend 🚀 18 | 19 | El frontend del proyecto es la interfaz de usuario con la que interactúan los usuarios finales, incluyendo la interfaz de inicio de sesión que se conecta al backend. Los estudiantes pueden acceder al código del frontend y explorar su implementación en el siguiente enlace: 20 | 21 | - [Frontend](./frontend) 22 | 23 | ⌨️ with ❤️ by [@camjasaez](https://github.com/camjasaez) -------------------------------------------------------------------------------- /backend/src/middlewares/authentication.middleware.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import jwt from "jsonwebtoken"; 4 | import { ACCESS_JWT_SECRET } from "../config/configEnv.js"; 5 | import { respondError } from "../utils/resHandler.js"; 6 | import { handleError } from "../utils/errorHandler.js"; 7 | 8 | /** 9 | * Verifica el token de acceso 10 | * @param {Object} req - Objeto de petición 11 | * @param {Object} res - Objeto de respuesta 12 | * @param {Function} next - Función para continuar con la siguiente función 13 | */ 14 | const verifyJWT = (req, res, next) => { 15 | try { 16 | const authHeader = req.headers.authorization || req.headers.Authorization; 17 | 18 | if (!authHeader?.startsWith("Bearer ")) { 19 | return respondError( 20 | req, 21 | res, 22 | 401, 23 | "No autorizado", 24 | "No hay token valido", 25 | ); 26 | } 27 | 28 | const token = authHeader.split(" ")[1]; 29 | 30 | jwt.verify(token, ACCESS_JWT_SECRET, (err, decoded) => { 31 | if (err) return respondError(req, res, 403, "No autorizado", err.message); 32 | req.email = decoded.email; 33 | req.roles = decoded.roles; 34 | next(); 35 | }); 36 | } catch (error) { 37 | handleError(error, "authentication.middleware -> verifyToken"); 38 | } 39 | }; 40 | 41 | export default verifyJWT; 42 | -------------------------------------------------------------------------------- /backend/src/models/user.model.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Import the 'mongoose' module to create the database connection 3 | import mongoose from "mongoose"; 4 | import bcrypt from "bcryptjs"; 5 | 6 | // Create the 'users' collection schema 7 | const userSchema = new mongoose.Schema( 8 | { 9 | username: { 10 | type: String, 11 | required: true, 12 | }, 13 | rut: { 14 | type: String, 15 | required: true, 16 | unique: true, 17 | }, 18 | password: { 19 | type: String, 20 | required: true, 21 | }, 22 | email: { 23 | type: String, 24 | required: true, 25 | unique: true, 26 | }, 27 | roles: [ 28 | { 29 | type: mongoose.Schema.Types.ObjectId, 30 | ref: "Role", 31 | }, 32 | ], 33 | }, 34 | { 35 | versionKey: false, 36 | }, 37 | ); 38 | 39 | /** Encrypts the user's password */ 40 | userSchema.statics.encryptPassword = async (password) => { 41 | const salt = await bcrypt.genSalt(10); 42 | return await bcrypt.hash(password, salt); 43 | }; 44 | 45 | /** Compares the user's password */ 46 | userSchema.statics.comparePassword = async (password, receivedPassword) => { 47 | return await bcrypt.compare(password, receivedPassword); 48 | }; 49 | 50 | /** 'User' data model */ 51 | const User = mongoose.model("User", userSchema); 52 | 53 | // Export the 'User' data model 54 | export default User; 55 | -------------------------------------------------------------------------------- /frontend/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/src/config/initialSetup.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Importa el modelo de datos 'Role' 3 | import Role from "../models/role.model.js"; 4 | import User from "../models/user.model.js"; 5 | 6 | /** 7 | * Crea los roles por defecto en la base de datos. 8 | * @async 9 | * @function createRoles 10 | * @returns {Promise} 11 | */ 12 | async function createRoles() { 13 | try { 14 | // Busca todos los roles en la base de datos 15 | const count = await Role.estimatedDocumentCount(); 16 | // Si no hay roles en la base de datos los crea 17 | if (count > 0) return; 18 | 19 | await Promise.all([ 20 | new Role({ name: "user" }).save(), 21 | new Role({ name: "admin" }).save(), 22 | ]); 23 | console.log("* => Roles creados exitosamente"); 24 | } catch (error) { 25 | console.error(error); 26 | } 27 | } 28 | 29 | /** 30 | * Crea los usuarios por defecto en la base de datos. 31 | * @async 32 | * @function createUsers 33 | * @returns {Promise} 34 | */ 35 | async function createUsers() { 36 | try { 37 | const count = await User.estimatedDocumentCount(); 38 | if (count > 0) return; 39 | 40 | const admin = await Role.findOne({ name: "admin" }); 41 | const user = await Role.findOne({ name: "user" }); 42 | 43 | await Promise.all([ 44 | new User({ 45 | username: "user", 46 | email: "user@email.com", 47 | rut: "12345678-9", 48 | password: await User.encryptPassword("user123"), 49 | roles: user._id, 50 | }).save(), 51 | new User({ 52 | username: "admin", 53 | email: "admin@email.com", 54 | rut: "12345678-0", 55 | password: await User.encryptPassword("admin123"), 56 | roles: admin._id, 57 | }).save(), 58 | ]); 59 | console.log("* => Users creados exitosamente"); 60 | } catch (error) { 61 | console.error(error); 62 | } 63 | } 64 | 65 | export { createRoles, createUsers }; 66 | -------------------------------------------------------------------------------- /backend/src/utils/resHandler.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * Envía una respuesta exitosa estandarizada. 4 | * @function respondSuccess 5 | * @param {Object} req - Objeto de petición 6 | * @param {Object} res - Objeto de respuesta 7 | * @param {Number} statusCode - Código de estado para la operación 8 | * @param {Object} data - Objeto que contiene los datos a enviar 9 | * @returns {JSON} - Objeto de respuesta JSON con el estado "Success" y los datos proporcionados 10 | */ 11 | function respondSuccess(req, res, statusCode = 200, data = {}) { 12 | return res.status(statusCode).json({ 13 | state: "Success", 14 | data, 15 | }); 16 | } 17 | 18 | /** 19 | * Envía una respuesta de error estandarizada. 20 | * @function respondError 21 | * @param {Object} req - El objeto de petición 22 | * @param {Object} res - El objeto de respuesta 23 | * @param {Number} statusCode - Código de estado para la operación 24 | * @param {String} message - La descripción del motivo del error 25 | * @param {Object} details - Información adicional sobre el error 26 | * @returns {JSON} - El objeto de respuesta JSON con el estado "Error", el mensaje de error y los detalles proporcionados 27 | */ 28 | function respondError( 29 | req, 30 | res, 31 | statusCode = 500, 32 | message = "Couldnt process the request", 33 | details = {}, 34 | ) { 35 | return res.status(statusCode).json({ 36 | state: "Error", 37 | message, 38 | details, 39 | }); 40 | } 41 | 42 | /** 43 | * Envía una respuesta de error interno estandarizada. 44 | * @function respondInternalError 45 | * @param {Object} req - El objeto de petición 46 | * @param {Object} res - El objeto de respuesta 47 | * @param {Number} statusCode - El código de estado para la operación 48 | * @param {String} message - La descripción del motivo del error 49 | * @returns {JSON} - El objeto de respuesta JSON con el estado "Error" y el mensaje de error proporcionados 50 | */ 51 | function respondInternalError( 52 | req, 53 | res, 54 | statusCode = 500, 55 | message = "Couldnt process the request", 56 | ) { 57 | return res.status(statusCode).json({ 58 | state: "Error", 59 | message, 60 | }); 61 | } 62 | 63 | export { respondSuccess, respondError, respondInternalError }; 64 | -------------------------------------------------------------------------------- /backend/src/server.js: -------------------------------------------------------------------------------- 1 | // Importa el archivo 'configEnv.js' para cargar las variables de entorno 2 | import { PORT, HOST } from "./config/configEnv.js"; 3 | // Importa el módulo 'cors' para agregar los cors 4 | import cors from "cors"; 5 | // Importa el módulo 'express' para crear la aplicacion web 6 | import express, { urlencoded, json } from "express"; 7 | // Importamos morgan para ver las peticiones que se hacen al servidor 8 | import morgan from "morgan"; 9 | // Importa el módulo 'cookie-parser' para manejar las cookies 10 | import cookieParser from "cookie-parser"; 11 | /** El enrutador principal */ 12 | import indexRoutes from "./routes/index.routes.js"; 13 | // Importa el archivo 'configDB.js' para crear la conexión a la base de datos 14 | import { setupDB } from "./config/configDB.js"; 15 | // Importa el handler de errores 16 | import { handleFatalError, handleError } from "./utils/errorHandler.js"; 17 | import { createRoles, createUsers } from "./config/initialSetup.js"; 18 | 19 | /** 20 | * Inicia el servidor web 21 | */ 22 | async function setupServer() { 23 | try { 24 | /** Instancia de la aplicacion */ 25 | const server = express(); 26 | server.disable("x-powered-by"); 27 | // Agregamos los cors 28 | server.use(cors({ credentials: true, origin: true })); 29 | // Agrega el middleware para el manejo de datos en formato URL 30 | server.use(urlencoded({ extended: true })); 31 | // Agrega el middleware para el manejo de datos en formato JSON 32 | server.use(json()); 33 | // Agregamos el middleware para el manejo de cookies 34 | server.use(cookieParser()); 35 | // Agregamos morgan para ver las peticiones que se hacen al servidor 36 | server.use(morgan("dev")); 37 | // Agrega el enrutador principal al servidor 38 | server.use("/api", indexRoutes); 39 | 40 | // Inicia el servidor en el puerto especificado 41 | server.listen(PORT, () => { 42 | console.log(`=> Servidor corriendo en ${HOST}:${PORT}/api`); 43 | }); 44 | } catch (err) { 45 | handleError(err, "/server.js -> setupServer"); 46 | } 47 | } 48 | 49 | /** 50 | * Inicia la API 51 | */ 52 | async function setupAPI() { 53 | try { 54 | // Inicia la conexión a la base de datos 55 | await setupDB(); 56 | // Inicia el servidor web 57 | await setupServer(); 58 | // Inicia la creación de los roles 59 | await createRoles(); 60 | // Inicia la creación del usuario admin y user 61 | await createUsers(); 62 | } catch (err) { 63 | handleFatalError(err, "/server.js -> setupAPI"); 64 | } 65 | } 66 | 67 | // Inicia la API 68 | setupAPI() 69 | .then(() => console.log("=> API Iniciada exitosamente")) 70 | .catch((err) => handleFatalError(err, "/server.js -> setupAPI")); 71 | -------------------------------------------------------------------------------- /backend/src/controllers/auth.controller.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import { respondSuccess, respondError } from "../utils/resHandler.js"; 4 | import { handleError } from "../utils/errorHandler.js"; 5 | 6 | /** Servicios de autenticación */ 7 | import AuthService from "../services/auth.service.js"; 8 | import { authLoginBodySchema } from "../schema/auth.schema.js"; 9 | 10 | /** 11 | * Inicia sesión con un usuario. 12 | * @async 13 | * @function login 14 | * @param {Object} req - Objeto de petición 15 | * @param {Object} res - Objeto de respuesta 16 | */ 17 | async function login(req, res) { 18 | try { 19 | const { body } = req; 20 | const { error: bodyError } = authLoginBodySchema.validate(body); 21 | if (bodyError) return respondError(req, res, 400, bodyError.message); 22 | 23 | const [accessToken, refreshToken, errorToken] = 24 | await AuthService.login(body); 25 | 26 | if (errorToken) return respondError(req, res, 400, errorToken); 27 | 28 | // * Existen mas opciones de seguirdad para las cookies *// 29 | res.cookie("jwt", refreshToken, { 30 | httpOnly: true, 31 | maxAge: 7 * 24 * 60 * 60 * 1000, // 7 días 32 | }); 33 | 34 | respondSuccess(req, res, 200, { accessToken }); 35 | } catch (error) { 36 | handleError(error, "auth.controller -> login"); 37 | respondError(req, res, 400, error.message); 38 | } 39 | } 40 | 41 | /** 42 | * @name logout 43 | * @description Cierra la sesión del usuario 44 | * @param {Object} req - Objeto de petición 45 | * @param {Object} res - Objeto de respuesta 46 | * @returns 47 | */ 48 | async function logout(req, res) { 49 | try { 50 | const cookies = req.cookies; 51 | if (!cookies?.jwt) return respondError(req, res, 400, "No hay token"); 52 | res.clearCookie("jwt", { httpOnly: true }); 53 | respondSuccess(req, res, 200, { message: "Sesión cerrada correctamente" }); 54 | } catch (error) { 55 | handleError(error, "auth.controller -> logout"); 56 | respondError(req, res, 400, error.message); 57 | } 58 | } 59 | 60 | /** 61 | * @name refresh 62 | * @description Refresca el token de acceso 63 | * @param {Object} req - Objeto de petición 64 | * @param {Object} res - Objeto de respuesta 65 | */ 66 | async function refresh(req, res) { 67 | try { 68 | const cookies = req.cookies; 69 | if (!cookies?.jwt) return respondError(req, res, 400, "No hay token"); 70 | 71 | const [accessToken, errorToken] = await AuthService.refresh(cookies); 72 | 73 | if (errorToken) return respondError(req, res, 400, errorToken); 74 | 75 | respondSuccess(req, res, 200, { accessToken }); 76 | } catch (error) { 77 | handleError(error, "auth.controller -> refresh"); 78 | respondError(req, res, 400, error.message); 79 | } 80 | } 81 | 82 | export default { 83 | login, 84 | logout, 85 | refresh, 86 | }; 87 | -------------------------------------------------------------------------------- /backend/src/schema/user.schema.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import Joi from "joi"; 4 | import ROLES from "../constants/roles.constants.js"; 5 | /** 6 | * Esquema de validación para el cuerpo de la solicitud de usuario. 7 | * @constant {Object} 8 | */ 9 | const userBodySchema = Joi.object({ 10 | username: Joi.string().required().messages({ 11 | "string.empty": "El nombre de usuario no puede estar vacío.", 12 | "any.required": "El nombre de usuario es obligatorio.", 13 | "string.base": "El nombre de usuario debe ser de tipo string.", 14 | }), 15 | rut: Joi.string().required().min(9).max(10) 16 | .pattern(/^[0-9]+[-|‐]{1}[0-9kK]{1}$/).messages({ 17 | "string.empty": "El rut no puede estar vacío.", 18 | "any.required": "El rut es obligatorio.", 19 | "string.base": "El rut debe ser de tipo string.", 20 | "string.min": "El rut debe tener al menos 9 caracteres.", 21 | "string.max": "El rut debe tener al menos 10 caracteres.", 22 | "string.pattern.base": "El rut tiene el formato XXXXXXXX-X, ejemplo: 12345678-9.", 23 | }), 24 | password: Joi.string().required().min(5).messages({ 25 | "string.empty": "La contraseña no puede estar vacía.", 26 | "any.required": "La contraseña es obligatoria.", 27 | "string.base": "La contraseña debe ser de tipo string.", 28 | "string.min": "La contraseña debe tener al menos 5 caracteres.", 29 | }), 30 | email: Joi.string().email().required().messages({ 31 | "string.empty": "El email no puede estar vacío.", 32 | "any.required": "El email es obligatorio.", 33 | "string.base": "El email debe ser de tipo string.", 34 | "string.email": "El email debe tener un formato válido.", 35 | }), 36 | roles: Joi.array() 37 | .items(Joi.string().valid(...ROLES)) 38 | .required() 39 | .messages({ 40 | "array.base": "El rol debe ser de tipo array.", 41 | "any.required": "El rol es obligatorio.", 42 | "string.base": "El rol debe ser de tipo string.", 43 | "any.only": "El rol proporcionado no es válido.", 44 | }), 45 | newPassword: Joi.string().min(5).messages({ 46 | "string.empty": "La contraseña no puede estar vacía.", 47 | "string.base": "La contraseña debe ser de tipo string.", 48 | "string.min": "La contraseña debe tener al menos 5 caracteres.", 49 | }), 50 | }).messages({ 51 | "object.unknown": "No se permiten propiedades adicionales.", 52 | }); 53 | 54 | /** 55 | * Esquema de validación para el id de usuario. 56 | * @constant {Object} 57 | */ 58 | const userIdSchema = Joi.object({ 59 | id: Joi.string() 60 | .required() 61 | .pattern(/^(?:[0-9a-fA-F]{24}|[0-9a-fA-F]{12})$/) 62 | .messages({ 63 | "string.empty": "El id no puede estar vacío.", 64 | "any.required": "El id es obligatorio.", 65 | "string.base": "El id debe ser de tipo string.", 66 | "string.pattern.base": "El id proporcionado no es un ObjectId válido.", 67 | }), 68 | }); 69 | 70 | export { userBodySchema, userIdSchema }; 71 | -------------------------------------------------------------------------------- /backend/src/services/auth.service.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /** Modelo de datos 'User' */ 4 | import User from "../models/user.model.js"; 5 | /** Modulo 'jsonwebtoken' para crear tokens */ 6 | import jwt from "jsonwebtoken"; 7 | 8 | import { ACCESS_JWT_SECRET, REFRESH_JWT_SECRET } from "../config/configEnv.js"; 9 | 10 | import { handleError } from "../utils/errorHandler.js"; 11 | 12 | /** 13 | * Inicia sesión con un usuario. 14 | * @async 15 | * @function login 16 | * @param {Object} user - Objeto de usuario 17 | */ 18 | async function login(user) { 19 | try { 20 | const { email, password } = user; 21 | 22 | const userFound = await User.findOne({ email: email }) 23 | .populate("roles") 24 | .exec(); 25 | if (!userFound) { 26 | return [null, null, "El usuario y/o contraseña son incorrectos"]; 27 | } 28 | 29 | const matchPassword = await User.comparePassword( 30 | password, 31 | userFound.password, 32 | ); 33 | 34 | if (!matchPassword) { 35 | return [null, null, "El usuario y/o contraseña son incorrectos"]; 36 | } 37 | 38 | const accessToken = jwt.sign( 39 | { email: userFound.email, roles: userFound.roles }, 40 | ACCESS_JWT_SECRET, 41 | { 42 | expiresIn: "1d", 43 | }, 44 | ); 45 | 46 | const refreshToken = jwt.sign( 47 | { email: userFound.email }, 48 | REFRESH_JWT_SECRET, 49 | { 50 | expiresIn: "7d", // 7 días 51 | }, 52 | ); 53 | 54 | return [accessToken, refreshToken, null]; 55 | } catch (error) { 56 | handleError(error, "auth.service -> signIn"); 57 | } 58 | } 59 | 60 | /** 61 | * Refresca el token de acceso 62 | * @async 63 | * @function refresh 64 | * @param {Object} cookies - Objeto de cookies 65 | */ 66 | async function refresh(cookies) { 67 | try { 68 | if (!cookies.jwt) return [null, "No hay autorización"]; 69 | const refreshToken = cookies.jwt; 70 | 71 | const accessToken = await jwt.verify( 72 | refreshToken, 73 | REFRESH_JWT_SECRET, 74 | async (err, user) => { 75 | if (err) return [null, "La sesion a caducado, vuelva a iniciar sesion"]; 76 | 77 | const userFound = await User.findOne({ 78 | email: user.email, 79 | }) 80 | .populate("roles") 81 | .exec(); 82 | 83 | if (!userFound) return [null, "No usuario no autorizado"]; 84 | 85 | const accessToken = jwt.sign( 86 | { email: userFound.email, roles: userFound.roles }, 87 | ACCESS_JWT_SECRET, 88 | { 89 | expiresIn: "1d", 90 | }, 91 | ); 92 | 93 | return [accessToken, null]; 94 | }, 95 | ); 96 | 97 | return accessToken; 98 | } catch (error) { 99 | handleError(error, "auth.service -> refresh"); 100 | } 101 | } 102 | 103 | export default { login, refresh }; 104 | -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | # Project 2 | .env 3 | #Node 4 | node_modules 5 | 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | .pnpm-debug.log* 14 | 15 | # Diagnostic reports (https://nodejs.org/api/report.html) 16 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 17 | 18 | # Runtime data 19 | pids 20 | *.pid 21 | *.seed 22 | *.pid.lock 23 | 24 | # Directory for instrumented libs generated by jscoverage/JSCover 25 | lib-cov 26 | 27 | # Coverage directory used by tools like istanbul 28 | coverage 29 | *.lcov 30 | 31 | # nyc test coverage 32 | .nyc_output 33 | 34 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 35 | .grunt 36 | 37 | # Bower dependency directory (https://bower.io/) 38 | bower_components 39 | 40 | # node-waf configuration 41 | .lock-wscript 42 | 43 | # Compiled binary addons (https://nodejs.org/api/addons.html) 44 | build/Release 45 | 46 | # Dependency directories 47 | backend/node_modules/ 48 | backend/upload/ 49 | frontend/node_modules/ 50 | jspm_packages/ 51 | 52 | # Snowpack dependency directory (https://snowpack.dev/) 53 | web_modules/ 54 | 55 | # TypeScript cache 56 | *.tsbuildinfo 57 | 58 | # Optional npm cache directory 59 | .npm 60 | 61 | # Optional eslint cache 62 | .eslintcache 63 | 64 | # Optional stylelint cache 65 | .stylelintcache 66 | 67 | # Microbundle cache 68 | .rpt2_cache/ 69 | .rts2_cache_cjs/ 70 | .rts2_cache_es/ 71 | .rts2_cache_umd/ 72 | 73 | # Optional REPL history 74 | .node_repl_history 75 | 76 | # Output of 'npm pack' 77 | *.tgz 78 | 79 | # Yarn Integrity file 80 | .yarn-integrity 81 | 82 | # dotenv environment variable files 83 | backend/.env 84 | frontend/.env 85 | .env.development.local 86 | .env.test.local 87 | .env.production.local 88 | .env.local 89 | 90 | # parcel-bundler cache (https://parceljs.org/) 91 | .cache 92 | .parcel-cache 93 | 94 | # Next.js build output 95 | .next 96 | out 97 | 98 | # Nuxt.js build / generate output 99 | .nuxt 100 | dist 101 | 102 | # Gatsby files 103 | .cache/ 104 | # Comment in the public line in if your project uses Gatsby and not Next.js 105 | # https://nextjs.org/blog/next-9-1#public-directory-support 106 | # public 107 | 108 | # vuepress build output 109 | .vuepress/dist 110 | 111 | # vuepress v2.x temp and cache directory 112 | .temp 113 | 114 | # Docusaurus cache and generated files 115 | .docusaurus 116 | 117 | # Serverless directories 118 | .serverless/ 119 | 120 | # FuseBox cache 121 | .fusebox/ 122 | 123 | # DynamoDB Local files 124 | .dynamodb/ 125 | 126 | # TernJS port file 127 | .tern-port 128 | 129 | # Stores VSCode versions used for testing VSCode extensions 130 | .vscode-test 131 | 132 | # yarn v2 133 | .yarn/cache 134 | .yarn/unplugged 135 | .yarn/build-state.yml 136 | .yarn/install-state.gz 137 | .pnp.* 138 | 139 | # JetBrains 140 | .idea/ 141 | 142 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 143 | 144 | # testing 145 | frontend/coverage 146 | 147 | # next.js 148 | frontend/.next/ 149 | frontend/out/ 150 | 151 | # production 152 | frontend/build 153 | 154 | # misc 155 | frontend/.DS_Store 156 | frontend/*.pem 157 | 158 | # local env files 159 | frontend/.env*.local 160 | 161 | # vercel 162 | frontend/.vercel 163 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Project 2 | .env 3 | #Node 4 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 5 | 6 | # dependencies 7 | /node_modules 8 | /.pnp 9 | .pnp.js 10 | 11 | # testing 12 | /coverage 13 | 14 | # next.js 15 | /.next/ 16 | /out/ 17 | 18 | # production 19 | /build 20 | 21 | # misc 22 | .DS_Store 23 | *.pem 24 | 25 | # debug 26 | npm-debug.log* 27 | yarn-debug.log* 28 | yarn-error.log* 29 | 30 | # local env files 31 | .env*.local 32 | 33 | # vercel 34 | .vercel 35 | 36 | # typescript 37 | *.tsbuildinfo 38 | next-env.d.ts 39 | 40 | 41 | # Logs 42 | logs 43 | *.log 44 | lerna-debug.log* 45 | .pnpm-debug.log* 46 | 47 | # Diagnostic reports (https://nodejs.org/api/report.html) 48 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 49 | 50 | # Runtime data 51 | pids 52 | *.pid 53 | *.seed 54 | *.pid.lock 55 | 56 | # Directory for instrumented libs generated by jscoverage/JSCover 57 | lib-cov 58 | 59 | # Coverage directory used by tools like istanbul 60 | coverage 61 | *.lcov 62 | 63 | # nyc test coverage 64 | .nyc_output 65 | 66 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 67 | .grunt 68 | 69 | # Bower dependency directory (https://bower.io/) 70 | bower_components 71 | 72 | # node-waf configuration 73 | .lock-wscript 74 | 75 | # Compiled binary addons (https://nodejs.org/api/addons.html) 76 | build/Release 77 | 78 | # Dependency directories 79 | backend/node_modules/ 80 | backend/upload/ 81 | frontend/node_modules/ 82 | jspm_packages/ 83 | 84 | # Snowpack dependency directory (https://snowpack.dev/) 85 | web_modules/ 86 | 87 | 88 | # Optional npm cache directory 89 | .npm 90 | 91 | # Optional eslint cache 92 | .eslintcache 93 | 94 | # Optional stylelint cache 95 | .stylelintcache 96 | 97 | # Microbundle cache 98 | .rpt2_cache/ 99 | .rts2_cache_cjs/ 100 | .rts2_cache_es/ 101 | .rts2_cache_umd/ 102 | 103 | # Optional REPL history 104 | .node_repl_history 105 | 106 | # Output of 'npm pack' 107 | *.tgz 108 | 109 | # Yarn Integrity file 110 | .yarn-integrity 111 | 112 | # dotenv environment variable files 113 | backend/.env 114 | frontend/.env.local 115 | .env.development.local 116 | .env.test.local 117 | .env.production.local 118 | .env.local 119 | 120 | # parcel-bundler cache (https://parceljs.org/) 121 | .cache 122 | .parcel-cache 123 | 124 | # Next.js build output 125 | .next 126 | out 127 | 128 | # Nuxt.js build / generate output 129 | .nuxt 130 | dist 131 | 132 | # Gatsby files 133 | .cache/ 134 | # Comment in the public line in if your project uses Gatsby and not Next.js 135 | # https://nextjs.org/blog/next-9-1#public-directory-support 136 | # public 137 | 138 | # vuepress build output 139 | .vuepress/dist 140 | 141 | # vuepress v2.x temp and cache directory 142 | .temp 143 | 144 | # Docusaurus cache and generated files 145 | .docusaurus 146 | 147 | # Serverless directories 148 | .serverless/ 149 | 150 | # FuseBox cache 151 | .fusebox/ 152 | 153 | # DynamoDB Local files 154 | .dynamodb/ 155 | 156 | # TernJS port file 157 | .tern-port 158 | 159 | # Stores VSCode versions used for testing VSCode extensions 160 | .vscode-test 161 | 162 | # yarn v2 163 | .yarn/cache 164 | .yarn/unplugged 165 | .yarn/build-state.yml 166 | .yarn/install-state.gz 167 | .pnp.* 168 | 169 | # JetBrains 170 | .idea/ 171 | .idea 172 | 173 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 174 | 175 | # testing 176 | frontend/coverage 177 | 178 | # next.js 179 | frontend/.next/ 180 | frontend/out/ 181 | 182 | # production 183 | frontend/build 184 | 185 | # misc 186 | frontend/.DS_Store 187 | frontend/*.pem 188 | 189 | # local env files 190 | frontend/.env*.local 191 | 192 | # vercel 193 | frontend/.vercel 194 | -------------------------------------------------------------------------------- /frontend/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/src/services/user.service.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Importa el modelo de datos 'User' 3 | import User from "../models/user.model.js"; 4 | import Role from "../models/role.model.js"; 5 | import { handleError } from "../utils/errorHandler.js"; 6 | 7 | /** 8 | * Obtiene todos los usuarios de la base de datos 9 | * @returns {Promise} Promesa con el objeto de los usuarios 10 | */ 11 | async function getUsers() { 12 | try { 13 | const users = await User.find() 14 | .select("-password") 15 | .populate("roles") 16 | .exec(); 17 | if (!users) return [null, "No hay usuarios"]; 18 | 19 | return [users, null]; 20 | } catch (error) { 21 | handleError(error, "user.service -> getUsers"); 22 | } 23 | } 24 | 25 | /** 26 | * Crea un nuevo usuario en la base de datos 27 | * @param {Object} user Objeto de usuario 28 | * @returns {Promise} Promesa con el objeto de usuario creado 29 | */ 30 | async function createUser(user) { 31 | try { 32 | const { username, rut, email, password, roles } = user; 33 | 34 | const userFound = await User.findOne({ email: user.email }); 35 | if (userFound) return [null, "El usuario ya existe"]; 36 | 37 | const rolesFound = await Role.find({ name: { $in: roles } }); 38 | if (rolesFound.length === 0) return [null, "El rol no existe"]; 39 | const myRole = rolesFound.map((role) => role._id); 40 | 41 | const newUser = new User({ 42 | username, 43 | rut, 44 | email, 45 | password: await User.encryptPassword(password), 46 | roles: myRole, 47 | }); 48 | await newUser.save(); 49 | 50 | return [newUser, null]; 51 | } catch (error) { 52 | handleError(error, "user.service -> createUser"); 53 | } 54 | } 55 | 56 | /** 57 | * Obtiene un usuario por su id de la base de datos 58 | * @param {string} Id del usuario 59 | * @returns {Promise} Promesa con el objeto de usuario 60 | */ 61 | async function getUserById(id) { 62 | try { 63 | const user = await User.findById({ _id: id }) 64 | .select("-password") 65 | .populate("roles") 66 | .exec(); 67 | 68 | if (!user) return [null, "El usuario no existe"]; 69 | 70 | return [user, null]; 71 | } catch (error) { 72 | handleError(error, "user.service -> getUserById"); 73 | } 74 | } 75 | 76 | /** 77 | * Actualiza un usuario por su id en la base de datos 78 | * @param {string} id Id del usuario 79 | * @param {Object} user Objeto de usuario 80 | * @returns {Promise} Promesa con el objeto de usuario actualizado 81 | */ 82 | async function updateUser(id, user) { 83 | try { 84 | const userFound = await User.findById(id); 85 | if (!userFound) return [null, "El usuario no existe"]; 86 | 87 | const { username, email, rut, password, newPassword, roles } = user; 88 | 89 | const matchPassword = await User.comparePassword( 90 | password, 91 | userFound.password, 92 | ); 93 | 94 | if (!matchPassword) { 95 | return [null, "La contraseña no coincide"]; 96 | } 97 | 98 | const rolesFound = await Role.find({ name: { $in: roles } }); 99 | if (rolesFound.length === 0) return [null, "El rol no existe"]; 100 | 101 | const myRole = rolesFound.map((role) => role._id); 102 | 103 | const userUpdated = await User.findByIdAndUpdate( 104 | id, 105 | { 106 | username, 107 | email, 108 | rut, 109 | password: await User.encryptPassword(newPassword || password), 110 | roles: myRole, 111 | }, 112 | { new: true }, 113 | ); 114 | 115 | return [userUpdated, null]; 116 | } catch (error) { 117 | handleError(error, "user.service -> updateUser"); 118 | } 119 | } 120 | 121 | /** 122 | * Elimina un usuario por su id de la base de datos 123 | * @param {string} Id del usuario 124 | * @returns {Promise} Promesa con el objeto de usuario eliminado 125 | */ 126 | async function deleteUser(id) { 127 | try { 128 | return await User.findByIdAndDelete(id); 129 | } catch (error) { 130 | handleError(error, "user.service -> deleteUser"); 131 | } 132 | } 133 | 134 | export default { 135 | getUsers, 136 | createUser, 137 | getUserById, 138 | updateUser, 139 | deleteUser, 140 | }; 141 | -------------------------------------------------------------------------------- /backend/README.md: -------------------------------------------------------------------------------- 1 | ## Backend Template para proyecto ingeniería de software 2 | 3 | ### Instrucciones de instalacion 4 | 5 | - Clonar el repositorio 6 | - Instalar dependencias con `npm install` 7 | - Crear archivo `.env` con las variables de entorno, en la carpeta `/config` 8 | - Sigue la estructura del archivo `.env.example` 9 | - Agrega la variable `PORT` con el puerto en el que quieres que corra el servidor 10 | - Agrega la variable `HOST` con la URL del servidor 11 | - Agrega la variable `DB_URL` con la URI de la base de datos 12 | - Agrega la variable `ACCESS_JWT_SECRET` con la clave secreta para crear los tokens de autenticacion 13 | - Agrega la variable `REFRESH_JWT_SECRET` con la clave secreta para crear los tokens de refresco 14 | - Correr el servidor con `npm start` o `npm run dev`. 15 | 16 | ### Estructura de carpetas 17 | 18 | ```bash 19 | 20 | ├── NombreProyecto 21 | │ ├── node_modules 22 | │ ├── src 23 | │ │ ├── config 24 | │ │ │ ├── .env.example 25 | │ │ │ ├── initialSetup.js 26 | │ │ │ ├── configDB.js 27 | │ │ │ └── configEnv.js 28 | │ │ ├── constants 29 | │ │ │ ├── roles.constants.js 30 | │ │ ├── controllers 31 | │ │ │ ├── auth.controller.js 32 | │ │ │ └── user.controller.js 33 | │ │ ├── middlewares 34 | │ │ │ ├── authentication.middleware.js 35 | │ │ │ └── authorization.middleware.js 36 | │ │ ├── models 37 | │ │ │ ├── auth.model.js 38 | │ │ │ └── user.model.js 39 | │ │ ├── routes 40 | │ │ │ ├── auth.route.js 41 | │ │ │ ├── user.route.js 42 | │ │ │ └── index.routes.js 43 | │ │ ├── services 44 | │ │ │ ├── auth.service.js 45 | │ │ │ └── user.service.js 46 | │ │ ├── schemas 47 | │ │ │ ├── user.schema.js 48 | │ │ │ └── auth.schema.js 49 | │ │ ├── utils 50 | │ │ │ ├── resHandler.js 51 | │ │ │ └── errorHandler.js 52 | │ │ └── server.js 53 | │ ├── .eslintrc.json 54 | │ ├── .prettierrc.json 55 | │ ├── .gitignore 56 | └── └── package.json 57 | ``` 58 | 59 | ## Arquitectura de la API 60 | 61 | ![img.png](ArquitecturaAPI.png) 62 | 63 | ## Instrucciones de uso 64 | 65 | - Una vez instaladas las dependencias y configuradas las variables de entorno, puedes correr el servidor con `npm start` 66 | - Recuerda que **debes utilizar** Postman o Insomnia para hacer las peticiones a la API 67 | - De manera automatica se creara un usuario administrador y user, con los siguientes datos: 68 | - **Administrador** 69 | - `email: admin@email.com` 70 | - `password: admin123` 71 | - **User** 72 | - `email: user@email.com` 73 | - `password: user123` 74 | - Tambien, de manera automatica se crean dos roles principales en la base de datos: 75 | - `admin` 76 | - `user` 77 | - Se debe **autenticar con el usuario admin** para poder usar el endpoint de usuarios ( Pueden modificar esto en el archivo de rutas ) 78 | - Para la autenticacion, se debe enviar un objeto JSON con el email y constraseña al endpoint `/api/auth/login` 79 | - Ejemplo: 80 | ```json 81 | { 82 | "email": "admin@email.com", 83 | "password": "admin123" 84 | } 85 | ``` 86 | - Devuelve un token que se **debe enviar en el header** de las peticiones que requieran autenticacion, con el nombre `Authorization` y el valor `Bearer ` 87 | - El token tiene una duracion de 24 horas, despues de ese tiempo, se puede refrescar el token con el endpoint `/api/auth/refresh` 88 | - El token de refresco, tiene una duracion de 7 dias, despues de ese tiempo, se debe volver a autenticar 89 | 90 | ## Consideraciones 91 | 92 | - El manejo de tokens, esta simplificado para hacerlo mas facil de entender 93 | - La abstracion de la autenticacion, se completará con el frontend 94 | 95 | ## Librerias utilizadas 96 | 97 | - [Node](https://nodejs.org/es/): Entorno de ejecucion de JS 98 | - [Express](https://expressjs.com/es/): Framework para crear servidores web 99 | - [Mongoose](https://mongoosejs.com/): Libreria para conectar a MongoDB 100 | - [JsonWebToken](https://www.npmjs.com/package/jsonwebtoken): Libreria para crear tokens de autenticacion 101 | - [Dotenv](https://www.npmjs.com/package/dotenv): Libreria para manejar variables de entorno 102 | - [Cors](https://www.npmjs.com/package/cors): Libreria para manejar el CORS 103 | - [Joi](https://www.npmjs.com/package/joi): Libreria para manejar validaciones 104 | - [Morgan](https://www.npmjs.com/package/morgan): Libreria para manejar logs 105 | 106 | [Volver al inicio](../README.md) 107 | 108 | -------------------------------------------------------------------------------- /backend/src/controllers/user.controller.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import { respondSuccess, respondError } from "../utils/resHandler.js"; 4 | import UserService from "../services/user.service.js"; 5 | import { userBodySchema, userIdSchema } from "../schema/user.schema.js"; 6 | import { handleError } from "../utils/errorHandler.js"; 7 | 8 | /** 9 | * Obtiene todos los usuarios 10 | * @param {Object} req - Objeto de petición 11 | * @param {Object} res - Objeto de respuesta 12 | */ 13 | async function getUsers(req, res) { 14 | try { 15 | const [usuarios, errorUsuarios] = await UserService.getUsers(); 16 | if (errorUsuarios) return respondError(req, res, 404, errorUsuarios); 17 | 18 | usuarios.length === 0 19 | ? respondSuccess(req, res, 204) 20 | : respondSuccess(req, res, 200, usuarios); 21 | } catch (error) { 22 | handleError(error, "user.controller -> getUsers"); 23 | respondError(req, res, 400, error.message); 24 | } 25 | } 26 | 27 | /** 28 | * Crea un nuevo usuario 29 | * @param {Object} req - Objeto de petición 30 | * @param {Object} res - Objeto de respuesta 31 | */ 32 | async function createUser(req, res) { 33 | try { 34 | const { body } = req; 35 | const { error: bodyError } = userBodySchema.validate(body); 36 | if (bodyError) return respondError(req, res, 400, bodyError.message); 37 | 38 | const [newUser, userError] = await UserService.createUser(body); 39 | 40 | if (userError) return respondError(req, res, 400, userError); 41 | if (!newUser) { 42 | return respondError(req, res, 400, "No se creo el usuario"); 43 | } 44 | 45 | respondSuccess(req, res, 201, newUser); 46 | } catch (error) { 47 | handleError(error, "user.controller -> createUser"); 48 | respondError(req, res, 500, "No se creo el usuario"); 49 | } 50 | } 51 | 52 | /** 53 | * Obtiene un usuario por su id 54 | * @param {Object} req - Objeto de petición 55 | * @param {Object} res - Objeto de respuesta 56 | */ 57 | async function getUserById(req, res) { 58 | try { 59 | const { params } = req; 60 | const { error: paramsError } = userIdSchema.validate(params); 61 | if (paramsError) return respondError(req, res, 400, paramsError.message); 62 | 63 | const [user, errorUser] = await UserService.getUserById(params.id); 64 | 65 | if (errorUser) return respondError(req, res, 404, errorUser); 66 | 67 | respondSuccess(req, res, 200, user); 68 | } catch (error) { 69 | handleError(error, "user.controller -> getUserById"); 70 | respondError(req, res, 500, "No se pudo obtener el usuario"); 71 | } 72 | } 73 | 74 | /** 75 | * Actualiza un usuario por su id 76 | * @param {Object} req - Objeto de petición 77 | * @param {Object} res - Objeto de respuesta 78 | */ 79 | async function updateUser(req, res) { 80 | try { 81 | const { params, body } = req; 82 | const { error: paramsError } = userIdSchema.validate(params); 83 | if (paramsError) return respondError(req, res, 400, paramsError.message); 84 | 85 | const { error: bodyError } = userBodySchema.validate(body); 86 | if (bodyError) return respondError(req, res, 400, bodyError.message); 87 | 88 | const [user, userError] = await UserService.updateUser(params.id, body); 89 | 90 | if (userError) return respondError(req, res, 400, userError); 91 | 92 | respondSuccess(req, res, 200, user); 93 | } catch (error) { 94 | handleError(error, "user.controller -> updateUser"); 95 | respondError(req, res, 500, "No se pudo actualizar el usuario"); 96 | } 97 | } 98 | 99 | /** 100 | * Elimina un usuario por su id 101 | * @param {Object} req - Objeto de petición 102 | * @param {Object} res - Objeto de respuesta 103 | */ 104 | async function deleteUser(req, res) { 105 | try { 106 | const { params } = req; 107 | const { error: paramsError } = userIdSchema.validate(params); 108 | if (paramsError) return respondError(req, res, 400, paramsError.message); 109 | 110 | const user = await UserService.deleteUser(params.id); 111 | !user 112 | ? respondError( 113 | req, 114 | res, 115 | 404, 116 | "No se encontro el usuario solicitado", 117 | "Verifique el id ingresado", 118 | ) 119 | : respondSuccess(req, res, 200, user); 120 | } catch (error) { 121 | handleError(error, "user.controller -> deleteUser"); 122 | respondError(req, res, 500, "No se pudo eliminar el usuario"); 123 | } 124 | } 125 | 126 | export default { 127 | getUsers, 128 | createUser, 129 | getUserById, 130 | updateUser, 131 | deleteUser, 132 | }; 133 | -------------------------------------------------------------------------------- /backend/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api-node", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "api-node", 9 | "version": "1.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "bcryptjs": "2.4.3", 13 | "cookie-parser": "1.4.6", 14 | "cors": "2.8.5", 15 | "dotenv": "^16.4.4", 16 | "express": "4.18.2", 17 | "joi": "17.10.2", 18 | "jsonwebtoken": "9.0.2", 19 | "mongoose": "^8.1.0", 20 | "morgan": "1.10.0" 21 | }, 22 | "devDependencies": { 23 | "eslint": "^8.56.0", 24 | "eslint-config-google": "0.14.0", 25 | "jsdoc": "4.0.2", 26 | "nodemon": "^3.0.3", 27 | "prettier": "^3.2.5" 28 | } 29 | }, 30 | "node_modules/@aashutoshrathi/word-wrap": { 31 | "version": "1.2.6", 32 | "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", 33 | "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", 34 | "dev": true, 35 | "engines": { 36 | "node": ">=0.10.0" 37 | } 38 | }, 39 | "node_modules/@babel/parser": { 40 | "version": "7.22.16", 41 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", 42 | "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==", 43 | "dev": true, 44 | "bin": { 45 | "parser": "bin/babel-parser.js" 46 | }, 47 | "engines": { 48 | "node": ">=6.0.0" 49 | } 50 | }, 51 | "node_modules/@eslint-community/eslint-utils": { 52 | "version": "4.4.0", 53 | "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", 54 | "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", 55 | "dev": true, 56 | "dependencies": { 57 | "eslint-visitor-keys": "^3.3.0" 58 | }, 59 | "engines": { 60 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 61 | }, 62 | "peerDependencies": { 63 | "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" 64 | } 65 | }, 66 | "node_modules/@eslint-community/regexpp": { 67 | "version": "4.8.1", 68 | "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.1.tgz", 69 | "integrity": "sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==", 70 | "dev": true, 71 | "engines": { 72 | "node": "^12.0.0 || ^14.0.0 || >=16.0.0" 73 | } 74 | }, 75 | "node_modules/@eslint/eslintrc": { 76 | "version": "2.1.4", 77 | "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", 78 | "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", 79 | "dev": true, 80 | "dependencies": { 81 | "ajv": "^6.12.4", 82 | "debug": "^4.3.2", 83 | "espree": "^9.6.0", 84 | "globals": "^13.19.0", 85 | "ignore": "^5.2.0", 86 | "import-fresh": "^3.2.1", 87 | "js-yaml": "^4.1.0", 88 | "minimatch": "^3.1.2", 89 | "strip-json-comments": "^3.1.1" 90 | }, 91 | "engines": { 92 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 93 | }, 94 | "funding": { 95 | "url": "https://opencollective.com/eslint" 96 | } 97 | }, 98 | "node_modules/@eslint/eslintrc/node_modules/debug": { 99 | "version": "4.3.4", 100 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 101 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 102 | "dev": true, 103 | "dependencies": { 104 | "ms": "2.1.2" 105 | }, 106 | "engines": { 107 | "node": ">=6.0" 108 | }, 109 | "peerDependenciesMeta": { 110 | "supports-color": { 111 | "optional": true 112 | } 113 | } 114 | }, 115 | "node_modules/@eslint/eslintrc/node_modules/ms": { 116 | "version": "2.1.2", 117 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 118 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 119 | "dev": true 120 | }, 121 | "node_modules/@eslint/js": { 122 | "version": "8.56.0", 123 | "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", 124 | "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", 125 | "dev": true, 126 | "engines": { 127 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 128 | } 129 | }, 130 | "node_modules/@hapi/hoek": { 131 | "version": "9.3.0", 132 | "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", 133 | "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" 134 | }, 135 | "node_modules/@hapi/topo": { 136 | "version": "5.1.0", 137 | "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", 138 | "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", 139 | "dependencies": { 140 | "@hapi/hoek": "^9.0.0" 141 | } 142 | }, 143 | "node_modules/@humanwhocodes/config-array": { 144 | "version": "0.11.14", 145 | "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", 146 | "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", 147 | "dev": true, 148 | "dependencies": { 149 | "@humanwhocodes/object-schema": "^2.0.2", 150 | "debug": "^4.3.1", 151 | "minimatch": "^3.0.5" 152 | }, 153 | "engines": { 154 | "node": ">=10.10.0" 155 | } 156 | }, 157 | "node_modules/@humanwhocodes/config-array/node_modules/debug": { 158 | "version": "4.3.4", 159 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 160 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 161 | "dev": true, 162 | "dependencies": { 163 | "ms": "2.1.2" 164 | }, 165 | "engines": { 166 | "node": ">=6.0" 167 | }, 168 | "peerDependenciesMeta": { 169 | "supports-color": { 170 | "optional": true 171 | } 172 | } 173 | }, 174 | "node_modules/@humanwhocodes/config-array/node_modules/ms": { 175 | "version": "2.1.2", 176 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 177 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 178 | "dev": true 179 | }, 180 | "node_modules/@humanwhocodes/module-importer": { 181 | "version": "1.0.1", 182 | "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", 183 | "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", 184 | "dev": true, 185 | "engines": { 186 | "node": ">=12.22" 187 | }, 188 | "funding": { 189 | "type": "github", 190 | "url": "https://github.com/sponsors/nzakas" 191 | } 192 | }, 193 | "node_modules/@humanwhocodes/object-schema": { 194 | "version": "2.0.3", 195 | "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", 196 | "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", 197 | "dev": true 198 | }, 199 | "node_modules/@jsdoc/salty": { 200 | "version": "0.2.5", 201 | "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.5.tgz", 202 | "integrity": "sha512-TfRP53RqunNe2HBobVBJ0VLhK1HbfvBYeTC1ahnN64PWvyYyGebmMiPkuwvD9fpw2ZbkoPb8Q7mwy0aR8Z9rvw==", 203 | "dev": true, 204 | "dependencies": { 205 | "lodash": "^4.17.21" 206 | }, 207 | "engines": { 208 | "node": ">=v12.0.0" 209 | } 210 | }, 211 | "node_modules/@mongodb-js/saslprep": { 212 | "version": "1.1.5", 213 | "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.5.tgz", 214 | "integrity": "sha512-XLNOMH66KhJzUJNwT/qlMnS4WsNDWD5ASdyaSH3EtK+F4r/CFGa3jT4GNi4mfOitGvWXtdLgQJkQjxSVrio+jA==", 215 | "dependencies": { 216 | "sparse-bitfield": "^3.0.3" 217 | } 218 | }, 219 | "node_modules/@nodelib/fs.scandir": { 220 | "version": "2.1.5", 221 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 222 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 223 | "dev": true, 224 | "dependencies": { 225 | "@nodelib/fs.stat": "2.0.5", 226 | "run-parallel": "^1.1.9" 227 | }, 228 | "engines": { 229 | "node": ">= 8" 230 | } 231 | }, 232 | "node_modules/@nodelib/fs.stat": { 233 | "version": "2.0.5", 234 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 235 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 236 | "dev": true, 237 | "engines": { 238 | "node": ">= 8" 239 | } 240 | }, 241 | "node_modules/@nodelib/fs.walk": { 242 | "version": "1.2.8", 243 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 244 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 245 | "dev": true, 246 | "dependencies": { 247 | "@nodelib/fs.scandir": "2.1.5", 248 | "fastq": "^1.6.0" 249 | }, 250 | "engines": { 251 | "node": ">= 8" 252 | } 253 | }, 254 | "node_modules/@sideway/address": { 255 | "version": "4.1.4", 256 | "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", 257 | "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", 258 | "dependencies": { 259 | "@hapi/hoek": "^9.0.0" 260 | } 261 | }, 262 | "node_modules/@sideway/formula": { 263 | "version": "3.0.1", 264 | "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", 265 | "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" 266 | }, 267 | "node_modules/@sideway/pinpoint": { 268 | "version": "2.0.0", 269 | "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", 270 | "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" 271 | }, 272 | "node_modules/@types/linkify-it": { 273 | "version": "3.0.3", 274 | "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.3.tgz", 275 | "integrity": "sha512-pTjcqY9E4nOI55Wgpz7eiI8+LzdYnw3qxXCfHyBDdPbYvbyLgWLJGh8EdPvqawwMK1Uo1794AUkkR38Fr0g+2g==", 276 | "dev": true 277 | }, 278 | "node_modules/@types/markdown-it": { 279 | "version": "12.2.3", 280 | "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", 281 | "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", 282 | "dev": true, 283 | "dependencies": { 284 | "@types/linkify-it": "*", 285 | "@types/mdurl": "*" 286 | } 287 | }, 288 | "node_modules/@types/mdurl": { 289 | "version": "1.0.2", 290 | "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", 291 | "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", 292 | "dev": true 293 | }, 294 | "node_modules/@types/webidl-conversions": { 295 | "version": "7.0.3", 296 | "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", 297 | "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" 298 | }, 299 | "node_modules/@types/whatwg-url": { 300 | "version": "11.0.4", 301 | "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.4.tgz", 302 | "integrity": "sha512-lXCmTWSHJvf0TRSO58nm978b8HJ/EdsSsEKLd3ODHFjo+3VGAyyTp4v50nWvwtzBxSMQrVOK7tcuN0zGPLICMw==", 303 | "dependencies": { 304 | "@types/webidl-conversions": "*" 305 | } 306 | }, 307 | "node_modules/@ungap/structured-clone": { 308 | "version": "1.2.0", 309 | "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", 310 | "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", 311 | "dev": true 312 | }, 313 | "node_modules/abbrev": { 314 | "version": "1.1.1", 315 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 316 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", 317 | "dev": true 318 | }, 319 | "node_modules/accepts": { 320 | "version": "1.3.8", 321 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 322 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 323 | "dependencies": { 324 | "mime-types": "~2.1.34", 325 | "negotiator": "0.6.3" 326 | }, 327 | "engines": { 328 | "node": ">= 0.6" 329 | } 330 | }, 331 | "node_modules/acorn": { 332 | "version": "8.11.3", 333 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", 334 | "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", 335 | "dev": true, 336 | "bin": { 337 | "acorn": "bin/acorn" 338 | }, 339 | "engines": { 340 | "node": ">=0.4.0" 341 | } 342 | }, 343 | "node_modules/acorn-jsx": { 344 | "version": "5.3.2", 345 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", 346 | "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", 347 | "dev": true, 348 | "peerDependencies": { 349 | "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" 350 | } 351 | }, 352 | "node_modules/ajv": { 353 | "version": "6.12.6", 354 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 355 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 356 | "dev": true, 357 | "dependencies": { 358 | "fast-deep-equal": "^3.1.1", 359 | "fast-json-stable-stringify": "^2.0.0", 360 | "json-schema-traverse": "^0.4.1", 361 | "uri-js": "^4.2.2" 362 | }, 363 | "funding": { 364 | "type": "github", 365 | "url": "https://github.com/sponsors/epoberezkin" 366 | } 367 | }, 368 | "node_modules/ansi-regex": { 369 | "version": "5.0.1", 370 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 371 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 372 | "dev": true, 373 | "engines": { 374 | "node": ">=8" 375 | } 376 | }, 377 | "node_modules/ansi-styles": { 378 | "version": "4.3.0", 379 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 380 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 381 | "dev": true, 382 | "dependencies": { 383 | "color-convert": "^2.0.1" 384 | }, 385 | "engines": { 386 | "node": ">=8" 387 | }, 388 | "funding": { 389 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 390 | } 391 | }, 392 | "node_modules/anymatch": { 393 | "version": "3.1.3", 394 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 395 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 396 | "dev": true, 397 | "dependencies": { 398 | "normalize-path": "^3.0.0", 399 | "picomatch": "^2.0.4" 400 | }, 401 | "engines": { 402 | "node": ">= 8" 403 | } 404 | }, 405 | "node_modules/argparse": { 406 | "version": "2.0.1", 407 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 408 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 409 | "dev": true 410 | }, 411 | "node_modules/array-flatten": { 412 | "version": "1.1.1", 413 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 414 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 415 | }, 416 | "node_modules/balanced-match": { 417 | "version": "1.0.2", 418 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 419 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 420 | "dev": true 421 | }, 422 | "node_modules/basic-auth": { 423 | "version": "2.0.1", 424 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", 425 | "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", 426 | "dependencies": { 427 | "safe-buffer": "5.1.2" 428 | }, 429 | "engines": { 430 | "node": ">= 0.8" 431 | } 432 | }, 433 | "node_modules/basic-auth/node_modules/safe-buffer": { 434 | "version": "5.1.2", 435 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 436 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 437 | }, 438 | "node_modules/bcryptjs": { 439 | "version": "2.4.3", 440 | "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", 441 | "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" 442 | }, 443 | "node_modules/binary-extensions": { 444 | "version": "2.2.0", 445 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 446 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 447 | "dev": true, 448 | "engines": { 449 | "node": ">=8" 450 | } 451 | }, 452 | "node_modules/bluebird": { 453 | "version": "3.7.2", 454 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", 455 | "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", 456 | "dev": true 457 | }, 458 | "node_modules/body-parser": { 459 | "version": "1.20.1", 460 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", 461 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", 462 | "dependencies": { 463 | "bytes": "3.1.2", 464 | "content-type": "~1.0.4", 465 | "debug": "2.6.9", 466 | "depd": "2.0.0", 467 | "destroy": "1.2.0", 468 | "http-errors": "2.0.0", 469 | "iconv-lite": "0.4.24", 470 | "on-finished": "2.4.1", 471 | "qs": "6.11.0", 472 | "raw-body": "2.5.1", 473 | "type-is": "~1.6.18", 474 | "unpipe": "1.0.0" 475 | }, 476 | "engines": { 477 | "node": ">= 0.8", 478 | "npm": "1.2.8000 || >= 1.4.16" 479 | } 480 | }, 481 | "node_modules/brace-expansion": { 482 | "version": "1.1.11", 483 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 484 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 485 | "dev": true, 486 | "dependencies": { 487 | "balanced-match": "^1.0.0", 488 | "concat-map": "0.0.1" 489 | } 490 | }, 491 | "node_modules/braces": { 492 | "version": "3.0.2", 493 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 494 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 495 | "dev": true, 496 | "dependencies": { 497 | "fill-range": "^7.0.1" 498 | }, 499 | "engines": { 500 | "node": ">=8" 501 | } 502 | }, 503 | "node_modules/bson": { 504 | "version": "6.6.0", 505 | "resolved": "https://registry.npmjs.org/bson/-/bson-6.6.0.tgz", 506 | "integrity": "sha512-BVINv2SgcMjL4oYbBuCQTpE3/VKOSxrOA8Cj/wQP7izSzlBGVomdm+TcUd0Pzy0ytLSSDweCKQ6X3f5veM5LQA==", 507 | "engines": { 508 | "node": ">=16.20.1" 509 | } 510 | }, 511 | "node_modules/buffer-equal-constant-time": { 512 | "version": "1.0.1", 513 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", 514 | "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" 515 | }, 516 | "node_modules/bytes": { 517 | "version": "3.1.2", 518 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 519 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 520 | "engines": { 521 | "node": ">= 0.8" 522 | } 523 | }, 524 | "node_modules/call-bind": { 525 | "version": "1.0.2", 526 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 527 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 528 | "dependencies": { 529 | "function-bind": "^1.1.1", 530 | "get-intrinsic": "^1.0.2" 531 | }, 532 | "funding": { 533 | "url": "https://github.com/sponsors/ljharb" 534 | } 535 | }, 536 | "node_modules/callsites": { 537 | "version": "3.1.0", 538 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 539 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 540 | "dev": true, 541 | "engines": { 542 | "node": ">=6" 543 | } 544 | }, 545 | "node_modules/catharsis": { 546 | "version": "0.9.0", 547 | "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", 548 | "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", 549 | "dev": true, 550 | "dependencies": { 551 | "lodash": "^4.17.15" 552 | }, 553 | "engines": { 554 | "node": ">= 10" 555 | } 556 | }, 557 | "node_modules/chalk": { 558 | "version": "4.1.2", 559 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 560 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 561 | "dev": true, 562 | "dependencies": { 563 | "ansi-styles": "^4.1.0", 564 | "supports-color": "^7.1.0" 565 | }, 566 | "engines": { 567 | "node": ">=10" 568 | }, 569 | "funding": { 570 | "url": "https://github.com/chalk/chalk?sponsor=1" 571 | } 572 | }, 573 | "node_modules/chokidar": { 574 | "version": "3.5.3", 575 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 576 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 577 | "dev": true, 578 | "funding": [ 579 | { 580 | "type": "individual", 581 | "url": "https://paulmillr.com/funding/" 582 | } 583 | ], 584 | "dependencies": { 585 | "anymatch": "~3.1.2", 586 | "braces": "~3.0.2", 587 | "glob-parent": "~5.1.2", 588 | "is-binary-path": "~2.1.0", 589 | "is-glob": "~4.0.1", 590 | "normalize-path": "~3.0.0", 591 | "readdirp": "~3.6.0" 592 | }, 593 | "engines": { 594 | "node": ">= 8.10.0" 595 | }, 596 | "optionalDependencies": { 597 | "fsevents": "~2.3.2" 598 | } 599 | }, 600 | "node_modules/chokidar/node_modules/glob-parent": { 601 | "version": "5.1.2", 602 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 603 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 604 | "dev": true, 605 | "dependencies": { 606 | "is-glob": "^4.0.1" 607 | }, 608 | "engines": { 609 | "node": ">= 6" 610 | } 611 | }, 612 | "node_modules/color-convert": { 613 | "version": "2.0.1", 614 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 615 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 616 | "dev": true, 617 | "dependencies": { 618 | "color-name": "~1.1.4" 619 | }, 620 | "engines": { 621 | "node": ">=7.0.0" 622 | } 623 | }, 624 | "node_modules/color-name": { 625 | "version": "1.1.4", 626 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 627 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 628 | "dev": true 629 | }, 630 | "node_modules/concat-map": { 631 | "version": "0.0.1", 632 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 633 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 634 | "dev": true 635 | }, 636 | "node_modules/content-disposition": { 637 | "version": "0.5.4", 638 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 639 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 640 | "dependencies": { 641 | "safe-buffer": "5.2.1" 642 | }, 643 | "engines": { 644 | "node": ">= 0.6" 645 | } 646 | }, 647 | "node_modules/content-type": { 648 | "version": "1.0.5", 649 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 650 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", 651 | "engines": { 652 | "node": ">= 0.6" 653 | } 654 | }, 655 | "node_modules/cookie": { 656 | "version": "0.4.1", 657 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", 658 | "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", 659 | "engines": { 660 | "node": ">= 0.6" 661 | } 662 | }, 663 | "node_modules/cookie-parser": { 664 | "version": "1.4.6", 665 | "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", 666 | "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", 667 | "dependencies": { 668 | "cookie": "0.4.1", 669 | "cookie-signature": "1.0.6" 670 | }, 671 | "engines": { 672 | "node": ">= 0.8.0" 673 | } 674 | }, 675 | "node_modules/cookie-signature": { 676 | "version": "1.0.6", 677 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 678 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 679 | }, 680 | "node_modules/cors": { 681 | "version": "2.8.5", 682 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", 683 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", 684 | "dependencies": { 685 | "object-assign": "^4", 686 | "vary": "^1" 687 | }, 688 | "engines": { 689 | "node": ">= 0.10" 690 | } 691 | }, 692 | "node_modules/cross-spawn": { 693 | "version": "7.0.3", 694 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 695 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 696 | "dev": true, 697 | "dependencies": { 698 | "path-key": "^3.1.0", 699 | "shebang-command": "^2.0.0", 700 | "which": "^2.0.1" 701 | }, 702 | "engines": { 703 | "node": ">= 8" 704 | } 705 | }, 706 | "node_modules/debug": { 707 | "version": "2.6.9", 708 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 709 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 710 | "dependencies": { 711 | "ms": "2.0.0" 712 | } 713 | }, 714 | "node_modules/deep-is": { 715 | "version": "0.1.4", 716 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", 717 | "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", 718 | "dev": true 719 | }, 720 | "node_modules/depd": { 721 | "version": "2.0.0", 722 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 723 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 724 | "engines": { 725 | "node": ">= 0.8" 726 | } 727 | }, 728 | "node_modules/destroy": { 729 | "version": "1.2.0", 730 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 731 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", 732 | "engines": { 733 | "node": ">= 0.8", 734 | "npm": "1.2.8000 || >= 1.4.16" 735 | } 736 | }, 737 | "node_modules/doctrine": { 738 | "version": "3.0.0", 739 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", 740 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", 741 | "dev": true, 742 | "dependencies": { 743 | "esutils": "^2.0.2" 744 | }, 745 | "engines": { 746 | "node": ">=6.0.0" 747 | } 748 | }, 749 | "node_modules/dotenv": { 750 | "version": "16.4.4", 751 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.4.tgz", 752 | "integrity": "sha512-XvPXc8XAQThSjAbY6cQ/9PcBXmFoWuw1sQ3b8HqUCR6ziGXjkTi//kB9SWa2UwqlgdAIuRqAa/9hVljzPehbYg==", 753 | "engines": { 754 | "node": ">=12" 755 | }, 756 | "funding": { 757 | "url": "https://dotenvx.com" 758 | } 759 | }, 760 | "node_modules/ecdsa-sig-formatter": { 761 | "version": "1.0.11", 762 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", 763 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", 764 | "dependencies": { 765 | "safe-buffer": "^5.0.1" 766 | } 767 | }, 768 | "node_modules/ee-first": { 769 | "version": "1.1.1", 770 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 771 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 772 | }, 773 | "node_modules/encodeurl": { 774 | "version": "1.0.2", 775 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 776 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", 777 | "engines": { 778 | "node": ">= 0.8" 779 | } 780 | }, 781 | "node_modules/entities": { 782 | "version": "2.1.0", 783 | "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", 784 | "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", 785 | "dev": true, 786 | "funding": { 787 | "url": "https://github.com/fb55/entities?sponsor=1" 788 | } 789 | }, 790 | "node_modules/escape-html": { 791 | "version": "1.0.3", 792 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 793 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 794 | }, 795 | "node_modules/escape-string-regexp": { 796 | "version": "4.0.0", 797 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 798 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 799 | "dev": true, 800 | "engines": { 801 | "node": ">=10" 802 | }, 803 | "funding": { 804 | "url": "https://github.com/sponsors/sindresorhus" 805 | } 806 | }, 807 | "node_modules/eslint": { 808 | "version": "8.56.0", 809 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", 810 | "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", 811 | "dev": true, 812 | "dependencies": { 813 | "@eslint-community/eslint-utils": "^4.2.0", 814 | "@eslint-community/regexpp": "^4.6.1", 815 | "@eslint/eslintrc": "^2.1.4", 816 | "@eslint/js": "8.56.0", 817 | "@humanwhocodes/config-array": "^0.11.13", 818 | "@humanwhocodes/module-importer": "^1.0.1", 819 | "@nodelib/fs.walk": "^1.2.8", 820 | "@ungap/structured-clone": "^1.2.0", 821 | "ajv": "^6.12.4", 822 | "chalk": "^4.0.0", 823 | "cross-spawn": "^7.0.2", 824 | "debug": "^4.3.2", 825 | "doctrine": "^3.0.0", 826 | "escape-string-regexp": "^4.0.0", 827 | "eslint-scope": "^7.2.2", 828 | "eslint-visitor-keys": "^3.4.3", 829 | "espree": "^9.6.1", 830 | "esquery": "^1.4.2", 831 | "esutils": "^2.0.2", 832 | "fast-deep-equal": "^3.1.3", 833 | "file-entry-cache": "^6.0.1", 834 | "find-up": "^5.0.0", 835 | "glob-parent": "^6.0.2", 836 | "globals": "^13.19.0", 837 | "graphemer": "^1.4.0", 838 | "ignore": "^5.2.0", 839 | "imurmurhash": "^0.1.4", 840 | "is-glob": "^4.0.0", 841 | "is-path-inside": "^3.0.3", 842 | "js-yaml": "^4.1.0", 843 | "json-stable-stringify-without-jsonify": "^1.0.1", 844 | "levn": "^0.4.1", 845 | "lodash.merge": "^4.6.2", 846 | "minimatch": "^3.1.2", 847 | "natural-compare": "^1.4.0", 848 | "optionator": "^0.9.3", 849 | "strip-ansi": "^6.0.1", 850 | "text-table": "^0.2.0" 851 | }, 852 | "bin": { 853 | "eslint": "bin/eslint.js" 854 | }, 855 | "engines": { 856 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 857 | }, 858 | "funding": { 859 | "url": "https://opencollective.com/eslint" 860 | } 861 | }, 862 | "node_modules/eslint-config-google": { 863 | "version": "0.14.0", 864 | "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz", 865 | "integrity": "sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==", 866 | "dev": true, 867 | "engines": { 868 | "node": ">=0.10.0" 869 | }, 870 | "peerDependencies": { 871 | "eslint": ">=5.16.0" 872 | } 873 | }, 874 | "node_modules/eslint-scope": { 875 | "version": "7.2.2", 876 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", 877 | "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", 878 | "dev": true, 879 | "dependencies": { 880 | "esrecurse": "^4.3.0", 881 | "estraverse": "^5.2.0" 882 | }, 883 | "engines": { 884 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 885 | }, 886 | "funding": { 887 | "url": "https://opencollective.com/eslint" 888 | } 889 | }, 890 | "node_modules/eslint-visitor-keys": { 891 | "version": "3.4.3", 892 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", 893 | "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", 894 | "dev": true, 895 | "engines": { 896 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 897 | }, 898 | "funding": { 899 | "url": "https://opencollective.com/eslint" 900 | } 901 | }, 902 | "node_modules/eslint/node_modules/debug": { 903 | "version": "4.3.4", 904 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 905 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 906 | "dev": true, 907 | "dependencies": { 908 | "ms": "2.1.2" 909 | }, 910 | "engines": { 911 | "node": ">=6.0" 912 | }, 913 | "peerDependenciesMeta": { 914 | "supports-color": { 915 | "optional": true 916 | } 917 | } 918 | }, 919 | "node_modules/eslint/node_modules/ms": { 920 | "version": "2.1.2", 921 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 922 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 923 | "dev": true 924 | }, 925 | "node_modules/espree": { 926 | "version": "9.6.1", 927 | "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", 928 | "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", 929 | "dev": true, 930 | "dependencies": { 931 | "acorn": "^8.9.0", 932 | "acorn-jsx": "^5.3.2", 933 | "eslint-visitor-keys": "^3.4.1" 934 | }, 935 | "engines": { 936 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 937 | }, 938 | "funding": { 939 | "url": "https://opencollective.com/eslint" 940 | } 941 | }, 942 | "node_modules/esquery": { 943 | "version": "1.5.0", 944 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", 945 | "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", 946 | "dev": true, 947 | "dependencies": { 948 | "estraverse": "^5.1.0" 949 | }, 950 | "engines": { 951 | "node": ">=0.10" 952 | } 953 | }, 954 | "node_modules/esrecurse": { 955 | "version": "4.3.0", 956 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 957 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 958 | "dev": true, 959 | "dependencies": { 960 | "estraverse": "^5.2.0" 961 | }, 962 | "engines": { 963 | "node": ">=4.0" 964 | } 965 | }, 966 | "node_modules/estraverse": { 967 | "version": "5.3.0", 968 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", 969 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", 970 | "dev": true, 971 | "engines": { 972 | "node": ">=4.0" 973 | } 974 | }, 975 | "node_modules/esutils": { 976 | "version": "2.0.3", 977 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 978 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 979 | "dev": true, 980 | "engines": { 981 | "node": ">=0.10.0" 982 | } 983 | }, 984 | "node_modules/etag": { 985 | "version": "1.8.1", 986 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 987 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 988 | "engines": { 989 | "node": ">= 0.6" 990 | } 991 | }, 992 | "node_modules/express": { 993 | "version": "4.18.2", 994 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", 995 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", 996 | "dependencies": { 997 | "accepts": "~1.3.8", 998 | "array-flatten": "1.1.1", 999 | "body-parser": "1.20.1", 1000 | "content-disposition": "0.5.4", 1001 | "content-type": "~1.0.4", 1002 | "cookie": "0.5.0", 1003 | "cookie-signature": "1.0.6", 1004 | "debug": "2.6.9", 1005 | "depd": "2.0.0", 1006 | "encodeurl": "~1.0.2", 1007 | "escape-html": "~1.0.3", 1008 | "etag": "~1.8.1", 1009 | "finalhandler": "1.2.0", 1010 | "fresh": "0.5.2", 1011 | "http-errors": "2.0.0", 1012 | "merge-descriptors": "1.0.1", 1013 | "methods": "~1.1.2", 1014 | "on-finished": "2.4.1", 1015 | "parseurl": "~1.3.3", 1016 | "path-to-regexp": "0.1.7", 1017 | "proxy-addr": "~2.0.7", 1018 | "qs": "6.11.0", 1019 | "range-parser": "~1.2.1", 1020 | "safe-buffer": "5.2.1", 1021 | "send": "0.18.0", 1022 | "serve-static": "1.15.0", 1023 | "setprototypeof": "1.2.0", 1024 | "statuses": "2.0.1", 1025 | "type-is": "~1.6.18", 1026 | "utils-merge": "1.0.1", 1027 | "vary": "~1.1.2" 1028 | }, 1029 | "engines": { 1030 | "node": ">= 0.10.0" 1031 | } 1032 | }, 1033 | "node_modules/express/node_modules/cookie": { 1034 | "version": "0.5.0", 1035 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 1036 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", 1037 | "engines": { 1038 | "node": ">= 0.6" 1039 | } 1040 | }, 1041 | "node_modules/fast-deep-equal": { 1042 | "version": "3.1.3", 1043 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 1044 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 1045 | "dev": true 1046 | }, 1047 | "node_modules/fast-json-stable-stringify": { 1048 | "version": "2.1.0", 1049 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 1050 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 1051 | "dev": true 1052 | }, 1053 | "node_modules/fast-levenshtein": { 1054 | "version": "2.0.6", 1055 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 1056 | "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", 1057 | "dev": true 1058 | }, 1059 | "node_modules/fastq": { 1060 | "version": "1.15.0", 1061 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", 1062 | "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", 1063 | "dev": true, 1064 | "dependencies": { 1065 | "reusify": "^1.0.4" 1066 | } 1067 | }, 1068 | "node_modules/file-entry-cache": { 1069 | "version": "6.0.1", 1070 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", 1071 | "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", 1072 | "dev": true, 1073 | "dependencies": { 1074 | "flat-cache": "^3.0.4" 1075 | }, 1076 | "engines": { 1077 | "node": "^10.12.0 || >=12.0.0" 1078 | } 1079 | }, 1080 | "node_modules/fill-range": { 1081 | "version": "7.0.1", 1082 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 1083 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 1084 | "dev": true, 1085 | "dependencies": { 1086 | "to-regex-range": "^5.0.1" 1087 | }, 1088 | "engines": { 1089 | "node": ">=8" 1090 | } 1091 | }, 1092 | "node_modules/finalhandler": { 1093 | "version": "1.2.0", 1094 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", 1095 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", 1096 | "dependencies": { 1097 | "debug": "2.6.9", 1098 | "encodeurl": "~1.0.2", 1099 | "escape-html": "~1.0.3", 1100 | "on-finished": "2.4.1", 1101 | "parseurl": "~1.3.3", 1102 | "statuses": "2.0.1", 1103 | "unpipe": "~1.0.0" 1104 | }, 1105 | "engines": { 1106 | "node": ">= 0.8" 1107 | } 1108 | }, 1109 | "node_modules/find-up": { 1110 | "version": "5.0.0", 1111 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 1112 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 1113 | "dev": true, 1114 | "dependencies": { 1115 | "locate-path": "^6.0.0", 1116 | "path-exists": "^4.0.0" 1117 | }, 1118 | "engines": { 1119 | "node": ">=10" 1120 | }, 1121 | "funding": { 1122 | "url": "https://github.com/sponsors/sindresorhus" 1123 | } 1124 | }, 1125 | "node_modules/flat-cache": { 1126 | "version": "3.1.0", 1127 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", 1128 | "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", 1129 | "dev": true, 1130 | "dependencies": { 1131 | "flatted": "^3.2.7", 1132 | "keyv": "^4.5.3", 1133 | "rimraf": "^3.0.2" 1134 | }, 1135 | "engines": { 1136 | "node": ">=12.0.0" 1137 | } 1138 | }, 1139 | "node_modules/flatted": { 1140 | "version": "3.2.9", 1141 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", 1142 | "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", 1143 | "dev": true 1144 | }, 1145 | "node_modules/forwarded": { 1146 | "version": "0.2.0", 1147 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 1148 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 1149 | "engines": { 1150 | "node": ">= 0.6" 1151 | } 1152 | }, 1153 | "node_modules/fresh": { 1154 | "version": "0.5.2", 1155 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 1156 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", 1157 | "engines": { 1158 | "node": ">= 0.6" 1159 | } 1160 | }, 1161 | "node_modules/fs.realpath": { 1162 | "version": "1.0.0", 1163 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1164 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 1165 | "dev": true 1166 | }, 1167 | "node_modules/fsevents": { 1168 | "version": "2.3.3", 1169 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 1170 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 1171 | "dev": true, 1172 | "hasInstallScript": true, 1173 | "optional": true, 1174 | "os": [ 1175 | "darwin" 1176 | ], 1177 | "engines": { 1178 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1179 | } 1180 | }, 1181 | "node_modules/function-bind": { 1182 | "version": "1.1.1", 1183 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 1184 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 1185 | }, 1186 | "node_modules/get-intrinsic": { 1187 | "version": "1.2.1", 1188 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", 1189 | "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", 1190 | "dependencies": { 1191 | "function-bind": "^1.1.1", 1192 | "has": "^1.0.3", 1193 | "has-proto": "^1.0.1", 1194 | "has-symbols": "^1.0.3" 1195 | }, 1196 | "funding": { 1197 | "url": "https://github.com/sponsors/ljharb" 1198 | } 1199 | }, 1200 | "node_modules/glob": { 1201 | "version": "7.2.3", 1202 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 1203 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 1204 | "dev": true, 1205 | "dependencies": { 1206 | "fs.realpath": "^1.0.0", 1207 | "inflight": "^1.0.4", 1208 | "inherits": "2", 1209 | "minimatch": "^3.1.1", 1210 | "once": "^1.3.0", 1211 | "path-is-absolute": "^1.0.0" 1212 | }, 1213 | "engines": { 1214 | "node": "*" 1215 | }, 1216 | "funding": { 1217 | "url": "https://github.com/sponsors/isaacs" 1218 | } 1219 | }, 1220 | "node_modules/glob-parent": { 1221 | "version": "6.0.2", 1222 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", 1223 | "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", 1224 | "dev": true, 1225 | "dependencies": { 1226 | "is-glob": "^4.0.3" 1227 | }, 1228 | "engines": { 1229 | "node": ">=10.13.0" 1230 | } 1231 | }, 1232 | "node_modules/globals": { 1233 | "version": "13.24.0", 1234 | "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", 1235 | "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", 1236 | "dev": true, 1237 | "dependencies": { 1238 | "type-fest": "^0.20.2" 1239 | }, 1240 | "engines": { 1241 | "node": ">=8" 1242 | }, 1243 | "funding": { 1244 | "url": "https://github.com/sponsors/sindresorhus" 1245 | } 1246 | }, 1247 | "node_modules/graceful-fs": { 1248 | "version": "4.2.11", 1249 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 1250 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", 1251 | "dev": true 1252 | }, 1253 | "node_modules/graphemer": { 1254 | "version": "1.4.0", 1255 | "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", 1256 | "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", 1257 | "dev": true 1258 | }, 1259 | "node_modules/has": { 1260 | "version": "1.0.3", 1261 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1262 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1263 | "dependencies": { 1264 | "function-bind": "^1.1.1" 1265 | }, 1266 | "engines": { 1267 | "node": ">= 0.4.0" 1268 | } 1269 | }, 1270 | "node_modules/has-flag": { 1271 | "version": "4.0.0", 1272 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1273 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1274 | "dev": true, 1275 | "engines": { 1276 | "node": ">=8" 1277 | } 1278 | }, 1279 | "node_modules/has-proto": { 1280 | "version": "1.0.1", 1281 | "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", 1282 | "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", 1283 | "engines": { 1284 | "node": ">= 0.4" 1285 | }, 1286 | "funding": { 1287 | "url": "https://github.com/sponsors/ljharb" 1288 | } 1289 | }, 1290 | "node_modules/has-symbols": { 1291 | "version": "1.0.3", 1292 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 1293 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 1294 | "engines": { 1295 | "node": ">= 0.4" 1296 | }, 1297 | "funding": { 1298 | "url": "https://github.com/sponsors/ljharb" 1299 | } 1300 | }, 1301 | "node_modules/http-errors": { 1302 | "version": "2.0.0", 1303 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 1304 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 1305 | "dependencies": { 1306 | "depd": "2.0.0", 1307 | "inherits": "2.0.4", 1308 | "setprototypeof": "1.2.0", 1309 | "statuses": "2.0.1", 1310 | "toidentifier": "1.0.1" 1311 | }, 1312 | "engines": { 1313 | "node": ">= 0.8" 1314 | } 1315 | }, 1316 | "node_modules/iconv-lite": { 1317 | "version": "0.4.24", 1318 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 1319 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 1320 | "dependencies": { 1321 | "safer-buffer": ">= 2.1.2 < 3" 1322 | }, 1323 | "engines": { 1324 | "node": ">=0.10.0" 1325 | } 1326 | }, 1327 | "node_modules/ignore": { 1328 | "version": "5.3.1", 1329 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", 1330 | "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", 1331 | "dev": true, 1332 | "engines": { 1333 | "node": ">= 4" 1334 | } 1335 | }, 1336 | "node_modules/ignore-by-default": { 1337 | "version": "1.0.1", 1338 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", 1339 | "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", 1340 | "dev": true 1341 | }, 1342 | "node_modules/import-fresh": { 1343 | "version": "3.3.0", 1344 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 1345 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 1346 | "dev": true, 1347 | "dependencies": { 1348 | "parent-module": "^1.0.0", 1349 | "resolve-from": "^4.0.0" 1350 | }, 1351 | "engines": { 1352 | "node": ">=6" 1353 | }, 1354 | "funding": { 1355 | "url": "https://github.com/sponsors/sindresorhus" 1356 | } 1357 | }, 1358 | "node_modules/imurmurhash": { 1359 | "version": "0.1.4", 1360 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 1361 | "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", 1362 | "dev": true, 1363 | "engines": { 1364 | "node": ">=0.8.19" 1365 | } 1366 | }, 1367 | "node_modules/inflight": { 1368 | "version": "1.0.6", 1369 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1370 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 1371 | "dev": true, 1372 | "dependencies": { 1373 | "once": "^1.3.0", 1374 | "wrappy": "1" 1375 | } 1376 | }, 1377 | "node_modules/inherits": { 1378 | "version": "2.0.4", 1379 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1380 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 1381 | }, 1382 | "node_modules/ipaddr.js": { 1383 | "version": "1.9.1", 1384 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 1385 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 1386 | "engines": { 1387 | "node": ">= 0.10" 1388 | } 1389 | }, 1390 | "node_modules/is-binary-path": { 1391 | "version": "2.1.0", 1392 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 1393 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 1394 | "dev": true, 1395 | "dependencies": { 1396 | "binary-extensions": "^2.0.0" 1397 | }, 1398 | "engines": { 1399 | "node": ">=8" 1400 | } 1401 | }, 1402 | "node_modules/is-extglob": { 1403 | "version": "2.1.1", 1404 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1405 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 1406 | "dev": true, 1407 | "engines": { 1408 | "node": ">=0.10.0" 1409 | } 1410 | }, 1411 | "node_modules/is-glob": { 1412 | "version": "4.0.3", 1413 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1414 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1415 | "dev": true, 1416 | "dependencies": { 1417 | "is-extglob": "^2.1.1" 1418 | }, 1419 | "engines": { 1420 | "node": ">=0.10.0" 1421 | } 1422 | }, 1423 | "node_modules/is-number": { 1424 | "version": "7.0.0", 1425 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1426 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1427 | "dev": true, 1428 | "engines": { 1429 | "node": ">=0.12.0" 1430 | } 1431 | }, 1432 | "node_modules/is-path-inside": { 1433 | "version": "3.0.3", 1434 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", 1435 | "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", 1436 | "dev": true, 1437 | "engines": { 1438 | "node": ">=8" 1439 | } 1440 | }, 1441 | "node_modules/isexe": { 1442 | "version": "2.0.0", 1443 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1444 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 1445 | "dev": true 1446 | }, 1447 | "node_modules/joi": { 1448 | "version": "17.10.2", 1449 | "resolved": "https://registry.npmjs.org/joi/-/joi-17.10.2.tgz", 1450 | "integrity": "sha512-hcVhjBxRNW/is3nNLdGLIjkgXetkeGc2wyhydhz8KumG23Aerk4HPjU5zaPAMRqXQFc0xNqXTC7+zQjxr0GlKA==", 1451 | "dependencies": { 1452 | "@hapi/hoek": "^9.0.0", 1453 | "@hapi/topo": "^5.0.0", 1454 | "@sideway/address": "^4.1.3", 1455 | "@sideway/formula": "^3.0.1", 1456 | "@sideway/pinpoint": "^2.0.0" 1457 | } 1458 | }, 1459 | "node_modules/js-yaml": { 1460 | "version": "4.1.0", 1461 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 1462 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 1463 | "dev": true, 1464 | "dependencies": { 1465 | "argparse": "^2.0.1" 1466 | }, 1467 | "bin": { 1468 | "js-yaml": "bin/js-yaml.js" 1469 | } 1470 | }, 1471 | "node_modules/js2xmlparser": { 1472 | "version": "4.0.2", 1473 | "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", 1474 | "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", 1475 | "dev": true, 1476 | "dependencies": { 1477 | "xmlcreate": "^2.0.4" 1478 | } 1479 | }, 1480 | "node_modules/jsdoc": { 1481 | "version": "4.0.2", 1482 | "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", 1483 | "integrity": "sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==", 1484 | "dev": true, 1485 | "dependencies": { 1486 | "@babel/parser": "^7.20.15", 1487 | "@jsdoc/salty": "^0.2.1", 1488 | "@types/markdown-it": "^12.2.3", 1489 | "bluebird": "^3.7.2", 1490 | "catharsis": "^0.9.0", 1491 | "escape-string-regexp": "^2.0.0", 1492 | "js2xmlparser": "^4.0.2", 1493 | "klaw": "^3.0.0", 1494 | "markdown-it": "^12.3.2", 1495 | "markdown-it-anchor": "^8.4.1", 1496 | "marked": "^4.0.10", 1497 | "mkdirp": "^1.0.4", 1498 | "requizzle": "^0.2.3", 1499 | "strip-json-comments": "^3.1.0", 1500 | "underscore": "~1.13.2" 1501 | }, 1502 | "bin": { 1503 | "jsdoc": "jsdoc.js" 1504 | }, 1505 | "engines": { 1506 | "node": ">=12.0.0" 1507 | } 1508 | }, 1509 | "node_modules/jsdoc/node_modules/escape-string-regexp": { 1510 | "version": "2.0.0", 1511 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", 1512 | "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", 1513 | "dev": true, 1514 | "engines": { 1515 | "node": ">=8" 1516 | } 1517 | }, 1518 | "node_modules/json-buffer": { 1519 | "version": "3.0.1", 1520 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", 1521 | "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", 1522 | "dev": true 1523 | }, 1524 | "node_modules/json-schema-traverse": { 1525 | "version": "0.4.1", 1526 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 1527 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 1528 | "dev": true 1529 | }, 1530 | "node_modules/json-stable-stringify-without-jsonify": { 1531 | "version": "1.0.1", 1532 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 1533 | "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", 1534 | "dev": true 1535 | }, 1536 | "node_modules/jsonwebtoken": { 1537 | "version": "9.0.2", 1538 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", 1539 | "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", 1540 | "dependencies": { 1541 | "jws": "^3.2.2", 1542 | "lodash.includes": "^4.3.0", 1543 | "lodash.isboolean": "^3.0.3", 1544 | "lodash.isinteger": "^4.0.4", 1545 | "lodash.isnumber": "^3.0.3", 1546 | "lodash.isplainobject": "^4.0.6", 1547 | "lodash.isstring": "^4.0.1", 1548 | "lodash.once": "^4.0.0", 1549 | "ms": "^2.1.1", 1550 | "semver": "^7.5.4" 1551 | }, 1552 | "engines": { 1553 | "node": ">=12", 1554 | "npm": ">=6" 1555 | } 1556 | }, 1557 | "node_modules/jsonwebtoken/node_modules/ms": { 1558 | "version": "2.1.3", 1559 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1560 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 1561 | }, 1562 | "node_modules/jwa": { 1563 | "version": "1.4.1", 1564 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", 1565 | "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", 1566 | "dependencies": { 1567 | "buffer-equal-constant-time": "1.0.1", 1568 | "ecdsa-sig-formatter": "1.0.11", 1569 | "safe-buffer": "^5.0.1" 1570 | } 1571 | }, 1572 | "node_modules/jws": { 1573 | "version": "3.2.2", 1574 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", 1575 | "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", 1576 | "dependencies": { 1577 | "jwa": "^1.4.1", 1578 | "safe-buffer": "^5.0.1" 1579 | } 1580 | }, 1581 | "node_modules/kareem": { 1582 | "version": "2.5.1", 1583 | "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz", 1584 | "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==", 1585 | "engines": { 1586 | "node": ">=12.0.0" 1587 | } 1588 | }, 1589 | "node_modules/keyv": { 1590 | "version": "4.5.3", 1591 | "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", 1592 | "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", 1593 | "dev": true, 1594 | "dependencies": { 1595 | "json-buffer": "3.0.1" 1596 | } 1597 | }, 1598 | "node_modules/klaw": { 1599 | "version": "3.0.0", 1600 | "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", 1601 | "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", 1602 | "dev": true, 1603 | "dependencies": { 1604 | "graceful-fs": "^4.1.9" 1605 | } 1606 | }, 1607 | "node_modules/levn": { 1608 | "version": "0.4.1", 1609 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", 1610 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", 1611 | "dev": true, 1612 | "dependencies": { 1613 | "prelude-ls": "^1.2.1", 1614 | "type-check": "~0.4.0" 1615 | }, 1616 | "engines": { 1617 | "node": ">= 0.8.0" 1618 | } 1619 | }, 1620 | "node_modules/linkify-it": { 1621 | "version": "3.0.3", 1622 | "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", 1623 | "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", 1624 | "dev": true, 1625 | "dependencies": { 1626 | "uc.micro": "^1.0.1" 1627 | } 1628 | }, 1629 | "node_modules/locate-path": { 1630 | "version": "6.0.0", 1631 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 1632 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 1633 | "dev": true, 1634 | "dependencies": { 1635 | "p-locate": "^5.0.0" 1636 | }, 1637 | "engines": { 1638 | "node": ">=10" 1639 | }, 1640 | "funding": { 1641 | "url": "https://github.com/sponsors/sindresorhus" 1642 | } 1643 | }, 1644 | "node_modules/lodash": { 1645 | "version": "4.17.21", 1646 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 1647 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 1648 | "dev": true 1649 | }, 1650 | "node_modules/lodash.includes": { 1651 | "version": "4.3.0", 1652 | "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", 1653 | "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" 1654 | }, 1655 | "node_modules/lodash.isboolean": { 1656 | "version": "3.0.3", 1657 | "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", 1658 | "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" 1659 | }, 1660 | "node_modules/lodash.isinteger": { 1661 | "version": "4.0.4", 1662 | "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", 1663 | "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" 1664 | }, 1665 | "node_modules/lodash.isnumber": { 1666 | "version": "3.0.3", 1667 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", 1668 | "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" 1669 | }, 1670 | "node_modules/lodash.isplainobject": { 1671 | "version": "4.0.6", 1672 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 1673 | "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" 1674 | }, 1675 | "node_modules/lodash.isstring": { 1676 | "version": "4.0.1", 1677 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", 1678 | "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" 1679 | }, 1680 | "node_modules/lodash.merge": { 1681 | "version": "4.6.2", 1682 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 1683 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", 1684 | "dev": true 1685 | }, 1686 | "node_modules/lodash.once": { 1687 | "version": "4.1.1", 1688 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", 1689 | "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" 1690 | }, 1691 | "node_modules/lru-cache": { 1692 | "version": "6.0.0", 1693 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 1694 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 1695 | "dependencies": { 1696 | "yallist": "^4.0.0" 1697 | }, 1698 | "engines": { 1699 | "node": ">=10" 1700 | } 1701 | }, 1702 | "node_modules/markdown-it": { 1703 | "version": "12.3.2", 1704 | "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", 1705 | "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", 1706 | "dev": true, 1707 | "dependencies": { 1708 | "argparse": "^2.0.1", 1709 | "entities": "~2.1.0", 1710 | "linkify-it": "^3.0.1", 1711 | "mdurl": "^1.0.1", 1712 | "uc.micro": "^1.0.5" 1713 | }, 1714 | "bin": { 1715 | "markdown-it": "bin/markdown-it.js" 1716 | } 1717 | }, 1718 | "node_modules/markdown-it-anchor": { 1719 | "version": "8.6.7", 1720 | "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", 1721 | "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", 1722 | "dev": true, 1723 | "peerDependencies": { 1724 | "@types/markdown-it": "*", 1725 | "markdown-it": "*" 1726 | } 1727 | }, 1728 | "node_modules/marked": { 1729 | "version": "4.3.0", 1730 | "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", 1731 | "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", 1732 | "dev": true, 1733 | "bin": { 1734 | "marked": "bin/marked.js" 1735 | }, 1736 | "engines": { 1737 | "node": ">= 12" 1738 | } 1739 | }, 1740 | "node_modules/mdurl": { 1741 | "version": "1.0.1", 1742 | "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", 1743 | "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", 1744 | "dev": true 1745 | }, 1746 | "node_modules/media-typer": { 1747 | "version": "0.3.0", 1748 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 1749 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", 1750 | "engines": { 1751 | "node": ">= 0.6" 1752 | } 1753 | }, 1754 | "node_modules/memory-pager": { 1755 | "version": "1.5.0", 1756 | "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", 1757 | "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" 1758 | }, 1759 | "node_modules/merge-descriptors": { 1760 | "version": "1.0.1", 1761 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 1762 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" 1763 | }, 1764 | "node_modules/methods": { 1765 | "version": "1.1.2", 1766 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 1767 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", 1768 | "engines": { 1769 | "node": ">= 0.6" 1770 | } 1771 | }, 1772 | "node_modules/mime": { 1773 | "version": "1.6.0", 1774 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 1775 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 1776 | "bin": { 1777 | "mime": "cli.js" 1778 | }, 1779 | "engines": { 1780 | "node": ">=4" 1781 | } 1782 | }, 1783 | "node_modules/mime-db": { 1784 | "version": "1.52.0", 1785 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 1786 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 1787 | "engines": { 1788 | "node": ">= 0.6" 1789 | } 1790 | }, 1791 | "node_modules/mime-types": { 1792 | "version": "2.1.35", 1793 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 1794 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 1795 | "dependencies": { 1796 | "mime-db": "1.52.0" 1797 | }, 1798 | "engines": { 1799 | "node": ">= 0.6" 1800 | } 1801 | }, 1802 | "node_modules/minimatch": { 1803 | "version": "3.1.2", 1804 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 1805 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 1806 | "dev": true, 1807 | "dependencies": { 1808 | "brace-expansion": "^1.1.7" 1809 | }, 1810 | "engines": { 1811 | "node": "*" 1812 | } 1813 | }, 1814 | "node_modules/mkdirp": { 1815 | "version": "1.0.4", 1816 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", 1817 | "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", 1818 | "dev": true, 1819 | "bin": { 1820 | "mkdirp": "bin/cmd.js" 1821 | }, 1822 | "engines": { 1823 | "node": ">=10" 1824 | } 1825 | }, 1826 | "node_modules/mongodb": { 1827 | "version": "6.3.0", 1828 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.3.0.tgz", 1829 | "integrity": "sha512-tt0KuGjGtLUhLoU263+xvQmPHEGTw5LbcNC73EoFRYgSHwZt5tsoJC110hDyO1kjQzpgNrpdcSza9PknWN4LrA==", 1830 | "dependencies": { 1831 | "@mongodb-js/saslprep": "^1.1.0", 1832 | "bson": "^6.2.0", 1833 | "mongodb-connection-string-url": "^3.0.0" 1834 | }, 1835 | "engines": { 1836 | "node": ">=16.20.1" 1837 | }, 1838 | "peerDependencies": { 1839 | "@aws-sdk/credential-providers": "^3.188.0", 1840 | "@mongodb-js/zstd": "^1.1.0", 1841 | "gcp-metadata": "^5.2.0", 1842 | "kerberos": "^2.0.1", 1843 | "mongodb-client-encryption": ">=6.0.0 <7", 1844 | "snappy": "^7.2.2", 1845 | "socks": "^2.7.1" 1846 | }, 1847 | "peerDependenciesMeta": { 1848 | "@aws-sdk/credential-providers": { 1849 | "optional": true 1850 | }, 1851 | "@mongodb-js/zstd": { 1852 | "optional": true 1853 | }, 1854 | "gcp-metadata": { 1855 | "optional": true 1856 | }, 1857 | "kerberos": { 1858 | "optional": true 1859 | }, 1860 | "mongodb-client-encryption": { 1861 | "optional": true 1862 | }, 1863 | "snappy": { 1864 | "optional": true 1865 | }, 1866 | "socks": { 1867 | "optional": true 1868 | } 1869 | } 1870 | }, 1871 | "node_modules/mongodb-connection-string-url": { 1872 | "version": "3.0.0", 1873 | "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.0.tgz", 1874 | "integrity": "sha512-t1Vf+m1I5hC2M5RJx/7AtxgABy1cZmIPQRMXw+gEIPn/cZNF3Oiy+l0UIypUwVB5trcWHq3crg2g3uAR9aAwsQ==", 1875 | "dependencies": { 1876 | "@types/whatwg-url": "^11.0.2", 1877 | "whatwg-url": "^13.0.0" 1878 | } 1879 | }, 1880 | "node_modules/mongoose": { 1881 | "version": "8.1.0", 1882 | "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.1.0.tgz", 1883 | "integrity": "sha512-kOA4Xnq2goqNpN9EmYElGNWfxA9H80fxcr7UdJKWi3UMflza0R7wpTihCpM67dE/0MNFljoa0sjQtlXVkkySAQ==", 1884 | "dependencies": { 1885 | "bson": "^6.2.0", 1886 | "kareem": "2.5.1", 1887 | "mongodb": "6.3.0", 1888 | "mpath": "0.9.0", 1889 | "mquery": "5.0.0", 1890 | "ms": "2.1.3", 1891 | "sift": "16.0.1" 1892 | }, 1893 | "engines": { 1894 | "node": ">=16.20.1" 1895 | }, 1896 | "funding": { 1897 | "type": "opencollective", 1898 | "url": "https://opencollective.com/mongoose" 1899 | } 1900 | }, 1901 | "node_modules/mongoose/node_modules/ms": { 1902 | "version": "2.1.3", 1903 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1904 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 1905 | }, 1906 | "node_modules/morgan": { 1907 | "version": "1.10.0", 1908 | "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", 1909 | "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", 1910 | "dependencies": { 1911 | "basic-auth": "~2.0.1", 1912 | "debug": "2.6.9", 1913 | "depd": "~2.0.0", 1914 | "on-finished": "~2.3.0", 1915 | "on-headers": "~1.0.2" 1916 | }, 1917 | "engines": { 1918 | "node": ">= 0.8.0" 1919 | } 1920 | }, 1921 | "node_modules/morgan/node_modules/on-finished": { 1922 | "version": "2.3.0", 1923 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 1924 | "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", 1925 | "dependencies": { 1926 | "ee-first": "1.1.1" 1927 | }, 1928 | "engines": { 1929 | "node": ">= 0.8" 1930 | } 1931 | }, 1932 | "node_modules/mpath": { 1933 | "version": "0.9.0", 1934 | "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", 1935 | "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", 1936 | "engines": { 1937 | "node": ">=4.0.0" 1938 | } 1939 | }, 1940 | "node_modules/mquery": { 1941 | "version": "5.0.0", 1942 | "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", 1943 | "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", 1944 | "dependencies": { 1945 | "debug": "4.x" 1946 | }, 1947 | "engines": { 1948 | "node": ">=14.0.0" 1949 | } 1950 | }, 1951 | "node_modules/mquery/node_modules/debug": { 1952 | "version": "4.3.4", 1953 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 1954 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 1955 | "dependencies": { 1956 | "ms": "2.1.2" 1957 | }, 1958 | "engines": { 1959 | "node": ">=6.0" 1960 | }, 1961 | "peerDependenciesMeta": { 1962 | "supports-color": { 1963 | "optional": true 1964 | } 1965 | } 1966 | }, 1967 | "node_modules/mquery/node_modules/ms": { 1968 | "version": "2.1.2", 1969 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1970 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 1971 | }, 1972 | "node_modules/ms": { 1973 | "version": "2.0.0", 1974 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1975 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 1976 | }, 1977 | "node_modules/natural-compare": { 1978 | "version": "1.4.0", 1979 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 1980 | "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", 1981 | "dev": true 1982 | }, 1983 | "node_modules/negotiator": { 1984 | "version": "0.6.3", 1985 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 1986 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", 1987 | "engines": { 1988 | "node": ">= 0.6" 1989 | } 1990 | }, 1991 | "node_modules/nodemon": { 1992 | "version": "3.0.3", 1993 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.3.tgz", 1994 | "integrity": "sha512-7jH/NXbFPxVaMwmBCC2B9F/V6X1VkEdNgx3iu9jji8WxWcvhMWkmhNWhI5077zknOnZnBzba9hZP6bCPJLSReQ==", 1995 | "dev": true, 1996 | "dependencies": { 1997 | "chokidar": "^3.5.2", 1998 | "debug": "^4", 1999 | "ignore-by-default": "^1.0.1", 2000 | "minimatch": "^3.1.2", 2001 | "pstree.remy": "^1.1.8", 2002 | "semver": "^7.5.3", 2003 | "simple-update-notifier": "^2.0.0", 2004 | "supports-color": "^5.5.0", 2005 | "touch": "^3.1.0", 2006 | "undefsafe": "^2.0.5" 2007 | }, 2008 | "bin": { 2009 | "nodemon": "bin/nodemon.js" 2010 | }, 2011 | "engines": { 2012 | "node": ">=10" 2013 | }, 2014 | "funding": { 2015 | "type": "opencollective", 2016 | "url": "https://opencollective.com/nodemon" 2017 | } 2018 | }, 2019 | "node_modules/nodemon/node_modules/debug": { 2020 | "version": "4.3.4", 2021 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 2022 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 2023 | "dev": true, 2024 | "dependencies": { 2025 | "ms": "2.1.2" 2026 | }, 2027 | "engines": { 2028 | "node": ">=6.0" 2029 | }, 2030 | "peerDependenciesMeta": { 2031 | "supports-color": { 2032 | "optional": true 2033 | } 2034 | } 2035 | }, 2036 | "node_modules/nodemon/node_modules/has-flag": { 2037 | "version": "3.0.0", 2038 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 2039 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 2040 | "dev": true, 2041 | "engines": { 2042 | "node": ">=4" 2043 | } 2044 | }, 2045 | "node_modules/nodemon/node_modules/ms": { 2046 | "version": "2.1.2", 2047 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 2048 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 2049 | "dev": true 2050 | }, 2051 | "node_modules/nodemon/node_modules/supports-color": { 2052 | "version": "5.5.0", 2053 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 2054 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 2055 | "dev": true, 2056 | "dependencies": { 2057 | "has-flag": "^3.0.0" 2058 | }, 2059 | "engines": { 2060 | "node": ">=4" 2061 | } 2062 | }, 2063 | "node_modules/nopt": { 2064 | "version": "1.0.10", 2065 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", 2066 | "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", 2067 | "dev": true, 2068 | "dependencies": { 2069 | "abbrev": "1" 2070 | }, 2071 | "bin": { 2072 | "nopt": "bin/nopt.js" 2073 | }, 2074 | "engines": { 2075 | "node": "*" 2076 | } 2077 | }, 2078 | "node_modules/normalize-path": { 2079 | "version": "3.0.0", 2080 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 2081 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 2082 | "dev": true, 2083 | "engines": { 2084 | "node": ">=0.10.0" 2085 | } 2086 | }, 2087 | "node_modules/object-assign": { 2088 | "version": "4.1.1", 2089 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 2090 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", 2091 | "engines": { 2092 | "node": ">=0.10.0" 2093 | } 2094 | }, 2095 | "node_modules/object-inspect": { 2096 | "version": "1.12.3", 2097 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", 2098 | "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", 2099 | "funding": { 2100 | "url": "https://github.com/sponsors/ljharb" 2101 | } 2102 | }, 2103 | "node_modules/on-finished": { 2104 | "version": "2.4.1", 2105 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 2106 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 2107 | "dependencies": { 2108 | "ee-first": "1.1.1" 2109 | }, 2110 | "engines": { 2111 | "node": ">= 0.8" 2112 | } 2113 | }, 2114 | "node_modules/on-headers": { 2115 | "version": "1.0.2", 2116 | "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", 2117 | "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", 2118 | "engines": { 2119 | "node": ">= 0.8" 2120 | } 2121 | }, 2122 | "node_modules/once": { 2123 | "version": "1.4.0", 2124 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 2125 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 2126 | "dev": true, 2127 | "dependencies": { 2128 | "wrappy": "1" 2129 | } 2130 | }, 2131 | "node_modules/optionator": { 2132 | "version": "0.9.3", 2133 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", 2134 | "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", 2135 | "dev": true, 2136 | "dependencies": { 2137 | "@aashutoshrathi/word-wrap": "^1.2.3", 2138 | "deep-is": "^0.1.3", 2139 | "fast-levenshtein": "^2.0.6", 2140 | "levn": "^0.4.1", 2141 | "prelude-ls": "^1.2.1", 2142 | "type-check": "^0.4.0" 2143 | }, 2144 | "engines": { 2145 | "node": ">= 0.8.0" 2146 | } 2147 | }, 2148 | "node_modules/p-limit": { 2149 | "version": "3.1.0", 2150 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 2151 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 2152 | "dev": true, 2153 | "dependencies": { 2154 | "yocto-queue": "^0.1.0" 2155 | }, 2156 | "engines": { 2157 | "node": ">=10" 2158 | }, 2159 | "funding": { 2160 | "url": "https://github.com/sponsors/sindresorhus" 2161 | } 2162 | }, 2163 | "node_modules/p-locate": { 2164 | "version": "5.0.0", 2165 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 2166 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 2167 | "dev": true, 2168 | "dependencies": { 2169 | "p-limit": "^3.0.2" 2170 | }, 2171 | "engines": { 2172 | "node": ">=10" 2173 | }, 2174 | "funding": { 2175 | "url": "https://github.com/sponsors/sindresorhus" 2176 | } 2177 | }, 2178 | "node_modules/parent-module": { 2179 | "version": "1.0.1", 2180 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 2181 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 2182 | "dev": true, 2183 | "dependencies": { 2184 | "callsites": "^3.0.0" 2185 | }, 2186 | "engines": { 2187 | "node": ">=6" 2188 | } 2189 | }, 2190 | "node_modules/parseurl": { 2191 | "version": "1.3.3", 2192 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 2193 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 2194 | "engines": { 2195 | "node": ">= 0.8" 2196 | } 2197 | }, 2198 | "node_modules/path-exists": { 2199 | "version": "4.0.0", 2200 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 2201 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 2202 | "dev": true, 2203 | "engines": { 2204 | "node": ">=8" 2205 | } 2206 | }, 2207 | "node_modules/path-is-absolute": { 2208 | "version": "1.0.1", 2209 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 2210 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 2211 | "dev": true, 2212 | "engines": { 2213 | "node": ">=0.10.0" 2214 | } 2215 | }, 2216 | "node_modules/path-key": { 2217 | "version": "3.1.1", 2218 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 2219 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 2220 | "dev": true, 2221 | "engines": { 2222 | "node": ">=8" 2223 | } 2224 | }, 2225 | "node_modules/path-to-regexp": { 2226 | "version": "0.1.7", 2227 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 2228 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" 2229 | }, 2230 | "node_modules/picomatch": { 2231 | "version": "2.3.1", 2232 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 2233 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 2234 | "dev": true, 2235 | "engines": { 2236 | "node": ">=8.6" 2237 | }, 2238 | "funding": { 2239 | "url": "https://github.com/sponsors/jonschlinkert" 2240 | } 2241 | }, 2242 | "node_modules/prelude-ls": { 2243 | "version": "1.2.1", 2244 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", 2245 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", 2246 | "dev": true, 2247 | "engines": { 2248 | "node": ">= 0.8.0" 2249 | } 2250 | }, 2251 | "node_modules/prettier": { 2252 | "version": "3.2.5", 2253 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", 2254 | "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", 2255 | "dev": true, 2256 | "bin": { 2257 | "prettier": "bin/prettier.cjs" 2258 | }, 2259 | "engines": { 2260 | "node": ">=14" 2261 | }, 2262 | "funding": { 2263 | "url": "https://github.com/prettier/prettier?sponsor=1" 2264 | } 2265 | }, 2266 | "node_modules/proxy-addr": { 2267 | "version": "2.0.7", 2268 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 2269 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 2270 | "dependencies": { 2271 | "forwarded": "0.2.0", 2272 | "ipaddr.js": "1.9.1" 2273 | }, 2274 | "engines": { 2275 | "node": ">= 0.10" 2276 | } 2277 | }, 2278 | "node_modules/pstree.remy": { 2279 | "version": "1.1.8", 2280 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", 2281 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", 2282 | "dev": true 2283 | }, 2284 | "node_modules/punycode": { 2285 | "version": "2.3.0", 2286 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", 2287 | "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", 2288 | "engines": { 2289 | "node": ">=6" 2290 | } 2291 | }, 2292 | "node_modules/qs": { 2293 | "version": "6.11.0", 2294 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", 2295 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", 2296 | "dependencies": { 2297 | "side-channel": "^1.0.4" 2298 | }, 2299 | "engines": { 2300 | "node": ">=0.6" 2301 | }, 2302 | "funding": { 2303 | "url": "https://github.com/sponsors/ljharb" 2304 | } 2305 | }, 2306 | "node_modules/queue-microtask": { 2307 | "version": "1.2.3", 2308 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 2309 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 2310 | "dev": true, 2311 | "funding": [ 2312 | { 2313 | "type": "github", 2314 | "url": "https://github.com/sponsors/feross" 2315 | }, 2316 | { 2317 | "type": "patreon", 2318 | "url": "https://www.patreon.com/feross" 2319 | }, 2320 | { 2321 | "type": "consulting", 2322 | "url": "https://feross.org/support" 2323 | } 2324 | ] 2325 | }, 2326 | "node_modules/range-parser": { 2327 | "version": "1.2.1", 2328 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 2329 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 2330 | "engines": { 2331 | "node": ">= 0.6" 2332 | } 2333 | }, 2334 | "node_modules/raw-body": { 2335 | "version": "2.5.1", 2336 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", 2337 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", 2338 | "dependencies": { 2339 | "bytes": "3.1.2", 2340 | "http-errors": "2.0.0", 2341 | "iconv-lite": "0.4.24", 2342 | "unpipe": "1.0.0" 2343 | }, 2344 | "engines": { 2345 | "node": ">= 0.8" 2346 | } 2347 | }, 2348 | "node_modules/readdirp": { 2349 | "version": "3.6.0", 2350 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 2351 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 2352 | "dev": true, 2353 | "dependencies": { 2354 | "picomatch": "^2.2.1" 2355 | }, 2356 | "engines": { 2357 | "node": ">=8.10.0" 2358 | } 2359 | }, 2360 | "node_modules/requizzle": { 2361 | "version": "0.2.4", 2362 | "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", 2363 | "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", 2364 | "dev": true, 2365 | "dependencies": { 2366 | "lodash": "^4.17.21" 2367 | } 2368 | }, 2369 | "node_modules/resolve-from": { 2370 | "version": "4.0.0", 2371 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 2372 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 2373 | "dev": true, 2374 | "engines": { 2375 | "node": ">=4" 2376 | } 2377 | }, 2378 | "node_modules/reusify": { 2379 | "version": "1.0.4", 2380 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 2381 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 2382 | "dev": true, 2383 | "engines": { 2384 | "iojs": ">=1.0.0", 2385 | "node": ">=0.10.0" 2386 | } 2387 | }, 2388 | "node_modules/rimraf": { 2389 | "version": "3.0.2", 2390 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 2391 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 2392 | "dev": true, 2393 | "dependencies": { 2394 | "glob": "^7.1.3" 2395 | }, 2396 | "bin": { 2397 | "rimraf": "bin.js" 2398 | }, 2399 | "funding": { 2400 | "url": "https://github.com/sponsors/isaacs" 2401 | } 2402 | }, 2403 | "node_modules/run-parallel": { 2404 | "version": "1.2.0", 2405 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 2406 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 2407 | "dev": true, 2408 | "funding": [ 2409 | { 2410 | "type": "github", 2411 | "url": "https://github.com/sponsors/feross" 2412 | }, 2413 | { 2414 | "type": "patreon", 2415 | "url": "https://www.patreon.com/feross" 2416 | }, 2417 | { 2418 | "type": "consulting", 2419 | "url": "https://feross.org/support" 2420 | } 2421 | ], 2422 | "dependencies": { 2423 | "queue-microtask": "^1.2.2" 2424 | } 2425 | }, 2426 | "node_modules/safe-buffer": { 2427 | "version": "5.2.1", 2428 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 2429 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 2430 | "funding": [ 2431 | { 2432 | "type": "github", 2433 | "url": "https://github.com/sponsors/feross" 2434 | }, 2435 | { 2436 | "type": "patreon", 2437 | "url": "https://www.patreon.com/feross" 2438 | }, 2439 | { 2440 | "type": "consulting", 2441 | "url": "https://feross.org/support" 2442 | } 2443 | ] 2444 | }, 2445 | "node_modules/safer-buffer": { 2446 | "version": "2.1.2", 2447 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 2448 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 2449 | }, 2450 | "node_modules/semver": { 2451 | "version": "7.5.4", 2452 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", 2453 | "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", 2454 | "dependencies": { 2455 | "lru-cache": "^6.0.0" 2456 | }, 2457 | "bin": { 2458 | "semver": "bin/semver.js" 2459 | }, 2460 | "engines": { 2461 | "node": ">=10" 2462 | } 2463 | }, 2464 | "node_modules/send": { 2465 | "version": "0.18.0", 2466 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", 2467 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", 2468 | "dependencies": { 2469 | "debug": "2.6.9", 2470 | "depd": "2.0.0", 2471 | "destroy": "1.2.0", 2472 | "encodeurl": "~1.0.2", 2473 | "escape-html": "~1.0.3", 2474 | "etag": "~1.8.1", 2475 | "fresh": "0.5.2", 2476 | "http-errors": "2.0.0", 2477 | "mime": "1.6.0", 2478 | "ms": "2.1.3", 2479 | "on-finished": "2.4.1", 2480 | "range-parser": "~1.2.1", 2481 | "statuses": "2.0.1" 2482 | }, 2483 | "engines": { 2484 | "node": ">= 0.8.0" 2485 | } 2486 | }, 2487 | "node_modules/send/node_modules/ms": { 2488 | "version": "2.1.3", 2489 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 2490 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 2491 | }, 2492 | "node_modules/serve-static": { 2493 | "version": "1.15.0", 2494 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", 2495 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", 2496 | "dependencies": { 2497 | "encodeurl": "~1.0.2", 2498 | "escape-html": "~1.0.3", 2499 | "parseurl": "~1.3.3", 2500 | "send": "0.18.0" 2501 | }, 2502 | "engines": { 2503 | "node": ">= 0.8.0" 2504 | } 2505 | }, 2506 | "node_modules/setprototypeof": { 2507 | "version": "1.2.0", 2508 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 2509 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 2510 | }, 2511 | "node_modules/shebang-command": { 2512 | "version": "2.0.0", 2513 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 2514 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 2515 | "dev": true, 2516 | "dependencies": { 2517 | "shebang-regex": "^3.0.0" 2518 | }, 2519 | "engines": { 2520 | "node": ">=8" 2521 | } 2522 | }, 2523 | "node_modules/shebang-regex": { 2524 | "version": "3.0.0", 2525 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 2526 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 2527 | "dev": true, 2528 | "engines": { 2529 | "node": ">=8" 2530 | } 2531 | }, 2532 | "node_modules/side-channel": { 2533 | "version": "1.0.4", 2534 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 2535 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 2536 | "dependencies": { 2537 | "call-bind": "^1.0.0", 2538 | "get-intrinsic": "^1.0.2", 2539 | "object-inspect": "^1.9.0" 2540 | }, 2541 | "funding": { 2542 | "url": "https://github.com/sponsors/ljharb" 2543 | } 2544 | }, 2545 | "node_modules/sift": { 2546 | "version": "16.0.1", 2547 | "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", 2548 | "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" 2549 | }, 2550 | "node_modules/simple-update-notifier": { 2551 | "version": "2.0.0", 2552 | "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", 2553 | "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", 2554 | "dev": true, 2555 | "dependencies": { 2556 | "semver": "^7.5.3" 2557 | }, 2558 | "engines": { 2559 | "node": ">=10" 2560 | } 2561 | }, 2562 | "node_modules/sparse-bitfield": { 2563 | "version": "3.0.3", 2564 | "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", 2565 | "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", 2566 | "dependencies": { 2567 | "memory-pager": "^1.0.2" 2568 | } 2569 | }, 2570 | "node_modules/statuses": { 2571 | "version": "2.0.1", 2572 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 2573 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 2574 | "engines": { 2575 | "node": ">= 0.8" 2576 | } 2577 | }, 2578 | "node_modules/strip-ansi": { 2579 | "version": "6.0.1", 2580 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 2581 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 2582 | "dev": true, 2583 | "dependencies": { 2584 | "ansi-regex": "^5.0.1" 2585 | }, 2586 | "engines": { 2587 | "node": ">=8" 2588 | } 2589 | }, 2590 | "node_modules/strip-json-comments": { 2591 | "version": "3.1.1", 2592 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 2593 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 2594 | "dev": true, 2595 | "engines": { 2596 | "node": ">=8" 2597 | }, 2598 | "funding": { 2599 | "url": "https://github.com/sponsors/sindresorhus" 2600 | } 2601 | }, 2602 | "node_modules/supports-color": { 2603 | "version": "7.2.0", 2604 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 2605 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 2606 | "dev": true, 2607 | "dependencies": { 2608 | "has-flag": "^4.0.0" 2609 | }, 2610 | "engines": { 2611 | "node": ">=8" 2612 | } 2613 | }, 2614 | "node_modules/text-table": { 2615 | "version": "0.2.0", 2616 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 2617 | "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", 2618 | "dev": true 2619 | }, 2620 | "node_modules/to-regex-range": { 2621 | "version": "5.0.1", 2622 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 2623 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 2624 | "dev": true, 2625 | "dependencies": { 2626 | "is-number": "^7.0.0" 2627 | }, 2628 | "engines": { 2629 | "node": ">=8.0" 2630 | } 2631 | }, 2632 | "node_modules/toidentifier": { 2633 | "version": "1.0.1", 2634 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 2635 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 2636 | "engines": { 2637 | "node": ">=0.6" 2638 | } 2639 | }, 2640 | "node_modules/touch": { 2641 | "version": "3.1.0", 2642 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", 2643 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", 2644 | "dev": true, 2645 | "dependencies": { 2646 | "nopt": "~1.0.10" 2647 | }, 2648 | "bin": { 2649 | "nodetouch": "bin/nodetouch.js" 2650 | } 2651 | }, 2652 | "node_modules/tr46": { 2653 | "version": "4.1.1", 2654 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", 2655 | "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", 2656 | "dependencies": { 2657 | "punycode": "^2.3.0" 2658 | }, 2659 | "engines": { 2660 | "node": ">=14" 2661 | } 2662 | }, 2663 | "node_modules/type-check": { 2664 | "version": "0.4.0", 2665 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", 2666 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", 2667 | "dev": true, 2668 | "dependencies": { 2669 | "prelude-ls": "^1.2.1" 2670 | }, 2671 | "engines": { 2672 | "node": ">= 0.8.0" 2673 | } 2674 | }, 2675 | "node_modules/type-fest": { 2676 | "version": "0.20.2", 2677 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", 2678 | "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", 2679 | "dev": true, 2680 | "engines": { 2681 | "node": ">=10" 2682 | }, 2683 | "funding": { 2684 | "url": "https://github.com/sponsors/sindresorhus" 2685 | } 2686 | }, 2687 | "node_modules/type-is": { 2688 | "version": "1.6.18", 2689 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 2690 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 2691 | "dependencies": { 2692 | "media-typer": "0.3.0", 2693 | "mime-types": "~2.1.24" 2694 | }, 2695 | "engines": { 2696 | "node": ">= 0.6" 2697 | } 2698 | }, 2699 | "node_modules/uc.micro": { 2700 | "version": "1.0.6", 2701 | "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", 2702 | "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", 2703 | "dev": true 2704 | }, 2705 | "node_modules/undefsafe": { 2706 | "version": "2.0.5", 2707 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", 2708 | "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", 2709 | "dev": true 2710 | }, 2711 | "node_modules/underscore": { 2712 | "version": "1.13.6", 2713 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", 2714 | "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", 2715 | "dev": true 2716 | }, 2717 | "node_modules/unpipe": { 2718 | "version": "1.0.0", 2719 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 2720 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 2721 | "engines": { 2722 | "node": ">= 0.8" 2723 | } 2724 | }, 2725 | "node_modules/uri-js": { 2726 | "version": "4.4.1", 2727 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 2728 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 2729 | "dev": true, 2730 | "dependencies": { 2731 | "punycode": "^2.1.0" 2732 | } 2733 | }, 2734 | "node_modules/utils-merge": { 2735 | "version": "1.0.1", 2736 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 2737 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", 2738 | "engines": { 2739 | "node": ">= 0.4.0" 2740 | } 2741 | }, 2742 | "node_modules/vary": { 2743 | "version": "1.1.2", 2744 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 2745 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 2746 | "engines": { 2747 | "node": ">= 0.8" 2748 | } 2749 | }, 2750 | "node_modules/webidl-conversions": { 2751 | "version": "7.0.0", 2752 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", 2753 | "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", 2754 | "engines": { 2755 | "node": ">=12" 2756 | } 2757 | }, 2758 | "node_modules/whatwg-url": { 2759 | "version": "13.0.0", 2760 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", 2761 | "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", 2762 | "dependencies": { 2763 | "tr46": "^4.1.1", 2764 | "webidl-conversions": "^7.0.0" 2765 | }, 2766 | "engines": { 2767 | "node": ">=16" 2768 | } 2769 | }, 2770 | "node_modules/which": { 2771 | "version": "2.0.2", 2772 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 2773 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 2774 | "dev": true, 2775 | "dependencies": { 2776 | "isexe": "^2.0.0" 2777 | }, 2778 | "bin": { 2779 | "node-which": "bin/node-which" 2780 | }, 2781 | "engines": { 2782 | "node": ">= 8" 2783 | } 2784 | }, 2785 | "node_modules/wrappy": { 2786 | "version": "1.0.2", 2787 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2788 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 2789 | "dev": true 2790 | }, 2791 | "node_modules/xmlcreate": { 2792 | "version": "2.0.4", 2793 | "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", 2794 | "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", 2795 | "dev": true 2796 | }, 2797 | "node_modules/yallist": { 2798 | "version": "4.0.0", 2799 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 2800 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" 2801 | }, 2802 | "node_modules/yocto-queue": { 2803 | "version": "0.1.0", 2804 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 2805 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 2806 | "dev": true, 2807 | "engines": { 2808 | "node": ">=10" 2809 | }, 2810 | "funding": { 2811 | "url": "https://github.com/sponsors/sindresorhus" 2812 | } 2813 | } 2814 | } 2815 | } 2816 | --------------------------------------------------------------------------------