From 29d4b5477f170ada2a63bf24b80ceeeeb667d01e Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 28 May 2024 10:41:10 -0700 Subject: [PATCH 1/6] Added docker images for MongoDB and Redis to project. Updated readme with instructions to run docker images --- README.md | 75 ++++++++++++++++++++++++++-------- Server/.gitignore | 5 ++- Server/docker/mongo/Dockerfile | 2 + Server/docker/redis/Dockerfile | 2 + 4 files changed, 67 insertions(+), 17 deletions(-) create mode 100644 Server/docker/mongo/Dockerfile create mode 100644 Server/docker/redis/Dockerfile diff --git a/README.md b/README.md index 8767a3633..a86b460e4 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,9 @@ BlueWave uptime monitoring application 1. [Installation (Client)](#client) 2. [Installation (Server)](#server) 3. [Configuration(Server)](#config-server) + - [Environment](#environmental-variables) + - [Database](#databases) + - [Docker Images](#docker-images) 4. [Endpoints](#endpoints) - POST [/api/v1/auth/register](#post-register) - POST [/api/v1/auth/login](#post-login) @@ -46,9 +49,11 @@ BlueWave uptime monitoring application --- -#### Configuration {#config-server} +#### Configuration -Configure the server with the following environmental variables +##### Environmental Variables + +Configure the server with the following environmental variables: | ENV Variable Name | Required/Optional | Type | Description | Accepted Values | | -------------------- | ----------------- | --------- | ----------------------------------------------------- | ------------------- | @@ -61,6 +66,45 @@ Configure the server with the following environmental variables --- +##### Databases + +This project requires a number of databases to run: + +1. Main database for the application. This project includes an implementation for a MongoDB database as well as a MongoDB Docker image. +2. A Redis database is required for the Queue implementation in the PingService. This project includes a Redis docker image. + +You may run your own databases locally, or you may use the docker images included in the project to get up and running quickly. + +###### (Optional) Running Docker Images + +Docker images are located in `./Server/docker` + +
+MongoDB Image +Located in `./Server/docker/mongo` + +The `./Server/docker/mongo/mongo_data` folder should be mounted to the MongoDB container in order to persist data. + +From the `mongo` folder run + +1. Build the image: `docker build -t .` +2. Run the docker image: `docker run -d -p 27017:27017 -v $(pwd)/../mongo/mongo_data:/data/db --name uptime_database_mongo uptime_database_mongo` + +
+
+Redis Image +Located in `./Server/docker/redis` + +the `./Server/docker/redis/redis_data` folder should be mounted to the Redis container in order to persist data. + +From the `Redis` folder run + +1. Build the image: `docker build -t ` +2. Run the image: `docker run -d -p 6379:6379 -v $(pwd)/../redis/redis_data:/data --name uptime_redis uptime_redis` +
+ +--- + #### Starting the Development Server 1. run `npm run dev` to start the development server @@ -122,15 +166,15 @@ Example:
Check -| Name | Type | Notes | -| ----------- | --------- | ------------------------------------------------| -| monitorId | `string` | Unique ID for the monitor | -| status | `boolean` | Indicates the service is Up or Down | -| responseTime| `integer` | Indicates the response time of the service (ms) | -| statusCode | `integer` | Status Code returned from the service | -| message | `string` | Message returned from the service | -| updatedAt | `Date` | Last time the check was updated | -| CreatedAt | `Date` | When the check was created | +| Name | Type | Notes | +| ------------ | --------- | ----------------------------------------------- | +| monitorId | `string` | Unique ID for the monitor | +| status | `boolean` | Indicates the service is Up or Down | +| responseTime | `integer` | Indicates the response time of the service (ms) | +| statusCode | `integer` | Status Code returned from the service | +| message | `string` | Message returned from the service | +| updatedAt | `Date` | Last time the check was updated | +| CreatedAt | `Date` | When the check was created |
@@ -138,17 +182,16 @@ Example: Alert | Name | Type | Notes | -| ----------- | --------- | --------------------------------------------------| +| ----------------- | --------- | ------------------------------------------------- | | checkId | `string` | Unique ID for the check | -| status | `boolean` | Indicates the service is Up or Down | +| status | `boolean` | Indicates the service is Up or Down | | message | `string` | Message for the user about the down service | | notifiedStatus | `boolean` | Indicates whether the user is notified | | acknowledgeStatus | `boolean` | Indicates whether the user acknowledged the alert | | updatedAt | `Date` | Last time the alert was updated | | CreatedAt | `Date` | When the alert was created | - ---- +##
POST /api/v1/auth/register @@ -636,7 +679,7 @@ curl --request POST \ --- -### Error handling {#error-handling} +### Error handling Errors are returned in a standard format: diff --git a/Server/.gitignore b/Server/.gitignore index 3fdb59050..51b2eb44c 100644 --- a/Server/.gitignore +++ b/Server/.gitignore @@ -1,3 +1,6 @@ node_modules .env -*.log \ No newline at end of file +*.log +*.sh +docker/mongo/mongo_data/* +docker/redis/redis_data/* \ No newline at end of file diff --git a/Server/docker/mongo/Dockerfile b/Server/docker/mongo/Dockerfile new file mode 100644 index 000000000..fa79e8a92 --- /dev/null +++ b/Server/docker/mongo/Dockerfile @@ -0,0 +1,2 @@ +FROM mongo +EXPOSE 27017 \ No newline at end of file diff --git a/Server/docker/redis/Dockerfile b/Server/docker/redis/Dockerfile new file mode 100644 index 000000000..af68ec61e --- /dev/null +++ b/Server/docker/redis/Dockerfile @@ -0,0 +1,2 @@ +FROM redis +EXPOSE 6379 \ No newline at end of file From d627f03e8e1b59cd0f8d60b5d518e72bd1c7b1cd Mon Sep 17 00:00:00 2001 From: veyselboybay Date: Wed, 5 Jun 2024 14:17:54 -0400 Subject: [PATCH 2/6] Implemented the emailing service --- README.md | 16 +++--- Server/index.js | 12 ---- Server/package-lock.json | 115 ++++++++++++++++++++++++++++++++++++++ Server/package.json | 1 + Server/utils/sendEmail.js | 63 ++++++++++----------- 5 files changed, 153 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index ff5190652..daf504923 100644 --- a/README.md +++ b/README.md @@ -63,14 +63,14 @@ BlueWave uptime monitoring application Configure the server with the following environmental variables -| ENV Variable Name | Required/Optional | Type | Description | Accepted Values | -| -------------------- | ----------------- | --------- | ----------------------------------------------------- | ------------------- | -| JWT_SECRET | Required | `string` | JWT secret | | -| DB_TYPE | Optional | `string` | Specify DB to use | `MongoDB \| FakeDB` | -| DB_CONNECTION_STRING | Required | `string` | Specifies URL for MongoDB Database | | -| PORT | Optional | `integer` | Specifies Port for Server | | -| MAILERSEND_API_KEY | Required | `string` | Specifies API KEY for MailerSend service | | -| SYSTEM_EMAIL_ADDRESS | Required | `string` | Specifies System email to be used in emailing service | | +| ENV Variable Name | Required/Optional | Type | Description | Accepted Values | +| -------------------- | ----------------- | --------- | ------------------------------------------------------------------------------------------- | ------------------- | +| JWT_SECRET | Required | `string` | JWT secret | | +| DB_TYPE | Optional | `string` | Specify DB to use | `MongoDB \| FakeDB` | +| DB_CONNECTION_STRING | Required | `string` | Specifies URL for MongoDB Database | | +| PORT | Optional | `integer` | Specifies Port for Server | | +| SENDGRID_API_KEY | Required | `string` | Specifies API KEY for SendGrid email service | | +| SYSTEM_EMAIL_ADDRESS | Required | `string` | Specifies System email to be used in emailing service, must be a verified email by sendgrid | | --- diff --git a/Server/index.js b/Server/index.js index d194606f6..f1b8c1a63 100644 --- a/Server/index.js +++ b/Server/index.js @@ -11,8 +11,6 @@ const logger = require("./utils/logger"); const { verifyJWT } = require("./middleware/verifyJWT"); const { handleErrors } = require("./middleware/handleErrors"); -// const { sendEmail } = require('./utils/sendEmail') - // ************************** // Here is where we can swap out DBs easily. Spin up a mongoDB instance and try it out. // Simply comment out the FakeDB and uncomment the MongoDB or vice versa. @@ -35,11 +33,6 @@ const db = DB_TYPE[process.env.DB_TYPE] ? DB_TYPE[process.env.DB_TYPE]() : require("./db/FakeDb"); -/** - * NOTES - * Email Service will be added - * Logger Service will be added (Winston or similar) - */ const app = express(); @@ -67,11 +60,6 @@ app.use("/api/v1/monitors", monitorRouter); app.use("/api/v1/checks", verifyJWT, checkRouter); app.use("/api/v1/alerts", verifyJWT, alertRouter); -// Testing email service -// app.use('/sendEmail', async (req, res) => { -// const response = sendEmail(['veysel.boybay@bluewavelabs.ca'], 'Testing email service', '

Testing Bluewavelabs

'); -// console.log(response); -// }) //health check app.use("/api/v1/healthy", (req, res) => { diff --git a/Server/package-lock.json b/Server/package-lock.json index 9ee830ebd..c8c366248 100644 --- a/Server/package-lock.json +++ b/Server/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@sendgrid/mail": "^8.1.3", "bcrypt": "^5.1.1", "cors": "^2.8.5", "dotenv": "^16.4.5", @@ -96,6 +97,41 @@ "sparse-bitfield": "^3.0.3" } }, + "node_modules/@sendgrid/client": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/@sendgrid/client/-/client-8.1.3.tgz", + "integrity": "sha512-mRwTticRZIdUTsnyzvlK6dMu3jni9ci9J+dW/6fMMFpGRAJdCJlivFVYQvqk8kRS3RnFzS7sf6BSmhLl1ldDhA==", + "dependencies": { + "@sendgrid/helpers": "^8.0.0", + "axios": "^1.6.8" + }, + "engines": { + "node": ">=12.*" + } + }, + "node_modules/@sendgrid/helpers": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sendgrid/helpers/-/helpers-8.0.0.tgz", + "integrity": "sha512-Ze7WuW2Xzy5GT5WRx+yEv89fsg/pgy3T1E3FS0QEx0/VvRmigMZ5qyVGhJz4SxomegDkzXv/i0aFPpHKN8qdAA==", + "dependencies": { + "deepmerge": "^4.2.2" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/@sendgrid/mail": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/@sendgrid/mail/-/mail-8.1.3.tgz", + "integrity": "sha512-Wg5iKSUOER83/cfY6rbPa+o3ChnYzWwv1OcsR8gCV8SKi+sUPIMroildimlnb72DBkQxcbylxng1W7f0RIX7MQ==", + "dependencies": { + "@sendgrid/client": "^8.1.3", + "@sendgrid/helpers": "^8.0.0" + }, + "engines": { + "node": ">=12.*" + } + }, "node_modules/@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", @@ -229,6 +265,21 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -422,6 +473,17 @@ "text-hex": "1.0.x" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -484,6 +546,14 @@ "ms": "2.0.0" } }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -500,6 +570,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -689,6 +767,38 @@ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1703,6 +1813,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", diff --git a/Server/package.json b/Server/package.json index 60777f7a5..9b5f08737 100644 --- a/Server/package.json +++ b/Server/package.json @@ -11,6 +11,7 @@ "author": "", "license": "ISC", "dependencies": { + "@sendgrid/mail": "^8.1.3", "bcrypt": "^5.1.1", "cors": "^2.8.5", "dotenv": "^16.4.5", diff --git a/Server/utils/sendEmail.js b/Server/utils/sendEmail.js index 712a651bd..488cd9170 100644 --- a/Server/utils/sendEmail.js +++ b/Server/utils/sendEmail.js @@ -1,43 +1,38 @@ -const { MailerSend, EmailParams, Sender, Recipient } = require('mailersend') -const logger = require('../utils/logger') - - -const mailersend = new MailerSend({ - apiKey: process.env.MAILERSEND_API_KEY, -}) +const sgMail = require('@sendgrid/mail') +const logger = require('./logger') +const dotenv = require('dotenv') +dotenv.config({path:__dirname+'/../.env'}) +sgMail.setApiKey(process.env.SENDGRID_API_KEY) +const SERVICE_NAME = 'Email_Service'; /** + * @async * @function - * @param {[string]} receivers - takes an array of strings - * @param {string} subject - takes a single string - * @param {string} contentHTML - takes a single string that contains HTML - * @returns {JSON} - * @example - * sendEmail(['veysel@bluewavelabs.ca','alex@bluewavelabs.ca','monzer@bluewavelabs.ca'],'Testing Email Servide','

BlueWaveLabs

') + * @param {[String]} receivers - takes an array of strings + * @param {String} subject - takes a single string + * @param {String} contentHTML - takes a single string that contains HTML + * @param {String} contentText - takes a string to be used if contentHTML is not compatible + * @example + * await sendEmail(['veysel@bluewavelabs.ca','alex@bluewavelabs.ca'],'Testing Email Service','

BlueWaveLabs

','Testing Email Service') */ -// TODO: from email should be in .env file -const sendEmail = async (receivers,subject,contentHTML) => { - // Sender - const from = process.env.SYSTEM_EMAIL_ADDRESS; - const sender = new Sender(from); - // receivers - let recipients = [] - receivers.map(email => recipients.push(new Recipient(email))); - // Set params - const emailParams = new EmailParams() - .setFrom(sender) - .setTo(recipients) - .setSubject(subject) - .setHtml(contentHTML); - +const sendEmail = async (receivers,subject, contentHTML, contentText = null ) => { + const msg = { + to: receivers, + from: { + name: 'Uptime System', + email: process.env.SYSTEM_EMAIL_ADDRESS // must be verified email by sendgrid + }, + subject: subject, + text: contentText || contentHTML, + html: contentHTML, + } try { - const response = await mailersend.email.send(emailParams); - logger.info("Email sent to receivers!",{"service":"Email"}) - return response; - + await sgMail.send(msg); + logger.info(`Emails sent to receivers:${receivers} with the subject:${subject}`,{service:SERVICE_NAME}) } catch (error) { - logger.error(error.body,{"service":"email"}) - console.log(error.body) + logger.error(`Sending Email action failed, ERROR:${error}`, { service: SERVICE_NAME }); } } + + module.exports = {sendEmail} \ No newline at end of file From dc98b07f551f0e9ca944409cdb34b1ac31ba2fe5 Mon Sep 17 00:00:00 2001 From: veyselboybay Date: Wed, 5 Jun 2024 14:46:48 -0400 Subject: [PATCH 3/6] removed the dontenv from email function --- Server/utils/sendEmail.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/Server/utils/sendEmail.js b/Server/utils/sendEmail.js index 488cd9170..d60900383 100644 --- a/Server/utils/sendEmail.js +++ b/Server/utils/sendEmail.js @@ -1,7 +1,5 @@ const sgMail = require('@sendgrid/mail') const logger = require('./logger') -const dotenv = require('dotenv') -dotenv.config({path:__dirname+'/../.env'}) sgMail.setApiKey(process.env.SENDGRID_API_KEY) const SERVICE_NAME = 'Email_Service'; /** From 88b0b0f97c9c461644961b12594df0c5f12d1409 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 5 Jun 2024 12:29:01 -0700 Subject: [PATCH 4/6] Added queue service, Added controller for testing purposes --- Server/controllers/queueController.js | 42 ++++ Server/index.js | 163 +++++++------- Server/package-lock.json | 293 ++++++++++++++++++++++++++ Server/package.json | 1 + Server/routes/queueRoute.js | 13 ++ Server/service/jobQueue.js | 195 +++++++++++++++++ 6 files changed, 632 insertions(+), 75 deletions(-) create mode 100644 Server/controllers/queueController.js create mode 100644 Server/routes/queueRoute.js create mode 100644 Server/service/jobQueue.js diff --git a/Server/controllers/queueController.js b/Server/controllers/queueController.js new file mode 100644 index 000000000..813fa9808 --- /dev/null +++ b/Server/controllers/queueController.js @@ -0,0 +1,42 @@ +const express = require("express"); +const logger = require("../utils/logger"); +const SERVICE_NAME = "JobQueue"; + +const getJobs = async (req, res, next) => { + try { + const jobs = await req.jobQueue.getJobs(); + return res.status(200).json({ jobs }); + } catch (error) { + error.service = SERVICE_NAME; + next(error); + return; + } +}; + +const addJob = async (req, res, next) => { + try { + await req.jobQueue.addJob(Math.random().toString(36).substring(7)); + return res.send("Added job"); + } catch (error) { + error.service = SERVICE_NAME; + next(error); + return; + } +}; + +const obliterateQueue = async (req, res, next) => { + try { + const obliterated = await req.jobQueue.obliterate(); + return res.status(200).send("Obliterated jobs"); + } catch (error) { + error.service = SERVICE_NAME; + next(error); + return; + } +}; + +module.exports = { + getJobs, + addJob, + obliterateQueue, +}; diff --git a/Server/index.js b/Server/index.js index d194606f6..571a95657 100644 --- a/Server/index.js +++ b/Server/index.js @@ -10,84 +10,97 @@ require("dotenv").config(); const logger = require("./utils/logger"); const { verifyJWT } = require("./middleware/verifyJWT"); const { handleErrors } = require("./middleware/handleErrors"); +const queueRouter = require("./routes/queueRoute"); +const JobQueue = require("./service/jobQueue"); -// const { sendEmail } = require('./utils/sendEmail') +// Need to wrap server setup in a function to handle async nature of JobQueue +const startApp = async () => { + // const { sendEmail } = require('./utils/sendEmail') -// ************************** -// Here is where we can swap out DBs easily. Spin up a mongoDB instance and try it out. -// Simply comment out the FakeDB and uncomment the MongoDB or vice versa. -// We can easily swap between any type of data source as long as the methods are implemented -// -// FakeDB -// const db = require("./db/FakeDb"); -// -// MongoDB -// const db = require("./db/MongoDB"); -// -// ************************** + // ************************** + // Here is where we can swap out DBs easily. Spin up a mongoDB instance and try it out. + // Simply comment out the FakeDB and uncomment the MongoDB or vice versa. + // We can easily swap between any type of data source as long as the methods are implemented + // + // FakeDB + // const db = require("./db/FakeDb"); + // + // MongoDB + // const db = require("./db/MongoDB"); + // + // ************************** + const DB_TYPE = { + MongoDB: () => require("./db/MongoDB"), + FakedDB: () => require("./db/FakeDb"), + }; -const DB_TYPE = { - MongoDB: () => require("./db/MongoDB"), - FakedDB: () => require("./db/FakeDb"), + const db = DB_TYPE[process.env.DB_TYPE] + ? DB_TYPE[process.env.DB_TYPE]() + : require("./db/FakeDb"); + + const jobQueue = await JobQueue.createJobQueue(); + /** + * NOTES + * Email Service will be added + * Logger Service will be added (Winston or similar) + */ + + const app = express(); + + // middlewares + app.use( + cors() + //We will add configuration later + ); + app.use(express.json()); + app.use(helmet()); + + // ************************** + // Make DB accessible anywhere we have a Request object + // By adding the DB to the request object, we can access it in any route + // Thus we do not need to import it in every route file, and we can easily swap out DBs as there is only one place to change it + // Same applies for JobQueue + // ************************** + app.use((req, res, next) => { + req.db = db; + req.jobQueue = jobQueue; + next(); + }); + + //routes + app.use("/api/v1/auth", authRouter); + app.use("/api/v1/monitors", monitorRouter); + app.use("/api/v1/checks", verifyJWT, checkRouter); + app.use("/api/v1/alerts", verifyJWT, alertRouter); + //Temporary route for testing, remove later + app.use("/api/v1/job", queueRouter); + + // Testing email service + // app.use('/sendEmail', async (req, res) => { + // const response = sendEmail(['veysel.boybay@bluewavelabs.ca'], 'Testing email service', '

Testing Bluewavelabs

'); + // console.log(response); + // }) + + //health check + app.use("/api/v1/healthy", (req, res) => { + try { + logger.info("Checking Health of the server."); + return res.status(200).json({ message: "Healthy" }); + } catch (error) { + logger.error(error.message); + return res.status(500).json({ message: error.message }); + } + }); + + /** + * Error handler middleware + * Should be called last + */ + app.use(handleErrors); + + connectDbAndRunServer(app, db); }; -const db = DB_TYPE[process.env.DB_TYPE] - ? DB_TYPE[process.env.DB_TYPE]() - : require("./db/FakeDb"); - -/** - * NOTES - * Email Service will be added - * Logger Service will be added (Winston or similar) - */ - -const app = express(); - -// middlewares -app.use( - cors() - //We will add configuration later -); -app.use(express.json()); -app.use(helmet()); - -// ************************** -// Make DB accessible anywhere we have a Request object -// By adding the DB to the request object, we can access it in any route -// Thus we do not need to import it in every route file, and we can easily swap out DBs as there is only one place to change it -// ************************** -app.use((req, res, next) => { - req.db = db; - next(); +startApp().catch((error) => { + console.log(error); }); - -//routes -app.use("/api/v1/auth", authRouter); -app.use("/api/v1/monitors", monitorRouter); -app.use("/api/v1/checks", verifyJWT, checkRouter); -app.use("/api/v1/alerts", verifyJWT, alertRouter); - -// Testing email service -// app.use('/sendEmail', async (req, res) => { -// const response = sendEmail(['veysel.boybay@bluewavelabs.ca'], 'Testing email service', '

Testing Bluewavelabs

'); -// console.log(response); -// }) - -//health check -app.use("/api/v1/healthy", (req, res) => { - try { - logger.info("Checking Health of the server."); - return res.status(200).json({ message: "Healthy" }); - } catch (error) { - logger.error(error.message); - return res.status(500).json({ message: error.message }); - } -}); - -/** - * Error handler middleware - * Should be called last - */ -app.use(handleErrors); - -connectDbAndRunServer(app, db); diff --git a/Server/package-lock.json b/Server/package-lock.json index 9ee830ebd..55b7858b3 100644 --- a/Server/package-lock.json +++ b/Server/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "bcrypt": "^5.1.1", + "bullmq": "5.7.15", "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.19.2", @@ -55,6 +56,12 @@ "@hapi/hoek": "^9.0.0" } }, + "node_modules/@ioredis/commands": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", + "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==", + "license": "MIT" + }, "node_modules/@mapbox/node-pre-gyp": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", @@ -96,6 +103,84 @@ "sparse-bitfield": "^3.0.3" } }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", + "integrity": "sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz", + "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz", + "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz", + "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz", + "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz", + "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", @@ -316,6 +401,21 @@ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" }, + "node_modules/bullmq": { + "version": "5.7.15", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.7.15.tgz", + "integrity": "sha512-XR5sTA8BPUY67sS37sMKGCDvSLaVpMq7aaQG8FGSKOUnPoJMRf17n1TibVWP3+yK0xKLdK5Y7PY9D874Fpeqpg==", + "license": "MIT", + "dependencies": { + "cron-parser": "^4.6.0", + "ioredis": "^5.4.1", + "msgpackr": "^1.10.1", + "node-abort-controller": "^3.1.1", + "semver": "^7.5.4", + "tslib": "^2.0.0", + "uuid": "^9.0.0" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -374,6 +474,15 @@ "node": ">=10" } }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/color": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", @@ -476,6 +585,18 @@ "node": ">= 0.10" } }, + "node_modules/cron-parser": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.9.0.tgz", + "integrity": "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==", + "license": "MIT", + "dependencies": { + "luxon": "^3.2.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -505,6 +626,15 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -992,6 +1122,53 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ioredis": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.4.1.tgz", + "integrity": "sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==", + "license": "MIT", + "dependencies": { + "@ioredis/commands": "^1.1.1", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.4", + "denque": "^2.1.0", + "lodash.defaults": "^4.2.0", + "lodash.isarguments": "^3.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, + "node_modules/ioredis/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/ioredis/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -1145,11 +1322,23 @@ "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "license": "MIT" + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", + "license": "MIT" + }, "node_modules/lodash.isboolean": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", @@ -1212,6 +1401,15 @@ "node": ">=10" } }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/mailersend": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/mailersend/-/mailersend-2.2.0.tgz", @@ -1478,6 +1676,37 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/msgpackr": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.10.2.tgz", + "integrity": "sha512-L60rsPynBvNE+8BWipKKZ9jHcSGbtyJYIwjRq0VrIvQ08cRjntGXJYW/tmciZ2IHWIY8WEW32Qa2xbh5+SKBZA==", + "license": "MIT", + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz", + "integrity": "sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.0.7" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.2" + } + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -1486,6 +1715,12 @@ "node": ">= 0.6" } }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "license": "MIT" + }, "node_modules/node-addon-api": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", @@ -1529,6 +1764,18 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz", + "integrity": "sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==", + "license": "MIT", + "optional": true, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, "node_modules/nodemon": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz", @@ -1778,6 +2025,27 @@ "node": ">=8.10.0" } }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "license": "MIT", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -1969,6 +2237,12 @@ "node": "*" } }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -2093,6 +2367,12 @@ "node": ">= 14.0.0" } }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "license": "0BSD" + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -2137,6 +2417,19 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/Server/package.json b/Server/package.json index 60777f7a5..d35461ebd 100644 --- a/Server/package.json +++ b/Server/package.json @@ -12,6 +12,7 @@ "license": "ISC", "dependencies": { "bcrypt": "^5.1.1", + "bullmq": "5.7.15", "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.19.2", diff --git a/Server/routes/queueRoute.js b/Server/routes/queueRoute.js new file mode 100644 index 000000000..79fa9b689 --- /dev/null +++ b/Server/routes/queueRoute.js @@ -0,0 +1,13 @@ +const router = require("express").Router(); +const queueController = require("../controllers/queueController"); + +// Get Jobs +router.get("/", queueController.getJobs); + +// Add Job +router.post("/", queueController.addJob); + +// Obliterate Queue +router.post("/obliterate", queueController.obliterateQueue); + +module.exports = router; diff --git a/Server/service/jobQueue.js b/Server/service/jobQueue.js new file mode 100644 index 000000000..84241f443 --- /dev/null +++ b/Server/service/jobQueue.js @@ -0,0 +1,195 @@ +const { Queue, Worker, Job } = require("bullmq"); +const QUEUE_NAME = "monitors"; +const connection = { + host: process.env.REDIS_HOST || "127.0.0.1", + port: process.env.REDIS_PORT || 6379, +}; +const JOBS_PER_WORKER = 5; +const logger = require("../utils/logger"); + +class JobQueue { + /** + * Constructs a new JobQueue + * @constructor + * @throws {Error} + */ + constructor() { + console.log(process.env.REDIS_PORT); + this.queue = new Queue(QUEUE_NAME, { + connection, + }); + this.workers = []; + } + + /** + * Static factory method to create a JobQueue + * @static + * @async + * @returns {Promise} - Returns a new JobQueue + * + */ + static async createJobQueue() { + const queue = new JobQueue(); + try { + const workerStats = await queue.getWorkerStats(); + await queue.scaleWorkers(workerStats); + return queue; + } catch (error) { + throw error; + } + } + + /** + * Creates a worker for the queue + * Operations are carried out in the async callback + * @returns {Worker} The newly created worker + */ + createWorker() { + const worker = new Worker( + QUEUE_NAME, + async (job) => { + // TODO Ping a monitor + console.log(`${job.name} completed, workers: ${this.workers.length}`); + }, + { + connection, + } + ); + return worker; + } + + /** + * @typedef {Object} WorkerStats + * @property {Array} jobs - Array of jobs in the Queue + * @property {number} - workerLoad - The number of jobs per worker + * + */ + + /** + * Gets stats related to the workers + * This is used for scaling workers right now + * In the future we will likely want to scale based on server performance metrics + * CPU Usage & memory usage, if too high, scale down workers. + * When to scale up? If jobs are taking too long to complete? + * @async + * @returns {Promise} - Returns the worker stats + */ + async getWorkerStats() { + try { + const jobs = await this.queue.getRepeatableJobs(); + const load = jobs.length / this.workers.length; + return { jobs, load }; + } catch (error) { + throw error; + } + } + + /** + * Scale Workers + * This function scales workers based on the load per worker + * If the load is higher than the JOBS_PER_WORKER threshold, we add more workers + * If the load is lower than the JOBS_PER_WORKER threshold, we release workers + * This approach ignores server performance, which we should add in the future + * + + * @async + * @param {WorkerStats} workerStats - The payload for the job. + * @returns {Promise} + */ + async scaleWorkers(workerStats) { + if (this.workers.length === 0) { + // There are no workers, need to add one + const worker = this.createWorker(); + this.workers.push(worker); + return true; + } + + if (workerStats.load > JOBS_PER_WORKER) { + // Find out how many more jobs we have than current workers can handle + const excessJobs = + workerStats.jobs.length - this.workers.length * JOBS_PER_WORKER; + + // Divide by jobs/worker to find out how many workers to add + const workersToAdd = Math.ceil(excessJobs / JOBS_PER_WORKER); + for (let i = 0; i < workersToAdd; i++) { + const worker = this.createWorker(); + this.workers.push(worker); + } + return true; + } + + if (workerStats.load < JOBS_PER_WORKER) { + // Find out how much excess capacity we have + const workerCapacity = this.workers.length * JOBS_PER_WORKER; + const excessCapacity = workerCapacity - workerStats.jobs.length; + // Calculate how many workers to remove + const workersToRemove = Math.floor(excessCapacity / JOBS_PER_WORKER); + for (let i = 0; i < workersToRemove; i++) { + const worker = this.workers.pop(); + try { + await worker.close(); + } catch (error) { + // Catch the error instead of throwing it + console.error("Error closing worker", error); + } + } + return true; + } + return false; + } + + /** + * Gets all jobs in the queue. + * + * @async + * @returns {Promise>} + * @throws {Error} - Throws error if getting jobs fails + */ + async getJobs() { + try { + const jobs = await this.queue.getRepeatableJobs(); + console.log("jobs", jobs); + return jobs; + } catch (error) { + throw error; + } + } + + /** + * Adds a job to the queue and scales workers based on worker stats. + * + * @async + * @param {string} jobName - The name of the job to be added. + * @param {Monitor} payload - The payload for the job. + * @throws {Error} - Will throw an error if the job cannot be added or workers don't scale + */ + async addJob(jobName, payload) { + try { + await this.queue.add(jobName, payload, { + repeat: { + every: 1000, + limit: 100, + }, + }); + const workerStats = await this.getWorkerStats(); + await this.scaleWorkers(workerStats); + } catch (error) { + throw error; + } + } + + /** + * @async + * @returns {Promise} - Returns true if obliteration is successful + */ + async obliterate() { + try { + await this.queue.obliterate(); + return true; + } catch (error) { + throw error; + } + } +} + +module.exports = JobQueue; From 44bee4141c1730e77e35254e202cc992d7da12af Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 5 Jun 2024 12:34:59 -0700 Subject: [PATCH 5/6] updated readme --- README.md | 2 + Server/package-lock.json | 501 +++++++++++++++++++++++++++------------ 2 files changed, 355 insertions(+), 148 deletions(-) diff --git a/README.md b/README.md index daf504923..2e6a081f1 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,8 @@ Configure the server with the following environmental variables | PORT | Optional | `integer` | Specifies Port for Server | | | SENDGRID_API_KEY | Required | `string` | Specifies API KEY for SendGrid email service | | | SYSTEM_EMAIL_ADDRESS | Required | `string` | Specifies System email to be used in emailing service, must be a verified email by sendgrid | | +| REDIS_HOST | Required | `string` | Host address for Redis database | | +| REDIS_PORT | Required | `integer` | Port for Redis database | | --- diff --git a/Server/package-lock.json b/Server/package-lock.json index 533bf77d7..faa647ddc 100644 --- a/Server/package-lock.json +++ b/Server/package-lock.json @@ -30,6 +30,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "license": "MIT", "engines": { "node": ">=0.1.90" } @@ -38,6 +39,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "license": "MIT", "dependencies": { "colorspace": "1.1.x", "enabled": "2.0.x", @@ -47,12 +49,14 @@ "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "license": "BSD-3-Clause" }, "node_modules/@hapi/topo": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "license": "BSD-3-Clause", "dependencies": { "@hapi/hoek": "^9.0.0" } @@ -67,6 +71,7 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "license": "BSD-3-Clause", "dependencies": { "detect-libc": "^2.0.0", "https-proxy-agent": "^5.0.0", @@ -82,24 +87,11 @@ "node-pre-gyp": "bin/node-pre-gyp" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@mongodb-js/saslprep": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.6.tgz", - "integrity": "sha512-jqTTXQ46H8cAxmXBu8wm1HTSIMBMrIcoVrsjdQkKdMBj3il/fSCgWyya4P2I1xjPBl69mw+nRphrPlcIqBd20Q==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.7.tgz", + "integrity": "sha512-dCHW/oEX0KJ4NjDULBo3JiOaK5+6axtpBbS+ao2ZInoAL9/YRQLhXzSNAFz7hP4nzLkIqsfYAK/PDE3+XHny0Q==", + "license": "MIT", "dependencies": { "sparse-bitfield": "^3.0.3" } @@ -186,6 +178,7 @@ "version": "8.1.3", "resolved": "https://registry.npmjs.org/@sendgrid/client/-/client-8.1.3.tgz", "integrity": "sha512-mRwTticRZIdUTsnyzvlK6dMu3jni9ci9J+dW/6fMMFpGRAJdCJlivFVYQvqk8kRS3RnFzS7sf6BSmhLl1ldDhA==", + "license": "MIT", "dependencies": { "@sendgrid/helpers": "^8.0.0", "axios": "^1.6.8" @@ -198,6 +191,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@sendgrid/helpers/-/helpers-8.0.0.tgz", "integrity": "sha512-Ze7WuW2Xzy5GT5WRx+yEv89fsg/pgy3T1E3FS0QEx0/VvRmigMZ5qyVGhJz4SxomegDkzXv/i0aFPpHKN8qdAA==", + "license": "MIT", "dependencies": { "deepmerge": "^4.2.2" }, @@ -209,6 +203,7 @@ "version": "8.1.3", "resolved": "https://registry.npmjs.org/@sendgrid/mail/-/mail-8.1.3.tgz", "integrity": "sha512-Wg5iKSUOER83/cfY6rbPa+o3ChnYzWwv1OcsR8gCV8SKi+sUPIMroildimlnb72DBkQxcbylxng1W7f0RIX7MQ==", + "license": "MIT", "dependencies": { "@sendgrid/client": "^8.1.3", "@sendgrid/helpers": "^8.0.0" @@ -221,6 +216,7 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "license": "BSD-3-Clause", "dependencies": { "@hapi/hoek": "^9.0.0" } @@ -228,27 +224,32 @@ "node_modules/@sideway/formula": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "license": "BSD-3-Clause" }, "node_modules/@sideway/pinpoint": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "license": "BSD-3-Clause" }, "node_modules/@types/triple-beam": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "license": "MIT" }, "node_modules/@types/webidl-conversions": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", - "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "license": "MIT" }, "node_modules/@types/whatwg-url": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.4.tgz", - "integrity": "sha512-lXCmTWSHJvf0TRSO58nm978b8HJ/EdsSsEKLd3ODHFjo+3VGAyyTp4v50nWvwtzBxSMQrVOK7tcuN0zGPLICMw==", + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "license": "MIT", "dependencies": { "@types/webidl-conversions": "*" } @@ -256,12 +257,14 @@ "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC" }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -274,6 +277,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", "dependencies": { "debug": "4" }, @@ -282,9 +286,10 @@ } }, "node_modules/agent-base/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -300,12 +305,14 @@ "node_modules/agent-base/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", "engines": { "node": ">=8" } @@ -315,6 +322,7 @@ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -326,12 +334,15 @@ "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "license": "ISC" }, "node_modules/are-we-there-yet": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -343,22 +354,26 @@ "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" }, "node_modules/async": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "license": "MIT" }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" }, "node_modules/axios": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -368,13 +383,15 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" }, "node_modules/bcrypt": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==", "hasInstallScript": true, + "license": "MIT", "dependencies": { "@mapbox/node-pre-gyp": "^1.0.11", "node-addon-api": "^5.0.0" @@ -388,6 +405,7 @@ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -399,6 +417,7 @@ "version": "1.20.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -422,18 +441,20 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -443,6 +464,7 @@ "version": "6.7.0", "resolved": "https://registry.npmjs.org/bson/-/bson-6.7.0.tgz", "integrity": "sha512-w2IquM5mYzYZv6rs3uN2DZTOBe2a0zXLj53TGDqwF4l6Sz/XsISrisXOJihArF9+BZ6Cq/GjVht7Sjfmri7ytQ==", + "license": "Apache-2.0", "engines": { "node": ">=16.20.1" } @@ -450,7 +472,8 @@ "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" }, "node_modules/bullmq": { "version": "5.7.15", @@ -471,6 +494,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -479,6 +503,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -498,6 +523,7 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -521,6 +547,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", "engines": { "node": ">=10" } @@ -538,6 +565,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "license": "MIT", "dependencies": { "color-convert": "^1.9.3", "color-string": "^1.6.0" @@ -547,6 +575,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -554,12 +583,14 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" }, "node_modules/color-string": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" @@ -569,6 +600,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", "bin": { "color-support": "bin.js" } @@ -577,6 +609,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "license": "MIT", "dependencies": { "color": "^3.1.3", "text-hex": "1.0.x" @@ -586,6 +619,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -596,17 +630,20 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC" }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -618,6 +655,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -626,6 +664,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -633,12 +672,14 @@ "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", "dependencies": { "object-assign": "^4", "vary": "^1" @@ -663,6 +704,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -671,6 +713,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -679,6 +722,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -695,6 +739,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -702,7 +747,8 @@ "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT" }, "node_modules/denque": { "version": "2.1.0", @@ -717,6 +763,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -725,6 +772,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -734,6 +782,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "license": "Apache-2.0", "engines": { "node": ">=8" } @@ -742,6 +791,7 @@ "version": "16.4.5", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "license": "BSD-2-Clause", "engines": { "node": ">=12" }, @@ -753,6 +803,7 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" } @@ -760,22 +811,26 @@ "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" }, "node_modules/enabled": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "license": "MIT" }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -784,6 +839,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" }, @@ -795,6 +851,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -802,12 +859,14 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -816,6 +875,7 @@ "version": "4.19.2", "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -856,18 +916,21 @@ "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" }, "node_modules/fecha": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "license": "MIT" }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -879,6 +942,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -895,7 +959,8 @@ "node_modules/fn.name": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "license": "MIT" }, "node_modules/follow-redirects": { "version": "1.15.6", @@ -907,6 +972,7 @@ "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -920,6 +986,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -933,6 +1000,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -941,6 +1009,7 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -949,6 +1018,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -960,6 +1030,7 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -970,7 +1041,8 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -978,6 +1050,7 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -990,6 +1063,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -998,6 +1072,8 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "license": "ISC", "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.2", @@ -1017,6 +1093,7 @@ "version": "5.1.3", "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", + "license": "Apache-2.0", "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^5.0.0", @@ -1031,6 +1108,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -1049,6 +1127,8 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1069,6 +1149,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -1080,6 +1161,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -1092,6 +1174,7 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -1100,6 +1183,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -1111,6 +1195,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -1122,6 +1207,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -1132,12 +1218,14 @@ "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC" }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -1149,6 +1237,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz", "integrity": "sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg==", + "license": "MIT", "engines": { "node": ">=16.0.0" } @@ -1157,6 +1246,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -1172,6 +1262,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", "dependencies": { "agent-base": "6", "debug": "4" @@ -1181,9 +1272,10 @@ } }, "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -1199,12 +1291,14 @@ "node_modules/https-proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -1216,12 +1310,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -1230,7 +1327,8 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, "node_modules/ioredis": { "version": "5.4.1", @@ -1283,6 +1381,7 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", "engines": { "node": ">= 0.10" } @@ -1290,13 +1389,15 @@ "node_modules/is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT" }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -1309,6 +1410,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -1317,6 +1419,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", "engines": { "node": ">=8" } @@ -1326,6 +1429,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -1338,6 +1442,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -1346,6 +1451,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", "engines": { "node": ">=8" }, @@ -1357,6 +1463,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz", "integrity": "sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==", + "license": "MIT", "dependencies": { "node-fetch": "^2.6.1", "unfetch": "^4.2.0" @@ -1366,6 +1473,7 @@ "version": "17.13.1", "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.1.tgz", "integrity": "sha512-vaBlIKCyo4FCUtCm7Eu4QZd/q02bWcxfUO6YSXAZOWF6gzcLBeba8kwotUdYJjDLW8Cz8RywsSOqiNJZW0mNvg==", + "license": "BSD-3-Clause", "dependencies": { "@hapi/hoek": "^9.3.0", "@hapi/topo": "^5.1.0", @@ -1378,6 +1486,7 @@ "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", "dependencies": { "jws": "^3.2.2", "lodash.includes": "^4.3.0", @@ -1398,12 +1507,14 @@ "node_modules/jsonwebtoken/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/jwa": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "license": "MIT", "dependencies": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", @@ -1414,6 +1525,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", "dependencies": { "jwa": "^1.4.1", "safe-buffer": "^5.0.1" @@ -1423,6 +1535,7 @@ "version": "2.6.3", "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz", "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==", + "license": "Apache-2.0", "engines": { "node": ">=12.0.0" } @@ -1430,7 +1543,8 @@ "node_modules/kuler": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "license": "MIT" }, "node_modules/lodash.defaults": { "version": "4.2.0", @@ -1441,7 +1555,8 @@ "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" }, "node_modules/lodash.isarguments": { "version": "3.1.0", @@ -1452,37 +1567,44 @@ "node_modules/lodash.isboolean": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" }, "node_modules/lodash.isinteger": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" }, "node_modules/lodash.isnumber": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" }, "node_modules/lodash.isstring": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" }, "node_modules/logform": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", + "license": "MIT", "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", @@ -1498,18 +1620,8 @@ "node_modules/logform/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/luxon": { "version": "3.4.4", @@ -1524,6 +1636,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/mailersend/-/mailersend-2.2.0.tgz", "integrity": "sha512-U5d2RseMDm7oQIXqvMo1Xfvimh2k4O+nC27TA2tR4cwMDoAiZ9e0JpnbQ8mbT7gJoNdUittLs3n/kfRapu5tZg==", + "license": "MIT", "dependencies": { "gaxios": "^5.0.1", "isomorphic-unfetch": "^3.1.0", @@ -1534,6 +1647,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", "dependencies": { "semver": "^6.0.0" }, @@ -1548,6 +1662,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -1556,6 +1671,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1563,17 +1679,20 @@ "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "license": "MIT" }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "license": "MIT" }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1582,6 +1701,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -1593,6 +1713,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1601,6 +1722,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -1612,6 +1734,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1623,6 +1746,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", "engines": { "node": ">=8" } @@ -1631,6 +1755,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -1643,6 +1768,7 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -1654,6 +1780,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -1662,12 +1789,13 @@ } }, "node_modules/mongodb": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.5.0.tgz", - "integrity": "sha512-Fozq68InT+JKABGLqctgtb8P56pRrJFkbhW0ux+x1mdHeyinor8oNzJqwLjV/t5X5nJGfTlluxfyMnOXNggIUA==", + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.6.2.tgz", + "integrity": "sha512-ZF9Ugo2JCG/GfR7DEb4ypfyJJyiKbg5qBYKRintebj8+DNS33CyGMkWbrS9lara+u+h+yEOGSRiLhFO/g1s1aw==", + "license": "Apache-2.0", "dependencies": { "@mongodb-js/saslprep": "^1.1.5", - "bson": "^6.4.0", + "bson": "^6.7.0", "mongodb-connection-string-url": "^3.0.0" }, "engines": { @@ -1707,26 +1835,28 @@ } }, "node_modules/mongodb-connection-string-url": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.0.tgz", - "integrity": "sha512-t1Vf+m1I5hC2M5RJx/7AtxgABy1cZmIPQRMXw+gEIPn/cZNF3Oiy+l0UIypUwVB5trcWHq3crg2g3uAR9aAwsQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", + "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", + "license": "Apache-2.0", "dependencies": { "@types/whatwg-url": "^11.0.2", "whatwg-url": "^13.0.0" } }, "node_modules/mongoose": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.3.3.tgz", - "integrity": "sha512-3kSk0db9DM2tLttCdS6WNRqewPleamFEa4Vz/Qldc0dB4Zow/FiZxb9GExHTJjBZQ9T2xiGleQ3GzRrES3hhsA==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.4.1.tgz", + "integrity": "sha512-odQ2WEWGL3hb0Qex+QMN4eH6D34WdMEw7F1If2MGABApSDmG9cMmqv/G1H6WsXmuaH9mkuuadW/WbLE5+tHJwA==", + "license": "MIT", "dependencies": { - "bson": "^6.5.0", + "bson": "^6.7.0", "kareem": "2.6.3", - "mongodb": "6.5.0", + "mongodb": "6.6.2", "mpath": "0.9.0", "mquery": "5.0.0", "ms": "2.1.3", - "sift": "16.0.1" + "sift": "17.1.3" }, "engines": { "node": ">=16.20.1" @@ -1739,12 +1869,14 @@ "node_modules/mongoose/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/mpath": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -1753,6 +1885,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", + "license": "MIT", "dependencies": { "debug": "4.x" }, @@ -1761,9 +1894,10 @@ } }, "node_modules/mquery/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -1779,12 +1913,14 @@ "node_modules/mquery/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/msgpackr": { "version": "1.10.2", @@ -1821,6 +1957,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1834,12 +1971,14 @@ "node_modules/node-addon-api": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", - "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", + "license": "MIT" }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -1858,17 +1997,20 @@ "node_modules/node-fetch/node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" }, "node_modules/node-fetch/node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" }, "node_modules/node-fetch/node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -1891,6 +2033,7 @@ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz", "integrity": "sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==", "dev": true, + "license": "MIT", "dependencies": { "chokidar": "^3.5.2", "debug": "^4", @@ -1915,10 +2058,11 @@ } }, "node_modules/nodemon/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -1935,13 +2079,14 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dev": true, + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", "dependencies": { "abbrev": "1" }, @@ -1949,7 +2094,7 @@ "nopt": "bin/nopt.js" }, "engines": { - "node": "*" + "node": ">=6" } }, "node_modules/normalize-path": { @@ -1957,6 +2102,7 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -1965,6 +2111,8 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", "dependencies": { "are-we-there-yet": "^2.0.0", "console-control-strings": "^1.1.0", @@ -1976,6 +2124,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -1984,6 +2133,7 @@ "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1992,6 +2142,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -2003,6 +2154,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", "dependencies": { "wrappy": "1" } @@ -2011,6 +2163,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "license": "MIT", "dependencies": { "fn.name": "1.x.x" } @@ -2019,6 +2172,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -2027,6 +2181,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -2034,13 +2189,15 @@ "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "license": "MIT" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -2052,6 +2209,7 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -2063,18 +2221,21 @@ "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", "engines": { "node": ">=6" } @@ -2083,6 +2244,7 @@ "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" }, @@ -2097,6 +2259,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -2105,6 +2268,7 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -2119,6 +2283,7 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -2133,6 +2298,7 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -2165,6 +2331,8 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -2192,12 +2360,14 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safe-stable-stringify": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "license": "MIT", "engines": { "node": ">=10" } @@ -2205,15 +2375,14 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -2225,6 +2394,7 @@ "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -2247,12 +2417,14 @@ "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "license": "MIT", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -2266,12 +2438,14 @@ "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -2287,12 +2461,14 @@ "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" }, "node_modules/side-channel": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -2307,19 +2483,22 @@ } }, "node_modules/sift": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", - "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" + "version": "17.1.3", + "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", + "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==", + "license": "MIT" }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" }, "node_modules/simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", "dependencies": { "is-arrayish": "^0.3.1" } @@ -2329,6 +2508,7 @@ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -2340,6 +2520,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "license": "MIT", "dependencies": { "memory-pager": "^1.0.2" } @@ -2348,6 +2529,7 @@ "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", "engines": { "node": "*" } @@ -2362,6 +2544,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -2370,6 +2553,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } @@ -2378,6 +2562,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2391,6 +2576,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2403,6 +2589,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -2414,6 +2601,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -2429,13 +2617,15 @@ "node_modules/text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "license": "MIT" }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -2447,18 +2637,17 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", "engines": { "node": ">=0.6" } }, "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", "dev": true, - "dependencies": { - "nopt": "~1.0.10" - }, + "license": "ISC", "bin": { "nodetouch": "bin/nodetouch.js" } @@ -2467,6 +2656,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "license": "MIT", "dependencies": { "punycode": "^2.3.0" }, @@ -2478,6 +2668,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "license": "MIT", "engines": { "node": ">= 14.0.0" } @@ -2492,6 +2683,7 @@ "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -2504,17 +2696,20 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/unfetch": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", - "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==" + "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==", + "license": "MIT" }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -2522,12 +2717,14 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", "engines": { "node": ">= 0.4.0" } @@ -2549,6 +2746,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -2557,6 +2755,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", "engines": { "node": ">=12" } @@ -2565,6 +2764,7 @@ "version": "13.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "license": "MIT", "dependencies": { "tr46": "^4.1.1", "webidl-conversions": "^7.0.0" @@ -2577,6 +2777,7 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } @@ -2585,6 +2786,7 @@ "version": "3.13.0", "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz", "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==", + "license": "MIT", "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", @@ -2606,6 +2808,7 @@ "version": "4.7.0", "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", + "license": "MIT", "dependencies": { "logform": "^2.3.2", "readable-stream": "^3.6.0", @@ -2618,12 +2821,14 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" } } } From 4a9fc8fdb9d2d6fdd0f9fbc3071cfad3ec855602 Mon Sep 17 00:00:00 2001 From: veyselboybay Date: Wed, 5 Jun 2024 18:30:23 -0400 Subject: [PATCH 6/6] added email service in register controller, updated read me --- README.md | 1 + Server/controllers/authController.js | 8 +- .../utils/emailTemplates/downAlertTemplate.js | 469 ++++++++++++++++++ Server/utils/emailTemplates/images/image1.png | Bin 0 -> 52427 bytes .../utils/emailTemplates/registerTemplate.js | 435 ++++++++++++++++ 5 files changed, 911 insertions(+), 2 deletions(-) create mode 100644 Server/utils/emailTemplates/downAlertTemplate.js create mode 100644 Server/utils/emailTemplates/images/image1.png create mode 100644 Server/utils/emailTemplates/registerTemplate.js diff --git a/README.md b/README.md index 10a7c93f9..e538e5050 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ Configure the server with the following environmental variables: | PORT | Optional | `integer` | Specifies Port for Server | | | SENDGRID_API_KEY | Required | `string` | Specifies API KEY for SendGrid email service | | | SYSTEM_EMAIL_ADDRESS | Required | `string` | Specifies System email to be used in emailing service, must be a verified email by sendgrid | | +| LOGIN_PAGE_URL | Required | `string` | Login url to be used in emailing service | | | REDIS_HOST | Required | `string` | Host address for Redis database | | | REDIS_PORT | Required | `integer` | Port for Redis database | | diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index 257048937..3db0a70a4 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -9,6 +9,8 @@ const logger = require("../utils/logger"); require("dotenv").config(); var jwt = require("jsonwebtoken"); const SERVICE_NAME = "auth"; +const { sendEmail } = require('../utils/sendEmail') +const { registerTemplate } = require('../utils/emailTemplates/registerTemplate') /** * Creates and returns JWT token with an arbitrary payload @@ -53,13 +55,15 @@ const registerController = async (req, res, next) => { // Create a new user try { const newUser = await req.db.insertUser(req, res); - // TODO: Send an email to user - // Will add this later logger.info("New user created!", { service: SERVICE_NAME, userId: newUser._id, }); const token = issueToken(newUser._doc); + + // Sending email to user with pre defined template + const template = registerTemplate('https://www.bluewavelabs.ca'); + await sendEmail([newUser.email], 'Welcome to Uptime Monitor', template, 'Registered.'); return res .status(200) diff --git a/Server/utils/emailTemplates/downAlertTemplate.js b/Server/utils/emailTemplates/downAlertTemplate.js new file mode 100644 index 000000000..2012d3c18 --- /dev/null +++ b/Server/utils/emailTemplates/downAlertTemplate.js @@ -0,0 +1,469 @@ +/** + * + * @param {String} loginUrl - login Url shared with registered user. + * @param {String} monitorName + * @param {String} timeStamp + * @returns {String} returns html content as String + */ +const downAlertTemplate = (loginUrl, monitorName, timeStamp) => { + return ` + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+
+
+ + + +
+
+
+ + + + + + + +
+ + + + + + + +
+   +
+ +
+ +
+
+
+ + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + + + + + +
+ + +

Uptime Monitor

+ + +
+ +
+
+
+ + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + + + + + +
+ +
+

by BlueWave Labs

+
+ +
+ +
+
+
+ + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + + + + + +
+ + +

System Down Alert

+ + +
+ + + + + + + +
+ + +

Your monitor service requires your attention

+ + +
+ +
+
+
+ + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + + + + + +
+ +
+

+

  • ${monitorName}
  • +
  • ${timeStamp}
  • +

    +
    + +
    + +
    +
    +
    + + +
    +
    +
    + + + + + +
    +
    +
    + + + +
    +
    +
    + + + + + + + +
    + +
    +

    Login your account to see more details!

    +
    + +
    + + + + + + + +
    + + + + +
    + +
    +
    +
    + + +
    +
    +
    + + + + + +
    +
    +
    + + + +
    +
    +
    + + + + + + + +
    + +
    +

    © 2024 BlueWave Labs. All Rights Reserved.

    +
    + +
    + +
    +
    +
    + + +
    +
    +
    + + + + + +
    +
    +
    + + + +
    +
    +
    + + + + + + + +
    + + + + + + + +
    +   +
    + +
    + +
    +
    +
    + + +
    +
    +
    + + + + +
    + + + + + + + ` +} + +module.exports = { downAlertTemplate } \ No newline at end of file diff --git a/Server/utils/emailTemplates/images/image1.png b/Server/utils/emailTemplates/images/image1.png new file mode 100644 index 0000000000000000000000000000000000000000..1df9d736faff4f64368a171fb8ac4b70012bedb9 GIT binary patch literal 52427 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 { + return ` + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    + + + +
    +
    +
    + + + + + + + +
    + + + + + + + +
    +   +
    + +
    + +
    +
    +
    + + +
    +
    +
    + + + + + +
    +
    +
    + + + +
    +
    +
    + + + + + + + +
    + + +

    Uptime Monitor

    + + +
    + +
    +
    +
    + + +
    +
    +
    + + + + + +
    +
    +
    + + + +
    +
    +
    + + + + + + + +
    + +
    +

    by BlueWave Labs

    +
    + +
    + +
    +
    +
    + + +
    +
    +
    + + + + + +
    +
    +
    + + + +
    +
    +
    + + + + + + + +
    + + +

    Registered!

    + + +
    + + + + + + + +
    + + +

    your account is ready for use

    + + +
    + +
    +
    +
    + + +
    +
    +
    + + + + + +
    +
    +
    + + + +
    +
    +
    + + + + + + + + + + + + + + + +
    + + + + +
    + +
    +
    +
    + + +
    +
    +
    + + + + + +
    +
    +
    + + + +
    +
    +
    + + + + + + + +
    + +
    +

    © 2024 BlueWave Labs. All Rights Reserved.

    +
    + +
    + +
    +
    +
    + + +
    +
    +
    + + + + + +
    +
    +
    + + + +
    +
    +
    + + + + + + + +
    + + + + + + + +
    +   +
    + +
    + +
    +
    +
    + + +
    +
    +
    + + + + +
    + + + + + + + ` +} + +module.exports = {registerTemplate} \ No newline at end of file