From 49b1a3f6b370c3a643f20f4d155394943fabd90e Mon Sep 17 00:00:00 2001 From: Rampeur Date: Wed, 13 Aug 2025 21:51:07 +0200 Subject: [PATCH] =?UTF-8?q?Ajout=20de=20la=20base=20de=20donn=C3=A9es=20My?= =?UTF-8?q?SQL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env | 10 +- .env.development | 8 +- .env.local | 8 +- .env.production | 8 +- .gitignore | 2 - app.js | 5 +- middlewares/exceptions.handler.js | 49 + nodemon.json | 10 +- package-lock.json | 962 +++++++++++++++++- package.json | 7 +- routes/api/index.js | 30 +- routes/index.js | 6 +- src/app.js | 19 + src/controllers/article.controller.js | 42 + src/controllers/user.controller.js | 36 + src/database/config/db.config.js | 33 + src/database/config/sequelize.js | 43 + src/database/index.js | 11 + .../migrations/20240926095920-create-user.js | 33 + .../20240926100622-create-project.js | 41 + src/database/models/article.js | 43 + src/database/models/comment.js | 0 src/database/models/tag.js | 0 src/database/models/user.js | 60 ++ src/database/relationships/index.js | 29 + src/database/seeders/index.js | 1 + src/routes/api/article.routes.js | 9 + src/routes/api/user.routes.js | 9 + src/routes/index.js | 10 + src/server.js | 24 + src/services/article.service.js | 23 + src/services/connectDB.js | 23 + src/services/user.service.js | 21 + src/utils/index.js | 1 + src/validations/index.js | 0 35 files changed, 1579 insertions(+), 37 deletions(-) create mode 100644 middlewares/exceptions.handler.js create mode 100644 src/app.js create mode 100644 src/controllers/article.controller.js create mode 100644 src/controllers/user.controller.js create mode 100644 src/database/config/db.config.js create mode 100644 src/database/config/sequelize.js create mode 100644 src/database/index.js create mode 100644 src/database/migrations/20240926095920-create-user.js create mode 100644 src/database/migrations/20240926100622-create-project.js create mode 100644 src/database/models/article.js create mode 100644 src/database/models/comment.js create mode 100644 src/database/models/tag.js create mode 100644 src/database/models/user.js create mode 100644 src/database/relationships/index.js create mode 100644 src/database/seeders/index.js create mode 100644 src/routes/api/article.routes.js create mode 100644 src/routes/api/user.routes.js create mode 100644 src/routes/index.js create mode 100644 src/server.js create mode 100644 src/services/article.service.js create mode 100644 src/services/connectDB.js create mode 100644 src/services/user.service.js create mode 100644 src/utils/index.js create mode 100644 src/validations/index.js diff --git a/.env b/.env index 87f48fc..eabe5fa 100644 --- a/.env +++ b/.env @@ -1,7 +1,7 @@ APP_ENV="development" NODE_ENV="development" DEBUG=false -SERVER_PORT="3200" +SERVER_PORT="3201" SECRET="$2b$10$2.JkQCRUa3fXESy/WyKVWO" SESSION_LIFETIME="3600" MONGODB_URI="mongodb://localhost:27017/adastradb" @@ -14,4 +14,10 @@ COUCHDB_DATABASE="adastradb" COUCHDB_DESIGN="adastra_app" COUCHDB_CREDENTIAL="cmFtcGV1cjpES3hwMjRQUw==" SKYDIVERID_API_URL="https://skydiver.id/api" -SKYDIVERID_API_TOKEN="xmqzgnGYMD.OJgFw1pCXCpJFGmZfSjmWK8lrpqAQNnu" \ No newline at end of file +SKYDIVERID_API_TOKEN="xmqzgnGYMD.OJgFw1pCXCpJFGmZfSjmWK8lrpqAQNnu" +MYSQL_DBNAME="c4adastracomdb2" +MYSQL_DBUSER="c4adastracomu2" +MYSQL_DBPASS="kbrnrt5jPK12" +MYSQL_DBHOST="ns388640.ip-176-31-255.eu" +MYSQL_DBPORT="3306" +MYSQL_DBTYPE="mysql" \ No newline at end of file diff --git a/.env.development b/.env.development index 0bea2f9..90eaad0 100644 --- a/.env.development +++ b/.env.development @@ -1,7 +1,7 @@ APP_ENV="development" NODE_ENV="development" DEBUG=false -SERVER_PORT="3200" +SERVER_PORT="3201" SECRET="$2b$10$2.JkQCRUa3fXESy/WyKVWO" SESSION_LIFETIME=3600 MONGODB_URI="mongodb://localhost:27017/adastradb" @@ -15,3 +15,9 @@ COUCHDB_DESIGN="adastra_app" COUCHDB_CREDENTIAL="cmFtcGV1cjpES3hwMjRQUw==" SKYDIVERID_API_URL="https://skydiver.id/api" SKYDIVERID_API_TOKEN="xmqzgnGYMD.OJgFw1pCXCpJFGmZfSjmWK8lrpqAQNnu" +MYSQL_DBNAME="c4adastracomdb2" +MYSQL_DBUSER="c4adastracomu2" +MYSQL_DBPASS="kbrnrt5jPK12" +MYSQL_DBHOST="ns388640.ip-176-31-255.eu" +MYSQL_DBPORT="3306" +MYSQL_DBTYPE="mysql" diff --git a/.env.local b/.env.local index a5278de..64813c6 100644 --- a/.env.local +++ b/.env.local @@ -1,7 +1,7 @@ APP_ENV="local" NODE_ENV="development" DEBUG=false -SERVER_PORT="3200" +SERVER_PORT="3201" SECRET="$2b$10$2.JkQCRUa3fXESy/WyKVWO" SESSION_LIFETIME=3600 MONGODB_URI="mongodb://localhost:27017/adastradb" @@ -15,3 +15,9 @@ COUCHDB_DESIGN="adastra_app" COUCHDB_CREDENTIAL="cmFtcGV1cjpES3hwMjRQUw==" SKYDIVERID_API_URL="https://skydiver.id/api" SKYDIVERID_API_TOKEN="xmqzgnGYMD.OJgFw1pCXCpJFGmZfSjmWK8lrpqAQNnu" +MYSQL_DBNAME="c4adastracomdb2" +MYSQL_DBUSER="c4adastracomu2" +MYSQL_DBPASS="kbrnrt5jPK12" +MYSQL_DBHOST="ns388640.ip-176-31-255.eu" +MYSQL_DBPORT="3306" +MYSQL_DBTYPE="mysql" diff --git a/.env.production b/.env.production index ff15f5f..8fa8723 100644 --- a/.env.production +++ b/.env.production @@ -1,7 +1,7 @@ APP_ENV="production" NODE_ENV="production" DEBUG=false -SERVER_PORT="3200" +SERVER_PORT="3201" SECRET="$2b$10$2.JkQCRUa3fXESy/WyKVWO" SESSION_LIFETIME=3600 MONGODB_URI="mongodb://localhost:27017/adastradb" @@ -15,3 +15,9 @@ COUCHDB_DESIGN="adastra_app" COUCHDB_CREDENTIAL="cmFtcGV1cjpES3hwMjRQUw==" SKYDIVERID_API_URL="https://skydiver.id/api" SKYDIVERID_API_TOKEN="xmqzgnGYMD.OJgFw1pCXCpJFGmZfSjmWK8lrpqAQNnu" +MYSQL_DBNAME="c4adastracomdb2" +MYSQL_DBUSER="c4adastracomu2" +MYSQL_DBPASS="kbrnrt5jPK12" +MYSQL_DBHOST="ns388640.ip-176-31-255.eu" +MYSQL_DBPORT="3306" +MYSQL_DBTYPE="mysql" diff --git a/.gitignore b/.gitignore index b740f61..2d8bf39 100644 --- a/.gitignore +++ b/.gitignore @@ -62,5 +62,3 @@ sonar.properties **/*.copy.ts **/*.copy.scss **/*.copy.html - -middlewares diff --git a/app.js b/app.js index 8b7b178..fbedb15 100644 --- a/app.js +++ b/app.js @@ -7,7 +7,8 @@ const { promisify } = require('util'), bodyParser = require('body-parser'), chalk = require('chalk'), utils = require('./routes/utils'), - exceptionHandler = require('./middlewares/exceptions.handler.js'); + exceptionHandler = require('./middlewares/exceptions.handler.js'), + connectDB = require('./src/services/connectDB'); var express = require('express'), session = require('express-session'), cors = require('cors'), @@ -65,6 +66,8 @@ if(isProduction){ require('./models/mongo'); require('./config/passport'); + +connectDB(); app.use(require('./routes')); app.use(exceptionHandler.notFoundErrorHandler); diff --git a/middlewares/exceptions.handler.js b/middlewares/exceptions.handler.js new file mode 100644 index 0000000..bbac03b --- /dev/null +++ b/middlewares/exceptions.handler.js @@ -0,0 +1,49 @@ +var appEnv = process.env.APP_ENV; +if (appEnv == undefined) { + appEnv = 'development'; +} +const isProduction = appEnv === 'production', + chalk = require('chalk'), + utils = require('../routes/utils'); + +const exceptionHandler = { + notFoundErrorHandler: (req, res, next) => { + let err = new Error('Not Found'); + err.status = 404; + console.log(`${utils.getDateTimeISOString()}`, chalk.yellow(`${err.status} ${err.message}`)); + next(err); + }, + logErrorHandler: (err, req, res, next) => { + console.log(`${utils.getDateTimeISOString()}`, chalk.red(`error handler : ${err.message} ${err.err}`)); + console.error(err.stack); + next(err); + }, + clientErrorHandler: (err, req, res, next) => { + if (req.xhr) { + res.status(err.status || 500); + } else { + next(err); + } + }, + // eslint-disable-next-line no-unused-vars + fianlErrorHandler: (err, req, res, next) => { + res.status(err.status || 500); + if (!isProduction) { + /* development error handler will print stacktrace */ + res.json({errors: { + message: err.message, + error: err.err, + stack: err.stack + }}); + } else { + /* production error handler no stacktraces leaked to user */ + res.json({errors: { + message: err.message, + error: {}, + stack: {} + }}); + } + } +}; + +module.exports = exceptionHandler; diff --git a/nodemon.json b/nodemon.json index 89a1986..59de8a0 100644 --- a/nodemon.json +++ b/nodemon.json @@ -3,7 +3,7 @@ "APP_ENV": "local", "NODE_ENV" : "development", "DEBUG": false, - "SERVER_PORT": "3200", + "SERVER_PORT": "3201", "SECRET": "$2b$10$aEsAUG7Dy8dcTORi1vaQle", "SESSION_LIFETIME": "3600", "MONGODB_URI": "mongodb://localhost:27017/adastradb", @@ -16,6 +16,12 @@ "COUCHDB_DESIGN": "adastra_app", "COUCHDB_CREDENTIAL": "cmFtcGV1cjpES3hwMjRQUw==", "SKYDIVERID_API_URL": "https://skydiver.id/api", - "SKYDIVERID_API_TOKEN": "xmqzgnGYMD.OJgFw1pCXCpJFGmZfSjmWK8lrpqAQNnu" + "SKYDIVERID_API_TOKEN": "xmqzgnGYMD.OJgFw1pCXCpJFGmZfSjmWK8lrpqAQNnu", + "MYSQL_DBNAME": "c4adastracomdb2", + "MYSQL_DBUSER": "c4adastracomu2", + "MYSQL_DBPASS": "kbrnrt5jPK12", + "MYSQL_DBHOST": "ns388640.ip-176-31-255.eu", + "MYSQL_DBPORT": "3306", + "MYSQL_DBTYPE": "mysql" } } diff --git a/package-lock.json b/package-lock.json index 3276bc9..530d3f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,11 +25,13 @@ "mongoose": "^6.12.6", "mongoose-unique-validator": "^3.1.0", "morgan": "^1.10.0", + "mysql2": "^3.14.3", "node-fetch": "^3.3.2", "passport": "^0.6.0", "passport-headerapikey": "^1.2.2", "passport-local": "^1.0.0", "request": "^2.88.2", + "sequelize": "^6.37.3", "slug": "^8.2.3", "underscore": "^1.13.6", "uuid": "^9.0.1" @@ -39,7 +41,8 @@ "eslint": "^9.0.0", "globals": "^15.0.0", "newman": "^5.3.2", - "nodemon": "^2.0.22" + "nodemon": "^2.0.22", + "sequelize-cli": "^6.6.2" }, "engines": { "node": "^16.20.2 || ^18.19.1 || ^20.11.1" @@ -890,6 +893,102 @@ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "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", @@ -991,6 +1090,22 @@ "node": ">= 8" } }, + "node_modules/@one-ini/wasm": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "dev": true + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@postman/form-data": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@postman/form-data/-/form-data-3.1.1.tgz", @@ -1623,6 +1738,14 @@ "node": ">=14.0.0" } }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dependencies": { + "@types/ms": "*" + } + }, "node_modules/@types/jsonwebtoken": { "version": "9.0.6", "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz", @@ -1631,6 +1754,11 @@ "@types/node": "*" } }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==" + }, "node_modules/@types/node": { "version": "20.11.21", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.21.tgz", @@ -1639,6 +1767,11 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/validator": { + "version": "13.15.2", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.2.tgz", + "integrity": "sha512-y7pa/oEJJ4iGYBxOpfAKn5b9+xuihvzDVnC/OSvlVnGxVg0pOqmjiMafiJ1KVNQEaPZf9HsEp5icEwGg8uIe5Q==" + }, "node_modules/@types/webidl-conversions": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", @@ -1827,6 +1960,15 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -1835,6 +1977,14 @@ "node": "*" } }, + "node_modules/aws-ssl-profiles": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", + "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==", + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/aws4": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", @@ -2151,6 +2301,17 @@ "colors": "1.4.0" } }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2209,6 +2370,16 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -2264,9 +2435,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", @@ -2353,6 +2524,14 @@ "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==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -2389,6 +2568,17 @@ "url": "https://dotenvx.com" } }, + "node_modules/dottie": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.6.tgz", + "integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -2411,6 +2601,57 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/editorconfig": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", + "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "dev": true, + "dependencies": { + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "9.0.1", + "semver": "^7.5.3" + }, + "bin": { + "editorconfig": "bin/editorconfig" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/editorconfig/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/minimatch": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -2474,6 +2715,15 @@ "node": ">= 0.4" } }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -3039,6 +3289,34 @@ } } }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -3087,6 +3365,21 @@ "node": ">= 0.6" } }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", @@ -3155,6 +3448,23 @@ "node": ">=10" } }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -3235,6 +3545,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -3330,9 +3646,9 @@ "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, "node_modules/hasown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", - "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { "function-bind": "^1.1.2" }, @@ -3506,6 +3822,14 @@ "node": ">=0.8.19" } }, + "node_modules/inflection": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.4.tgz", + "integrity": "sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw==", + "engines": [ + "node >= 0.4.0" + ] + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -3520,6 +3844,12 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "node_modules/ip-address": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", @@ -3561,6 +3891,21 @@ "node": ">=8" } }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -3608,6 +3953,11 @@ "node": ">=8" } }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" + }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -3624,6 +3974,21 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jake": { "version": "10.8.7", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", @@ -3641,6 +4006,113 @@ "node": ">=10" } }, + "node_modules/js-beautify": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.4.tgz", + "integrity": "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==", + "dev": true, + "dependencies": { + "config-chain": "^1.1.13", + "editorconfig": "^1.0.4", + "glob": "^10.4.2", + "js-cookie": "^3.0.5", + "nopt": "^7.2.1" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/js-beautify/node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/js-beautify/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/js-beautify/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-beautify/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-beautify/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/js-beautify/node_modules/nopt": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "dev": true, + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/js-sha512": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz", @@ -3691,6 +4163,18 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/jsonwebtoken": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", @@ -3860,6 +4344,11 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==" + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -3871,6 +4360,20 @@ "node": ">=10" } }, + "node_modules/lru.min": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.2.tgz", + "integrity": "sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg==", + "engines": { + "bun": ">=1.0.0", + "deno": ">=1.30.0", + "node": ">=8.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wellwelwel" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -4043,6 +4546,25 @@ "node": ">=10" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.48.tgz", + "integrity": "sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw==", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, "node_modules/mongodb": { "version": "4.17.2", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.17.2.tgz", @@ -4179,6 +4701,55 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/mysql2": { + "version": "3.14.3", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.14.3.tgz", + "integrity": "sha512-fD6MLV8XJ1KiNFIF0bS7Msl8eZyhlTDCDl75ajU5SJtpdx9ZPEACulJcqJWr1Y8OYyxsFc4j3+nflpmhxCU5aQ==", + "dependencies": { + "aws-ssl-profiles": "^1.1.1", + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.3", + "long": "^5.2.1", + "lru.min": "^1.0.0", + "named-placeholders": "^1.1.3", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/mysql2/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", + "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", + "dependencies": { + "lru-cache": "^7.14.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/named-placeholders/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -4515,6 +5086,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -4615,6 +5192,34 @@ "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -4630,6 +5235,17 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, + "node_modules/pg-connection-string": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz", + "integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -4948,6 +5564,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -5156,6 +5778,35 @@ "uuid": "bin/uuid" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -5165,6 +5816,11 @@ "node": ">=4" } }, + "node_modules/retry-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-7.1.1.tgz", + "integrity": "sha512-hMD7odLOt3LkTjcif8aRZqi/hybjpLNgSk5oF5FCowfCjok6LukpN2bDX7R5wDmbgBQFn7YoBxSagmtXHaJYJw==" + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -5278,6 +5934,131 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" + }, + "node_modules/sequelize": { + "version": "6.37.7", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.37.7.tgz", + "integrity": "sha512-mCnh83zuz7kQxxJirtFD7q6Huy6liPanI67BSlbzSYgVNl5eXVdE2CN1FuAeZwG1SNpGsNRCV+bJAVVnykZAFA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/sequelize" + } + ], + "dependencies": { + "@types/debug": "^4.1.8", + "@types/validator": "^13.7.17", + "debug": "^4.3.4", + "dottie": "^2.0.6", + "inflection": "^1.13.4", + "lodash": "^4.17.21", + "moment": "^2.29.4", + "moment-timezone": "^0.5.43", + "pg-connection-string": "^2.6.1", + "retry-as-promised": "^7.0.4", + "semver": "^7.5.4", + "sequelize-pool": "^7.1.0", + "toposort-class": "^1.0.1", + "uuid": "^8.3.2", + "validator": "^13.9.0", + "wkx": "^0.5.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependenciesMeta": { + "ibm_db": { + "optional": true + }, + "mariadb": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "oracledb": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-hstore": { + "optional": true + }, + "snowflake-sdk": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "tedious": { + "optional": true + } + } + }, + "node_modules/sequelize-cli": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/sequelize-cli/-/sequelize-cli-6.6.3.tgz", + "integrity": "sha512-1YYPrcSRt/bpMDDSKM5ubY1mnJ2TEwIaGZcqITw4hLtGtE64nIqaBnLtMvH8VKHg6FbWpXTiFNc2mS/BtQCXZw==", + "dev": true, + "dependencies": { + "fs-extra": "^9.1.0", + "js-beautify": "1.15.4", + "lodash": "^4.17.21", + "picocolors": "^1.1.1", + "resolve": "^1.22.1", + "umzug": "^2.3.0", + "yargs": "^16.2.0" + }, + "bin": { + "sequelize": "lib/sequelize", + "sequelize-cli": "lib/sequelize" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sequelize-pool": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-7.1.0.tgz", + "integrity": "sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/sequelize/node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/sequelize/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/sequelize/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/serialised-error": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/serialised-error/-/serialised-error-1.1.3.tgz", @@ -5461,6 +6242,14 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" }, + "node_modules/sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/sshpk": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", @@ -5537,6 +6326,21 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -5548,6 +6352,19 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -5577,6 +6394,18 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/tar": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", @@ -5625,6 +6454,11 @@ "node": ">=0.6" } }, + "node_modules/toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg==" + }, "node_modules/touch": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", @@ -5747,6 +6581,24 @@ "node": ">= 0.8" } }, + "node_modules/umzug": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", + "integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==", + "dev": true, + "dependencies": { + "bluebird": "^3.7.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/umzug/node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", @@ -5763,6 +6615,15 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -5816,6 +6677,14 @@ "node": ">=10" } }, + "node_modules/validator": { + "version": "13.15.15", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.15.tgz", + "integrity": "sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -5888,6 +6757,14 @@ "string-width": "^1.0.2 || 2 || 3 || 4" } }, + "node_modules/wkx": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", + "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -5903,6 +6780,41 @@ "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", "dev": true }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -5917,11 +6829,47 @@ "node": ">=8.0" } }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index ebb0059..48c3884 100644 --- a/package.json +++ b/package.json @@ -45,13 +45,16 @@ "request": "^2.88.2", "slug": "^8.2.3", "underscore": "^1.13.6", - "uuid": "^9.0.1" + "uuid": "^9.0.1", + "sequelize": "^6.37.3", + "mysql2": "^3.14.3" }, "devDependencies": { "@eslint/js": "^9.0.0", "eslint": "^9.0.0", "globals": "^15.0.0", "newman": "^5.3.2", - "nodemon": "^2.0.22" + "nodemon": "^2.0.22", + "sequelize-cli": "^6.6.2" } } diff --git a/routes/api/index.js b/routes/api/index.js index 6a52f7f..9acda18 100644 --- a/routes/api/index.js +++ b/routes/api/index.js @@ -1,19 +1,19 @@ -var router = require('express').Router(); +var routes = require('express').Router(); -router.use('/', require('./users')); -router.use('/articles', require('./articles')); -router.use('/comments', require('./comments')); -router.use('/tags', require('./tags')); -router.use('/profiles', require('./profiles')); -router.use('/applications', require('./applications')); -router.use('/aeronefs', require('./aeronefs')); -router.use('/canopies', require('./canopies')); -router.use('/dropzones', require('./dropzones')); -router.use('/jumps', require('./jumps')); -router.use('/pages', require('./pages')); -router.use('/qcm', require('./qcm')); +routes.use('/', require('./users')); +routes.use('/articles', require('./articles')); +routes.use('/comments', require('./comments')); +routes.use('/tags', require('./tags')); +routes.use('/profiles', require('./profiles')); +routes.use('/applications', require('./applications')); +routes.use('/aeronefs', require('./aeronefs')); +routes.use('/canopies', require('./canopies')); +routes.use('/dropzones', require('./dropzones')); +routes.use('/jumps', require('./jumps')); +routes.use('/pages', require('./pages')); +routes.use('/qcm', require('./qcm')); -router.use(function (err, req, res, next) { +routes.use(function (err, req, res, next) { if (err.name === 'ValidationError') { return res.status(422).json({ errors: Object.keys(err.errors).reduce(function (errors, key) { @@ -25,4 +25,4 @@ router.use(function (err, req, res, next) { return next(err); }); -module.exports = router; \ No newline at end of file +module.exports = routes; \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index 470acba..77f8a4d 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,4 +1,4 @@ -var router = require('express').Router(); -router.use('/api', require('./api')); +var routes = require('express').Router(); +routes.use('/api', require('./api')); -module.exports = router; +module.exports = routes; diff --git a/src/app.js b/src/app.js new file mode 100644 index 0000000..ff3fb4c --- /dev/null +++ b/src/app.js @@ -0,0 +1,19 @@ +//import express to use express methods and properties +const express = require('express'); +const routes = require('./routes'); + +//create an instance of express +const app = express(); + +//use express.json() to parse incoming requests with JSON payloads +app.use(express.json()); +app.use(express.urlencoded({ extended: true })); //parse incoming requests with urlencoded payloads + +app.use('/api/v1', routes); + +//catch all routes that are not defined to avoid running into errors when a route is not defined +app.use('*', (req, res) => { + res.status(404).json({ error: 'Path does not found, try again' }); +}); + +module.exports = app; //export app to be used in other files diff --git a/src/controllers/article.controller.js b/src/controllers/article.controller.js new file mode 100644 index 0000000..46e46e5 --- /dev/null +++ b/src/controllers/article.controller.js @@ -0,0 +1,42 @@ +const { ArticleService } = require('../services/article.service'); + +const createArticle = async (req, res) => { + try { + const { name, description, userId } = req.body; + + const article = await ArticleService.createArticle({ + name, + description, + userId, + }); + + res.status(201).json({ + message: 'Article created successfully', + data: article, + }); + } catch (err) { + res.status(500).json({ + message: 'something went wrong while creating article', + error: err.message, + }); + } +}; + +const getArticlesByUserId = async (req, res) => { + try { + const { userId } = req.params; + + const articles = await ArticleService.getArticlesByUserId(userId); + + res.status(200).json({ + data: articles, + }); + } catch (err) { + res.status(500).json({ + message: 'something went wrong while fetching articles', + error: err.message, + }); + } +}; + +module.exports = { createArticle, getArticlesByUserId }; \ No newline at end of file diff --git a/src/controllers/user.controller.js b/src/controllers/user.controller.js new file mode 100644 index 0000000..a276102 --- /dev/null +++ b/src/controllers/user.controller.js @@ -0,0 +1,36 @@ +const { UserService } = require('../services/user.service'); + +const createUser = async (req, res) => { + try { + const { name, email } = req.body; + + const user = await UserService.createUser({ name, email }); + + res.status(201).json({ + message: 'User created successfully', + data: user, + }); + } catch (err) { + res.status(500).json({ + message: 'something went wrong while creating user', + error: err.message, + }); + } +}; + +const getAllUsers = async (req, res) => { + try { + const users = await UserService.getAllUsers(); + + res.status(200).json({ + data: users, + }); + } catch (err) { + res.status(500).json({ + message: 'something went wrong while fetching users', + error: err.message, + }); + } +}; + +module.exports = { createUser, getAllUsers }; \ No newline at end of file diff --git a/src/database/config/db.config.js b/src/database/config/db.config.js new file mode 100644 index 0000000..059f957 --- /dev/null +++ b/src/database/config/db.config.js @@ -0,0 +1,33 @@ +module.exports = { + "development": { + "username": process.env.MYSQL_DBUSER, + "password": process.env.MYSQL_DBPASS, + "database": process.env.MYSQL_DBNAME, + "host": process.env.MYSQL_DBHOST, + "port": process.env.MYSQL_DBPORT, + "dialect": process.env.MYSQL_DBTYPE + }, + "test": { + "username": process.env.MYSQL_DBUSER, + "password": process.env.MYSQL_DBPASS, + "database": process.env.MYSQL_DBNAME, + "host": process.env.MYSQL_DBHOST, + "port": process.env.MYSQL_DBPORT, + "dialect": process.env.MYSQL_DBTYPE + }, + "production": { + "username": process.env.MYSQL_DBUSER, + "password": process.env.MYSQL_DBPASS, + "database": process.env.MYSQL_DBNAME, + "host": process.env.MYSQL_DBHOST, + "port": process.env.MYSQL_DBPORT, + "dialect": process.env.MYSQL_DBTYPE, + "dialectOptions": { + "ssl": { + // enable this for production environment only if using a secure connection + "require": true, + "rejectUnauthorized": false + }, + } + } +} \ No newline at end of file diff --git a/src/database/config/sequelize.js b/src/database/config/sequelize.js new file mode 100644 index 0000000..a4defbe --- /dev/null +++ b/src/database/config/sequelize.js @@ -0,0 +1,43 @@ +const { Sequelize } = require('sequelize'); + +const Op = Sequelize.Op; +const sequelize = new Sequelize( + process.env.MYSQL_DBNAME, + process.env.MYSQL_DBUSER, + process.env.MYSQL_DBPASS, + { + host: process.env.MYSQL_DBHOST, + port: process.env.MYSQL_DBPORT, + dialect: process.env.MYSQL_DBTYPE, + $like: Op.like, + $not: Op.not, + timezone: '+02:00', + define: { + charset: 'utf8mb4', + collate: 'utf8mb4_general_ci', + underscored: false, + freezeTableName: true, + }, + pool: { + //explain this line of code? this means that the connection pool will have a minimum of 0 connections and a maximum of 5 connections + min: 0, + max: 5, + }, + logQueryParameters: process.env.APP_ENV === 'development', // this line of code will log the query parameters if the environment is development + benchmark: true, + }); + +/* +const checkConnection = async () => { + try { + await sequelize.authenticate(); + console.log(`DB Connected`.cyan.underline.bold); + } catch (error) { + console.error("Unable to connect to the database:".red.bold, error); + } +}; + +checkConnection(); +*/ + +module.exports = sequelize; diff --git a/src/database/index.js b/src/database/index.js new file mode 100644 index 0000000..b6e92cc --- /dev/null +++ b/src/database/index.js @@ -0,0 +1,11 @@ +const sequelize = require('./config/sequelize'); +const ArticleModel = require('./models/article'); +const UserModel = require('./models/user'); + +const DB = { + sequelize, + User: UserModel(sequelize), + Article: ArticleModel(sequelize), +}; + +module.exports = DB; diff --git a/src/database/migrations/20240926095920-create-user.js b/src/database/migrations/20240926095920-create-user.js new file mode 100644 index 0000000..9e99769 --- /dev/null +++ b/src/database/migrations/20240926095920-create-user.js @@ -0,0 +1,33 @@ +'use strict'; +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable('Users', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + name: { + type: Sequelize.STRING, + }, + email: { + type: Sequelize.STRING, + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE, + defaultValue: Sequelize.NOW, + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE, + defaultValue: Sequelize.NOW, + }, + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('Users'); + }, +}; diff --git a/src/database/migrations/20240926100622-create-project.js b/src/database/migrations/20240926100622-create-project.js new file mode 100644 index 0000000..65f68ec --- /dev/null +++ b/src/database/migrations/20240926100622-create-project.js @@ -0,0 +1,41 @@ +'use strict'; +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable('article', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + name: { + type: Sequelize.STRING, + }, + description: { + type: Sequelize.TEXT, + }, + userId: { + type: Sequelize.INTEGER, + allowNull: false, + references: { + model: 'User', + key: 'id', + }, + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE, + defaultValue: Sequelize.NOW, + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE, + defaultValue: Sequelize.NOW, + }, + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('article'); + }, +}; diff --git a/src/database/models/article.js b/src/database/models/article.js new file mode 100644 index 0000000..e7b2ee4 --- /dev/null +++ b/src/database/models/article.js @@ -0,0 +1,43 @@ +const { DataTypes, Model } = require("sequelize"); +const sequelize = require("../config/sequelize"); +const slug = require("slug"); + +class Article extends Model { } + +const ArticleModel = () => { + Article.init( + { + id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true, allowNull: false }, + slug: { type: DataTypes.STRING, allowNull: false }, + title: { type: DataTypes.STRING, allowNull: false }, + description: { type: DataTypes.TEXT }, + body: { type: DataTypes.TEXT, allowNull: false } + }, + { + sequelize, + modelName: 'Article', + tableName: 'article', + timestamps: true, + createdAt: true, + updatedAt: true + } + ); + + Article.beforeValidate((article) => { + article.slug =slug(`${article.title}`) + '-' + (Math.random() * Math.pow(36, 6) | 0).toString(36); + }); + + Article.prototype.toJSONFor = function () { + return { + id: this.id, + slug: this.slug, + title: this.title, + description: this.description, + body: this.body + }; + }; + + return Article; +}; + +module.exports = ArticleModel; diff --git a/src/database/models/comment.js b/src/database/models/comment.js new file mode 100644 index 0000000..e69de29 diff --git a/src/database/models/tag.js b/src/database/models/tag.js new file mode 100644 index 0000000..e69de29 diff --git a/src/database/models/user.js b/src/database/models/user.js new file mode 100644 index 0000000..05e4c9e --- /dev/null +++ b/src/database/models/user.js @@ -0,0 +1,60 @@ +const { DataTypes, Model } = require("sequelize"); +const sequelize = require("../config/sequelize"); +const bcrypt = require("bcrypt"); + +class User extends Model { } + +const UserModel = () => { + User.init( + { + id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true, allowNull: false }, + email: { type: DataTypes.STRING, allowNull: false, unique: true }, + username: { type: DataTypes.STRING, allowNull: false, unique: true }, + firstname: { type: DataTypes.STRING }, + lastname: { type: DataTypes.STRING }, + bio: { type: DataTypes.TEXT, allowNull: true }, + image: { type: DataTypes.TEXT, allowNull: true }, + role: { type: DataTypes.STRING }, + password: { type: DataTypes.STRING, allowNull: false } + }, + { + sequelize, + modelName: 'User', + tableName: 'user', + timestamps: false, + createdAt: true, + updatedAt: true + } + ); + + Model.prototype.matchPassword = async function (enteredPassword) { + return await bcrypt.compare(enteredPassword, this.password); + }; + + const DEFAULT_SALT_ROUNDS = 10; + + User.addHook("beforeCreate", async (user) => { + const encryptedPassword = await bcrypt.hash( + user.password, + DEFAULT_SALT_ROUNDS + ); + user.password = encryptedPassword; + }); + + User.prototype.toJSONFor = function () { + return { + id: this.id, + email: this.email, + username: this.username, + firstname: this.firstname, + lastname: this.lastname, + bio: this.bio, + image: this.image, + role: this.role + }; + }; + + return User; +}; + +module.exports = UserModel; diff --git a/src/database/relationships/index.js b/src/database/relationships/index.js new file mode 100644 index 0000000..0614884 --- /dev/null +++ b/src/database/relationships/index.js @@ -0,0 +1,29 @@ +const DB = require('../index'); + +const associate = () => { + DB.User.hasMany(DB.Article, { + foreignKey: 'userId', + as: 'projects', + }); + + DB.Article.belongsTo(DB.User, { + foreignKey: 'userId', + as: 'user', + }); + /* + DB.User.belongsToMany(DB.User, { as: "followers", through: "Followers", foreignKey: "userId", timestamps: false }); + DB.User.belongsToMany(DB.User, { as: "following", through: "Followers", foreignKey: "followerId", timestamps: false }); + DB.User.hasMany(DB.Article, { foreignKey: "authorId", onDelete: "CASCADE" }); + DB.Article.belongsTo(DB.User, { as: "author", foreignKey: "authorId" }); + DB.User.hasMany(DB.Comment, { foreignKey: "authorId", onDelete: "CASCADE" }); + DB.Comment.belongsTo(DB.User, { as: "author", foreignKey: "authorId" }); + DB.Article.hasMany(DB.omment, { foreignKey: "articleId", onDelete: "CASCADE" }); + DB.Comment.belongsTo(DB.Article, { foreignKey: "articleId" }); + DB.User.belongsToMany(DB.Article, { as: "favorites", through: "Favorites", timestamps: false }); + DB.Article.belongsToMany(DB.User, { through: "Favorites", foreignKey: "articleId", timestamps: false }); + DB.Article.belongsToMany(DB.Tag, { through: "TagLists", as: "tagLists", foreignKey: "articleId", timestamps: false, onDelete: "CASCADE" }); + DB.Tag.belongsToMany(DB.Article, { through: "ArticleTags", uniqueKey: false, timestamps: false }); + */ +}; + +module.exports = associate; diff --git a/src/database/seeders/index.js b/src/database/seeders/index.js new file mode 100644 index 0000000..0abae44 --- /dev/null +++ b/src/database/seeders/index.js @@ -0,0 +1 @@ +console.log('this is placeholder for models'); diff --git a/src/routes/api/article.routes.js b/src/routes/api/article.routes.js new file mode 100644 index 0000000..c6bb219 --- /dev/null +++ b/src/routes/api/article.routes.js @@ -0,0 +1,9 @@ +const express = require('express'); +const { createProject, getProjectsByUserId } = require('../../controllers/article.controller'); + +const projectRouter = express.Router(); + +projectRouter.post('/', createProject); +projectRouter.get('/:userId', getProjectsByUserId); + +module.exports = projectRouter; diff --git a/src/routes/api/user.routes.js b/src/routes/api/user.routes.js new file mode 100644 index 0000000..4ce8e2a --- /dev/null +++ b/src/routes/api/user.routes.js @@ -0,0 +1,9 @@ +const express = require('express'); +const { createUser, getAllUsers } = require('../../controllers/user.controller'); + +const userRouter = express.Router(); + +userRouter.post('/register', createUser); +userRouter.get('/', getAllUsers); + +module.exports = userRouter; diff --git a/src/routes/index.js b/src/routes/index.js new file mode 100644 index 0000000..c11124d --- /dev/null +++ b/src/routes/index.js @@ -0,0 +1,10 @@ +const express = require('express'); +const articleRouter = require('./api/article.routes'); +const userRouter = require('./api/user.routes'); + +const routes = express.Router(); + +routes.use('/user', userRouter); +routes.use('/article', articleRouter); + +module.exports = routes; diff --git a/src/server.js b/src/server.js new file mode 100644 index 0000000..8a28974 --- /dev/null +++ b/src/server.js @@ -0,0 +1,24 @@ +const http = require('http'); // import the http module from node.js core to create a server instance +const app = require('./app'); // import the express app from the app.js file +const connectDB = require('./services/connectDB'); + +const PORT = process.env.PORT || 3000; // set the port number to be used by the server instance + +/* create a server instance using the http.createServer method + * there is no right or wrong way to create a server instance weather using the http.createServer method or the app.listen method + * I usualy use the http.createServer method because it gives me more control over the server instance like adding a socket.io instance to the server instance + */ +const server = http.createServer(app); + +// Adding server instance inside a callback function also gives a flexibility to add more logic before starting the server +const startServer = () => { + // Listen to the server instance on the specified port number + connectDB(); // connect to the database before starting the server + server.listen(PORT, () => { + console.log( + `Server is running on port ${PORT} AND NODE_ENV is ${process.env.NODE_ENV}` + ); + }); +}; + +startServer(); // start the server instance diff --git a/src/services/article.service.js b/src/services/article.service.js new file mode 100644 index 0000000..433ba4e --- /dev/null +++ b/src/services/article.service.js @@ -0,0 +1,23 @@ +const DB = require('../database'); + +const { Projects } = DB; + +module.exports = class ProjectService { + static async createProject(data) { + return Projects.create(data); + } + + static async getProjectsByUserId(userId) { + return Projects.findAll({ + where: { userId }, + include: [ + { + model: DB.Users, + as: 'user', + attributes: ['name', 'email'], + }, + ], + order: [['createdAt', 'DESC']], + }); + } +} diff --git a/src/services/connectDB.js b/src/services/connectDB.js new file mode 100644 index 0000000..98d2f30 --- /dev/null +++ b/src/services/connectDB.js @@ -0,0 +1,23 @@ +const DB = require('../database'); +const sequelize = require('../database/config/sequelize'); +const associate = require('../database/relationships'); + +// Connect to the database and log a message to the console +const connectDB = async () => { + try { + await sequelize.authenticate(); + console.log('Connection has been established successfully🔥'); + + // Synchronize the database with the models without need of dropping the tables + await DB.sequelize.sync({ + force: false, + }); + + associate(); // Call the associate function to create the relationships between the models + } catch (error) { + console.error('Unable to connect to the database:', error); + process.exit(1); // Exit the process if the connection is not successful + } +}; + +module.exports = connectDB; diff --git a/src/services/user.service.js b/src/services/user.service.js new file mode 100644 index 0000000..e2b9d08 --- /dev/null +++ b/src/services/user.service.js @@ -0,0 +1,21 @@ +const DB = require('../database'); + +const { Users } = DB; + +module.exports = class UserService { + static async createUser(data) { + return Users.create(data); + } + + static async getAllUsers() { + return Users.findAll({ + order: [['createdAt', 'DESC']], + }); + } + + static async getUserById(id) { + return Users.findByPk(id); + } +} + +//module.exports = userService; \ No newline at end of file diff --git a/src/utils/index.js b/src/utils/index.js new file mode 100644 index 0000000..9d9587d --- /dev/null +++ b/src/utils/index.js @@ -0,0 +1 @@ +console.log('this is placeholder for routes'); diff --git a/src/validations/index.js b/src/validations/index.js new file mode 100644 index 0000000..e69de29