diff --git a/.eslintrc.json b/.eslintrc.json index 2f70f7a..14826a3 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -20,6 +20,7 @@ ], "rules": { "import/first": 2, + "camelcase":"error", "import/newline-after-import": 2, "import/order": [ "error", diff --git a/.husky/pre-commit b/.husky/pre-commit index 05c8921..b4aa20e 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -2,4 +2,4 @@ . "$(dirname -- "$0")/_/husky.sh" npm test -npm run eslint \ No newline at end of file +# npm run eslint \ No newline at end of file diff --git a/jest.config.ts b/jest.config.ts index dae6de5..abad9c8 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -1,18 +1,32 @@ +import { pathsToModuleNameMapper } from 'ts-jest'; + +// import { compilerOptions } from './tsconfig.json'; + +const TS_CONFIG_PATH = './tsconfig.json'; +const SRC_PATH = '/src'; + const config = { preset: 'ts-jest', testEnvironment: 'node', roots: ['/src/tests'], setupFiles: ['/src/tests/setup.ts'], - moduleNameMapper: { - '@core/(.*)': ['/src/core/$1'], - '@helpers/(.*)': ['/src/helpers/$1'], - '@routes/(.*)': ['/src/routes/$1'], - '@test/(.*)': ['/src/tests/$1'], - '@app': ['/src/app.ts'], - '@routes': ['/src/routes/index.ts'], - '@server': ['/src/server.ts'], - '@config': ['/src/config.ts'] - }, + moduleNameMapper: pathsToModuleNameMapper( + { + '@core/*': ['./src/core/*'], + '@database': ['./src/database.ts'], + '@helpers/*': ['./src/helpers/*'], + '@apps': ['./src/apps/index.ts'], + '@apps/*': ['./src/apps/*'], + '@test/*': ['./src/tests/*'], + '@config': ['./src/config.ts'], + '@app': ['./src/app.ts'], + '@server': ['./src/server.ts'], + '@bin/*': ['./src/bin/*'] + }, + { + prefix: '/' + } + ), collectCoverageFrom: ['/src/**/*.ts', '!**/node_modules/**'] }; diff --git a/package-lock.json b/package-lock.json index 71df7f5..46a2944 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,28 +9,49 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "accesscontrol": "^2.2.1", + "bcrypt": "^5.1.0", + "bcryptjs": "^2.4.3", + "boxen": "^7.0.2", + "chalk": "^5.2.0", "concurrently": "^7.6.0", + "connect-mongo": "^4.6.0", "dotenv": "^16.0.3", "eslint": "^8.31.0", "express": "^4.18.2", + "express-session": "^1.17.3", "express-validator": "^6.14.2", "http-status-codes": "^2.2.0", "joi": "^17.7.0", "jsonwebtoken": "^9.0.0", + "loadash": "^1.0.0", "mongoose": "^6.8.2", "morgan": "^1.10.0", + "passport": "^0.6.0", + "passport-jwt": "^4.0.1", + "passport-local": "^1.0.0", "supertest": "^6.3.3", "typescript": "^4.9.4", "winston": "^3.8.2", - "winston-daily-rotate-file": "^4.7.1" + "winston-daily-rotate-file": "^4.7.1", + "yargs": "^17.7.1" + }, + "bin": { + "moon": "bin/index.ts" }, "devDependencies": { + "@types/bcrypt": "^5.0.0", + "@types/bcryptjs": "^2.4.2", "@types/cors": "^2.8.13", "@types/express": "^4.17.15", + "@types/express-session": "^1.17.6", "@types/jest": "^29.2.5", "@types/jsonwebtoken": "^9.0.0", + "@types/lodash": "^4.14.191", "@types/morgan": "^1.9.4", "@types/node": "^18.11.18", + "@types/passport-jwt": "^3.0.8", + "@types/passport-local": "^1.0.35", "@types/supertest": "^2.0.12", "@typescript-eslint/eslint-plugin": "^5.48.0", "@typescript-eslint/parser": "^5.48.0", @@ -39,6 +60,7 @@ "eslint-plugin-import": "^2.26.0", "husky": "^8.0.0", "jest": "^29.3.1", + "lodash": "^4.17.21", "module-alias": "^2.2.2", "nodemon": "^2.0.20", "prettier": "^2.8.2", @@ -2046,6 +2068,22 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/@jest/core": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.3.1.tgz", @@ -2093,6 +2131,22 @@ } } }, + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/@jest/environment": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.3.1.tgz", @@ -2218,6 +2272,22 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/@jest/schemas": { "version": "29.0.0", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", @@ -2320,6 +2390,22 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/@jest/types": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", @@ -2337,6 +2423,22 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", @@ -2384,6 +2486,39 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", + "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "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/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2523,6 +2658,21 @@ "@babel/types": "^7.3.0" } }, + "node_modules/@types/bcrypt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.0.tgz", + "integrity": "sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/bcryptjs": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz", + "integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==", + "dev": true + }, "node_modules/@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -2580,6 +2730,15 @@ "@types/range-parser": "*" } }, + "node_modules/@types/express-session": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.17.6.tgz", + "integrity": "sha512-L6sB04HVA4HEZo1hDL65JXdZdBJtzZnCiw/P7MnO4w6746tJCNtXlHtzEASyI9ccn9zyOw6IbqQuhVa03VpO4w==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, "node_modules/@types/graceful-fs": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", @@ -2644,6 +2803,12 @@ "@types/node": "*" } }, + "node_modules/@types/lodash": { + "version": "4.14.191", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", + "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", + "dev": true + }, "node_modules/@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", @@ -2664,6 +2829,47 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==" }, + "node_modules/@types/passport": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.11.tgz", + "integrity": "sha512-pz1cx9ptZvozyGKKKIPLcVDVHwae4hrH5d6g5J+DkMRRjR3cVETb4jMabhXAUbg3Ov7T22nFHEgaK2jj+5CBpw==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/passport-jwt": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/passport-jwt/-/passport-jwt-3.0.8.tgz", + "integrity": "sha512-VKJZDJUAHFhPHHYvxdqFcc5vlDht8Q2pL1/ePvKAgqRThDaCc84lSYOTQmnx3+JIkDlN+2KfhFhXIzlcVT+Pcw==", + "dev": true, + "dependencies": { + "@types/express": "*", + "@types/jsonwebtoken": "*", + "@types/passport-strategy": "*" + } + }, + "node_modules/@types/passport-local": { + "version": "1.0.35", + "resolved": "https://registry.npmjs.org/@types/passport-local/-/passport-local-1.0.35.tgz", + "integrity": "sha512-K4eLTJ8R0yYW8TvCqkjB0pTKoqfUSdl5PfZdidTjV2ETV3604fQxtY6BHKjQWAx50WUS0lqzBvKv3LoI1ZBPeA==", + "dev": true, + "dependencies": { + "@types/express": "*", + "@types/passport": "*", + "@types/passport-strategy": "*" + } + }, + "node_modules/@types/passport-strategy": { + "version": "0.2.35", + "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.35.tgz", + "integrity": "sha512-o5D19Jy2XPFoX2rKApykY15et3Apgax00RRLf0RUotPDUsYrQa7x4howLYr9El2mlUApHmCMv5CZ1IXqKFQ2+g==", + "dev": true, + "dependencies": { + "@types/express": "*", + "@types/passport": "*" + } + }, "node_modules/@types/prettier": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", @@ -2964,8 +3170,7 @@ "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==", - "dev": true + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "node_modules/accepts": { "version": "1.3.8", @@ -2979,6 +3184,14 @@ "node": ">= 0.6" } }, + "node_modules/accesscontrol": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/accesscontrol/-/accesscontrol-2.2.1.tgz", + "integrity": "sha512-52EvFk/J9EF+w4mYQoKnOTkEMj01R1U5n2fc1dai6x1xkgOks3DGkx01qQL2cKFxGmE4Tn1krAU3jJA9L1NMkg==", + "dependencies": { + "notation": "^1.3.6" + } + }, "node_modules/acorn": { "version": "8.8.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", @@ -3007,6 +3220,17 @@ "node": ">=0.4.0" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -3022,6 +3246,14 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dependencies": { + "string-width": "^4.1.0" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -3084,6 +3316,23 @@ "node": ">= 8" } }, + "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==" + }, + "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==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -3151,6 +3400,17 @@ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, "node_modules/async": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", @@ -3194,6 +3454,22 @@ "@babel/core": "^7.8.0" } }, + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", @@ -3304,6 +3580,24 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/bcrypt": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.0.tgz", + "integrity": "sha512-RHBS7HI5N5tEnGTmtR/pppX0mmDSBpQ4aCBsj7CEQfYXDcO74A8sIBYcJMuCsis2E81zDxeENYhv66oZwLiA+Q==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.10", + "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -3324,6 +3618,11 @@ "readable-stream": "^3.4.0" } }, + "node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, "node_modules/body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -3366,6 +3665,122 @@ "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", "optional": true }, + "node_modules/boxen": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.2.tgz", + "integrity": "sha512-1Z4UJabXUP1/R9rLpoU3O2lEMnG3pPLAs/ZD2lF3t2q7qD5lM8rqbtnvtvm4N0wEyNlE+9yZVTVAGmd1V5jabg==", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.0", + "chalk": "^5.0.1", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/boxen/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==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/boxen/node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/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==" + }, + "node_modules/boxen/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==", + "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/boxen/node_modules/strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/boxen/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/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==", + "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/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3535,15 +3950,11 @@ ] }, "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" @@ -3603,9 +4014,17 @@ "node": ">= 6" } }, - "node_modules/ci-info": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz", + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz", "integrity": "sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==", "dev": true, "funding": [ @@ -3624,6 +4043,17 @@ "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -3729,6 +4159,14 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/color-support": { + "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==", + "bin": { + "color-support": "bin.js" + } + }, "node_modules/color/node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -3798,6 +4236,32 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, + "node_modules/concurrently/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/concurrently/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -3812,6 +4276,26 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/connect-mongo": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/connect-mongo/-/connect-mongo-4.6.0.tgz", + "integrity": "sha512-8new4Z7NLP3CGP65Aw6ls3xDBeKVvHRSh39CXuDZTQsvpeeU9oNMzfFgvqmHqZ6gWpxIl663RyoVEmCAGf1yOg==", + "dependencies": { + "debug": "^4.3.1", + "kruptein": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "mongodb": "^4.1.0" + } + }, + "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==" + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -3976,6 +4460,11 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -3993,6 +4482,14 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -4060,6 +4557,11 @@ "node": ">=12" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -4491,6 +4993,22 @@ "eslint": ">=7.0.0" } }, + "node_modules/eslint-nibble/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/eslint-plugin-import": { "version": "2.26.0", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", @@ -4700,6 +5218,21 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/espree": { "version": "9.4.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", @@ -4864,6 +5397,45 @@ "node": ">= 0.10.0" } }, + "node_modules/express-session": { + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.3.tgz", + "integrity": "sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==", + "dependencies": { + "cookie": "0.4.2", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.1", + "uid-safe": "~2.1.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/express-session/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express-session/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express-session/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "node_modules/express-validator": { "version": "6.14.2", "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.14.2.tgz", @@ -5169,6 +5741,28 @@ "node": ">= 0.6" } }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -5220,6 +5814,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -5514,6 +6127,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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==" + }, "node_modules/hexoid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", @@ -5548,6 +6166,18 @@ "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.2.0.tgz", "integrity": "sha512-feERVo9iWxvnejp3SEfm/+oNG517npqL2/PIA8ORjyOZjGC7TwCRQsZylciLS64i6pJ0wRYz3rkXLRwbtFa8Ng==" }, + "node_modules/https-proxy-agent": { + "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==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -5704,6 +6334,22 @@ "node": ">=12.0.0" } }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/internal-slot": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", @@ -6188,6 +6834,22 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-circus/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-cli": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.3.1.tgz", @@ -6222,6 +6884,22 @@ } } }, + "node_modules/jest-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-config": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.3.1.tgz", @@ -6267,6 +6945,22 @@ } } }, + "node_modules/jest-config/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-diff": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", @@ -6282,6 +6976,22 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-docblock": { "version": "29.2.0", "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.2.0.tgz", @@ -6310,6 +7020,22 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-each/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-environment-node": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.3.1.tgz", @@ -6389,6 +7115,22 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-message-util": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", @@ -6409,7 +7151,23 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-mock": { + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-mock": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.3.1.tgz", "integrity": "sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==", @@ -6482,6 +7240,22 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-runner": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.3.1.tgz", @@ -6514,6 +7288,22 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-runtime": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.3.1.tgz", @@ -6547,6 +7337,22 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-snapshot": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.3.1.tgz", @@ -6582,6 +7388,22 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-snapshot/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-util": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", @@ -6599,6 +7421,22 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-validate": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.3.1.tgz", @@ -6628,6 +7466,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-watcher": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.3.1.tgz", @@ -6647,6 +7501,22 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-worker": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz", @@ -6815,6 +7685,17 @@ "node": ">=6" } }, + "node_modules/kruptein": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/kruptein/-/kruptein-3.0.6.tgz", + "integrity": "sha512-EQJjTwAJfQkC4NfdQdo3HXM2a9pmBm8oidzH270cYu1MbgXPNPMJuldN7OPX+qdhPO5rw4X3/iKz0BFBfkXGKA==", + "dependencies": { + "asn1.js": "^5.4.1" + }, + "engines": { + "node": ">8" + } + }, "node_modules/kuler": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", @@ -6847,6 +7728,12 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "node_modules/loadash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/loadash/-/loadash-1.0.0.tgz", + "integrity": "sha512-xlX5HBsXB3KG0FJbJJG/3kYWCfsCyCSus3T+uHVu6QL6YxAdggmm3QeyLgn54N2yi5/UE6xxL5ZWJAAiHzHYEg==", + "deprecated": "Package is unsupport. Please use the lodash package instead." + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -6893,6 +7780,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/logform": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/logform/-/logform-2.4.2.tgz", @@ -6920,7 +7823,6 @@ "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==", - "dev": true, "dependencies": { "semver": "^6.0.0" }, @@ -6935,7 +7837,6 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, "bin": { "semver": "bin/semver.js" } @@ -7049,6 +7950,11 @@ "node": ">=6" } }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -7069,6 +7975,48 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.3.tgz", + "integrity": "sha512-OW2r4sQ0sI+z5ckEt5c1Tri4xTgZwYDxpE54eqWlQloQRoWtXjqt9udJ5Z4dSv7wK+nfFI7FRXyCpBSft+gpFw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/module-alias": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.2.tgz", @@ -7218,6 +8166,49 @@ "node": ">= 0.6" } }, + "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==" + }, + "node_modules/node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "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==" + }, + "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==" + }, + "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==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -7321,6 +8312,11 @@ "node": ">=0.10.0" } }, + "node_modules/notation": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/notation/-/notation-1.3.6.tgz", + "integrity": "sha512-DIuJmrP/Gg1DcXKaApsqcjsJD6jEccqKSfmU3BUx/f1GHsMiTJh70cERwYc64tOmTRTARCeMwkqNNzjh3AHhiw==" + }, "node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -7333,11 +8329,21 @@ "node": ">=8" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -7491,6 +8497,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -7574,6 +8596,51 @@ "node": ">= 0.8" } }, + "node_modules/passport": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz", + "integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "dependencies": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", + "integrity": "sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==", + "dependencies": { + "passport-strategy": "1.x.x" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -7618,6 +8685,11 @@ "node": ">=8" } }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -7830,6 +8902,14 @@ } ] }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -8183,6 +9263,11 @@ "node": ">= 0.8.0" } }, + "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==" + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -8253,8 +9338,7 @@ "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==", - "dev": true + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/simple-swizzle": { "version": "0.2.2", @@ -8572,6 +9656,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tar": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", + "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^4.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -8801,6 +9901,22 @@ "balanced-match": "^1.0.0" } }, + "node_modules/ts-patch/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/ts-patch/node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", @@ -8956,10 +10072,21 @@ "integrity": "sha512-qdgpCk9oRHkIBhznxaHAapCFapJt5e4FbFik7Y4qdqtp6VyC3smAIPoDEIkjZ2eiF7x5+QxUPYNwJAtw0thsTw==", "dev": true, "dependencies": { - "minimatch": "^3.0.4" + "minimatch": "^3.0.4" + }, + "peerDependencies": { + "typescript": ">=3.6.5" + } + }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "dependencies": { + "random-bytes": "~1.0.0" }, - "peerDependencies": { - "typescript": ">=3.6.5" + "engines": { + "node": ">= 0.8" } }, "node_modules/unbox-primitive": { @@ -9187,6 +10314,74 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/widest-line/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==" + }, + "node_modules/widest-line/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==", + "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/widest-line/node_modules/strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/winston": { "version": "3.8.2", "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz", @@ -9294,9 +10489,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -10962,6 +12157,18 @@ "jest-message-util": "^29.3.1", "jest-util": "^29.3.1", "slash": "^3.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "@jest/core": { @@ -10998,6 +12205,18 @@ "pretty-format": "^29.3.1", "slash": "^3.0.0", "strip-ansi": "^6.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "@jest/environment": { @@ -11098,6 +12317,16 @@ "@jridgewell/resolve-uri": "3.1.0", "@jridgewell/sourcemap-codec": "1.4.14" } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } } } }, @@ -11189,6 +12418,16 @@ "@jridgewell/resolve-uri": "3.1.0", "@jridgewell/sourcemap-codec": "1.4.14" } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } } } }, @@ -11204,6 +12443,18 @@ "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "@jridgewell/gen-mapping": { @@ -11244,6 +12495,32 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "@mapbox/node-pre-gyp": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", + "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", + "requires": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "dependencies": { + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "requires": { + "abbrev": "1" + } + } + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -11374,6 +12651,21 @@ "@babel/types": "^7.3.0" } }, + "@types/bcrypt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.0.tgz", + "integrity": "sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/bcryptjs": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz", + "integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==", + "dev": true + }, "@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -11431,6 +12723,15 @@ "@types/range-parser": "*" } }, + "@types/express-session": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.17.6.tgz", + "integrity": "sha512-L6sB04HVA4HEZo1hDL65JXdZdBJtzZnCiw/P7MnO4w6746tJCNtXlHtzEASyI9ccn9zyOw6IbqQuhVa03VpO4w==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, "@types/graceful-fs": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", @@ -11495,6 +12796,12 @@ "@types/node": "*" } }, + "@types/lodash": { + "version": "4.14.191", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", + "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", + "dev": true + }, "@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", @@ -11515,6 +12822,47 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==" }, + "@types/passport": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.11.tgz", + "integrity": "sha512-pz1cx9ptZvozyGKKKIPLcVDVHwae4hrH5d6g5J+DkMRRjR3cVETb4jMabhXAUbg3Ov7T22nFHEgaK2jj+5CBpw==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/passport-jwt": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/passport-jwt/-/passport-jwt-3.0.8.tgz", + "integrity": "sha512-VKJZDJUAHFhPHHYvxdqFcc5vlDht8Q2pL1/ePvKAgqRThDaCc84lSYOTQmnx3+JIkDlN+2KfhFhXIzlcVT+Pcw==", + "dev": true, + "requires": { + "@types/express": "*", + "@types/jsonwebtoken": "*", + "@types/passport-strategy": "*" + } + }, + "@types/passport-local": { + "version": "1.0.35", + "resolved": "https://registry.npmjs.org/@types/passport-local/-/passport-local-1.0.35.tgz", + "integrity": "sha512-K4eLTJ8R0yYW8TvCqkjB0pTKoqfUSdl5PfZdidTjV2ETV3604fQxtY6BHKjQWAx50WUS0lqzBvKv3LoI1ZBPeA==", + "dev": true, + "requires": { + "@types/express": "*", + "@types/passport": "*", + "@types/passport-strategy": "*" + } + }, + "@types/passport-strategy": { + "version": "0.2.35", + "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.35.tgz", + "integrity": "sha512-o5D19Jy2XPFoX2rKApykY15et3Apgax00RRLf0RUotPDUsYrQa7x4howLYr9El2mlUApHmCMv5CZ1IXqKFQ2+g==", + "dev": true, + "requires": { + "@types/express": "*", + "@types/passport": "*" + } + }, "@types/prettier": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", @@ -11722,8 +13070,7 @@ "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "accepts": { "version": "1.3.8", @@ -11734,6 +13081,14 @@ "negotiator": "0.6.3" } }, + "accesscontrol": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/accesscontrol/-/accesscontrol-2.2.1.tgz", + "integrity": "sha512-52EvFk/J9EF+w4mYQoKnOTkEMj01R1U5n2fc1dai6x1xkgOks3DGkx01qQL2cKFxGmE4Tn1krAU3jJA9L1NMkg==", + "requires": { + "notation": "^1.3.6" + } + }, "acorn": { "version": "8.8.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", @@ -11751,6 +13106,14 @@ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -11762,6 +13125,14 @@ "uri-js": "^4.2.2" } }, + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "requires": { + "string-width": "^4.1.0" + } + }, "ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -11802,6 +13173,20 @@ "picomatch": "^2.0.4" } }, + "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==" + }, + "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==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, "arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -11854,6 +13239,17 @@ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, "async": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", @@ -11883,6 +13279,18 @@ "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "babel-plugin-istanbul": { @@ -11965,6 +13373,20 @@ } } }, + "bcrypt": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.0.tgz", + "integrity": "sha512-RHBS7HI5N5tEnGTmtR/pppX0mmDSBpQ4aCBsj7CEQfYXDcO74A8sIBYcJMuCsis2E81zDxeENYhv66oZwLiA+Q==", + "requires": { + "@mapbox/node-pre-gyp": "^1.0.10", + "node-addon-api": "^5.0.0" + } + }, + "bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -11982,6 +13404,11 @@ "readable-stream": "^3.4.0" } }, + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, "body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -12022,6 +13449,76 @@ "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", "optional": true }, + "boxen": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.2.tgz", + "integrity": "sha512-1Z4UJabXUP1/R9rLpoU3O2lEMnG3pPLAs/ZD2lF3t2q7qD5lM8rqbtnvtvm4N0wEyNlE+9yZVTVAGmd1V5jabg==", + "requires": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.0", + "chalk": "^5.0.1", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==" + }, + "camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==" + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==" + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -12130,13 +13627,9 @@ "dev": true }, "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==" }, "char-regex": { "version": "1.0.2", @@ -12177,6 +13670,11 @@ } } }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, "ci-info": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz", @@ -12189,6 +13687,11 @@ "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, + "cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==" + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -12284,6 +13787,11 @@ "simple-swizzle": "^0.2.2" } }, + "color-support": { + "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==" + }, "colorspace": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", @@ -12327,6 +13835,25 @@ "yargs": "^17.3.1" }, "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -12337,6 +13864,20 @@ } } }, + "connect-mongo": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/connect-mongo/-/connect-mongo-4.6.0.tgz", + "integrity": "sha512-8new4Z7NLP3CGP65Aw6ls3xDBeKVvHRSh39CXuDZTQsvpeeU9oNMzfFgvqmHqZ6gWpxIl663RyoVEmCAGf1yOg==", + "requires": { + "debug": "^4.3.1", + "kruptein": "^3.0.0" + } + }, + "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==" + }, "content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -12458,6 +13999,11 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -12468,6 +14014,11 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, + "detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==" + }, "detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -12517,6 +14068,11 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, "ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -12705,6 +14261,17 @@ "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "eslint-filtered-fix": { @@ -12865,6 +14432,18 @@ "eslint-summary": "^1.0.0", "inquirer": "^8.2.3", "optionator": "^0.9.1" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "eslint-plugin-import": { @@ -13135,20 +14714,55 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "express-session": { + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.3.tgz", + "integrity": "sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==", + "requires": { + "cookie": "0.4.2", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" + "uid-safe": "~2.1.5" }, "dependencies": { + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -13404,6 +15018,24 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -13439,6 +15071,22 @@ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true }, + "gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + } + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -13641,6 +15289,11 @@ "has-symbols": "^1.0.2" } }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, "hexoid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", @@ -13669,6 +15322,15 @@ "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.2.0.tgz", "integrity": "sha512-feERVo9iWxvnejp3SEfm/+oNG517npqL2/PIA8ORjyOZjGC7TwCRQsZylciLS64i6pJ0wRYz3rkXLRwbtFa8Ng==" }, + "https-proxy-agent": { + "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==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, "human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -13770,6 +15432,18 @@ "strip-ansi": "^6.0.0", "through": "^2.3.6", "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "internal-slot": { @@ -14104,6 +15778,18 @@ "pretty-format": "^29.3.1", "slash": "^3.0.0", "stack-utils": "^2.0.3" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "jest-cli": { @@ -14124,6 +15810,18 @@ "jest-validate": "^29.3.1", "prompts": "^2.0.1", "yargs": "^17.3.1" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "jest-config": { @@ -14154,6 +15852,18 @@ "pretty-format": "^29.3.1", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "jest-diff": { @@ -14166,6 +15876,18 @@ "diff-sequences": "^29.3.1", "jest-get-type": "^29.2.0", "pretty-format": "^29.3.1" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "jest-docblock": { @@ -14188,6 +15910,18 @@ "jest-get-type": "^29.2.0", "jest-util": "^29.3.1", "pretty-format": "^29.3.1" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "jest-environment-node": { @@ -14250,6 +15984,18 @@ "jest-diff": "^29.3.1", "jest-get-type": "^29.2.0", "pretty-format": "^29.3.1" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "jest-message-util": { @@ -14267,6 +16013,18 @@ "pretty-format": "^29.3.1", "slash": "^3.0.0", "stack-utils": "^2.0.3" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "jest-mock": { @@ -14308,6 +16066,18 @@ "resolve": "^1.20.0", "resolve.exports": "^1.1.0", "slash": "^3.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "jest-resolve-dependencies": { @@ -14347,6 +16117,18 @@ "jest-worker": "^29.3.1", "p-limit": "^3.1.0", "source-map-support": "0.5.13" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "jest-runtime": { @@ -14377,6 +16159,18 @@ "jest-util": "^29.3.1", "slash": "^3.0.0", "strip-bom": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "jest-snapshot": { @@ -14409,6 +16203,18 @@ "natural-compare": "^1.4.0", "pretty-format": "^29.3.1", "semver": "^7.3.5" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "jest-util": { @@ -14423,6 +16229,18 @@ "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", "picomatch": "^2.2.3" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "jest-validate": { @@ -14444,6 +16262,16 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } } } }, @@ -14461,6 +16289,18 @@ "emittery": "^0.13.1", "jest-util": "^29.3.1", "string-length": "^4.0.1" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "jest-worker": { @@ -14592,6 +16432,14 @@ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true }, + "kruptein": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/kruptein/-/kruptein-3.0.6.tgz", + "integrity": "sha512-EQJjTwAJfQkC4NfdQdo3HXM2a9pmBm8oidzH270cYu1MbgXPNPMJuldN7OPX+qdhPO5rw4X3/iKz0BFBfkXGKA==", + "requires": { + "asn1.js": "^5.4.1" + } + }, "kuler": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", @@ -14618,6 +16466,11 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "loadash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/loadash/-/loadash-1.0.0.tgz", + "integrity": "sha512-xlX5HBsXB3KG0FJbJJG/3kYWCfsCyCSus3T+uHVu6QL6YxAdggmm3QeyLgn54N2yi5/UE6xxL5ZWJAAiHzHYEg==" + }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -14650,6 +16503,18 @@ "requires": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "logform": { @@ -14676,7 +16541,6 @@ "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==", - "dev": true, "requires": { "semver": "^6.0.0" }, @@ -14684,8 +16548,7 @@ "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, @@ -14771,6 +16634,11 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -14785,6 +16653,35 @@ "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", "dev": true }, + "minipass": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.3.tgz", + "integrity": "sha512-OW2r4sQ0sI+z5ckEt5c1Tri4xTgZwYDxpE54eqWlQloQRoWtXjqt9udJ5Z4dSv7wK+nfFI7FRXyCpBSft+gpFw==" + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, "module-alias": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.2.tgz", @@ -14906,6 +16803,40 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, + "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==" + }, + "node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "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==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -14983,6 +16914,11 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, + "notation": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/notation/-/notation-1.3.6.tgz", + "integrity": "sha512-DIuJmrP/Gg1DcXKaApsqcjsJD6jEccqKSfmU3BUx/f1GHsMiTJh70cERwYc64tOmTRTARCeMwkqNNzjh3AHhiw==" + }, "npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -14992,11 +16928,21 @@ "path-key": "^3.0.0" } }, + "npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, "object-hash": { "version": "2.2.0", @@ -15103,6 +17049,18 @@ "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, "os-tmpdir": { @@ -15158,6 +17116,38 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, + "passport": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz", + "integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==", + "requires": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + } + }, + "passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "requires": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, + "passport-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", + "integrity": "sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==", + "requires": { + "passport-strategy": "1.x.x" + } + }, + "passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==" + }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -15190,6 +17180,11 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -15329,6 +17324,11 @@ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" }, + "random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==" + }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -15575,6 +17575,11 @@ "send": "0.18.0" } }, + "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==" + }, "setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -15627,8 +17632,7 @@ "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==", - "dev": true + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "simple-swizzle": { "version": "0.2.2", @@ -15872,6 +17876,19 @@ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, + "tar": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", + "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^4.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } + }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -16022,6 +18039,16 @@ "balanced-match": "^1.0.0" } }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, "glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", @@ -16140,6 +18167,14 @@ "minimatch": "^3.0.4" } }, + "uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "requires": { + "random-bytes": "~1.0.0" + } + }, "unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -16309,6 +18344,52 @@ "is-typed-array": "^1.1.10" } }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "requires": { + "string-width": "^5.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, "winston": { "version": "3.8.2", "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz", @@ -16389,9 +18470,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "requires": { "cliui": "^8.0.1", "escalade": "^3.1.1", diff --git a/package.json b/package.json index c9b2370..12f4b86 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,9 @@ "version": "1.0.0", "description": "Nodejs-expressjs starter kit with boilerplate code", "main": "app.ts", + "bin": { + "moon": "./src/bin/index.js" + }, "scripts": { "start": "npm run build && npm run serve", "serve": "tsc ./build/src/server.js", @@ -15,20 +18,28 @@ "eslint": "eslint . --ext .js,.ts", "upgrade": "npm update --save-dev && npm update --save", "test": "jest --forceExit --detectOpenHandles --coverage --verbose", + "jest":"jest", "lint:fix": "eslint src --fix --ext .js,.jsx,.ts,.tsx .", "nibble": "eslint-nibble src --ext .js,.jsx,.ts,.tsx .", + "seed":"tsc ./src/bin/index.ts", "prepare": "husky install", "prepare-ts": "npx ts-patch install -s" }, "author": "", "license": "ISC", "devDependencies": { + "@types/bcrypt": "^5.0.0", + "@types/bcryptjs": "^2.4.2", "@types/cors": "^2.8.13", "@types/express": "^4.17.15", + "@types/express-session": "^1.17.6", "@types/jest": "^29.2.5", "@types/jsonwebtoken": "^9.0.0", + "@types/lodash": "^4.14.191", "@types/morgan": "^1.9.4", "@types/node": "^18.11.18", + "@types/passport-jwt": "^3.0.8", + "@types/passport-local": "^1.0.35", "@types/supertest": "^2.0.12", "@typescript-eslint/eslint-plugin": "^5.48.0", "@typescript-eslint/parser": "^5.48.0", @@ -37,6 +48,7 @@ "eslint-plugin-import": "^2.26.0", "husky": "^8.0.0", "jest": "^29.3.1", + "lodash": "^4.17.21", "module-alias": "^2.2.2", "nodemon": "^2.0.20", "prettier": "^2.8.2", @@ -47,19 +59,30 @@ "typescript-transform-paths": "^3.4.6" }, "dependencies": { + "accesscontrol": "^2.2.1", + "bcrypt": "^5.1.0", + "bcryptjs": "^2.4.3", + "boxen": "^7.0.2", + "chalk": "^5.2.0", "concurrently": "^7.6.0", + "connect-mongo": "^4.6.0", "dotenv": "^16.0.3", "eslint": "^8.31.0", "express": "^4.18.2", + "express-session": "^1.17.3", "express-validator": "^6.14.2", "http-status-codes": "^2.2.0", "joi": "^17.7.0", "jsonwebtoken": "^9.0.0", "mongoose": "^6.8.2", "morgan": "^1.10.0", + "passport": "^0.6.0", + "passport-jwt": "^4.0.1", + "passport-local": "^1.0.0", "supertest": "^6.3.3", "typescript": "^4.9.4", "winston": "^3.8.2", - "winston-daily-rotate-file": "^4.7.1" + "winston-daily-rotate-file": "^4.7.1", + "yargs": "^17.7.1" } } diff --git a/src/app.ts b/src/app.ts index fa7dc77..b2992f8 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,6 +1,9 @@ import express, { NextFunction, Request, Response } from 'express'; import morgan from 'morgan'; import cors from 'cors'; +import session from 'express-session'; +import Mongostore from 'connect-mongo'; +import mongoose from 'mongoose'; // modules import { corsUrl, environment } from '@config'; import Logger from '@core/Logger'; @@ -10,16 +13,39 @@ import { InternalError, ErrorType } from '@core/ApiError'; -import routes from '@routes'; +import routes from '@apps/index'; +import passport from '@helpers/passport'; +import '@database'; const app = express(); +const sessionStore = Mongostore.create({ + client: mongoose.connection.getClient(), + collectionName: 'session' +}); + app.use(express.json({ limit: '10mb' })); app.use( express.urlencoded({ limit: '10mb', extended: true, parameterLimit: 50000 }) ); + app.use(morgan('tiny')); app.use(cors({ origin: corsUrl, optionsSuccessStatus: 200 })); +app.use( + session({ + secret: 'secret', + resave: false, + saveUninitialized: true, + store: sessionStore, + cookie: { + maxAge: 1000 * 60 * 60 * 24 + } + }) +); + +app.use(passport.initialize()); +app.use(passport.session()); + process.on('uncaughtException', (e) => { Logger.error(e); }); @@ -30,6 +56,7 @@ app.use('/', routes); // catch 404 and forward to error handler app.use((req, res, next) => next(new NotFoundError())); +// eslint-disable-next-line @typescript-eslint/no-unused-vars app.use((err: Error, req: Request, res: Response, next: NextFunction) => { if (err instanceof ApiError) { ApiError.handle(err, res); diff --git a/src/apps/Core/Auth/auth.controller.ts b/src/apps/Core/Auth/auth.controller.ts new file mode 100644 index 0000000..cf48d80 --- /dev/null +++ b/src/apps/Core/Auth/auth.controller.ts @@ -0,0 +1,69 @@ +import { Request, Response } from 'express'; +import { ExtractJwt } from 'passport-jwt'; +import asyncHandler from '@helpers/asyncHandler'; +import { SuccessResponse } from '@core/ApiResponse'; +// +import { createUser } from '@apps/Core/User/model/user.repository'; +import { User } from '@apps/Core/User/model/user.model'; + +import { + blackListToken, + createJwtToken, + findByToken, + getTokenWithUserId, + isTokenBlackListed, + getTokenWithIpAddress, + blackListTokens +} from './model/auth.repository'; + +export const Login = asyncHandler(async (req: Request, res: Response) => { + const user = req.user as User; + const ip = req.ip; + const { deviceName } = req.body; + + const jwtTokens = await getTokenWithIpAddress(ip); + await blackListTokens(jwtTokens.map((token) => token.accessKey)); + + const generatedToken = user.generateJWT(); + await createJwtToken({ + accessKey: generatedToken.accessToken, + client: user, + ipAddress: ip, + deviceName + }); + + const response = { + ...generatedToken, + user: { + username: user.username, + email: user.email, + id: user._id, + role: user.role?.roleName + } + }; + new SuccessResponse('Login Successfully', response).send(res); +}); + +export const Register = asyncHandler(async (req: Request, res: Response) => { + const { email, username, password, role } = req.body; + const user = await createUser(email, username, password, role); + const response = { + ...user.generateJWT(), + user: { + username: user.username, + email: user.email, + id: user._id, + role: user.role?.roleName + } + }; + new SuccessResponse('Register Successfully', response).send(res); +}); + +export const Logout = asyncHandler(async (req: Request, res: Response) => { + const jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken(); + const token = jwtFromRequest(req); + + await blackListToken(token!); + + new SuccessResponse('Logout Successfully', {}).send(res); +}); diff --git a/src/apps/Core/Auth/auth.routes.ts b/src/apps/Core/Auth/auth.routes.ts new file mode 100644 index 0000000..fe943d3 --- /dev/null +++ b/src/apps/Core/Auth/auth.routes.ts @@ -0,0 +1,22 @@ +import express from 'express'; +import validator from '@helpers/validator'; +import passport from 'passport'; +import { ProtectRoutes } from '@helpers/auth'; + +import { Login, Logout, Register } from './auth.controller'; +import schema from './auth.schema'; + +const router = express.Router(); + +router.post( + '/login', + validator(schema.loginUserSchema), + passport.authenticate('local'), + Login +); + +router.post('/register', validator(schema.registerUserSchema), Register); + +router.get('/logout', ProtectRoutes, Logout); + +export default router; diff --git a/src/apps/Core/Auth/auth.schema.ts b/src/apps/Core/Auth/auth.schema.ts new file mode 100644 index 0000000..364becb --- /dev/null +++ b/src/apps/Core/Auth/auth.schema.ts @@ -0,0 +1,14 @@ +import Joi from 'joi'; +import { JoiObjectId } from '@helpers/validator'; + +export default { + registerUserSchema: Joi.object().keys({ + email: Joi.string().email().required(), + username: Joi.string().required(), + password: Joi.string().required() + }), + loginUserSchema: Joi.object().keys({ + email: Joi.string().email().required(), + password: Joi.string() + }) +}; diff --git a/src/apps/Core/Auth/model/auth.model.ts b/src/apps/Core/Auth/model/auth.model.ts new file mode 100644 index 0000000..b9538cd --- /dev/null +++ b/src/apps/Core/Auth/model/auth.model.ts @@ -0,0 +1,53 @@ +import { Schema, model, Types } from 'mongoose'; +import { User } from '@apps/Core/User/model/user.model'; + +// +import { BaseModel } from '../../Base/model/Base'; + +export const DOCUMENT_NAME = 'JWTtoken'; +export const COLLECTION_NAME = 'JWTtokens'; + +export interface JWTtoken extends BaseModel { + client: Omit; + accessKey: string; + ipAddress: string; + blacklisted?: boolean; + deviceName?: string; +} + +const schema = new Schema( + { + ipAddress: { + type: Schema.Types.String, + required: true, + trim: true + }, + client: { + type: Schema.Types.ObjectId, + required: true, + ref: 'User' + }, + accessKey: { + type: Schema.Types.String, + required: true, + trim: true + }, + blacklisted: { + type: Schema.Types.Boolean, + default: false + } + }, + { + versionKey: false + } +); + +schema.index({ client: 1 }); +schema.index({ client: 1, primaryKey: 1, status: 1 }); +schema.index({ client: 1, primaryKey: 1, secondaryKey: 1 }); + +export const JwtTokenModel = model( + DOCUMENT_NAME, + schema, + COLLECTION_NAME +); diff --git a/src/apps/Core/Auth/model/auth.repository.ts b/src/apps/Core/Auth/model/auth.repository.ts new file mode 100644 index 0000000..2030cdd --- /dev/null +++ b/src/apps/Core/Auth/model/auth.repository.ts @@ -0,0 +1,58 @@ +import { BadRequestError, NoDataError } from '@core/ApiError'; +import { Types } from 'mongoose'; + +import { JwtTokenModel, JWTtoken } from './auth.model'; + +export const createJwtToken = async ( + jwtToken: Pick< + JWTtoken, + 'accessKey' | 'client' | 'deviceName' | 'ipAddress' + > +): Promise => { + await JwtTokenModel.create(jwtToken); + return true; +}; + +export const findByToken = async (token: string): Promise => { + const jwtToken = await JwtTokenModel.findOne({ accessKey: token }); + if (jwtToken) return jwtToken; + throw new NoDataError(`No token found for ${token}`); +}; + +export const isTokenBlackListed = async (token: string): Promise => { + const jwtToken = await findByToken(token); + return jwtToken.blacklisted!; +}; + +export const blackListToken = async (token: string): Promise => { + const jwtToken = await JwtTokenModel.updateOne( + { accessKey: { $in: token } }, + { blacklisted: true } + ); + + if (!jwtToken) throw new NoDataError(`No token found for ${token}`); +}; + +export const blackListTokens = async (token: string[]) => { + await JwtTokenModel.updateMany( + { accessKey: { $in: token } }, + { $set: { blacklisted: true } } + ); +}; + +export const getTokenWithUserId = async ( + id: Types.ObjectId +): Promise => { + const jwtTokens = await JwtTokenModel.find({ client: id }).lean(); + return jwtTokens; +}; + +export const getTokenWithIpAddress = async ( + ip: string +): Promise => { + const jwtTokens = await JwtTokenModel.find({ + ipAddress: ip, + blacklisted: false + }).lean(); + return jwtTokens; +}; diff --git a/src/apps/Core/Base/index.ts b/src/apps/Core/Base/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/apps/Core/Base/model/Base.repository.ts b/src/apps/Core/Base/model/Base.repository.ts new file mode 100644 index 0000000..f0275ea --- /dev/null +++ b/src/apps/Core/Base/model/Base.repository.ts @@ -0,0 +1,20 @@ +import { BadRequestError } from '@core/ApiError'; + +export const errorHandler = async (callback: () => any) => { + try { + return callback(); + } catch (error: { code: number; keyPattern: any; keyValue: any } | any) { + const keys = Object.keys(error.keyPattern); + const errorMessage: string[] = []; + switch (error.code) { + case 11000: + keys.forEach((key) => { + const message = ` "${key}" with "${error.keyValue[key]}" already exist`; + errorMessage.push(message); + }); + throw new BadRequestError(`${errorMessage}`); + default: + throw new BadRequestError('Unknown error '); + } + } +}; diff --git a/src/apps/Core/Base/model/Base.ts b/src/apps/Core/Base/model/Base.ts new file mode 100644 index 0000000..ba0c998 --- /dev/null +++ b/src/apps/Core/Base/model/Base.ts @@ -0,0 +1,7 @@ +import { Types } from 'mongoose'; + +export interface BaseModel { + _id: Types.ObjectId; + createdAt: Date; + updatedAt: Date; +} diff --git a/src/apps/Core/Permission/index.ts b/src/apps/Core/Permission/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/apps/Core/Permission/model/permission.repository.ts b/src/apps/Core/Permission/model/permission.repository.ts new file mode 100644 index 0000000..9f2b34c --- /dev/null +++ b/src/apps/Core/Permission/model/permission.repository.ts @@ -0,0 +1,145 @@ +import { BadRequestError, NoDataError } from '@core/ApiError'; +import mongoose, { Types } from 'mongoose'; + +import { Permissions, PermissionsModel } from './permissions.model'; + +const createMultiplePermissions = async ( + permission: Pick[] +) => { + // const isExists = await mongoose.connection.db + // .listCollections({ + // name: { $in: permission.map((x) => x.resource) } + // }) + // .toArray(); + // if (isExists.length !== permission.length) { + // throw new BadRequestError( + // `can not create permissions, with model that does not exist` + // ); + // } + // const bulkOps = permission.map((doc) => ({ + // updateOne: { + // filter: { resource: doc.resource }, + // update: { $set: doc }, + // upsert: true + // } + // })); + + const permissions = await PermissionsModel.insertMany(permission); + return permissions; +}; + +const createPermissions = async ( + permission: Pick +): Promise => { + try { + const isExists = await mongoose.connection.db + .listCollections({ + name: permission.resource + }) + .toArray(); + if (isExists.length === 0) { + throw new BadRequestError( + `there is no database table with name ${permission.resource}` + ); + } + const newPermission = await PermissionsModel.create(permission); + return newPermission; + } catch (error: { code: number; keyPattern: any; keyValue: any } | any) { + const keys = Object.keys(error.keyPattern); + const errorMessage: string[] = []; + switch (error.code) { + case 11000: + keys.forEach((key) => { + const message = ` "${key}" with "${error.keyValue[key]}" already exist`; + errorMessage.push(message); + }); + throw new BadRequestError(`${errorMessage}`); + default: + throw new BadRequestError('Unknown error '); + } + } +}; + +const updatedPermissions = async ({ + action, + resource, + attributes, + _id +}: Pick< + Permissions, + 'action' | 'resource' | '_id' | 'attributes' +>): Promise => { + try { + const isExists = await mongoose.connection.db + .listCollections({ + name: resource + }) + .toArray(); + if (isExists.length === 0) { + throw new BadRequestError( + `there is no database table with name ${resource}` + ); + } + const updatedPermissions = await PermissionsModel.findByIdAndUpdate( + _id, + { action, resource, attributes: attributes || '*' }, + { new: true } + ) + .lean() + .exec(); + return updatedPermissions; + } catch (error: { code: number; keyPattern: any; keyValue: any } | any) { + const keys = Object.keys(error.keyPattern); + const errorMessage: string[] = []; + switch (error.code) { + case 11000: + keys.forEach((key) => { + const message = ` "${key}" with "${error.keyValue[key]}" already exist`; + errorMessage.push(message); + }); + throw new BadRequestError(`${errorMessage}`); + default: + throw new BadRequestError('Unknown error '); + } + } +}; + +const findPermissionById = async ( + id: Types.ObjectId +): Promise => { + const permission = await PermissionsModel.findOne({ _id: id }) + .lean() + .exec(); + if (!permission) throw new NoDataError('no permission found'); + return permission; +}; + +const findAllPermissionsById = async ( + ids: Types.ObjectId[] +): Promise => { + const permissions = await PermissionsModel.find({ _id: { $in: ids } }) + .lean() + .exec(); + return permissions; +}; +const getAllPermissions = async (): Promise => { + const permissions = await PermissionsModel.find(); + return permissions; +}; + +const deletePermissionByID = async (ids: Types.ObjectId[]): Promise => { + const result = await PermissionsModel.deleteMany({ _id: { $in: ids } }); + if (result.deletedCount === 0) { + throw new NoDataError(`No permission with id ${ids}`); + } +}; + +export { + createPermissions, + updatedPermissions, + findPermissionById, + findAllPermissionsById, + deletePermissionByID, + getAllPermissions, + createMultiplePermissions +}; diff --git a/src/apps/Core/Permission/model/permissions.model.ts b/src/apps/Core/Permission/model/permissions.model.ts new file mode 100644 index 0000000..1584a8a --- /dev/null +++ b/src/apps/Core/Permission/model/permissions.model.ts @@ -0,0 +1,44 @@ +import { Schema, model } from 'mongoose'; +import { BaseModel } from '@apps/Core/Base/model/Base'; + +export const DOCUMENT_NAME = 'Permission'; +export const COLLECTION_NAME = 'permissions'; + +export interface Permissions extends BaseModel { + resource: string; + attributes: string[]; + action: 'create' | 'read' | 'delete' | 'update'; +} + +const schema = new Schema( + { + resource: { + type: Schema.Types.String, + required: true, + trim: true + }, + attributes: [ + { + type: Schema.Types.String, + required: true, + trim: true, + default: '*', + unique: true + } + ], + action: { + type: Schema.Types.String, + enum: ['create', 'read', 'delete', 'update'], + required: true + } + }, + { timestamps: true } +); + +schema.index({ resource: 1, attributes: 1, action: 1 }, { unique: true }); + +export const PermissionsModel = model( + DOCUMENT_NAME, + schema, + COLLECTION_NAME +); diff --git a/src/apps/Core/Permission/permission.controller.ts b/src/apps/Core/Permission/permission.controller.ts new file mode 100644 index 0000000..9032929 --- /dev/null +++ b/src/apps/Core/Permission/permission.controller.ts @@ -0,0 +1,81 @@ +import { Types } from 'mongoose'; +import { Request, Response } from 'express'; +import asyncHandler from '@helpers/asyncHandler'; +import { SuccessResponse } from '@core/ApiResponse'; + +import { + createPermissions, + deletePermissionByID, + findAllPermissionsById, + findPermissionById, + getAllPermissions, + updatedPermissions +} from './model/permission.repository'; + +export const CreatePermission = asyncHandler( + async (req: Request, res: Response) => { + const { resource, action, attributes } = req.body; + const permission = await createPermissions({ + action: action, + resource: resource, + attributes: attributes ?? ['*'] + }); + + new SuccessResponse('Permission created successfully', permission).send( + res + ); + } +); + +export const UpdatePermission = asyncHandler( + async (req: Request, res: Response) => { + const { resource, action, attributes } = req.body; + const { id } = req.params; + + const permission = await updatedPermissions({ + _id: id as unknown as Types.ObjectId, + action, + resource, + attributes + }); + + new SuccessResponse('Permission updated successfully', permission).send( + res + ); + } +); + +export const FindAllPermissionsById = asyncHandler( + async (req: Request, res: Response) => { + const { ids } = req.body; + const permissions = await findAllPermissionsById(ids); + + new SuccessResponse('Permissions', permissions).send(res); + } +); + +export const GetPermission = asyncHandler( + async (req: Request, res: Response) => { + const { id } = req.params; + const permission = await findPermissionById( + id as unknown as Types.ObjectId + ); + new SuccessResponse('Permission', permission).send(res); + } +); + +export const GetAllPermission = asyncHandler( + async (req: Request, res: Response) => { + const permissions = await getAllPermissions(); + new SuccessResponse('Permissions', permissions).send(res); + } +); + +export const DeletePermissionByID = asyncHandler( + async (req: Request, res: Response) => { + const { id } = req.params; + + await deletePermissionByID([id as unknown as Types.ObjectId]); + new SuccessResponse('Permission deleted successfully', {}).send(res); + } +); diff --git a/src/apps/Core/Permission/permission.routes.ts b/src/apps/Core/Permission/permission.routes.ts new file mode 100644 index 0000000..fd33ec7 --- /dev/null +++ b/src/apps/Core/Permission/permission.routes.ts @@ -0,0 +1,64 @@ +import express from 'express'; +import validator, { ValidationSource } from '@helpers/validator'; +import { ProtectRoutes } from '@helpers/auth'; +import permission from '@helpers/permission'; + +import { COLLECTION_NAME } from './model/permissions.model'; +import { + CreatePermission, + DeletePermissionByID, + GetAllPermission, + GetPermission, + UpdatePermission +} from './permission.controller'; +import schema from './permission.schema'; + +const router = express.Router(); + +router.get( + '/', + ProtectRoutes, + permission(COLLECTION_NAME, 'read'), + GetAllPermission +); + +router.get( + '/:id', + ProtectRoutes, + permission(COLLECTION_NAME, 'read'), + validator(schema.permissionId, ValidationSource.PARAM), + GetPermission +); + +router.post( + '/', + ProtectRoutes, + permission(COLLECTION_NAME, 'read'), + validator(schema.permissionSchema), + CreatePermission +); + +router.put( + '/:id', + ProtectRoutes, + permission(COLLECTION_NAME, 'read'), + validator(schema.permissionId, ValidationSource.PARAM), + validator(schema.permissionSchema), + UpdatePermission +); + +router.delete( + '/:id', + permission(COLLECTION_NAME, 'read'), + validator(schema.permissionId, ValidationSource.PARAM), + DeletePermissionByID +); + +router.delete( + '/', + permission(COLLECTION_NAME, 'read'), + validator(schema.permissionIds, ValidationSource.BODY), + DeletePermissionByID +); + +export default router; diff --git a/src/apps/Core/Permission/permission.schema.ts b/src/apps/Core/Permission/permission.schema.ts new file mode 100644 index 0000000..a6f1028 --- /dev/null +++ b/src/apps/Core/Permission/permission.schema.ts @@ -0,0 +1,18 @@ +import Joi from 'joi'; +import { JoiObjectId } from '@helpers/validator'; + +export default { + permissionSchema: Joi.object().keys({ + resource: Joi.string().required(), + action: Joi.string() + .valid('create', 'read', 'view', 'update') + .required(), + attributes: Joi.array().items(Joi.string()).optional() + }), + permissionId: Joi.object().keys({ + id: JoiObjectId().required() + }), + permissionIds: Joi.object().keys({ + ids: Joi.array().items(JoiObjectId().required()).required() + }) +}; diff --git a/src/apps/Core/Role/index.ts b/src/apps/Core/Role/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/apps/Core/Role/model/role.model.ts b/src/apps/Core/Role/model/role.model.ts new file mode 100644 index 0000000..87777a4 --- /dev/null +++ b/src/apps/Core/Role/model/role.model.ts @@ -0,0 +1,36 @@ +import { Schema, model } from 'mongoose'; + +import { BaseModel } from '../../Base/model/Base'; +import { + Permissions, + DOCUMENT_NAME as PERMISSION_DOCUMENT_NAME +} from '../../Permission/model/permissions.model'; + +export const DOCUMENT_NAME = 'Role'; +export const COLLECTION_NAME = 'roles'; + +export interface Role extends BaseModel { + roleName: string; + permissions: Permissions[]; +} + +const schema = new Schema({ + roleName: { + type: Schema.Types.String, + required: true, + trim: true, + unique: true + }, + permissions: { + type: [ + { + type: Schema.Types.ObjectId, + ref: PERMISSION_DOCUMENT_NAME + } + ] + } +}); + +schema.index({ RoleName: 1 }); + +export const RoleModel = model(DOCUMENT_NAME, schema, COLLECTION_NAME); diff --git a/src/apps/Core/Role/model/role.repository.ts b/src/apps/Core/Role/model/role.repository.ts new file mode 100644 index 0000000..b4d6521 --- /dev/null +++ b/src/apps/Core/Role/model/role.repository.ts @@ -0,0 +1,132 @@ +import { Types } from 'mongoose'; +import { BadRequestError, NoDataError } from '@core/ApiError'; +import { findAllPermissionsById } from '@apps/Core/Permission/model/permission.repository'; + +import { Role, RoleModel } from './role.model'; + +const createMultipleRole = async ( + roles: Pick[] +) => { + const bulkOps = roles.map((doc) => ({ + updateOne: { + filter: { roleName: doc.roleName }, + update: { $set: doc }, + upsert: true + } + })); + + const role = await RoleModel.bulkWrite(bulkOps); + return role; +}; + +const createRole = async ( + roleName: string, + permissionsIds: Types.ObjectId[] +): Promise => { + const permissions = await findAllPermissionsById(permissionsIds); + if (!permissions) { + throw new NoDataError('Permission not found'); + } + try { + const role = await RoleModel.create({ + roleName: roleName, + permissions + }); + return role; + } catch (error: { code: number; keyPattern: any; keyValue: any } | any) { + const keys = Object.keys(error.keyPattern); + const errorMessage: string[] = []; + switch (error.code) { + case 11000: + keys.forEach((key) => { + const message = ` "${key}" with "${error.keyValue[key]}" already exist`; + errorMessage.push(message); + }); + throw new BadRequestError(`${errorMessage}`); + default: + throw new BadRequestError('Unknown error '); + } + } +}; + +const findRoleById = async (id: Types.ObjectId): Promise => { + const role = await RoleModel.findOne({ _id: id }).lean().exec(); + return role; +}; + +const getAllRole = async (): Promise => { + const roles = await RoleModel.find({}).populate('permissions'); + return roles; +}; + +const findAllRolesById = async (ids: Types.ObjectId[]): Promise => { + const roles = await RoleModel.find({ _id: { $in: ids } }) + .lean() + .exec(); + return roles; +}; + +const getRoleByName = async (roleName: string) => { + const role = await RoleModel.findOne({ roleName: roleName }); + if (role) return role; + throw new NoDataError(`no role found with '${roleName}' name`); +}; + +const updateRoleById = async ( + roleName: string, + permissionsIds: Types.ObjectId[], + id: Types.ObjectId +): Promise => { + const permissions = await findAllPermissionsById(permissionsIds); + + if (!permissions) { + throw new NoDataError('Permission not found'); + } + const role = await findRoleById(id); + + if (role === null) { + throw new NoDataError('Role not found'); + } + role.roleName = roleName; + role.permissions = permissions; + + try { + const updateRole = await RoleModel.findByIdAndUpdate(id, role, { + new: true + }) + .lean() + .exec(); + + return updateRole; + } catch (error: { code: number; keyPattern: any; keyValue: any } | any) { + const keys = Object.keys(error.keyPattern); + const errorMessage: string[] = []; + + switch (error.code) { + case 11000: + keys.forEach((key) => { + const message = ` "${key}" with "${error.keyValue[key]}" already exist`; + errorMessage.push(message); + }); + throw new BadRequestError(`${errorMessage}`); + default: + throw error; + } + } +}; + +const deleteRoleById = async (id: Types.ObjectId): Promise => { + const result = await RoleModel.deleteOne({ _id: id }); + return result.deletedCount > 0; +}; + +export { + createRole, + findRoleById, + createMultipleRole, + updateRoleById, + deleteRoleById, + findAllRolesById, + getAllRole, + getRoleByName +}; diff --git a/src/apps/Core/Role/role.controller.ts b/src/apps/Core/Role/role.controller.ts new file mode 100644 index 0000000..73b3cc2 --- /dev/null +++ b/src/apps/Core/Role/role.controller.ts @@ -0,0 +1,53 @@ +import { Types } from 'mongoose'; +import { Request, Response } from 'express'; +import asyncHandler from '@helpers/asyncHandler'; +import { SuccessResponse } from '@core/ApiResponse'; + +import { + createRole, + deleteRoleById, + updateRoleById, + findRoleById, + getAllRole +} from './model/role.repository'; + +export const CreateRole = asyncHandler(async (req: Request, res: Response) => { + const { roleName, permissions } = req.body; + + const role = await createRole(roleName, permissions); + + new SuccessResponse('Role created successfully', role).send(res); +}); + +export const GetAllRoles = asyncHandler(async (req: Request, res: Response) => { + const roles = await getAllRole(); + console.log(roles); + new SuccessResponse('roles', roles).send(res); +}); + +export const GetRole = asyncHandler(async (req: Request, res: Response) => { + const { id } = req.params; + + const role = await findRoleById(id as unknown as Types.ObjectId); + + new SuccessResponse('role', role).send(res); +}); + +export const UpdateRole = asyncHandler(async (req: Request, res: Response) => { + const { id } = req.params; + const { roleName, permissions } = req.body; + + const role = await updateRoleById( + roleName, + permissions, + id as unknown as Types.ObjectId + ); + + new SuccessResponse('role updated successfully', role).send(res); +}); + +export const DeleteRole = asyncHandler(async (req: Request, res: Response) => { + const { id } = req.params; + await deleteRoleById(id as unknown as Types.ObjectId); + new SuccessResponse('Role deleted successfully', {}).send(res); +}); diff --git a/src/apps/Core/Role/role.routes.ts b/src/apps/Core/Role/role.routes.ts new file mode 100644 index 0000000..aed70a8 --- /dev/null +++ b/src/apps/Core/Role/role.routes.ts @@ -0,0 +1,58 @@ +import express from 'express'; +import { ProtectRoutes } from '@helpers/auth'; +import validator, { ValidationSource } from '@helpers/validator'; +import permission from '@helpers/permission'; + +import { COLLECTION_NAME } from './model/role.model'; +import { + CreateRole, + DeleteRole, + GetAllRoles, + GetRole, + UpdateRole +} from './role.controller'; +import schema from './role.schema'; + +const router = express.Router(); + +router.get( + '/', + ProtectRoutes, + permission(COLLECTION_NAME, 'read'), + GetAllRoles +); + +router.get( + '/:id', + ProtectRoutes, + permission(COLLECTION_NAME, 'read'), + validator(schema.roleId, ValidationSource.PARAM), + GetRole +); + +router.post( + '/', + ProtectRoutes, + permission(COLLECTION_NAME, 'create'), + validator(schema.roleSchema), + CreateRole +); + +router.put( + '/:id', + ProtectRoutes, + permission(COLLECTION_NAME, 'update'), + validator(schema.roleId, ValidationSource.PARAM), + validator(schema.roleSchema), + UpdateRole +); + +router.delete( + '/:id', + ProtectRoutes, + permission(COLLECTION_NAME, 'delete'), + validator(schema.roleId, ValidationSource.PARAM), + DeleteRole +); + +export default router; diff --git a/src/apps/Core/Role/role.schema.ts b/src/apps/Core/Role/role.schema.ts new file mode 100644 index 0000000..1796b98 --- /dev/null +++ b/src/apps/Core/Role/role.schema.ts @@ -0,0 +1,12 @@ +import Joi from 'joi'; +import { JoiObjectId } from '@helpers/validator'; + +export default { + roleSchema: Joi.object().keys({ + roleName: Joi.string().required(), + permissions: Joi.array().items(JoiObjectId().required()).required() + }), + roleId: Joi.object().keys({ + id: JoiObjectId().required() + }) +}; diff --git a/src/apps/Core/User/index.ts b/src/apps/Core/User/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/apps/Core/User/model/user.model.ts b/src/apps/Core/User/model/user.model.ts new file mode 100644 index 0000000..32be687 --- /dev/null +++ b/src/apps/Core/User/model/user.model.ts @@ -0,0 +1,73 @@ +import { Schema, model } from 'mongoose'; +import bcrypt from 'bcrypt'; +import jwt from 'jsonwebtoken'; +import { SECRET_KEY } from '@config'; +// + +import { BaseModel } from '../../Base/model/Base'; +import { + Role, + DOCUMENT_NAME as RoleDocumentName +} from '../../Role/model/role.model'; + +export const DOCUMENT_NAME = 'User'; +export const COLLECTION_NAME = 'users'; + +export interface User extends BaseModel { + email: string; + username: string; + password: string; + role?: Role; + validatePassword(password: string): boolean; + generateJWT(): { accessToken: string }; +} + +const schema = new Schema( + { + email: { + type: Schema.Types.String, + required: true, + trim: true, + unique: true + }, + username: { + type: Schema.Types.String, + required: true, + trim: true + }, + password: { + type: Schema.Types.String, + select: false, + required: true + }, + role: { + type: Schema.Types.ObjectId, + ref: RoleDocumentName + } + }, + { timestamps: true } +); +schema.methods.validatePassword = async function (password: string) { + const user = await UserModel.findById(this._id).select('+password'); + const hash = await bcrypt.compare(password, user!.password); + return hash; +}; + +schema.methods.generateJWT = function () { + const secret = SECRET_KEY; + return { + accessToken: jwt.sign( + { + email: this.email, + id: this._id + }, + secret, + { expiresIn: '1d' } + ) + }; +}; + +schema.index({ email: 1 }); +schema.index({ username: 1 }); + +export const UserModel = model(DOCUMENT_NAME, schema, COLLECTION_NAME); diff --git a/src/apps/Core/User/model/user.repository.ts b/src/apps/Core/User/model/user.repository.ts new file mode 100644 index 0000000..97676a5 --- /dev/null +++ b/src/apps/Core/User/model/user.repository.ts @@ -0,0 +1,155 @@ +import { Types } from 'mongoose'; +import bcrypt from 'bcrypt'; +import { BadRequestError, NoDataError } from '@core/ApiError'; +import { + findRoleById, + getRoleByName +} from '@apps/Core/Role/model/role.repository'; +import { errorHandler } from '@apps/Core/Base/model/Base.repository'; + +import { User, UserModel } from './user.model'; + +const createMultipleUsers = async ( + users: Pick[] +) => { + const bulkOps = users.map((doc) => ({ + updateOne: { + filter: { email: doc.email }, + update: { $set: doc }, + upsert: true + } + })); + + const user = await UserModel.bulkWrite(bulkOps); + return user; +}; + +const createUser = async ( + email: string, + username: string, + password: string, + role: string | undefined +): Promise => { + try { + const passwordHash = await bcrypt.hash(password, 10); + const roles = await getRoleByName(role || 'user'); + + const user = await UserModel.create({ + username, + password: passwordHash, + email, + roles + }); + + return user; + } catch (error: { code: number; keyPattern: any; keyValue: any } | any) { + const keys = error.keyPattern && Object.keys(error?.keyPattern); + const errorMessage: string[] = []; + switch (error.code) { + case 11000: + keys.forEach((key: string) => { + const message = ` "${key}" with "${error.keyValue[key]}" already exist`; + errorMessage.push(message); + }); + throw new BadRequestError(`${errorMessage}`); + default: + console.log(error); + throw new BadRequestError('Unknown error '); + } + } +}; + +const findUserByEmail = async (email: string): Promise => { + const user = await UserModel.findOne({ email: email }); + return user; + // if (user) return user; + // throw new NoDataError(`User with "${email}" not found`); +}; + +const findUserById = async (id: string): Promise => { + const user = await UserModel.aggregate([ + { $match: { _id: id } }, + { + $lookup: { + from: 'roles', + localField: 'role', + foreignField: '_id', + as: 'role' + } + }, + { + $unwind: '$role' + }, + { + $addFields: { + role: '$role.roleName' + } + } + ]); + if (user.length > 0) return user[0]; + throw new NoDataError(`User with "${id}" not found`); +}; + +const getAllUsers = async (): Promise => { + const users = await UserModel.aggregate([ + // Lookup the roles collection and populate the role field for each user document + { + $lookup: { + from: 'roles', + localField: 'role', + foreignField: '_id', + as: 'role' + } + }, + // Unwind the role array to deconstruct the documents + { + $unwind: '$role' + }, + // Add a roleName field to each user document by projecting it from the role collection + { + $addFields: { + role: '$role.roleName' + } + } + ]); + return users; +}; + +const updateUser = async (user: User, roleId?: Types.ObjectId) => { + return errorHandler(async () => { + if (roleId) { + const role = await findRoleById(roleId); + if (!role) { + throw new NoDataError(`Role with "${roleId}" not found`); + } + user.role = role; + } + if (user.password) { + user.password = await bcrypt.hash(user.password, 10); + } + const newUser = await UserModel.findByIdAndUpdate(user._id, user, { + new: true + }) + .select('+password') + .lean(); + if (newUser) return newUser; + throw new NoDataError(`User with "${user._id}" not found`); + }); +}; + +const deleteUser = async (id: Types.ObjectId): Promise => { + const result = await UserModel.deleteOne({ _id: id }); + + if (result.deletedCount > 0) return; + throw new NoDataError(`User with "${id}" not found`); +}; + +export { + createUser, + findUserByEmail, + findUserById, + updateUser, + deleteUser, + getAllUsers, + createMultipleUsers +}; diff --git a/src/apps/Core/User/user.controller.ts b/src/apps/Core/User/user.controller.ts new file mode 100644 index 0000000..9f90f8d --- /dev/null +++ b/src/apps/Core/User/user.controller.ts @@ -0,0 +1,55 @@ +import { Types } from 'mongoose'; +import { Request, Response } from 'express'; +import asyncHandler from '@helpers/asyncHandler'; +import { SuccessResponse } from '@core/ApiResponse'; + +import { + createUser, + deleteUser, + findUserByEmail, + findUserById, + updateUser, + getAllUsers +} from './model/user.repository'; + +export const CreateUser = asyncHandler(async (req: Request, res: Response) => { + const { email, username, password, role } = req.body; + + const user = await createUser(email, username, password, role); + + new SuccessResponse('user created successfully', user).send(res); +}); + +export const UpdateUser = asyncHandler(async (req: Request, res: Response) => { + const { email, username, password, role } = req.body; + const user = await findUserByEmail(email); + + if (password) { + user!.password = password; + } + + user!.username = username; + + const newUser = await updateUser(user!, role); + + new SuccessResponse('user updated successfully', newUser).send(res); +}); + +export const GetUser = asyncHandler(async (req: Request, res: Response) => { + const { id } = req.params; + const user = await findUserById(id); + + new SuccessResponse('User', user).send(res); +}); + +export const GetUsers = asyncHandler(async (req: Request, res: Response) => { + const users = await getAllUsers(); + new SuccessResponse('Users', users).send(res); +}); + +export const DeleteUser = asyncHandler(async (req: Request, res: Response) => { + const { id } = req.params; + await deleteUser(id as unknown as Types.ObjectId); + + new SuccessResponse('User deleted Successful', {}).send(res); +}); diff --git a/src/apps/Core/User/user.routes.ts b/src/apps/Core/User/user.routes.ts new file mode 100644 index 0000000..2ea6b82 --- /dev/null +++ b/src/apps/Core/User/user.routes.ts @@ -0,0 +1,53 @@ +import express from 'express'; +import validator, { ValidationSource } from '@helpers/validator'; +import { ProtectRoutes } from '@helpers/auth'; +import permission from '@helpers/permission'; + +import { COLLECTION_NAME } from './model/user.model'; +import { + CreateUser, + DeleteUser, + GetUser, + GetUsers, + UpdateUser +} from './user.controller'; +import schema from './user.schema'; + +const router = express.Router(); + +router.get('/', permission(COLLECTION_NAME, 'read'), ProtectRoutes, GetUsers); + +router.get( + '/:id', + ProtectRoutes, + permission(COLLECTION_NAME, 'read'), + validator(schema.userId, ValidationSource.PARAM), + GetUser +); + +router.post( + '/', + ProtectRoutes, + permission(COLLECTION_NAME, 'create'), + validator(schema.createUserSchema), + CreateUser +); + +router.put( + '/:id', + ProtectRoutes, + permission(COLLECTION_NAME, 'update'), + validator(schema.userId, ValidationSource.PARAM), + validator(schema.updateUserSchema), + UpdateUser +); + +router.delete( + '/:id', + ProtectRoutes, + permission(COLLECTION_NAME, 'delete'), + validator(schema.userId, ValidationSource.PARAM), + DeleteUser +); + +export default router; diff --git a/src/apps/Core/User/user.schema.ts b/src/apps/Core/User/user.schema.ts new file mode 100644 index 0000000..ce03026 --- /dev/null +++ b/src/apps/Core/User/user.schema.ts @@ -0,0 +1,20 @@ +import Joi from 'joi'; +import { JoiObjectId } from '@helpers/validator'; + +export default { + createUserSchema: Joi.object().keys({ + email: Joi.string().email().required(), + username: Joi.string().required(), + password: Joi.string().required(), + role: JoiObjectId() + }), + updateUserSchema: Joi.object().keys({ + email: Joi.string().email().required(), + username: Joi.string().required(), + password: Joi.string(), + role: JoiObjectId() + }), + userId: Joi.object().keys({ + id: JoiObjectId().required() + }) +}; diff --git a/src/apps/Core/index.ts b/src/apps/Core/index.ts new file mode 100644 index 0000000..4a2b941 --- /dev/null +++ b/src/apps/Core/index.ts @@ -0,0 +1,16 @@ +import express from 'express'; + +// +import Permission from './Permission/permission.routes'; +import User from './User/user.routes'; +import Role from './Role/role.routes'; +import Auth from './Auth/auth.routes'; + +const router = express.Router(); + +router.use('/permission', Permission); +router.use('/role', Role); +router.use('/user', User); +router.use('/auth', Auth); + +export default router; diff --git a/src/routes/Demo/Demo.controller.ts b/src/apps/Demo/Demo.controller.ts similarity index 100% rename from src/routes/Demo/Demo.controller.ts rename to src/apps/Demo/Demo.controller.ts diff --git a/src/routes/Demo/Demo.router.ts b/src/apps/Demo/Demo.router.ts similarity index 100% rename from src/routes/Demo/Demo.router.ts rename to src/apps/Demo/Demo.router.ts diff --git a/src/routes/Demo/index.ts b/src/apps/Demo/index.ts similarity index 100% rename from src/routes/Demo/index.ts rename to src/apps/Demo/index.ts diff --git a/src/routes/index.ts b/src/apps/index.ts similarity index 57% rename from src/routes/index.ts rename to src/apps/index.ts index b4e58c9..38f9b3c 100644 --- a/src/routes/index.ts +++ b/src/apps/index.ts @@ -1,9 +1,10 @@ import express from 'express'; // -import { TestRoute } from './Demo'; +import Core from './Core'; const router = express.Router(); -router.use('/test', TestRoute); +router.use('/core', Core); + export default router; diff --git a/src/bin/index.ts b/src/bin/index.ts new file mode 100644 index 0000000..146a7c7 --- /dev/null +++ b/src/bin/index.ts @@ -0,0 +1,44 @@ +import { db } from '@config'; +import mongoose from 'mongoose'; + +import { Permission, Role, User } from './seeder/index'; + +// const dbURI = `mongodb://${db.user}:${encodeURIComponent(db.password)}@${ +// db.host +// }:${db.port}/${db.name}`; + +const dbURI = + process.env.NODE_ENV == 'test' + ? 'mongodb://127.0.0.1:27017/tempTest' + : 'mongodb://127.0.0.1:27017/temp'; + +const options = { + autoIndex: true, + minPoolSize: db.minPoolSize, // Maintain up to x socket connections + maxPoolSize: db.maxPoolSize, // Maintain up to x socket connections + connectTimeoutMS: 60000, // Give up initial connection after 10 seconds + socketTimeoutMS: 45000 // Close sockets after 45 seconds of inactivity +}; + +function setRunValidators(this: any, next: (err?: any) => any) { + this.setOptions({ runValidators: true }); + next(); +} + +mongoose.set('strictQuery', true); + +// Create the database connection +console.log('hello'); +mongoose + .connect(dbURI, options) + .then(async () => { + console.log('hello'); + await Permission.seed(); + await Role.seed(); + await User.seed(); + }) + .catch((e) => { + // Logger.info('Mongoose connection error'); + // Logger.error(e); + console.log('hello lop'); + }); diff --git a/src/bin/seeder/core/permission.ts b/src/bin/seeder/core/permission.ts new file mode 100644 index 0000000..1e9fc52 --- /dev/null +++ b/src/bin/seeder/core/permission.ts @@ -0,0 +1,23 @@ +import { createMultiplePermissions } from '@apps/Core/Permission/model/permission.repository'; +import { Permissions } from '@apps/Core/Permission/model/permissions.model'; + +const permissions: Pick[] = [ + { resource: 'permissions', action: 'create', attributes: ['*'] }, + { resource: 'permissions', action: 'read', attributes: ['*'] }, + { resource: 'permissions', action: 'update', attributes: ['*'] }, + { resource: 'permissions', action: 'delete', attributes: ['*'] }, + + { resource: 'roles', action: 'create', attributes: ['*'] }, + { resource: 'roles', action: 'read', attributes: ['*'] }, + { resource: 'roles', action: 'update', attributes: ['*'] }, + { resource: 'roles', action: 'delete', attributes: ['*'] }, + + { resource: 'users', action: 'create', attributes: ['*'] }, + { resource: 'users', action: 'read', attributes: ['*'] }, + { resource: 'users', action: 'update', attributes: ['*'] }, + { resource: 'users', action: 'delete', attributes: ['*'] } +]; + +export const seed = async () => { + await createMultiplePermissions(permissions); +}; diff --git a/src/bin/seeder/core/role.ts b/src/bin/seeder/core/role.ts new file mode 100644 index 0000000..be623f9 --- /dev/null +++ b/src/bin/seeder/core/role.ts @@ -0,0 +1,26 @@ +import { Types } from 'mongoose'; +import { Role } from '@apps/Core/Role/model/role.model'; +import { createMultipleRole } from '@apps/Core/Role/model/role.repository'; +import { getAllPermissions } from '@apps/Core/Permission/model/permission.repository'; + +const getRoleData = async () => { + const permissions = await getAllPermissions(); + const roles: Pick[] = [ + { + roleName: 'admin', + permissions: permissions + }, + { + roleName: 'user', + permissions: [] + } + ]; + return roles; +}; + +export const seed = async () => { + const roles = await getRoleData(); + createMultipleRole(roles); + + console.log('Role seeded successfully'); +}; diff --git a/src/bin/seeder/core/user.ts b/src/bin/seeder/core/user.ts new file mode 100644 index 0000000..d0f50c7 --- /dev/null +++ b/src/bin/seeder/core/user.ts @@ -0,0 +1,22 @@ +import { getRoleByName } from '@apps/Core/Role/model/role.repository'; +import { User } from '@apps/Core/User/model/user.model'; +import { createMultipleUsers } from '@apps/Core/User/model/user.repository'; + +const getUserData = async () => { + const adminRole = await getRoleByName('admin'); + + const user: Pick[] = [ + { + email: 'admin@gmail.com', + username: 'admin', + password: 'admin1234', + role: adminRole + } + ]; + return user; +}; + +export const seed = async () => { + const users = await getUserData(); + await createMultipleUsers(users); +}; diff --git a/src/bin/seeder/index.ts b/src/bin/seeder/index.ts new file mode 100644 index 0000000..3e55f29 --- /dev/null +++ b/src/bin/seeder/index.ts @@ -0,0 +1,5 @@ +import * as Permission from './core/permission'; +import * as Role from './core/role'; +import * as User from './core/user'; + +export { Permission, Role, User }; diff --git a/src/config.ts b/src/config.ts index db920d3..d2085a7 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,8 +1,17 @@ export const environment = process.env.NODE_ENV; export const port = process.env.PORT || 5000; export const timezone = process.env.TZ; +export const SECRET_KEY = process.env.SECRET_KEY || 'secret'; -export const db = {}; +export const db = { + name: process.env.DB_NAME || '', + host: process.env.DB_HOST || '', + port: process.env.DB_PORT || '', + user: process.env.DB_USER || '', + password: process.env.DB_USER_PWD || '', + minPoolSize: parseInt(process.env.DB_MIN_POOL_SIZE || '5'), + maxPoolSize: parseInt(process.env.DB_MAX_POOL_SIZE || '10') +}; export const corsUrl = process.env.CORS_URL; diff --git a/src/core/ApiResponse.ts b/src/core/ApiResponse.ts index 26c3069..8ecd70a 100644 --- a/src/core/ApiResponse.ts +++ b/src/core/ApiResponse.ts @@ -22,6 +22,7 @@ abstract class ApiResponse { ): Response { for (const [key, value] of Object.entries(headers)) res.append(key, value); + return res .status(this.status as number) .json(ApiResponse.sanitize(response)); diff --git a/src/database.ts b/src/database.ts new file mode 100644 index 0000000..2e2c62b --- /dev/null +++ b/src/database.ts @@ -0,0 +1,74 @@ +import mongoose from 'mongoose'; +import Logger from '@core/Logger'; +import { db } from '@config'; + +// const dbURI = `mongodb://${db.user}:${encodeURIComponent(db.password)}@${ +// db.host +// }:${db.port}/${db.name}`; + +const dbURI = + process.env.NODE_ENV == 'test' + ? 'mongodb://127.0.0.1:27017/tempTest' + : 'mongodb://127.0.0.1:27017/temp'; + +const options = { + autoIndex: true, + minPoolSize: db.minPoolSize, // Maintain up to x socket connections + maxPoolSize: db.maxPoolSize, // Maintain up to x socket connections + connectTimeoutMS: 60000, // Give up initial connection after 10 seconds + socketTimeoutMS: 45000 // Close sockets after 45 seconds of inactivity +}; + +Logger.debug(dbURI); + +function setRunValidators(this: any, next: (err?: any) => any) { + this.setOptions({ runValidators: true }); + next(); +} + +mongoose.set('strictQuery', true); + +// Create the database connection +mongoose + .plugin((schema: any) => { + schema.pre('findOneAndUpdate', setRunValidators); + schema.pre('updateMany', setRunValidators); + schema.pre('updateOne', setRunValidators); + schema.pre('update', setRunValidators); + }) + .connect(dbURI, options) + .then(() => { + Logger.info('Mongoose connection done'); + }) + .catch((e) => { + Logger.info('Mongoose connection error'); + Logger.error(e); + }); + +// CONNECTION EVENTS +// When successfully connected +mongoose.connection.on('connected', () => { + Logger.debug('Mongoose default connection open to ' + dbURI); +}); + +// If the connection throws an error +mongoose.connection.on('error', (err) => { + Logger.error('Mongoose default connection error: ' + err); +}); + +// When the connection is disconnected +mongoose.connection.on('disconnected', () => { + Logger.info('Mongoose default connection disconnected'); +}); + +// If the Node process ends, close the Mongoose connection +process.on('SIGINT', () => { + mongoose.connection.close(() => { + Logger.info( + 'Mongoose default connection disconnected through app termination' + ); + process.exit(0); + }); +}); + +export const connection = mongoose.connection; diff --git a/src/helpers/auth.ts b/src/helpers/auth.ts new file mode 100644 index 0000000..209a5a5 --- /dev/null +++ b/src/helpers/auth.ts @@ -0,0 +1,3 @@ +import passport from 'passport'; + +export const ProtectRoutes = passport.authenticate('jwt', { session: false }); diff --git a/src/helpers/passport.ts b/src/helpers/passport.ts new file mode 100644 index 0000000..5c8df8f --- /dev/null +++ b/src/helpers/passport.ts @@ -0,0 +1,70 @@ +import passport from 'passport'; +import { + Strategy as JWTStrategy, + ExtractJwt, + StrategyOptions, + VerifiedCallback +} from 'passport-jwt'; +import { Strategy as LocalStrategy } from 'passport-local'; +// +import { + findUserById, + findUserByEmail +} from '@apps/Core/User/model/user.repository'; +import { findByToken } from '@apps/Core/Auth/model/auth.repository'; +import { SECRET_KEY } from '@config'; +import { Request } from 'express'; +import { JwtPayload } from 'jsonwebtoken'; +import { NoDataError } from '@core/ApiError'; + +const JWToptions: StrategyOptions = { + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + secretOrKey: SECRET_KEY, + passReqToCallback: true +}; + +const strategy = new JWTStrategy( + JWToptions, + async (req: Request, payload: JwtPayload, done: VerifiedCallback) => { + const user = await findUserById(payload.sub!); + if (user) { + const token = ExtractJwt.fromAuthHeaderAsBearerToken()(req); + const jwtToken = await findByToken(token!); + + if (jwtToken.blacklisted === false && jwtToken.ipAddress === req.ip) + return done(undefined, { ...user }); + } + return done(undefined, false); + } +); + +passport.use( + 'local', + new LocalStrategy( + { usernameField: 'email', passwordField: 'password', session: false }, + async (email, password, done) => { + const user = await findUserByEmail(email); + if (!user) { + return done(new NoDataError('No user name found'), false); + } + + const isCorrect = user!.validatePassword(password); + if (!isCorrect) { + return done(null, false); + } + + return done(null, user); + } + ) +); + +passport.serializeUser((user, done) => { + done(null, user); +}); + +passport.deserializeUser((user: any, done) => { + done(null, user); +}); +passport.use(strategy); + +export default passport; diff --git a/src/helpers/permission.ts b/src/helpers/permission.ts new file mode 100644 index 0000000..5d95704 --- /dev/null +++ b/src/helpers/permission.ts @@ -0,0 +1,95 @@ +import { Response, NextFunction, Request } from 'express'; +import mongoose from 'mongoose'; +import accessControl from 'accesscontrol'; +import { ForbiddenError, InternalError } from '@core/ApiError'; +import { getAllRole } from '@apps/Core/Role/model/role.repository'; +import { User } from '@apps/Core/User/model/user.model'; + +interface GrantType { + role: string; + resource: string; + action: string; + attributes: string; +} + +const getAccessControl = async (): Promise => { + const roles = await getAllRole(); + const grantList: GrantType[] = []; + roles.forEach((role) => { + role.permissions.forEach((permission) => { + const grant = { + role: role.roleName, + resource: permission.resource, + action: `${permission.action}:any`, + attributes: permission.attributes.join(' ,') + }; + grantList.push(grant); + }); + }); + return grantList; +}; + +export default ( + resource: string, + action: 'create' | 'read' | 'update' | 'delete' + ) => + async (req: Request, res: Response, next: NextFunction) => { + const ac = new accessControl.AccessControl(); + const isExists = await mongoose.connection.db + .listCollections({ + name: resource + }) + .toArray(); + + if (isExists.length === 0) { + next( + `model with name of '${resource}' does not exists exists, can not check permissions` + ); + } + + const grantList = await getAccessControl(); + ac.setGrants(grantList); + + try { + const user: Partial = req.user!; + const role = user.role?.roleName || 'user'; + switch (action) { + case 'create': + if (ac.can(role).create(resource).granted) next(); + else { + throw new ForbiddenError( + 'Sorry you do not have permission to create this resource' + ); + } + break; + case 'read': + if (ac.can(role).read(resource).granted) next(); + else { + throw new ForbiddenError( + 'Sorry you do not have permission to read this resource' + ); + } + break; + case 'update': + if (ac.can(role).update(resource).granted) next(); + else { + throw new ForbiddenError( + 'Sorry you do not have permission to update this resource' + ); + } + break; + case 'delete': + if (ac.can(role).delete(resource).granted) next(); + else { + throw new ForbiddenError( + 'Sorry you do not have permission to delete this resource' + ); + } + break; + default: + throw new InternalError('Sorry, invalid action type'); + } + } catch (error) { + next(error); + } + }; diff --git a/src/tests/test/core/auth.test.ts b/src/tests/test/core/auth.test.ts new file mode 100644 index 0000000..03587a7 --- /dev/null +++ b/src/tests/test/core/auth.test.ts @@ -0,0 +1,57 @@ +import { StatusCodes } from 'http-status-codes'; +import mongoose from 'mongoose'; +import supertest from 'supertest'; +import app from '@app'; +import { createUser } from '@apps/Core/User/model/user.repository'; + +afterAll(() => { + mongoose.connection.db.dropCollection('users'); +}); +describe('Auth test', () => { + const request = supertest(app); + it('Register', async () => { + const response = await request.post('/core/auth/register').send({ + email: 'test2@gmail.com', + username: 'test2', + password: 'test2password' + }); + + expect(response.status).toBe(StatusCodes.OK); + expect(response.body.statusCode).toBe('10000'); + expect(response.body.data.accessToken).not.toBeNull(); + }); + describe('login', () => { + beforeAll(async () => { + const t = await createUser( + 'test@gmail.com', + 'test', + 'test1234', + 'user' + ); + }); + + it('Success login', async () => { + const response = await request.post('/core/auth/login').send({ + email: 'test@gmail.com', + password: 'test1234' + }); + expect(response.status).toBe(StatusCodes.OK); + expect(response.body.statusCode).toBe('10000'); + expect(response.body.data.accessToken).not.toBeNull(); + }); + + it('wrong user login', async () => { + const response = await request.post('/core/auth/login').send({ + email: 'wrongtest@gmail.com', + password: 'test1234' + }); + console.log(response); + // expect(response.status).toBe(StatusCodes.OK); + // expect(response.body.statusCode).toBe('10000'); + // expect(response.body.data.accessToken).not.toBeNull(); + }); + afterAll(() => { + mongoose.connection.close(); + }); + }); +}); diff --git a/src/tests/test/core/role.ts b/src/tests/test/core/role.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/tests/test/test.test.ts b/src/tests/test/test.test.ts index ff2fef6..94a2d19 100644 --- a/src/tests/test/test.test.ts +++ b/src/tests/test/test.test.ts @@ -1,15 +1,20 @@ import { StatusCodes } from 'http-status-codes'; +import mongoose from 'mongoose'; import supertest from 'supertest'; import app from '@app'; describe('Demo test', () => { const request = supertest(app); it('Success test', async () => { - const response = await request.get('/test'); - expect(response.status).toBe(StatusCodes.OK); + const response = await request.get('/core/permission'); + expect(response.status).toBe(StatusCodes.UNAUTHORIZED); }); it('Route Not Found test', async () => { const response = await request.get('/'); expect(response.status).toBe(StatusCodes.NOT_FOUND); }); + + afterAll(() => { + mongoose.connection.close(); + }); }); diff --git a/tsconfig.json b/tsconfig.json index 7aaa095..46501db 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,38 +1,38 @@ { "compilerOptions": { - "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + "target": "es2016" , "lib": [ "es6" ] , - "module": "commonjs" /* Specify what module code is generated. */, - "baseUrl": "." /* Specify the base directory to resolve non-relative module names. */, + "module": "commonjs" , + "baseUrl": "." , "paths": { "@core/*": ["./src/core/*"], + "@database":["./src/database.ts"], "@helpers/*":["./src/helpers/*"], - "@routes":["./src/routes/index.ts"], - "@routes/*":["./src/routes/*"], + "@apps":["./src/apps/index.ts"], + "@apps/*":["./src/apps/*"], "@test/*":["./src/tests/*"], "@config":["./src/config.ts"], "@app":["./src/app.ts"], "@server":["./src/server.ts"], + "@bin/*":["./src/bin/*"] }, - "resolveJsonModule": true /* Enable importing .json files. */, - "allowJs": true /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */, - "outDir": "build" /* Specify an output folder for all emitted files. */, - "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - "strict": true /* Enable all strict type-checking options. */, - "noImplicitAny": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */, - "strictNullChecks": true /* When type checking, take into account 'null' and 'undefined'. */, - "noImplicitThis": true /* Enable error reporting when 'this' is given the type 'any'. */, - "skipLibCheck": true /* Skip type checking all .d.ts files. */ + "resolveJsonModule": true , + "allowJs": true , + "outDir": "build", + "esModuleInterop": true , + "forceConsistentCasingInFileNames": true , + "strict": true , + "noImplicitAny": true, + "strictNullChecks": true , + "noImplicitThis": true , + "skipLibCheck": true }, "plugins":[ - /* Transform paths in output .js files */ { "transform":"typescript-transform-paths" }, - /* Transform paths in output .d.ts files */ { "transform":"typescript-transform-paths", "afterDeclarations": true