├── src ├── models │ ├── index.js │ ├── article.model.js │ └── user.model.js ├── constant │ └── index.js ├── middlewares │ ├── index.js │ ├── error.middleware.js │ ├── logger.middleware.js │ └── auth.middleware.js ├── config │ ├── database.config.js │ ├── paths.config.js │ └── passport.config.js ├── routes │ ├── index.js │ ├── auth.routes.js │ ├── users.routes.js │ └── articles.routes.js ├── seeders │ └── role.seeders.js ├── server.js ├── utils │ └── index.js └── controllers │ ├── auth.controller.js │ ├── user.controller.js │ └── article.controller.js ├── .gitignore ├── sample.env ├── package.json ├── README.md └── yarn.lock /src/models/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ArticleModel: require("./article.model.js"), 3 | UserModel: require("./user.model.js"), 4 | }; 5 | -------------------------------------------------------------------------------- /src/constant/index.js: -------------------------------------------------------------------------------- 1 | const ROLES = { 2 | ADMIN: "admin", 3 | MODERATOR: "moderator", 4 | USER: "user", 5 | }; 6 | 7 | module.exports = { 8 | ROLES, 9 | }; 10 | -------------------------------------------------------------------------------- /src/middlewares/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | logger: require("./logger.middleware"), 3 | authorize: require("./auth.middleware"), 4 | errorHandler: require("./error.middleware"), 5 | }; 6 | -------------------------------------------------------------------------------- /src/config/database.config.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const dbString = process.env.MONGOHQ_URL; 4 | const dbOptions = {}; 5 | const dbConnection = mongoose.createConnection(dbString, dbOptions); 6 | // Expose the connection 7 | module.exports = dbConnection; 8 | -------------------------------------------------------------------------------- /.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 | .env 26 | -------------------------------------------------------------------------------- /src/config/paths.config.js: -------------------------------------------------------------------------------- 1 | const authBaseURI = "/auth"; 2 | const userBaseURI = "/users"; 3 | const articleBaseURI = "/articles"; 4 | const activateAccountURI = "/activate-account"; 5 | 6 | const paths = { 7 | authBaseURI: authBaseURI, 8 | userBaseURI: userBaseURI, 9 | articleBaseURI: articleBaseURI, 10 | activateAccountURI: activateAccountURI, 11 | }; 12 | 13 | module.exports = paths; 14 | -------------------------------------------------------------------------------- /src/routes/index.js: -------------------------------------------------------------------------------- 1 | const { Router } = require("express"); 2 | 3 | const { 4 | articleBaseURI, 5 | authBaseURI, 6 | userBaseURI, 7 | } = require("../config/paths.config"); 8 | 9 | const router = Router(); 10 | 11 | router.use(authBaseURI, require("./auth.routes.js")); 12 | router.use(userBaseURI, require("./users.routes.js")); 13 | router.use(articleBaseURI, require("./articles.routes.js")); 14 | 15 | module.exports = router; 16 | -------------------------------------------------------------------------------- /src/middlewares/error.middleware.js: -------------------------------------------------------------------------------- 1 | function errorHandler(err, req, res, next) { 2 | console.log("Middleware Error Hadnling"); 3 | const errStatus = err.statusCode || 500; 4 | const errMsg = err.message || "Something went wrong"; 5 | return res.status(errStatus).json({ 6 | success: false, 7 | status: errStatus, 8 | message: errMsg, 9 | data: process.env.NODE_ENV === "development" ? err.stack : {}, 10 | }); 11 | } 12 | 13 | module.exports = errorHandler; 14 | -------------------------------------------------------------------------------- /src/middlewares/logger.middleware.js: -------------------------------------------------------------------------------- 1 | const colors = require("colors"); 2 | 3 | function logger(req, res, next) { 4 | const methodColor = { 5 | GET: "green", 6 | POST: "blue", 7 | PUT: "yellow", 8 | DELETE: "red", 9 | }; 10 | 11 | const color = methodColor[req.method] || "white"; 12 | 13 | console.log( 14 | `[${new Date().toLocaleString()}] ${req.method} ${req.protocol}://${req.get( 15 | "host" 16 | )}${req.originalUrl}`[color] 17 | ); 18 | next(); 19 | } 20 | 21 | module.exports = logger; 22 | -------------------------------------------------------------------------------- /src/middlewares/auth.middleware.js: -------------------------------------------------------------------------------- 1 | const { throwError } = require("../utils"); 2 | 3 | function authorize(roles) { 4 | return (req, res, next) => { 5 | const { role } = req.user; 6 | 7 | try { 8 | if (roles.includes(role)) { 9 | return next(); // User is authorized, proceed to the next middleware or route handler 10 | } 11 | 12 | throwError(403, `You are not authorize to perform this action`); 13 | } catch (error) { 14 | return next(error); 15 | } 16 | }; 17 | } 18 | 19 | module.exports = authorize; 20 | -------------------------------------------------------------------------------- /src/config/passport.config.js: -------------------------------------------------------------------------------- 1 | const JwtStrategy = require("passport-jwt").Strategy; 2 | const ExtractJwt = require("passport-jwt").ExtractJwt; 3 | const UserModel = require("../models/user.model"); 4 | 5 | const options = { 6 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), 7 | secretOrKey: process.env.JWT_SECRET, 8 | }; 9 | 10 | module.exports = (passport) => { 11 | passport.use( 12 | new JwtStrategy(options, async (jwt_payload, done) => { 13 | const user = await UserModel.findOne({ 14 | email: jwt_payload.email, 15 | }); 16 | 17 | if (user) { 18 | return done(null, user); 19 | } 20 | 21 | return done(null, false); 22 | }) 23 | ); 24 | }; 25 | -------------------------------------------------------------------------------- /sample.env: -------------------------------------------------------------------------------- 1 | # App port 2 | #PORT = 5000 3 | 4 | # NODE ENV 5 | # development or production 6 | #NODE_ENV = development 7 | 8 | # Database 9 | #MONGOHQ_URL = mongodb://localhost:27017/miniblog 10 | 11 | # Hosts 12 | #API_HOST = "your API_HOST" 13 | #CLIENT_HOST = "your CLIENT_HOST" 14 | 15 | # Session, Cookie and JWT encryption strings 16 | #SESSION_SECRET = "reughoshgosuhfihseiuhgfisoegdfohqqnblkwb" 17 | #JWT_SECRET = "reug][hoshgosuhfih@_àéjp687gser976&&)l896@" 18 | 19 | # Admin secret signup params rout 20 | #ADMIN_SECRET_SIGNUP_PARAMS_ROUTE = "lskglmjlhnpophgesg6gv54vctvh686646879xlfh" 21 | 22 | # Nodemailer 23 | # "Gmail" or other service on production 24 | # "mailhog" or other service on development 25 | #NODEMAILER_SERVICE = "mailhog" 26 | #NODEMAILER_USER = "may@gmail.com" 27 | #NODEMAILER_PASS = "myPassWord" -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-js-mvc-tuto", 3 | "version": "1.0.0", 4 | "main": "./src/server.js", 5 | "repository": "https://github.com/Randy-RM/express-js-mvc-tuto.git", 6 | "author": "Randy-RM ", 7 | "license": "MIT", 8 | "scripts": { 9 | "dev": "nodemon ./src/server.js", 10 | "prod": "node ./src/server.js", 11 | "seed": "node ./src/seeders/role.seeders.js" 12 | }, 13 | "dependencies": { 14 | "bcrypt": "^5.1.1", 15 | "colors": "^1.4.0", 16 | "cors": "^2.8.5", 17 | "dotenv": "^16.4.5", 18 | "express": "^4.18.3", 19 | "helmet": "^8.0.0", 20 | "jsonwebtoken": "^9.0.2", 21 | "lodash": "^4.17.21", 22 | "mongodb": "^6.4.0", 23 | "mongoose": "^8.2.1", 24 | "nodemailer": "^6.9.13", 25 | "passport": "^0.7.0", 26 | "passport-jwt": "^4.0.1" 27 | }, 28 | "devDependencies": { 29 | "nodemon": "^3.1.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/models/article.model.js: -------------------------------------------------------------------------------- 1 | const { Schema } = require("mongoose"); 2 | const dbConnection = require("../config/database.config"); 3 | 4 | const ArticleSchema = new Schema( 5 | { 6 | title: { 7 | type: String, 8 | required: [true, "Please enter title"], 9 | }, 10 | summary: { 11 | type: String, 12 | required: [true, "Please enter content"], 13 | }, 14 | content: { 15 | type: String, 16 | required: [true, "Please enter content"], 17 | }, 18 | isPublished: { 19 | type: Boolean, 20 | default: false, 21 | }, 22 | isArchived: { type: Boolean, default: false }, 23 | user: { 24 | type: Schema.Types.ObjectId, 25 | ref: "User", 26 | required: [true, "User is required for article"], 27 | }, 28 | }, 29 | { 30 | timestamps: true, 31 | } 32 | ); 33 | 34 | const ArticleModel = dbConnection.model("Article", ArticleSchema); 35 | 36 | module.exports = ArticleModel; 37 | -------------------------------------------------------------------------------- /src/routes/auth.routes.js: -------------------------------------------------------------------------------- 1 | const { Router } = require("express"); 2 | const { 3 | activateAccount, 4 | deleteAccount, 5 | logout, 6 | recoverAccount, 7 | signin, 8 | signup, 9 | } = require("../controllers/auth.controller.js"); 10 | 11 | const authRouter = Router(); 12 | 13 | // Create and save a new user account. 14 | authRouter.post("/signup", signup); 15 | 16 | // Create and save a new admin account. 17 | authRouter.post(`/signup/:adminRouteParams`, signup); 18 | 19 | // Verify and confirm user account. 20 | authRouter.get("/activate-account/:uniqueString", activateAccount); 21 | 22 | // Signin if user have an account. 23 | authRouter.post("/signin", signin); 24 | 25 | // Recover account if user have one. 26 | authRouter.post("/recover-account", recoverAccount); 27 | 28 | // Logout user. 29 | authRouter.get("/logout", logout); 30 | 31 | // Delete user account 32 | authRouter.post("/delete-account", deleteAccount); 33 | 34 | module.exports = authRouter; 35 | -------------------------------------------------------------------------------- /src/models/user.model.js: -------------------------------------------------------------------------------- 1 | const bcrypt = require("bcrypt"); 2 | const { Schema } = require("mongoose"); 3 | const dbConnection = require("../config/database.config"); 4 | const { ROLES } = require("../constant"); 5 | 6 | const validRoles = [ROLES.USER, ROLES.MODERATOR, ROLES.ADMIN]; 7 | 8 | const UserSchema = new Schema({ 9 | username: { 10 | type: String, 11 | required: [true, "Please enter user name"], 12 | }, 13 | email: { 14 | type: String, 15 | required: [true, "Please enter email"], 16 | unique: true, 17 | }, 18 | password: { 19 | type: String, 20 | required: [true, "Please enter password"], 21 | }, 22 | isUserActive: { 23 | type: Boolean, 24 | default: false, 25 | }, 26 | uniqueString: { 27 | type: String, 28 | }, 29 | role: { 30 | type: String, 31 | enum: validRoles, 32 | default: "user", 33 | }, 34 | }); 35 | 36 | UserSchema.methods.isUserPassword = async function (password) { 37 | const user = this; 38 | const compare = await bcrypt.compare(password, user.password); 39 | return compare; 40 | }; 41 | 42 | const UserModel = dbConnection.model("User", UserSchema); 43 | 44 | module.exports = UserModel; 45 | -------------------------------------------------------------------------------- /src/seeders/role.seeders.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | const Role = require("../models/role.model"); 3 | const mongoose = require("mongoose"); 4 | 5 | //get your mongoose string 6 | const dbUrl = process.env.MONGOHQ_URL; 7 | 8 | //create your array. i inserted only 1 object here 9 | const roles = [ 10 | new Role({ roleName: "admin" }), 11 | new Role({ roleName: "author" }), 12 | new Role({ roleName: "user" }), 13 | ]; 14 | //connect mongoose 15 | mongoose 16 | .connect(String(dbUrl), {}) 17 | .catch((err) => { 18 | console.log(err.stack); 19 | process.exit(1); 20 | }) 21 | .then(() => { 22 | console.log("connected to db in development environment"); 23 | }); 24 | 25 | const clearAndCreateNewRoleCollection = async () => { 26 | await Role.deleteMany({}) 27 | .then((roleCollection) => { 28 | // Number of documents deleted 29 | console.log("Role deleted", roleCollection.deletedCount); 30 | //save your data. this is an async operation 31 | //after you make sure you seeded all the roles, disconnect automatically 32 | roles.map(async (role, index) => { 33 | await role.save(); 34 | if (index === roles.length - 1) { 35 | console.log("seed done"); 36 | mongoose.disconnect(); 37 | } 38 | }); 39 | }) 40 | .catch(() => console.log("Role collection deletion failed")); 41 | }; 42 | 43 | clearAndCreateNewRoleCollection(); 44 | -------------------------------------------------------------------------------- /src/routes/users.routes.js: -------------------------------------------------------------------------------- 1 | const { Router } = require("express"); 2 | const passport = require("passport"); 3 | const { 4 | createUser, 5 | deleteAllUsers, 6 | deleteUser, 7 | getAllUsers, 8 | getOneUser, 9 | updateUser, 10 | } = require("../controllers/user.controller.js"); 11 | const { authorize } = require("../middlewares"); 12 | 13 | const { ROLES } = require("../constant"); 14 | 15 | const userRouter = Router(); 16 | 17 | //Get all users 18 | userRouter.get( 19 | `/`, 20 | [passport.authenticate("jwt", { session: false }), authorize([ROLES.ADMIN])], 21 | getAllUsers 22 | ); 23 | 24 | //Get one user by userId 25 | userRouter.get( 26 | `/:userId`, 27 | [passport.authenticate("jwt", { session: false })], 28 | getOneUser 29 | ); 30 | 31 | //Create a new user 32 | userRouter.post( 33 | `/`, 34 | [passport.authenticate("jwt", { session: false }), authorize([ROLES.ADMIN])], 35 | createUser 36 | ); 37 | 38 | //Update user by userId 39 | userRouter.put( 40 | `/:userId`, 41 | [passport.authenticate("jwt", { session: false })], 42 | updateUser 43 | ); 44 | 45 | //Delete user by userId 46 | userRouter.delete( 47 | `/:userId`, 48 | [passport.authenticate("jwt", { session: false })], 49 | deleteUser 50 | ); 51 | 52 | //Delete all users 53 | userRouter.delete( 54 | `/`, 55 | [passport.authenticate("jwt", { session: false }), authorize([ROLES.ADMIN])], 56 | deleteAllUsers 57 | ); 58 | 59 | module.exports = userRouter; 60 | -------------------------------------------------------------------------------- /src/routes/articles.routes.js: -------------------------------------------------------------------------------- 1 | const { Router } = require("express"); 2 | const passport = require("passport"); 3 | const { 4 | createArticle, 5 | deleteAllArticles, 6 | deleteArticle, 7 | getAllArticles, 8 | getOneArticle, 9 | getUserArticles, 10 | updateArticle, 11 | } = require("../controllers/article.controller.js"); 12 | const { authorize } = require("../middlewares"); 13 | 14 | const { ROLES } = require("../constant"); 15 | 16 | const articleRouter = Router(); 17 | 18 | //Get all articles 19 | articleRouter.get(`/`, getAllArticles); 20 | 21 | //Get one article by articleId 22 | articleRouter.get(`/:articleId`, getOneArticle); 23 | 24 | //Get user articles by userId 25 | articleRouter.get( 26 | `/:userId/articles`, 27 | [ 28 | passport.authenticate("jwt", { session: false }), 29 | authorize([ROLES.ADMIN, ROLES.MODERATOR]), 30 | ], 31 | getUserArticles 32 | ); 33 | 34 | //Create a new article 35 | articleRouter.post( 36 | `/`, 37 | [passport.authenticate("jwt", { session: false }), authorize([ROLES.ADMIN])], 38 | createArticle 39 | ); 40 | 41 | //Update article by articleId 42 | articleRouter.put( 43 | `/:articleId`, 44 | [ 45 | passport.authenticate("jwt", { session: false }), 46 | authorize([ROLES.ADMIN, ROLES.MODERATOR]), 47 | ], 48 | updateArticle 49 | ); 50 | 51 | //Delete article by articleId 52 | articleRouter.delete( 53 | `/:articleId`, 54 | [ 55 | passport.authenticate("jwt", { session: false }), 56 | authorize([ROLES.ADMIN, ROLES.MODERATOR]), 57 | ], 58 | deleteArticle 59 | ); 60 | 61 | //Delete all articles 62 | articleRouter.delete( 63 | `/`, 64 | [passport.authenticate("jwt", { session: false }), authorize([ROLES.ADMIN])], 65 | deleteAllArticles 66 | ); 67 | 68 | module.exports = articleRouter; 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Welcome to this Node JS & Express Js BackEnd project 2 | 3 | 4 | 5 | This project has been set up to help those who are new to **BackEnd** programming with **Javascript** in a **Node Js** environment. It has been organized following a few best practices such as the **MVC** design pattern, the **Camel case** naming convention, etc... 6 | 7 | ### Note 8 | 9 | > This application is a simple blog API with role-based authentication. 10 | 11 | ## Overview of main technologies used 12 | 13 | - **Express Js** : It's a Node Js Framework that helps us quickly set up an **API**. [Express Js Doc](https://expressjs.com/) 14 | - **MongoDB** : This is our document-oriented NoSql database. 15 | - **Passport Js** : It's our authentication middleware that integrates easily with Express Js. [Passport Js Doc](https://www.passportjs.org/) 16 | - **Mongoose** : It's our middleware that makes it easy to manipulate entities in a database. [Mongoose Js Doc](https://mongoosejs.com/) 17 | 18 | ## Project installation 19 | 20 | 1. Installation of dependencies : Open the terminal at the root of the project and type the command `yarn install` . 21 | 2. Rename `sample.env` file to `.env` . 22 | 3. Uncomment **environment variables** in the newly renamed `.env` file. 23 | 4. Replace the value of `MONGOHQ_URL` environment variable in your `.env` file with the link to your **MongoDB database**. 24 | 5. Return to the previously opened terminal and type command `yarn seed` 25 | 6. Launch the project in **Dev mode** by typing the command `yarn dev` 26 | 27 | ### Note 28 | 29 | > You can use this project as a basis exemple for getting started your backEnd 30 | > projects with Node Js & Express Js 31 | -------------------------------------------------------------------------------- /src/server.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | const express = require("express"); 3 | const cors = require("cors"); 4 | const helmet = require("helmet"); 5 | const passport = require("passport"); 6 | const dbConnection = require("./config/database.config"); 7 | const router = require("./routes"); 8 | const { logger, errorHandler } = require("./middlewares"); 9 | 10 | /** 11 | * -------------- GENERAL SETUP ---------------- 12 | */ 13 | const app = express(); 14 | const PORT = process.env.PORT || 8000; 15 | const corsOptions = { 16 | origin: 17 | process.env.NODE_ENV === "production" 18 | ? [`${process.env.API_HOST}`, `${process.env.CLIENT_HOST}`] 19 | : "*", 20 | }; 21 | app.use(express.json()); 22 | app.use(express.urlencoded({ extended: false })); 23 | app.use(cors(corsOptions)); 24 | app.use(helmet()); 25 | app.use((req, res, next) => { 26 | res.header( 27 | "Access-Control-Allow-Headers", 28 | "x-access-token, Origin, Content-Type, Accept" 29 | ); 30 | next(); 31 | }); 32 | 33 | /** 34 | * -------------- PASSPORT AUTHENTICATION ---------------- 35 | */ 36 | // Need to require the entire Passport config 37 | // module so index.js knows about it 38 | require("./config/passport.config")(passport); 39 | app.use(passport.initialize()); 40 | 41 | /** 42 | * -------------- ROUTE ---------------- 43 | */ 44 | // logger middleware 45 | app.use(logger); 46 | // Imports all of the routes 47 | // from ./routes/index 48 | app.use("/api", router); 49 | app.get("/api", (req, res, next) => { 50 | return res.json({ message: "Welcome to Express MVC Tuto API" }); 51 | }); 52 | // Register the error handler middleware 53 | // ERROR HANDLER MIDDLEWARE (Last middleware to use) 54 | app.use(errorHandler); 55 | 56 | /** 57 | * -------------- RUN SERVER ---------------- 58 | */ 59 | dbConnection.once("open", () => { 60 | console.log("Successful connection to DB"); 61 | app.listen(PORT, () => { 62 | console.log(`Server listen on http://localhost:${PORT}`); 63 | }); 64 | }); 65 | 66 | dbConnection.on("error", (error) => { 67 | console.log("DB connection error : ", error); 68 | console.log(`Server can't listen on http://localhost:${PORT}`); 69 | }); 70 | -------------------------------------------------------------------------------- /src/utils/index.js: -------------------------------------------------------------------------------- 1 | const nodemailer = require("nodemailer"); 2 | const { RoleModel } = require("../models/index.js"); 3 | const { authBaseURI, activateAccountURI } = require("../config/paths.config"); 4 | const { ROLES } = require("../constant"); 5 | 6 | async function getRoles() { 7 | try { 8 | const roles = await RoleModel.find().select("roleName"); 9 | const rolesNames = roles.map(({ roleName }) => roleName); 10 | const userRoles = Object.fromEntries( 11 | rolesNames.map((role) => [role, role]) 12 | ); 13 | return userRoles; 14 | } catch (error) { 15 | console.log(error); 16 | throw error; 17 | } 18 | } 19 | 20 | function isRoleExist(role) { 21 | return [ROLES.ADMIN, ROLES.MODERATOR, ROLES.USER].includes(role); 22 | } 23 | 24 | function isAllowedToManipulate(resourceOwnerId, connectedUser) { 25 | const { id: loggedUserId, role: loggedUserRole } = connectedUser; 26 | if (resourceOwnerId != loggedUserId) { 27 | if (loggedUserRole != ROLES.ADMIN) { 28 | return false; 29 | } 30 | } 31 | return true; 32 | } 33 | 34 | function randomStringGenerator() { 35 | // considering a 8 length string 36 | const stringLength = 8; 37 | let randomString = ""; 38 | for (let i = 0; i < stringLength; i++) { 39 | randomString += Math.floor(Math.random() * 10 + 1); 40 | } 41 | return randomString; 42 | } 43 | 44 | async function sendAccountActivationEmail(email, uniqueString, apiHostDomain) { 45 | let transport; 46 | if (process.env.NODE_ENV === "development") { 47 | transport = nodemailer.createTransport({ 48 | service: process.env.NODEMAILER_SERVICE, 49 | port: 1025, 50 | }); 51 | } else { 52 | // on production env get this kind of config 53 | transport = nodemailer.createTransport({ 54 | service: process.env.NODEMAILER_SERVICE, 55 | auth: { 56 | user: process.env.NODEMAILER_USER, 57 | pass: process.env.NODEMAILER_PASS, 58 | }, 59 | }); 60 | } 61 | 62 | const sender = "MiniBlog My Company "; 63 | const mailOptions = { 64 | from: sender, 65 | to: email, 66 | subject: "Email confirmation", 67 | html: `Press Here to verify your email.`, 68 | }; 69 | 70 | transport.sendMail(mailOptions, (error, response) => { 71 | if (error) { 72 | console.log("Confirmation email not sent"); 73 | console.log(error); 74 | } else { 75 | console.log("Confirmation email sent"); 76 | } 77 | }); 78 | } 79 | 80 | function throwError(errorStatusCode, errorMessage) { 81 | const error = new Error(`${errorMessage}`); 82 | error.statusCode = errorStatusCode; 83 | throw error; 84 | } 85 | 86 | module.exports = { 87 | getRoles: getRoles, 88 | isRoleExist: isRoleExist, 89 | isAllowedToManipulate: isAllowedToManipulate, 90 | randomStringGenerator: randomStringGenerator, 91 | sendAccountActivationEmail: sendAccountActivationEmail, 92 | throwError: throwError, 93 | }; 94 | -------------------------------------------------------------------------------- /src/controllers/auth.controller.js: -------------------------------------------------------------------------------- 1 | const bcrypt = require("bcrypt"); 2 | const jwt = require("jsonwebtoken"); 3 | const { UserModel } = require("../models"); 4 | const { 5 | randomStringGenerator, 6 | throwError, 7 | /** 8 | * to be uncommented 9 | * to set up mail sending, 10 | * activation and confirmation functionality 11 | */ 12 | // sendAccountActivationEmail, 13 | } = require("../utils"); 14 | 15 | /* 16 | -------------------------- 17 | Create and save a new user 18 | in the database 19 | -------------------------- 20 | */ 21 | async function signup(req, res, next) { 22 | const { adminRouteParams } = req.params; 23 | const { username, email, password } = req.body; 24 | /** 25 | * to be uncommented 26 | * to set up mail sending, 27 | * activation and confirmation functionality 28 | */ 29 | // const apiHostDomain = req.headers.host; 30 | const adminSecret = process.env.ADMIN_SECRET_SIGNUP_PARAMS_ROUTE; 31 | const userRole = 32 | adminRouteParams && adminRouteParams === adminSecret ? "admin" : "user"; 33 | 34 | try { 35 | const hashedPassword = await bcrypt.hash(password, 10); 36 | 37 | await UserModel.create({ 38 | username: username, 39 | email: email, 40 | password: hashedPassword, 41 | uniqueString: randomStringGenerator(), 42 | role: userRole, 43 | /** 44 | * to be commented 45 | * to set up mail sending, 46 | * activation and confirmation functionality 47 | */ 48 | isUserActive: true, 49 | }); 50 | 51 | /** 52 | * to be uncommented 53 | * to set up mail sending, 54 | * activation and confirmation functionality 55 | */ 56 | // send mail to user 57 | // sendAccountActivationEmail( 58 | // newUser.email, 59 | // newUser.uniqueString, 60 | // apiHostDomain 61 | // ); 62 | 63 | return res.status(201).json({ message: "User created" }); 64 | } catch (error) { 65 | return next(error); 66 | } 67 | } 68 | 69 | /* 70 | -------------------------- 71 | Activate user account 72 | -------------------------- 73 | */ 74 | async function activateAccount(req, res, next) { 75 | // getting the string 76 | const { uniqueString } = req.params; 77 | const filter = { uniqueString: uniqueString }; 78 | const update = { isUserActive: true }; 79 | 80 | try { 81 | // check is there is anyone with this string and update 82 | const user = await UserModel.findOneAndUpdate(filter, update, { 83 | returnOriginal: false, 84 | }); 85 | 86 | if (!user) { 87 | throwError(500, `problems arising from verification`); 88 | } 89 | 90 | console.log("User account is activated"); 91 | return res.json({ message: "User account is activated" }); 92 | // return res.redirect(`${process.env.CLIENT_HOST}${process.env.CLIENT_VERIFY}`); 93 | } catch (error) { 94 | return next(error); 95 | } 96 | } 97 | 98 | /* 99 | -------------------------- 100 | Signin if user have an account 101 | and roles 102 | -------------------------- 103 | */ 104 | async function signin(req, res, next) { 105 | const { email, password } = req.body; 106 | 107 | try { 108 | const user = await UserModel.findOne({ email: email }); 109 | 110 | if (!user) { 111 | throwError(404, `User with this email "${email}" not found`); 112 | } 113 | 114 | const passwordMatch = await user.isUserPassword(password); 115 | 116 | if (!passwordMatch) { 117 | throwError(400, `Invalid password for "${email}"`); 118 | } 119 | 120 | const token = jwt.sign({ email: user.email }, process.env.JWT_SECRET, { 121 | expiresIn: "1h", 122 | }); 123 | 124 | return res.json({ 125 | message: "Logged in successfully", 126 | data: { 127 | user: { 128 | username: user.username, 129 | email: user.email, 130 | userRole: user.role, 131 | }, 132 | token: token, 133 | }, 134 | }); 135 | } catch (error) { 136 | return next(error); 137 | } 138 | } 139 | 140 | /* 141 | -------------------------- 142 | Logout if user is logged 143 | -------------------------- 144 | */ 145 | async function logout(req, res) { 146 | req.logout(function (error) { 147 | if (error) { 148 | return res.status(500).json({ message: error.message }); 149 | } 150 | return res.send("User is logout"); 151 | }); 152 | } 153 | 154 | /* 155 | -------------------------- 156 | Recover user account 157 | -------------------------- 158 | */ 159 | async function recoverAccount(req, res) { 160 | return res.send("User account is recovered"); 161 | } 162 | 163 | /* 164 | -------------------------- 165 | Delete user account 166 | -------------------------- 167 | */ 168 | async function deleteAccount(req, res) { 169 | return res.send("User account is deleted"); 170 | } 171 | 172 | module.exports = { 173 | activateAccount, 174 | deleteAccount, 175 | logout, 176 | recoverAccount, 177 | signin, 178 | signup, 179 | }; 180 | -------------------------------------------------------------------------------- /src/controllers/user.controller.js: -------------------------------------------------------------------------------- 1 | const bcrypt = require("bcrypt"); 2 | const { UserModel } = require("../models"); 3 | const { isAllowedToManipulate, isRoleExist, throwError } = require("../utils"); 4 | 5 | /* 6 | -------------------------- 7 | Retrieve one user from 8 | the database. 9 | -------------------------- 10 | */ 11 | async function getOneUser(req, res, next) { 12 | const { userId } = req.params; 13 | const { user: connectedUser } = req; 14 | 15 | try { 16 | const user = await UserModel.findById(userId); 17 | 18 | if (!user) { 19 | throwError(404, `User with id "${userId}" not found`); 20 | } 21 | 22 | if (!isAllowedToManipulate(user.id, connectedUser)) { 23 | throwError(401, `Unauthorized to manipulate resource`); 24 | } 25 | 26 | return res.status(200).json({ 27 | success: true, 28 | status: 200, 29 | message: `User found`, 30 | data: user, 31 | }); 32 | } catch (error) { 33 | return next(error); 34 | } 35 | } 36 | 37 | /* 38 | -------------------------- 39 | Retrieve all users from 40 | the database. 41 | -------------------------- 42 | */ 43 | async function getAllUsers(req, res, next) { 44 | const { cursor, limit = 10 } = req.query; 45 | let query = {}; 46 | 47 | // If a cursor is provided, add it to the query 48 | if (cursor) { 49 | query = { _id: { $gt: cursor } }; 50 | } 51 | 52 | try { 53 | const users = await UserModel.find({ ...query }).limit(Number(limit)); 54 | 55 | if (!users || users.length === 0) { 56 | throwError(404, `Users not found`); 57 | } 58 | 59 | // Extract the next and previous cursor from the result 60 | const prevCursor = cursor && users.length > 0 ? users[0]._id : null; 61 | const nextCursor = users.length > 0 ? users[users.length - 1]._id : null; 62 | 63 | return res.status(200).json({ 64 | success: true, 65 | status: 200, 66 | message: `Users found`, 67 | data: { 68 | nextCursor, 69 | prevCursor, 70 | totalResults: users.length, 71 | data: users, 72 | }, 73 | }); 74 | } catch (error) { 75 | return next(error); 76 | } 77 | } 78 | 79 | /* 80 | -------------------------- 81 | Create and save a new user 82 | in the database 83 | -------------------------- 84 | */ 85 | async function createUser(req, res, next) { 86 | const { username, email, password, role } = req.body; 87 | 88 | try { 89 | const hashedPassword = await bcrypt.hash(password, 10); 90 | 91 | if (!isRoleExist(role) && role != undefined) { 92 | throwError(422, `The role "${role}" does not exist`); 93 | } 94 | 95 | const user = await UserModel.create({ 96 | username, 97 | email, 98 | password: hashedPassword, 99 | isUserActive: true, 100 | role: role || undefined, 101 | }) 102 | .then((user) => { 103 | return { 104 | username: user.username, 105 | email: user.email, 106 | isUserActive: user.isUserActive, 107 | role: user.role, 108 | }; 109 | }) 110 | .catch((error) => { 111 | throwError(422, `User already exists with email "${email}"`); 112 | }); 113 | 114 | return res.status(201).json({ 115 | success: true, 116 | status: 201, 117 | message: `User created`, 118 | data: user, 119 | }); 120 | } catch (error) { 121 | return next(error); 122 | } 123 | } 124 | 125 | /* 126 | -------------------------- 127 | Update a user by the id 128 | in the request 129 | -------------------------- 130 | */ 131 | async function updateUser(req, res, next) { 132 | const { userId } = req.params; 133 | const { user: connectedUser } = req; 134 | 135 | try { 136 | let user = await UserModel.findById(userId); 137 | 138 | if (!user) { 139 | throwError(404, `User with id "${userId}" not found`); 140 | } 141 | 142 | if (!isAllowedToManipulate(user.id, connectedUser)) { 143 | throwError(401, `Unauthorized to manipulate resource`); 144 | } 145 | 146 | user = await UserModel.findByIdAndUpdate( 147 | userId, 148 | { ...req.body }, 149 | { 150 | select: { _id: 1, username: 1, email: 1, role: 1, isUserActive: 1 }, 151 | new: true, 152 | } 153 | ); 154 | 155 | return res.status(200).json({ 156 | success: true, 157 | status: 200, 158 | message: `User updated successfully`, 159 | data: user, 160 | }); 161 | } catch (error) { 162 | return next(error); 163 | } 164 | } 165 | 166 | /* 167 | -------------------------- 168 | Delete a user with 169 | the specified id 170 | in the request 171 | -------------------------- 172 | */ 173 | async function deleteUser(req, res, next) { 174 | const { userId } = req.params; 175 | const { user: connectedUser } = req; 176 | 177 | try { 178 | const user = await UserModel.findById(userId); 179 | 180 | if (!user) { 181 | throwError(404, `User with id "${userId}" not found`); 182 | } 183 | 184 | if (!isAllowedToManipulate(user.id, connectedUser)) { 185 | throwError(401, `Unauthorized to manipulate resource`); 186 | } 187 | 188 | await user.deleteOne(); 189 | 190 | return res.status(200).json({ 191 | success: true, 192 | status: 200, 193 | message: `User deleted successfully`, 194 | data: {}, 195 | }); 196 | } catch (error) { 197 | return next(error); 198 | } 199 | } 200 | 201 | /* 202 | -------------------------- 203 | Delete all users from 204 | the database. 205 | -------------------------- 206 | */ 207 | async function deleteAllUsers(req, res) { 208 | return res.send("Users are deleted"); 209 | } 210 | 211 | module.exports = { 212 | createUser, 213 | deleteAllUsers, 214 | deleteUser, 215 | getAllUsers, 216 | getOneUser, 217 | updateUser, 218 | }; 219 | -------------------------------------------------------------------------------- /src/controllers/article.controller.js: -------------------------------------------------------------------------------- 1 | const { ArticleModel, UserModel } = require("../models"); 2 | const { isAllowedToManipulate, throwError } = require("../utils"); 3 | 4 | /* 5 | -------------------------- 6 | Retrieve one article from 7 | the database. 8 | -------------------------- 9 | */ 10 | async function getOneArticle(req, res, next) { 11 | const { articleId } = req.params; 12 | 13 | try { 14 | const article = await ArticleModel.findById(articleId).populate({ 15 | path: "user", 16 | model: "User", 17 | select: { _id: 0, username: 1, email: 1 }, 18 | }); 19 | 20 | if (!article) { 21 | throwError(404, `Article with id "${articleId}" not found`); 22 | } 23 | 24 | return res.status(200).json({ 25 | success: true, 26 | status: 200, 27 | message: `Article found`, 28 | data: article, 29 | }); 30 | } catch (error) { 31 | return next(error); 32 | } 33 | } 34 | 35 | /* 36 | -------------------------- 37 | Retrieve user articles from 38 | the database. 39 | -------------------------- 40 | */ 41 | async function getUserArticles(req, res, next) { 42 | const { userId } = req.params; 43 | const { cursor, limit = 10 } = req.query; 44 | let query = {}; 45 | 46 | // If a cursor is provided, add it to the query 47 | if (cursor) { 48 | query = { _id: { $gt: cursor } }; 49 | } 50 | 51 | try { 52 | const articles = await ArticleModel.find({ user: userId, ...query }) 53 | .select({ 54 | id: 1, 55 | title: 1, 56 | summary: 1, 57 | isPublished: 1, 58 | isArchived: 1, 59 | createdAt: 1, 60 | }) 61 | .limit(Number(limit)); 62 | 63 | if (!articles || articles.length === 0) { 64 | throwError(404, `Articles not found`); 65 | } 66 | 67 | // Extract the next and previous cursor from the result 68 | const prevCursor = cursor && articles.length > 0 ? articles[0]._id : null; 69 | const nextCursor = 70 | articles.length > 0 ? articles[articles.length - 1]._id : null; 71 | 72 | return res.status(200).json({ 73 | success: true, 74 | status: 200, 75 | message: `Articles found`, 76 | data: { 77 | nextCursor, 78 | prevCursor, 79 | totalResults: articles.length, 80 | data: articles, 81 | }, 82 | }); 83 | } catch (error) { 84 | return next(error); 85 | } 86 | } 87 | 88 | /* 89 | -------------------------- 90 | Retrieve all articles from 91 | the database. 92 | -------------------------- 93 | */ 94 | async function getAllArticles(req, res, next) { 95 | const { 96 | cursor, 97 | limit = 10, 98 | sort = "desc", 99 | isPublished = false, 100 | isArchived = false, 101 | } = req.query; 102 | let query = {}; 103 | 104 | // If a cursor is provided, add it to the query 105 | if (cursor) { 106 | query = { ...query, _id: { $gt: cursor } }; 107 | } 108 | if (isPublished) { 109 | query = { ...query, isPublished: isPublished }; 110 | } 111 | if (isArchived) { 112 | query = { ...query, isArchived: isArchived }; 113 | } 114 | 115 | try { 116 | // Fetch articles using the cursor-based query 117 | const articles = await ArticleModel.find({ ...query }) 118 | .select({ title: 1, summary: 1, createdAt: 1 }) 119 | .populate({ 120 | path: "user", 121 | model: "User", 122 | select: { _id: 0, username: 1, email: 1 }, 123 | }) 124 | .limit(Number(limit)); 125 | 126 | if (!articles || articles.length === 0) { 127 | throwError(404, `Articles not found`); 128 | } 129 | 130 | // Extract the next and previous cursor from the result 131 | const prevCursor = cursor && articles.length > 0 ? articles[0]._id : null; 132 | const nextCursor = 133 | articles.length > 0 ? articles[articles.length - 1]._id : null; 134 | 135 | return res.status(200).json({ 136 | success: true, 137 | status: 200, 138 | message: `Articles found`, 139 | data: { 140 | nextCursor, 141 | prevCursor, 142 | totalResults: articles.length, 143 | data: articles, 144 | }, 145 | }); 146 | } catch (error) { 147 | return next(error); 148 | } 149 | } 150 | 151 | /* 152 | -------------------------- 153 | Create and save a new article 154 | in the database 155 | -------------------------- 156 | */ 157 | async function createArticle(req, res, next) { 158 | const { id: userId } = req.user; 159 | 160 | try { 161 | const user = await UserModel.findById(userId); 162 | 163 | if (!user) { 164 | throwError(500, `Something went wrong`); 165 | } 166 | 167 | let article = await ArticleModel.create({ ...req.body, user }); 168 | article = await article.populate({ 169 | path: "user", 170 | model: "User", 171 | select: { _id: 0, username: 1, email: 1 }, 172 | }); 173 | 174 | return res.status(201).json({ 175 | success: true, 176 | status: 201, 177 | message: `Article created`, 178 | data: article, 179 | }); 180 | } catch (error) { 181 | return next(error); 182 | } 183 | } 184 | 185 | /* 186 | -------------------------- 187 | Update article by the id 188 | in the request 189 | -------------------------- 190 | */ 191 | async function updateArticle(req, res, next) { 192 | const { articleId } = req.params; 193 | const { user: connectedUser } = req; 194 | 195 | try { 196 | let article = await ArticleModel.findById(articleId); 197 | 198 | if (!article) { 199 | throwError(404, `Article with id "${articleId}" not found`); 200 | } 201 | 202 | if (!isAllowedToManipulate(article.user, connectedUser)) { 203 | throwError(401, `Unauthorized to manipulate resource`); 204 | } 205 | 206 | article = await ArticleModel.findByIdAndUpdate( 207 | articleId, 208 | { 209 | ...req.body, 210 | }, 211 | { new: true } 212 | ).populate({ 213 | path: "user", 214 | model: "User", 215 | select: { _id: 0, username: 1, email: 1 }, 216 | }); 217 | 218 | return res.status(200).json({ 219 | success: true, 220 | status: 200, 221 | message: `Article updated successfully`, 222 | data: article, 223 | }); 224 | } catch (error) { 225 | return next(error); 226 | } 227 | } 228 | 229 | /* 230 | -------------------------- 231 | Delete article with 232 | the specified id 233 | in the request 234 | -------------------------- 235 | */ 236 | async function deleteArticle(req, res, next) { 237 | const { articleId } = req.params; 238 | const { user: connectedUser } = req; 239 | 240 | try { 241 | const article = await ArticleModel.findById(articleId).populate({ 242 | path: "user", 243 | model: "User", 244 | select: { _id: 0, username: 1, email: 1 }, 245 | }); 246 | 247 | if (!article) { 248 | throwError(404, `Article with id "${articleId}" not found`); 249 | } 250 | 251 | if (!isAllowedToManipulate(article.user, connectedUser)) { 252 | throwError(401, `Unauthorized to manipulate resource`); 253 | } 254 | 255 | await article.deleteOne(); 256 | 257 | return res.status(200).json({ 258 | success: true, 259 | status: 200, 260 | message: `Article deleted successfully`, 261 | data: article, 262 | }); 263 | } catch (error) { 264 | return next(error); 265 | } 266 | } 267 | 268 | /* 269 | -------------------------- 270 | Delete all articles from 271 | the database. 272 | -------------------------- 273 | */ 274 | async function deleteAllArticles(req, res) { 275 | return res.send("Articles are deleted"); 276 | } 277 | 278 | module.exports = { 279 | createArticle, 280 | deleteAllArticles, 281 | deleteArticle, 282 | getAllArticles, 283 | getOneArticle, 284 | getUserArticles, 285 | updateArticle, 286 | }; 287 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@mapbox/node-pre-gyp@^1.0.11": 6 | version "1.0.11" 7 | resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa" 8 | integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ== 9 | dependencies: 10 | detect-libc "^2.0.0" 11 | https-proxy-agent "^5.0.0" 12 | make-dir "^3.1.0" 13 | node-fetch "^2.6.7" 14 | nopt "^5.0.0" 15 | npmlog "^5.0.1" 16 | rimraf "^3.0.2" 17 | semver "^7.3.5" 18 | tar "^6.1.11" 19 | 20 | "@mongodb-js/saslprep@^1.1.5": 21 | version "1.1.7" 22 | resolved "https://registry.yarnpkg.com/@mongodb-js/saslprep/-/saslprep-1.1.7.tgz#d1700facfd6916c50c2c88fd6d48d363a56c702f" 23 | integrity sha512-dCHW/oEX0KJ4NjDULBo3JiOaK5+6axtpBbS+ao2ZInoAL9/YRQLhXzSNAFz7hP4nzLkIqsfYAK/PDE3+XHny0Q== 24 | dependencies: 25 | sparse-bitfield "^3.0.3" 26 | 27 | "@types/webidl-conversions@*": 28 | version "7.0.3" 29 | resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz#1306dbfa53768bcbcfc95a1c8cde367975581859" 30 | integrity sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA== 31 | 32 | "@types/whatwg-url@^11.0.2": 33 | version "11.0.5" 34 | resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-11.0.5.tgz#aaa2546e60f0c99209ca13360c32c78caf2c409f" 35 | integrity sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ== 36 | dependencies: 37 | "@types/webidl-conversions" "*" 38 | 39 | abbrev@1: 40 | version "1.1.1" 41 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" 42 | integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== 43 | 44 | accepts@~1.3.8: 45 | version "1.3.8" 46 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" 47 | integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== 48 | dependencies: 49 | mime-types "~2.1.34" 50 | negotiator "0.6.3" 51 | 52 | agent-base@6: 53 | version "6.0.2" 54 | resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" 55 | integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== 56 | dependencies: 57 | debug "4" 58 | 59 | ansi-regex@^5.0.1: 60 | version "5.0.1" 61 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" 62 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 63 | 64 | anymatch@~3.1.2: 65 | version "3.1.3" 66 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" 67 | integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== 68 | dependencies: 69 | normalize-path "^3.0.0" 70 | picomatch "^2.0.4" 71 | 72 | "aproba@^1.0.3 || ^2.0.0": 73 | version "2.0.0" 74 | resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" 75 | integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== 76 | 77 | are-we-there-yet@^2.0.0: 78 | version "2.0.0" 79 | resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" 80 | integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== 81 | dependencies: 82 | delegates "^1.0.0" 83 | readable-stream "^3.6.0" 84 | 85 | array-flatten@1.1.1: 86 | version "1.1.1" 87 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 88 | integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== 89 | 90 | balanced-match@^1.0.0: 91 | version "1.0.2" 92 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 93 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 94 | 95 | bcrypt@^5.1.1: 96 | version "5.1.1" 97 | resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-5.1.1.tgz#0f732c6dcb4e12e5b70a25e326a72965879ba6e2" 98 | integrity sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww== 99 | dependencies: 100 | "@mapbox/node-pre-gyp" "^1.0.11" 101 | node-addon-api "^5.0.0" 102 | 103 | binary-extensions@^2.0.0: 104 | version "2.3.0" 105 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" 106 | integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== 107 | 108 | body-parser@1.20.2: 109 | version "1.20.2" 110 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" 111 | integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== 112 | dependencies: 113 | bytes "3.1.2" 114 | content-type "~1.0.5" 115 | debug "2.6.9" 116 | depd "2.0.0" 117 | destroy "1.2.0" 118 | http-errors "2.0.0" 119 | iconv-lite "0.4.24" 120 | on-finished "2.4.1" 121 | qs "6.11.0" 122 | raw-body "2.5.2" 123 | type-is "~1.6.18" 124 | unpipe "1.0.0" 125 | 126 | brace-expansion@^1.1.7: 127 | version "1.1.11" 128 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 129 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 130 | dependencies: 131 | balanced-match "^1.0.0" 132 | concat-map "0.0.1" 133 | 134 | braces@~3.0.2: 135 | version "3.0.3" 136 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" 137 | integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== 138 | dependencies: 139 | fill-range "^7.1.1" 140 | 141 | bson@^6.7.0: 142 | version "6.7.0" 143 | resolved "https://registry.yarnpkg.com/bson/-/bson-6.7.0.tgz#51973b132cdc424c8372fda3cb43e3e3e2ae2227" 144 | integrity sha512-w2IquM5mYzYZv6rs3uN2DZTOBe2a0zXLj53TGDqwF4l6Sz/XsISrisXOJihArF9+BZ6Cq/GjVht7Sjfmri7ytQ== 145 | 146 | buffer-equal-constant-time@1.0.1: 147 | version "1.0.1" 148 | resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" 149 | integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== 150 | 151 | bytes@3.1.2: 152 | version "3.1.2" 153 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" 154 | integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== 155 | 156 | call-bind@^1.0.7: 157 | version "1.0.7" 158 | resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" 159 | integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== 160 | dependencies: 161 | es-define-property "^1.0.0" 162 | es-errors "^1.3.0" 163 | function-bind "^1.1.2" 164 | get-intrinsic "^1.2.4" 165 | set-function-length "^1.2.1" 166 | 167 | chokidar@^3.5.2: 168 | version "3.6.0" 169 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" 170 | integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== 171 | dependencies: 172 | anymatch "~3.1.2" 173 | braces "~3.0.2" 174 | glob-parent "~5.1.2" 175 | is-binary-path "~2.1.0" 176 | is-glob "~4.0.1" 177 | normalize-path "~3.0.0" 178 | readdirp "~3.6.0" 179 | optionalDependencies: 180 | fsevents "~2.3.2" 181 | 182 | chownr@^2.0.0: 183 | version "2.0.0" 184 | resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" 185 | integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== 186 | 187 | color-support@^1.1.2: 188 | version "1.1.3" 189 | resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" 190 | integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== 191 | 192 | colors@^1.4.0: 193 | version "1.4.0" 194 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" 195 | integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== 196 | 197 | concat-map@0.0.1: 198 | version "0.0.1" 199 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 200 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== 201 | 202 | console-control-strings@^1.0.0, console-control-strings@^1.1.0: 203 | version "1.1.0" 204 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" 205 | integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== 206 | 207 | content-disposition@0.5.4: 208 | version "0.5.4" 209 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" 210 | integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== 211 | dependencies: 212 | safe-buffer "5.2.1" 213 | 214 | content-type@~1.0.4, content-type@~1.0.5: 215 | version "1.0.5" 216 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" 217 | integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== 218 | 219 | cookie-signature@1.0.6: 220 | version "1.0.6" 221 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 222 | integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== 223 | 224 | cookie@0.6.0: 225 | version "0.6.0" 226 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" 227 | integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== 228 | 229 | cors@^2.8.5: 230 | version "2.8.5" 231 | resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" 232 | integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== 233 | dependencies: 234 | object-assign "^4" 235 | vary "^1" 236 | 237 | debug@2.6.9: 238 | version "2.6.9" 239 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 240 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 241 | dependencies: 242 | ms "2.0.0" 243 | 244 | debug@4, debug@4.x, debug@^4: 245 | version "4.3.4" 246 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" 247 | integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== 248 | dependencies: 249 | ms "2.1.2" 250 | 251 | define-data-property@^1.1.4: 252 | version "1.1.4" 253 | resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" 254 | integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== 255 | dependencies: 256 | es-define-property "^1.0.0" 257 | es-errors "^1.3.0" 258 | gopd "^1.0.1" 259 | 260 | delegates@^1.0.0: 261 | version "1.0.0" 262 | resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" 263 | integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== 264 | 265 | depd@2.0.0: 266 | version "2.0.0" 267 | resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" 268 | integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== 269 | 270 | destroy@1.2.0: 271 | version "1.2.0" 272 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" 273 | integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== 274 | 275 | detect-libc@^2.0.0: 276 | version "2.0.3" 277 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" 278 | integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== 279 | 280 | dotenv@^16.4.5: 281 | version "16.4.5" 282 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" 283 | integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== 284 | 285 | ecdsa-sig-formatter@1.0.11: 286 | version "1.0.11" 287 | resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" 288 | integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== 289 | dependencies: 290 | safe-buffer "^5.0.1" 291 | 292 | ee-first@1.1.1: 293 | version "1.1.1" 294 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 295 | integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== 296 | 297 | emoji-regex@^8.0.0: 298 | version "8.0.0" 299 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 300 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 301 | 302 | encodeurl@~1.0.2: 303 | version "1.0.2" 304 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 305 | integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== 306 | 307 | es-define-property@^1.0.0: 308 | version "1.0.0" 309 | resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" 310 | integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== 311 | dependencies: 312 | get-intrinsic "^1.2.4" 313 | 314 | es-errors@^1.3.0: 315 | version "1.3.0" 316 | resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" 317 | integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== 318 | 319 | escape-html@~1.0.3: 320 | version "1.0.3" 321 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 322 | integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== 323 | 324 | etag@~1.8.1: 325 | version "1.8.1" 326 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" 327 | integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== 328 | 329 | express@^4.18.3: 330 | version "4.19.2" 331 | resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" 332 | integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== 333 | dependencies: 334 | accepts "~1.3.8" 335 | array-flatten "1.1.1" 336 | body-parser "1.20.2" 337 | content-disposition "0.5.4" 338 | content-type "~1.0.4" 339 | cookie "0.6.0" 340 | cookie-signature "1.0.6" 341 | debug "2.6.9" 342 | depd "2.0.0" 343 | encodeurl "~1.0.2" 344 | escape-html "~1.0.3" 345 | etag "~1.8.1" 346 | finalhandler "1.2.0" 347 | fresh "0.5.2" 348 | http-errors "2.0.0" 349 | merge-descriptors "1.0.1" 350 | methods "~1.1.2" 351 | on-finished "2.4.1" 352 | parseurl "~1.3.3" 353 | path-to-regexp "0.1.7" 354 | proxy-addr "~2.0.7" 355 | qs "6.11.0" 356 | range-parser "~1.2.1" 357 | safe-buffer "5.2.1" 358 | send "0.18.0" 359 | serve-static "1.15.0" 360 | setprototypeof "1.2.0" 361 | statuses "2.0.1" 362 | type-is "~1.6.18" 363 | utils-merge "1.0.1" 364 | vary "~1.1.2" 365 | 366 | fill-range@^7.1.1: 367 | version "7.1.1" 368 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" 369 | integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== 370 | dependencies: 371 | to-regex-range "^5.0.1" 372 | 373 | finalhandler@1.2.0: 374 | version "1.2.0" 375 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" 376 | integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== 377 | dependencies: 378 | debug "2.6.9" 379 | encodeurl "~1.0.2" 380 | escape-html "~1.0.3" 381 | on-finished "2.4.1" 382 | parseurl "~1.3.3" 383 | statuses "2.0.1" 384 | unpipe "~1.0.0" 385 | 386 | forwarded@0.2.0: 387 | version "0.2.0" 388 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" 389 | integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== 390 | 391 | fresh@0.5.2: 392 | version "0.5.2" 393 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 394 | integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== 395 | 396 | fs-minipass@^2.0.0: 397 | version "2.1.0" 398 | resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" 399 | integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== 400 | dependencies: 401 | minipass "^3.0.0" 402 | 403 | fs.realpath@^1.0.0: 404 | version "1.0.0" 405 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 406 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 407 | 408 | fsevents@~2.3.2: 409 | version "2.3.3" 410 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" 411 | integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== 412 | 413 | function-bind@^1.1.2: 414 | version "1.1.2" 415 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" 416 | integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== 417 | 418 | gauge@^3.0.0: 419 | version "3.0.2" 420 | resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" 421 | integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== 422 | dependencies: 423 | aproba "^1.0.3 || ^2.0.0" 424 | color-support "^1.1.2" 425 | console-control-strings "^1.0.0" 426 | has-unicode "^2.0.1" 427 | object-assign "^4.1.1" 428 | signal-exit "^3.0.0" 429 | string-width "^4.2.3" 430 | strip-ansi "^6.0.1" 431 | wide-align "^1.1.2" 432 | 433 | get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: 434 | version "1.2.4" 435 | resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" 436 | integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== 437 | dependencies: 438 | es-errors "^1.3.0" 439 | function-bind "^1.1.2" 440 | has-proto "^1.0.1" 441 | has-symbols "^1.0.3" 442 | hasown "^2.0.0" 443 | 444 | glob-parent@~5.1.2: 445 | version "5.1.2" 446 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 447 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 448 | dependencies: 449 | is-glob "^4.0.1" 450 | 451 | glob@^7.1.3: 452 | version "7.2.3" 453 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" 454 | integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== 455 | dependencies: 456 | fs.realpath "^1.0.0" 457 | inflight "^1.0.4" 458 | inherits "2" 459 | minimatch "^3.1.1" 460 | once "^1.3.0" 461 | path-is-absolute "^1.0.0" 462 | 463 | gopd@^1.0.1: 464 | version "1.0.1" 465 | resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" 466 | integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== 467 | dependencies: 468 | get-intrinsic "^1.1.3" 469 | 470 | has-flag@^3.0.0: 471 | version "3.0.0" 472 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 473 | integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== 474 | 475 | has-property-descriptors@^1.0.2: 476 | version "1.0.2" 477 | resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" 478 | integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== 479 | dependencies: 480 | es-define-property "^1.0.0" 481 | 482 | has-proto@^1.0.1: 483 | version "1.0.3" 484 | resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" 485 | integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== 486 | 487 | has-symbols@^1.0.3: 488 | version "1.0.3" 489 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" 490 | integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== 491 | 492 | has-unicode@^2.0.1: 493 | version "2.0.1" 494 | resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" 495 | integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== 496 | 497 | hasown@^2.0.0: 498 | version "2.0.2" 499 | resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" 500 | integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== 501 | dependencies: 502 | function-bind "^1.1.2" 503 | 504 | helmet@^8.0.0: 505 | version "8.0.0" 506 | resolved "https://registry.yarnpkg.com/helmet/-/helmet-8.0.0.tgz#05370fb1953aa7b81bd0ddfa459221247be6ea5c" 507 | integrity sha512-VyusHLEIIO5mjQPUI1wpOAEu+wl6Q0998jzTxqUYGE45xCIcAxy3MsbEK/yyJUJ3ADeMoB6MornPH6GMWAf+Pw== 508 | 509 | http-errors@2.0.0: 510 | version "2.0.0" 511 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" 512 | integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== 513 | dependencies: 514 | depd "2.0.0" 515 | inherits "2.0.4" 516 | setprototypeof "1.2.0" 517 | statuses "2.0.1" 518 | toidentifier "1.0.1" 519 | 520 | https-proxy-agent@^5.0.0: 521 | version "5.0.1" 522 | resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" 523 | integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== 524 | dependencies: 525 | agent-base "6" 526 | debug "4" 527 | 528 | iconv-lite@0.4.24: 529 | version "0.4.24" 530 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 531 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 532 | dependencies: 533 | safer-buffer ">= 2.1.2 < 3" 534 | 535 | ignore-by-default@^1.0.1: 536 | version "1.0.1" 537 | resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" 538 | integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA== 539 | 540 | inflight@^1.0.4: 541 | version "1.0.6" 542 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 543 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 544 | dependencies: 545 | once "^1.3.0" 546 | wrappy "1" 547 | 548 | inherits@2, inherits@2.0.4, inherits@^2.0.3: 549 | version "2.0.4" 550 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 551 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 552 | 553 | ipaddr.js@1.9.1: 554 | version "1.9.1" 555 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" 556 | integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== 557 | 558 | is-binary-path@~2.1.0: 559 | version "2.1.0" 560 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 561 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 562 | dependencies: 563 | binary-extensions "^2.0.0" 564 | 565 | is-extglob@^2.1.1: 566 | version "2.1.1" 567 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 568 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== 569 | 570 | is-fullwidth-code-point@^3.0.0: 571 | version "3.0.0" 572 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 573 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 574 | 575 | is-glob@^4.0.1, is-glob@~4.0.1: 576 | version "4.0.3" 577 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 578 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 579 | dependencies: 580 | is-extglob "^2.1.1" 581 | 582 | is-number@^7.0.0: 583 | version "7.0.0" 584 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 585 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 586 | 587 | jsonwebtoken@^9.0.0, jsonwebtoken@^9.0.2: 588 | version "9.0.2" 589 | resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" 590 | integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== 591 | dependencies: 592 | jws "^3.2.2" 593 | lodash.includes "^4.3.0" 594 | lodash.isboolean "^3.0.3" 595 | lodash.isinteger "^4.0.4" 596 | lodash.isnumber "^3.0.3" 597 | lodash.isplainobject "^4.0.6" 598 | lodash.isstring "^4.0.1" 599 | lodash.once "^4.0.0" 600 | ms "^2.1.1" 601 | semver "^7.5.4" 602 | 603 | jwa@^1.4.1: 604 | version "1.4.1" 605 | resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" 606 | integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== 607 | dependencies: 608 | buffer-equal-constant-time "1.0.1" 609 | ecdsa-sig-formatter "1.0.11" 610 | safe-buffer "^5.0.1" 611 | 612 | jws@^3.2.2: 613 | version "3.2.2" 614 | resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" 615 | integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== 616 | dependencies: 617 | jwa "^1.4.1" 618 | safe-buffer "^5.0.1" 619 | 620 | kareem@2.6.3: 621 | version "2.6.3" 622 | resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.6.3.tgz#23168ec8ffb6c1abfd31b7169a6fb1dd285992ac" 623 | integrity sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q== 624 | 625 | lodash.includes@^4.3.0: 626 | version "4.3.0" 627 | resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" 628 | integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== 629 | 630 | lodash.isboolean@^3.0.3: 631 | version "3.0.3" 632 | resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" 633 | integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== 634 | 635 | lodash.isinteger@^4.0.4: 636 | version "4.0.4" 637 | resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" 638 | integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== 639 | 640 | lodash.isnumber@^3.0.3: 641 | version "3.0.3" 642 | resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" 643 | integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== 644 | 645 | lodash.isplainobject@^4.0.6: 646 | version "4.0.6" 647 | resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" 648 | integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== 649 | 650 | lodash.isstring@^4.0.1: 651 | version "4.0.1" 652 | resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" 653 | integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== 654 | 655 | lodash.once@^4.0.0: 656 | version "4.1.1" 657 | resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" 658 | integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== 659 | 660 | lodash@^4.17.21: 661 | version "4.17.21" 662 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 663 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 664 | 665 | make-dir@^3.1.0: 666 | version "3.1.0" 667 | resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" 668 | integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== 669 | dependencies: 670 | semver "^6.0.0" 671 | 672 | media-typer@0.3.0: 673 | version "0.3.0" 674 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 675 | integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== 676 | 677 | memory-pager@^1.0.2: 678 | version "1.5.0" 679 | resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" 680 | integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== 681 | 682 | merge-descriptors@1.0.1: 683 | version "1.0.1" 684 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 685 | integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== 686 | 687 | methods@~1.1.2: 688 | version "1.1.2" 689 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 690 | integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== 691 | 692 | mime-db@1.52.0: 693 | version "1.52.0" 694 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" 695 | integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== 696 | 697 | mime-types@~2.1.24, mime-types@~2.1.34: 698 | version "2.1.35" 699 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" 700 | integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== 701 | dependencies: 702 | mime-db "1.52.0" 703 | 704 | mime@1.6.0: 705 | version "1.6.0" 706 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" 707 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== 708 | 709 | minimatch@^3.1.1, minimatch@^3.1.2: 710 | version "3.1.2" 711 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 712 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 713 | dependencies: 714 | brace-expansion "^1.1.7" 715 | 716 | minipass@^3.0.0: 717 | version "3.3.6" 718 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" 719 | integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== 720 | dependencies: 721 | yallist "^4.0.0" 722 | 723 | minipass@^5.0.0: 724 | version "5.0.0" 725 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" 726 | integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== 727 | 728 | minizlib@^2.1.1: 729 | version "2.1.2" 730 | resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" 731 | integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== 732 | dependencies: 733 | minipass "^3.0.0" 734 | yallist "^4.0.0" 735 | 736 | mkdirp@^1.0.3: 737 | version "1.0.4" 738 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" 739 | integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== 740 | 741 | mongodb-connection-string-url@^3.0.0: 742 | version "3.0.1" 743 | resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz#c13e6ac284ae401752ebafdb8cd7f16c6723b141" 744 | integrity sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg== 745 | dependencies: 746 | "@types/whatwg-url" "^11.0.2" 747 | whatwg-url "^13.0.0" 748 | 749 | mongodb@6.6.2, mongodb@^6.4.0: 750 | version "6.6.2" 751 | resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-6.6.2.tgz#7ecdd788e9162f6c5726cef40bdd2813cc01e56c" 752 | integrity sha512-ZF9Ugo2JCG/GfR7DEb4ypfyJJyiKbg5qBYKRintebj8+DNS33CyGMkWbrS9lara+u+h+yEOGSRiLhFO/g1s1aw== 753 | dependencies: 754 | "@mongodb-js/saslprep" "^1.1.5" 755 | bson "^6.7.0" 756 | mongodb-connection-string-url "^3.0.0" 757 | 758 | mongoose@^8.2.1: 759 | version "8.4.0" 760 | resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-8.4.0.tgz#b5236cf0a02e40aba3a329148a6ceccc9d9d4ac7" 761 | integrity sha512-fgqRMwVEP1qgRYfh+tUe2YBBFnPO35FIg2lfFH+w9IhRGg1/ataWGIqvf/MjwM29cZ60D5vSnqtN2b8Qp0sOZA== 762 | dependencies: 763 | bson "^6.7.0" 764 | kareem "2.6.3" 765 | mongodb "6.6.2" 766 | mpath "0.9.0" 767 | mquery "5.0.0" 768 | ms "2.1.3" 769 | sift "17.1.3" 770 | 771 | mpath@0.9.0: 772 | version "0.9.0" 773 | resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.9.0.tgz#0c122fe107846e31fc58c75b09c35514b3871904" 774 | integrity sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew== 775 | 776 | mquery@5.0.0: 777 | version "5.0.0" 778 | resolved "https://registry.yarnpkg.com/mquery/-/mquery-5.0.0.tgz#a95be5dfc610b23862df34a47d3e5d60e110695d" 779 | integrity sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg== 780 | dependencies: 781 | debug "4.x" 782 | 783 | ms@2.0.0: 784 | version "2.0.0" 785 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 786 | integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== 787 | 788 | ms@2.1.2: 789 | version "2.1.2" 790 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 791 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 792 | 793 | ms@2.1.3, ms@^2.1.1: 794 | version "2.1.3" 795 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 796 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 797 | 798 | negotiator@0.6.3: 799 | version "0.6.3" 800 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" 801 | integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== 802 | 803 | node-addon-api@^5.0.0: 804 | version "5.1.0" 805 | resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" 806 | integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== 807 | 808 | node-fetch@^2.6.7: 809 | version "2.7.0" 810 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" 811 | integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== 812 | dependencies: 813 | whatwg-url "^5.0.0" 814 | 815 | nodemailer@^6.9.13: 816 | version "6.9.13" 817 | resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.13.tgz#5b292bf1e92645f4852ca872c56a6ba6c4a3d3d6" 818 | integrity sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA== 819 | 820 | nodemon@^3.1.0: 821 | version "3.1.0" 822 | resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-3.1.0.tgz#ff7394f2450eb6a5e96fe4180acd5176b29799c9" 823 | integrity sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA== 824 | dependencies: 825 | chokidar "^3.5.2" 826 | debug "^4" 827 | ignore-by-default "^1.0.1" 828 | minimatch "^3.1.2" 829 | pstree.remy "^1.1.8" 830 | semver "^7.5.3" 831 | simple-update-notifier "^2.0.0" 832 | supports-color "^5.5.0" 833 | touch "^3.1.0" 834 | undefsafe "^2.0.5" 835 | 836 | nopt@^5.0.0: 837 | version "5.0.0" 838 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" 839 | integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== 840 | dependencies: 841 | abbrev "1" 842 | 843 | normalize-path@^3.0.0, normalize-path@~3.0.0: 844 | version "3.0.0" 845 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 846 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 847 | 848 | npmlog@^5.0.1: 849 | version "5.0.1" 850 | resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" 851 | integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== 852 | dependencies: 853 | are-we-there-yet "^2.0.0" 854 | console-control-strings "^1.1.0" 855 | gauge "^3.0.0" 856 | set-blocking "^2.0.0" 857 | 858 | object-assign@^4, object-assign@^4.1.1: 859 | version "4.1.1" 860 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 861 | integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== 862 | 863 | object-inspect@^1.13.1: 864 | version "1.13.1" 865 | resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" 866 | integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== 867 | 868 | on-finished@2.4.1: 869 | version "2.4.1" 870 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" 871 | integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== 872 | dependencies: 873 | ee-first "1.1.1" 874 | 875 | once@^1.3.0: 876 | version "1.4.0" 877 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 878 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 879 | dependencies: 880 | wrappy "1" 881 | 882 | parseurl@~1.3.3: 883 | version "1.3.3" 884 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" 885 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== 886 | 887 | passport-jwt@^4.0.1: 888 | version "4.0.1" 889 | resolved "https://registry.yarnpkg.com/passport-jwt/-/passport-jwt-4.0.1.tgz#c443795eff322c38d173faa0a3c481479646ec3d" 890 | integrity sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ== 891 | dependencies: 892 | jsonwebtoken "^9.0.0" 893 | passport-strategy "^1.0.0" 894 | 895 | passport-strategy@1.x.x, passport-strategy@^1.0.0: 896 | version "1.0.0" 897 | resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" 898 | integrity sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA== 899 | 900 | passport@^0.7.0: 901 | version "0.7.0" 902 | resolved "https://registry.yarnpkg.com/passport/-/passport-0.7.0.tgz#3688415a59a48cf8068417a8a8092d4492ca3a05" 903 | integrity sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ== 904 | dependencies: 905 | passport-strategy "1.x.x" 906 | pause "0.0.1" 907 | utils-merge "^1.0.1" 908 | 909 | path-is-absolute@^1.0.0: 910 | version "1.0.1" 911 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 912 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 913 | 914 | path-to-regexp@0.1.7: 915 | version "0.1.7" 916 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 917 | integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== 918 | 919 | pause@0.0.1: 920 | version "0.0.1" 921 | resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" 922 | integrity sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg== 923 | 924 | picomatch@^2.0.4, picomatch@^2.2.1: 925 | version "2.3.1" 926 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 927 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 928 | 929 | proxy-addr@~2.0.7: 930 | version "2.0.7" 931 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" 932 | integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== 933 | dependencies: 934 | forwarded "0.2.0" 935 | ipaddr.js "1.9.1" 936 | 937 | pstree.remy@^1.1.8: 938 | version "1.1.8" 939 | resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" 940 | integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== 941 | 942 | punycode@^2.3.0: 943 | version "2.3.1" 944 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" 945 | integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== 946 | 947 | qs@6.11.0: 948 | version "6.11.0" 949 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" 950 | integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== 951 | dependencies: 952 | side-channel "^1.0.4" 953 | 954 | range-parser@~1.2.1: 955 | version "1.2.1" 956 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" 957 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== 958 | 959 | raw-body@2.5.2: 960 | version "2.5.2" 961 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" 962 | integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== 963 | dependencies: 964 | bytes "3.1.2" 965 | http-errors "2.0.0" 966 | iconv-lite "0.4.24" 967 | unpipe "1.0.0" 968 | 969 | readable-stream@^3.6.0: 970 | version "3.6.2" 971 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" 972 | integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== 973 | dependencies: 974 | inherits "^2.0.3" 975 | string_decoder "^1.1.1" 976 | util-deprecate "^1.0.1" 977 | 978 | readdirp@~3.6.0: 979 | version "3.6.0" 980 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" 981 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== 982 | dependencies: 983 | picomatch "^2.2.1" 984 | 985 | rimraf@^3.0.2: 986 | version "3.0.2" 987 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" 988 | integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== 989 | dependencies: 990 | glob "^7.1.3" 991 | 992 | safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0: 993 | version "5.2.1" 994 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 995 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 996 | 997 | "safer-buffer@>= 2.1.2 < 3": 998 | version "2.1.2" 999 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 1000 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 1001 | 1002 | semver@^6.0.0: 1003 | version "6.3.1" 1004 | resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" 1005 | integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== 1006 | 1007 | semver@^7.3.5, semver@^7.5.3, semver@^7.5.4: 1008 | version "7.6.2" 1009 | resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" 1010 | integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== 1011 | 1012 | send@0.18.0: 1013 | version "0.18.0" 1014 | resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" 1015 | integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== 1016 | dependencies: 1017 | debug "2.6.9" 1018 | depd "2.0.0" 1019 | destroy "1.2.0" 1020 | encodeurl "~1.0.2" 1021 | escape-html "~1.0.3" 1022 | etag "~1.8.1" 1023 | fresh "0.5.2" 1024 | http-errors "2.0.0" 1025 | mime "1.6.0" 1026 | ms "2.1.3" 1027 | on-finished "2.4.1" 1028 | range-parser "~1.2.1" 1029 | statuses "2.0.1" 1030 | 1031 | serve-static@1.15.0: 1032 | version "1.15.0" 1033 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" 1034 | integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== 1035 | dependencies: 1036 | encodeurl "~1.0.2" 1037 | escape-html "~1.0.3" 1038 | parseurl "~1.3.3" 1039 | send "0.18.0" 1040 | 1041 | set-blocking@^2.0.0: 1042 | version "2.0.0" 1043 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 1044 | integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== 1045 | 1046 | set-function-length@^1.2.1: 1047 | version "1.2.2" 1048 | resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" 1049 | integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== 1050 | dependencies: 1051 | define-data-property "^1.1.4" 1052 | es-errors "^1.3.0" 1053 | function-bind "^1.1.2" 1054 | get-intrinsic "^1.2.4" 1055 | gopd "^1.0.1" 1056 | has-property-descriptors "^1.0.2" 1057 | 1058 | setprototypeof@1.2.0: 1059 | version "1.2.0" 1060 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" 1061 | integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== 1062 | 1063 | side-channel@^1.0.4: 1064 | version "1.0.6" 1065 | resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" 1066 | integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== 1067 | dependencies: 1068 | call-bind "^1.0.7" 1069 | es-errors "^1.3.0" 1070 | get-intrinsic "^1.2.4" 1071 | object-inspect "^1.13.1" 1072 | 1073 | sift@17.1.3: 1074 | version "17.1.3" 1075 | resolved "https://registry.yarnpkg.com/sift/-/sift-17.1.3.tgz#9d2000d4d41586880b0079b5183d839c7a142bf7" 1076 | integrity sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ== 1077 | 1078 | signal-exit@^3.0.0: 1079 | version "3.0.7" 1080 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" 1081 | integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== 1082 | 1083 | simple-update-notifier@^2.0.0: 1084 | version "2.0.0" 1085 | resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz#d70b92bdab7d6d90dfd73931195a30b6e3d7cebb" 1086 | integrity sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w== 1087 | dependencies: 1088 | semver "^7.5.3" 1089 | 1090 | sparse-bitfield@^3.0.3: 1091 | version "3.0.3" 1092 | resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" 1093 | integrity sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ== 1094 | dependencies: 1095 | memory-pager "^1.0.2" 1096 | 1097 | statuses@2.0.1: 1098 | version "2.0.1" 1099 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" 1100 | integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== 1101 | 1102 | "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.3: 1103 | version "4.2.3" 1104 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 1105 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 1106 | dependencies: 1107 | emoji-regex "^8.0.0" 1108 | is-fullwidth-code-point "^3.0.0" 1109 | strip-ansi "^6.0.1" 1110 | 1111 | string_decoder@^1.1.1: 1112 | version "1.3.0" 1113 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" 1114 | integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== 1115 | dependencies: 1116 | safe-buffer "~5.2.0" 1117 | 1118 | strip-ansi@^6.0.1: 1119 | version "6.0.1" 1120 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 1121 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 1122 | dependencies: 1123 | ansi-regex "^5.0.1" 1124 | 1125 | supports-color@^5.5.0: 1126 | version "5.5.0" 1127 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1128 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1129 | dependencies: 1130 | has-flag "^3.0.0" 1131 | 1132 | tar@^6.1.11: 1133 | version "6.2.1" 1134 | resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" 1135 | integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== 1136 | dependencies: 1137 | chownr "^2.0.0" 1138 | fs-minipass "^2.0.0" 1139 | minipass "^5.0.0" 1140 | minizlib "^2.1.1" 1141 | mkdirp "^1.0.3" 1142 | yallist "^4.0.0" 1143 | 1144 | to-regex-range@^5.0.1: 1145 | version "5.0.1" 1146 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 1147 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 1148 | dependencies: 1149 | is-number "^7.0.0" 1150 | 1151 | toidentifier@1.0.1: 1152 | version "1.0.1" 1153 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" 1154 | integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== 1155 | 1156 | touch@^3.1.0: 1157 | version "3.1.1" 1158 | resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.1.tgz#097a23d7b161476435e5c1344a95c0f75b4a5694" 1159 | integrity sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA== 1160 | 1161 | tr46@^4.1.1: 1162 | version "4.1.1" 1163 | resolved "https://registry.yarnpkg.com/tr46/-/tr46-4.1.1.tgz#281a758dcc82aeb4fe38c7dfe4d11a395aac8469" 1164 | integrity sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw== 1165 | dependencies: 1166 | punycode "^2.3.0" 1167 | 1168 | tr46@~0.0.3: 1169 | version "0.0.3" 1170 | resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" 1171 | integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== 1172 | 1173 | type-is@~1.6.18: 1174 | version "1.6.18" 1175 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" 1176 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== 1177 | dependencies: 1178 | media-typer "0.3.0" 1179 | mime-types "~2.1.24" 1180 | 1181 | undefsafe@^2.0.5: 1182 | version "2.0.5" 1183 | resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" 1184 | integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== 1185 | 1186 | unpipe@1.0.0, unpipe@~1.0.0: 1187 | version "1.0.0" 1188 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 1189 | integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== 1190 | 1191 | util-deprecate@^1.0.1: 1192 | version "1.0.2" 1193 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1194 | integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== 1195 | 1196 | utils-merge@1.0.1, utils-merge@^1.0.1: 1197 | version "1.0.1" 1198 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 1199 | integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== 1200 | 1201 | vary@^1, vary@~1.1.2: 1202 | version "1.1.2" 1203 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 1204 | integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== 1205 | 1206 | webidl-conversions@^3.0.0: 1207 | version "3.0.1" 1208 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" 1209 | integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== 1210 | 1211 | webidl-conversions@^7.0.0: 1212 | version "7.0.0" 1213 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" 1214 | integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== 1215 | 1216 | whatwg-url@^13.0.0: 1217 | version "13.0.0" 1218 | resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-13.0.0.tgz#b7b536aca48306394a34e44bda8e99f332410f8f" 1219 | integrity sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig== 1220 | dependencies: 1221 | tr46 "^4.1.1" 1222 | webidl-conversions "^7.0.0" 1223 | 1224 | whatwg-url@^5.0.0: 1225 | version "5.0.0" 1226 | resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" 1227 | integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== 1228 | dependencies: 1229 | tr46 "~0.0.3" 1230 | webidl-conversions "^3.0.0" 1231 | 1232 | wide-align@^1.1.2: 1233 | version "1.1.5" 1234 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" 1235 | integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== 1236 | dependencies: 1237 | string-width "^1.0.2 || 2 || 3 || 4" 1238 | 1239 | wrappy@1: 1240 | version "1.0.2" 1241 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1242 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 1243 | 1244 | yallist@^4.0.0: 1245 | version "4.0.0" 1246 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" 1247 | integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== 1248 | --------------------------------------------------------------------------------