diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..12228ed --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,36 @@ +name: Build and Release + +on: + push: + branches: + - main # Modify to your branch name + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: '14' # Modify to your Node.js version + + - name: Install dependencies + run: npm install + + - name: Build TypeScript + run: npm run build # Modify to your build script if necessary + + # Add more steps for testing, linting, etc. + + - name: Release to GitHub + uses: softprops/action-gh-release@v1 + with: + files: | + # List files to include in the release + dist/*.js # Modify based on your build output + token: ${{ secrets.GITHUB_TOKEN }} + body: Release ${{ github.sha }} diff --git a/README.md b/README.md index dcd8bc0..6f244fc 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,37 @@ -# NodeJS-Backend-Structure - NodeJS Backend Structure. +Project Name +============ + +Description +----------- + +This project is a Node.js application structured to assist developers in \[add a brief description of the project's purpose or functionality\]. + +Usage +----- + +\[Add instructions or information on how to use or run the Node.js application.\] + +License +------- + +This project is licensed under the MIT License - see the LICENSE file for details. + +Authors +------- + +* [Vimukthi Indunil](https://github.com/darkwaves-ofc) +* [Achira Nimnaka](https://github.com/achiragaming) + +Contribution +------------ + +\[Explain how others can contribute to the project if contributions are welcome.\] + +Acknowledgments +--------------- + +\[Add any acknowledgments or credits to resources or individuals that have been helpful in the project.\] + +* * * + +Feel free to enrich the sections by adding detailed usage instructions, guidelines for contributions, acknowledgments, or any other relevant information about your project. Adjust the placeholders like `[add a brief description of the project's purpose or functionality]` with the actual project's details. This README provides a basic structure that you can build upon. \ No newline at end of file diff --git a/nodemon.json b/nodemon.json new file mode 100644 index 0000000..a64efe1 --- /dev/null +++ b/nodemon.json @@ -0,0 +1,6 @@ +{ + "watch": ["src"], + "ext": "ts", + "ignore": ["src/**/*.spec.ts"], + "exec": "npm run devStart" +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..e439378 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3954 @@ +{ + "name": "nodejs-backend-structure", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "nodejs-backend-structure", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "amqplib": "^0.10.3", + "axios": "^1.4.0", + "bcrypt": "^5.1.1", + "body-parser": "^1.20.2", + "canvas": "^2.11.2", + "chalk": "^4.1.2", + "circular-json": "^0.5.9", + "colors": "^1.4.0", + "cookie-parser": "^1.4.6", + "cors": "^2.8.5", + "dayjs": "^1.11.7", + "diskusage-ng": "^1.0.4", + "dotenv": "^16.3.1", + "ejs": "^3.1.9", + "express": "^4.18.2", + "file-type": "^18.5.0", + "jsonwebtoken": "^9.0.0", + "kafkajs": "^2.2.4", + "loaders.css": "^0.1.2", + "moment": "^2.29.4", + "mongoose": "^7.2.2", + "multer": "^1.4.5-lts.1", + "nodemon": "^3.0.2", + "pidusage": "^3.0.2", + "prettier": "^3.1.1", + "randomcolor": "^0.6.2", + "socket.io": "^4.7.2", + "systeminformation": "^5.21.17", + "ua-parser-js": "^1.0.35", + "uuid": "^9.0.0", + "voucher-code-generator": "^1.3.0", + "ws": "^8.13.0" + }, + "devDependencies": { + "@types/amqplib": "^0.10.4", + "@types/circular-json": "^0.4.0", + "@types/cookie-parser": "^1.4.6", + "@types/ejs": "^3.1.5", + "@types/express": "^4.17.21", + "@types/jsonwebtoken": "^9.0.5", + "@types/node": "^20.10.6", + "@types/randomcolor": "^0.5.9", + "@types/ua-parser-js": "^0.7.39", + "@types/uuid": "^9.0.7", + "@types/ws": "^8.5.10", + "eslint": "^8.56.0", + "typescript": "^5.3.3" + }, + "engines": { + "node": ">=16.5.0" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@acuminous/bitsyntax": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@acuminous/bitsyntax/-/bitsyntax-0.1.2.tgz", + "integrity": "sha512-29lUK80d1muEQqiUsSo+3A0yP6CdspgC95EnKBMi22Xlwt79i/En4Vr67+cXhU+cZjbti3TgGGC5wy1stIywVQ==", + "dependencies": { + "buffer-more-ints": "~1.0.0", + "debug": "^4.3.4", + "safe-buffer": "~5.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "dev": true + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "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/@mongodb-js/saslprep": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.1.tgz", + "integrity": "sha512-t7c5K033joZZMspnHg/gWPE4kandgc2OxE74aYOtGKfgB9VPuVJPix0H6fhmm2erj5PBJ21mqcx34lpIGtUCsQ==", + "optional": true, + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" + }, + "node_modules/@types/amqplib": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@types/amqplib/-/amqplib-0.10.4.tgz", + "integrity": "sha512-Y5Sqquh/LqDxSgxYaAAFNM0M7GyONtSDCcFMJk+DQwYEjibPyW6y+Yu9H9omdkKc3epyXULmFN3GTaeBHhn2Hg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/circular-json": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@types/circular-json/-/circular-json-0.4.0.tgz", + "integrity": "sha512-7+kYB7x5a7nFWW1YPBh3KxhwKfiaI4PbZ1RvzBU91LZy7lWJO822CI+pqzSre/DZ7KsCuMKdHnLHHFu8AyXbQg==", + "dev": true + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-KoooCrD56qlLskXPLGUiJxOMnv5l/8m7cQD2OxJ73NPMhuSz9PmvwRD6EpjDyKBVrdJDdQ4bQK7JFNHnNmax0w==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ejs": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.5.tgz", + "integrity": "sha512-nv+GSx77ZtXiJzwKdsASqi+YQ5Z7vwHsTP0JY2SiQgjGckkBRKZnk8nIM+7oUZ1VCtuTz0+By4qVR7fqzp/Dfg==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.41", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz", + "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz", + "integrity": "sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.10.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.6.tgz", + "integrity": "sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/qs": { + "version": "6.9.11", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", + "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==", + "dev": true + }, + "node_modules/@types/randomcolor": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@types/randomcolor/-/randomcolor-0.5.9.tgz", + "integrity": "sha512-k58cfpkK15AKn1m+oRd9nh5BnuiowhbyvBBdAzcddtARMr3xRzP0VlFaAKovSG6N6Knx08EicjPlOMzDejerrQ==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/ua-parser-js": { + "version": "0.7.39", + "resolved": "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.39.tgz", + "integrity": "sha512-P/oDfpofrdtF5xw433SPALpdSchtJmY7nsJItf8h3KXqOslkbySh8zq4dSWXH2oTjRvJ5PczVEoCZPow6GicLg==", + "dev": true + }, + "node_modules/@types/uuid": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz", + "integrity": "sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==", + "dev": true + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + }, + "node_modules/@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "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==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.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", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/amqplib": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.10.3.tgz", + "integrity": "sha512-UHmuSa7n8vVW/a5HGh2nFPqAEr8+cD4dEZ6u9GjP91nHfr1a54RyAKyra7Sb5NH7NBKOUlyQSMXIp0qAixKexw==", + "dependencies": { + "@acuminous/bitsyntax": "^0.1.2", + "buffer-more-ints": "~1.0.0", + "readable-stream": "1.x >=1.1.9", + "url-parse": "~1.5.10" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" + }, + "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/are-we-there-yet/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/are-we-there-yet/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/are-we-there-yet/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.3.tgz", + "integrity": "sha512-fWyNdeawGam70jXSVlKl+SUNVcL6j6W79CuSIPfi6HnDUmSCH6gyUys/HrqHeA/wU0Az41rRgean494d0Jb+ww==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/bcrypt": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", + "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.11", + "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/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/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bson": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", + "integrity": "sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g==", + "engines": { + "node": ">=14.20.1" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/buffer-more-ints": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz", + "integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "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/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "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/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "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/circular-json": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz", + "integrity": "sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ==", + "deprecated": "CircularJSON is in maintenance only, flatted is its successor." + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "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/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.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", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "dependencies": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/dayjs": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/diskusage-ng": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/diskusage-ng/-/diskusage-ng-1.0.4.tgz", + "integrity": "sha512-30qT0Bn2dNGii6dAXllGgYRaIt+7gPhwCJks+byhutkCOCgsqfqvXmAV2zTDOvU1ylnGHUjZMMaKhM95FyQQrg==", + "engines": { + "node": ">=8.8.0" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/ejs": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", + "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", + "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", + "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "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", + "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" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/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/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/node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-type": { + "version": "18.7.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-18.7.0.tgz", + "integrity": "sha512-ihHtXRzXEziMrQ56VSgU7wkxh55iNchFkosu7Y9/S+tXHdKyrGjVK0ujbqNnsxzea+78MaLhN6PGmfYSAv1ACw==", + "dependencies": { + "readable-web-to-node-stream": "^3.0.2", + "strtok3": "^7.0.0", + "token-types": "^5.0.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/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/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "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", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "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/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "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/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jake": { + "version": "10.8.7", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", + "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/kafkajs": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/kafkajs/-/kafkajs-2.2.4.tgz", + "integrity": "sha512-j/YeapB1vfPT2iOIUn/vxdyKEuhuY2PxMBvf5JWux6iSaukAccrMtXEY/Lb7OvavDhOWME589bpLrEdnVHjfjA==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/kareem": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz", + "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/loaders.css": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/loaders.css/-/loaders.css-0.1.2.tgz", + "integrity": "sha512-Rhowlq24ey1VOeor+3wYOt9+MjaxBOJm1u4KlQgNC3+0xJ0LS4wq4iG57D/BPzvuD/7HHDGQOWJ+81oR2EI9bQ==" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "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==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "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": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, + "node_modules/mongodb": { + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.1.tgz", + "integrity": "sha512-NBGA8AfJxGPeB12F73xXwozt8ZpeIPmCUeWRwl9xejozTXFes/3zaep9zhzs1B/nKKsw4P3I4iPfXl3K7s6g+Q==", + "dependencies": { + "bson": "^5.5.0", + "mongodb-connection-string-url": "^2.6.0", + "socks": "^2.7.1" + }, + "engines": { + "node": ">=14.20.1" + }, + "optionalDependencies": { + "@mongodb-js/saslprep": "^1.1.0" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.0.0", + "kerberos": "^1.0.0 || ^2.0.0", + "mongodb-client-encryption": ">=2.3.0 <3", + "snappy": "^7.2.2" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "dependencies": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "node_modules/mongoose": { + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.6.7.tgz", + "integrity": "sha512-6Ihl7Y7OlSEMiwyjar3N8sMKRZa3LNGcayES8I+Hluo0sV6j1SVOo8MXXnwi+z3+Hcyk4zO47+xL87fBTNlWVw==", + "dependencies": { + "bson": "^5.5.0", + "kareem": "2.5.1", + "mongodb": "5.9.1", + "mpath": "0.9.0", + "mquery": "5.0.0", + "ms": "2.1.3", + "sift": "16.0.1" + }, + "engines": { + "node": ">=14.20.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/mongoose/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", + "dependencies": { + "debug": "4.x" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multer": { + "version": "1.4.5-lts.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz", + "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/nan": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", + "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "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.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "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/nodemon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.2.tgz", + "integrity": "sha512-9qIN2LNTrEzpOPBaWHTm4Asy1LxXLSickZStAQ4IZe7zsoIpD/A7LWxhZV3t4Zu352uBcqVnRsDXSMR2Sc3lTA==", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/peek-readable": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", + "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidusage": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-3.0.2.tgz", + "integrity": "sha512-g0VU+y08pKw5M8EZ2rIGiEBaB8wrQMjYGFfW2QVIfyT8V+fq8YFLkvlz4bz5ljvFDJYNFCWT3PWqcRr2FKO81w==", + "dependencies": { + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pidusage/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz", + "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randomcolor": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/randomcolor/-/randomcolor-0.6.2.tgz", + "integrity": "sha512-Mn6TbyYpFgwFuQ8KJKqf3bqqY9O1y37/0jgSK/61PUxV4QfIMv0+K2ioq8DfOjkBslcjwSzRfIDEXfzA9aCx7A==" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", + "dependencies": { + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/readable-web-to-node-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readable-web-to-node-stream/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/readable-web-to-node-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/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/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "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/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sift": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", + "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" + }, + "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==" + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socket.io": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.2.tgz", + "integrity": "sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "dependencies": { + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-adapter/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "optional": true, + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strtok3": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", + "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/systeminformation": { + "version": "5.21.22", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.21.22.tgz", + "integrity": "sha512-gNHloAJSyS+sKWkwvmvozZ1eHrdVTEsynWMTY6lvLGBB70gflkBQFw8drXXr1oEXY84+Vr9tOOrN8xHZLJSycA==", + "os": [ + "darwin", + "linux", + "win32", + "freebsd", + "openbsd", + "netbsd", + "sunos", + "android" + ], + "bin": { + "systeminformation": "lib/cli.js" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "Buy me a coffee", + "url": "https://www.buymeacoffee.com/systeminfo" + } + }, + "node_modules/tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/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/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/token-types": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", + "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ua-parser-js": { + "version": "1.0.37", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz", + "integrity": "sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/voucher-code-generator": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/voucher-code-generator/-/voucher-code-generator-1.3.0.tgz", + "integrity": "sha512-t4wnI91KC58LtjX2I0rJDhRm1JTXD+G7A+7iqp0sRSgpeJP4eKLexDRDLe2nedR7xFQcVlZudDZRBLrMP5+KTA==" + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..969204d --- /dev/null +++ b/package.json @@ -0,0 +1,111 @@ +{ + "name": "nodejs-backend-structure", + "version": "1.0.0", + "description": "NodeJS Backend Structure.", + "main": "dist/index.js", + "preview": false, + "homepage": "https://github.com/darkwaves-ofc/NodeJS-Backend-Structure", + "bugs": { + "url": "https://github.com/darkwaves-ofc/NodeJS-Backend-Structure/issues", + "email": "darkwavestech@gmail.com" + }, + "engines": { + "node": ">=16.5.0" + }, + "author": "Dark Waves (https://github.com/darkwaves-ofc)", + "files": [ + "dist/**/**/*" + ], + "scripts": { + "build": "npm run format && tsc", + "start": "npm run build && node dist/index.js", + "devStart": "tsc --incremental && node dist/index.js", + "dev": "nodemon", + "format": "prettier --write \"src/\"" + }, + "keywords": [ + "nodejs", + "backend-strucutre", + "nodejs-backend", + "nodejs-backend-structure", + "express-structure", + "mongoose", + "mongodb", + "kafka", + "rabbitmq", + "amqp", + "socket.io", + "typescript", + "es6", + "es7", + "es8" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/darkwaves-ofc/NodeJS-Backend-Structure.git" + }, + "contributors": [ + "Vimukthi Indunil (https://github.com/darkwaves-ofc)", + "AchiraGaming (https://github.com/achiragaming)" + ], + "publishConfig": { + "access": "public" + }, + "license": "MIT", + "devDependencies": { + "@types/amqplib": "^0.10.4", + "@types/circular-json": "^0.4.0", + "@types/cookie-parser": "^1.4.6", + "@types/ejs": "^3.1.5", + "@types/express": "^4.17.21", + "@types/jsonwebtoken": "^9.0.5", + "@types/node": "^20.10.6", + "@types/randomcolor": "^0.5.9", + "@types/ua-parser-js": "^0.7.39", + "@types/uuid": "^9.0.7", + "@types/ws": "^8.5.10", + "eslint": "^8.56.0", + "typescript": "^5.3.3", + "@types/events": "^3.0.0", + "discord.js": "^14.6.0", + "prettier": "^2.7.1", + "tslint": "^6.1.3", + "tslint-config-prettier": "^1.18.0", + "typedoc": "^0.23.20" + + }, + "dependencies": { + "amqplib": "^0.10.3", + "axios": "^1.4.0", + "bcrypt": "^5.1.1", + "body-parser": "^1.20.2", + "canvas": "^2.11.2", + "chalk": "^4.1.2", + "circular-json": "^0.5.9", + "colors": "^1.4.0", + "cookie-parser": "^1.4.6", + "cors": "^2.8.5", + "dayjs": "^1.11.7", + "diskusage-ng": "^1.0.4", + "dotenv": "^16.3.1", + "ejs": "^3.1.9", + "express": "^4.18.2", + "file-type": "^18.5.0", + "jsonwebtoken": "^9.0.0", + "kafkajs": "^2.2.4", + "loaders.css": "^0.1.2", + "moment": "^2.29.4", + "mongoose": "^7.2.2", + "multer": "^1.4.5-lts.1", + "nodemon": "^3.0.2", + "pidusage": "^3.0.2", + "prettier": "^3.1.1", + "randomcolor": "^0.6.2", + "socket.io": "^4.7.2", + "systeminformation": "^5.21.17", + "ua-parser-js": "^1.0.35", + "uuid": "^9.0.0", + "voucher-code-generator": "^1.3.0", + "ws": "^8.13.0" + } +} diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..7bdfdf6 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,62 @@ +"use strict"; + +import * as dotenv from "dotenv"; + +dotenv.config(); + +interface Config { + mongourl: string | undefined; + website: { + links: string[]; + fontendUri: string | undefined; + port: string | undefined; + clientId: string | undefined; + clientSecret: string | undefined; + redirectUri: string; + secretKey: string | undefined; + callBackUri: string | undefined; + }; + loadDefaultIps: boolean; + cacheToken: string | undefined; + geoLocationApiKey: string | undefined; + rabbitMQ: string | undefined; + database: { + DashboardData: { name: string }[]; + }; +} + +function parseBoolean(value: any): boolean { + if (typeof value === "string") { + value = value.trim().toLowerCase(); + } + switch (value) { + case true: + case "true": + return true; + default: + return false; + } +} + +const config: Config = { + mongourl: process.env.MONGO_URI, + website: { + links: process.env.Link ? process.env.Link.split(",") : [], + fontendUri: process.env.fontEndUri, + port: process.env.Port, + clientId: process.env.ClientId, + clientSecret: process.env.ClientSecret, + redirectUri: "", + secretKey: process.env.SecretKey, + callBackUri: process.env.CallBackUri, + }, + loadDefaultIps: parseBoolean(process.env.LoadDefaults), + cacheToken: process.env.CacheToken, + geoLocationApiKey: process.env.geoLocationAPiKey, + rabbitMQ: process.env.RabbitMQURL, + database: { + DashboardData: [{ name: "admin" }], + }, +}; + +export = config; diff --git a/src/handlers/initDatabase.ts b/src/handlers/initDatabase.ts new file mode 100644 index 0000000..4ec6890 --- /dev/null +++ b/src/handlers/initDatabase.ts @@ -0,0 +1,412 @@ +"use strict"; + +import { EventEmitter } from "events"; +import { readdir } from "fs"; +import dashboardDataDb from "../schema/dashboard"; +import userData from "../schema/userData"; + +export = class DatabaseInitializer { + private client: any; + + constructor(client: any) { + if (!client) return new Error(`client is required`); + this.client = client; + } + + private convertIdsRecursive(obj: any): any { + if (obj instanceof Array) { + return obj.map((item) => this.convertIdsRecursive(item)); + } else if (obj instanceof Object) { + const newObj = { ...obj }; + for (const key in newObj) { + if (newObj.hasOwnProperty(key)) { + if (key === "_id" && newObj[key].$oid) { + newObj[key] = newObj[key].$oid; + } else { + newObj[key] = this.convertIdsRecursive(newObj[key]); + } + } + } + return newObj; + } + return obj; + } + + public async loadDashboardDatas() { + const schemas = [ + { + _id: { + $oid: "655c26d1527821278fc1cd82", + }, + type: "admin", + navigationLinks: [ + { + title: "Home", + icon: "fa-house", + path: "/home", + url: "/Home", + _id: { + $oid: "655c26d1527821278fc1cd83", + }, + subMenu: [], + }, + { + title: "Events", + icon: "fa-calendar", + path: "/events/*", + url: "/Events", + subMenu: [ + { + url: "/Events/Manager", + icon: "fa-bars-progress", + title: "Event Manager", + _id: { + $oid: "655c26d1527821278fc1cd85", + }, + }, + ], + _id: { + $oid: "655c26d1527821278fc1cd84", + }, + }, + { + title: "Users", + icon: "fa-users", + path: "/user/*", + url: "/User", + subMenu: [ + { + url: "/User/Edit", + icon: "fa-user-pen", + title: "User Edit", + _id: { + $oid: "655c4b3fd711067102915a3e", + }, + }, + { + url: "/User/Add", + icon: "fa-user-plus", + title: "User Add", + }, + ], + _id: { + $oid: "655c4b3fd711067102915a3d", + }, + }, + { + title: "Members", + icon: "fa-people-line", + path: "/members/*", + url: "/Members", + subMenu: [ + { + url: "/Members/Add", + icon: "fa-person-circle-plus", + title: "Add Members", + }, + { + url: "/Members/Edit", + icon: "fa-people-pulling", + title: "Edit Members", + }, + ], + }, + { + title: "Broadcast", + icon: "fa-bullhorn", + path: "/broadcast/*", + url: "/Broadcast", + _id: { + $oid: "655c26d1527821278fc1cd87", + }, + subMenu: [], + }, + { + title: "Settings", + icon: "fa-gear", + path: "/settings/*", + url: "/Settings", + _id: { + $oid: "655c26d1527821278fc1cd88", + }, + subMenu: [], + }, + ], + __v: 0, + }, + { + _id: { + $oid: "655c27b0fc5c652837dde1fc", + }, + type: "staff", + navigationLinks: [ + { + title: "Home", + icon: "fa-house", + path: "/home", + url: "/Home", + _id: { + $oid: "655c27b0fc5c652837dde1fd", + }, + subMenu: [], + }, + { + title: "Submit", + icon: "fa-clipboard-list", + path: "/submit/*", + url: "/Submit", + _id: { + $oid: "655c27b0fc5c652837dde201", + }, + }, + ], + __v: 0, + }, + { + _id: { + $oid: "655c4b3fd711067102915a37", + }, + type: "owner", + navigationLinks: [ + { + title: "Home", + icon: "fa-house", + path: "/home", + url: "/Home", + _id: { + $oid: "655c4b3fd711067102915a38", + }, + subMenu: [], + }, + { + title: "Approves", + icon: "fa-list-check", + path: "/approve/*", + url: "/Approve", + }, + { + title: "Events", + icon: "fa-calendar", + path: "/events/*", + url: "/Events", + subMenu: [ + { + url: "/Events/Manager", + icon: "fa-bars-progress", + title: "Event Manager", + _id: { + $oid: "655c4b3fd711067102915a3a", + }, + }, + ], + _id: { + $oid: "655c4b3fd711067102915a39", + }, + }, + { + title: "Broadcast", + icon: "fa-bullhorn", + path: "/broadcast/*", + url: "/Broadcast", + _id: { + $oid: "655c4b3fd711067102915a3c", + }, + subMenu: [], + }, + { + title: "Members", + icon: "fa-people-line", + path: "/members/*", + url: "/Members", + subMenu: [ + { + url: "/Members/Add", + icon: "fa-person-circle-plus", + title: "Add Members", + }, + { + url: "/Members/Edit", + icon: "fa-people-pulling", + title: "Edit Members", + }, + ], + }, + { + title: "Users", + icon: "fa-users", + path: "/user/*", + url: "/User", + subMenu: [ + { + url: "/User/Edit", + icon: "fa-user-pen", + title: "User Edit", + _id: { + $oid: "655c4b3fd711067102915a3e", + }, + }, + { + url: "/User/Add", + icon: "fa-user-plus", + title: "User Add", + }, + ], + _id: { + $oid: "655c4b3fd711067102915a3d", + }, + }, + { + title: "Settings", + icon: "fa-gear", + path: "/settings/*", + url: "/Settings", + _id: { + $oid: "655c4b3fd711067102915a44", + }, + subMenu: [], + }, + ], + __v: 0, + }, + ]; + + for (const schema of schemas) { + const id = schema._id.$oid; + let schemaDb = await dashboardDataDb.findOne({ _id: id }).catch(() => {}); + if (schemaDb) continue; + schemaDb = await new dashboardDataDb( + this.convertIdsRecursive(schema), + ).save(); + } + } + + public async loadAdminMembers() { + const schemas = [ + { + _id: "6551912eadeb5039127c163e", + notifications: { + unread: [], + all: [], + }, + roles: { + roleType: "owner", + roleIndex: "1", + }, + owner: false, + eventData: [], + friends: [], + status: 1, + statusMessage: "", + flags: [], + createdAt: "1699844400526", + deleted: false, + tokens: [], + email: "darkwavesofc4@gmail.com", + userName: "darkwaves", + password: + "$2b$10$EhggKEGsa6hG6S6KYiSkr.Hf.YfISk568oMxuSTsKDFVn6EkoXccG", + phoneNumber: "071725466", + school: "mrcm", + name: "Dark Waves", + __v: 8, + }, + { + _id: "655197a2c45fdaaaca434122", + notifications: { + unread: [], + all: [], + }, + roles: { + roleType: "owner", + roleIndex: "1", + }, + owner: false, + eventData: [], + friends: [], + status: 1, + statusMessage: "", + flags: [], + createdAt: "1699846051627", + deleted: false, + tokens: [], + email: "darkwavesofc2@gmail.com", + userName: "darkwaves1", + password: + "$2b$10$Fszw4Ogvg4EMKgCJtOBgB.y/jgagXPVFm/H21ziGpI11mYCntnZqi", + phoneNumber: "071725466", + school: "mrcm", + name: "Dark Waves", + __v: 6, + }, + { + _id: "655197c6c45fdaaaca43412e", + notifications: { + unread: [], + all: [], + }, + roles: { + roleType: "staff", + roleIndex: "3", + }, + owner: false, + eventData: [], + friends: [], + status: 1, + statusMessage: "", + flags: [], + createdAt: "1699846087062", + deleted: false, + tokens: [], + email: "darkwavesofc3@gmail.com", + userName: "darkwaves2", + password: + "$2b$10$GsaBJezgygV8asMb4.3TveMv4dj3y9da.aC2oUufLyQtXA3ztGaOi", + phoneNumber: "071725466", + school: "mrcm", + name: "Dark Waves", + __v: 2, + }, + { + _id: "6551981b7296875721663e74", + notifications: { + unread: [], + all: [], + }, + roles: { + roleType: "admin", + roleIndex: "2", + }, + owner: false, + eventData: [], + friends: [], + status: 1, + statusMessage: "", + flags: [], + createdAt: "1699846172030", + deleted: false, + tokens: [], + email: "darkwavesofc5@gmail.com", + userName: "darkwaves3", + password: + "$2b$10$q5l9MLltuqDk51MOa.BQBO0N5WjooNkPhehXfppPKX7/ZVU8YkUw.", + phoneNumber: "071725466", + school: "mrcm", + name: "Dark Waves", + __v: 3, + }, + ]; + + for (const schema of schemas) { + const id = schema._id.$oid; + let schemaDb = await userData.findOne({ _id: id }).catch(() => {}); + if (schemaDb) continue; + schemaDb = await new userData(this.convertIdsRecursive(schema)).save(); + } + } + + public async start() { + // await this.loadDashboardDatas(); + // await this.loadAdminMembers(); + this.client.logger.log("[ DB ] Database initialized:"); + } +}; diff --git a/src/handlers/loadincomingEvents.ts b/src/handlers/loadincomingEvents.ts new file mode 100644 index 0000000..167ab86 --- /dev/null +++ b/src/handlers/loadincomingEvents.ts @@ -0,0 +1,109 @@ +"use strict"; + +import { EventEmitter } from "events"; +import { readdir } from "fs"; +import socketIo, { Server, Socket } from "socket.io"; +import { ParsedUrlQuery } from "querystring"; + +interface Client { + server: any; + config: any; + links: string[]; + parseURL: (link: string) => any; + ipport: (link: string, port: number) => string; + port: number; + logger: any; + wspaths: Map; + io: Server; + wsevents: EventEmitter; +} + +interface WebSocketPath { + name: string; + run: (client: Client, socket: Socket, request: any) => void; +} + +export = class WebSocketInitializer { + private client: Client; + + constructor(client: Client) { + if (!client) throw new Error(`client is required`); + this.client = client; + this.client.wspaths = new Map(); + } + + public async start() { + this.client.wsevents = new EventEmitter().setMaxListeners( + 0, + ) as EventEmitter; + + const io = socketIo(this.client.server, { + cors: { + origin: this.client.config.website.fontendUri, + methods: ["GET", "POST", "PUT", "PATCH", "DELETE"], + credentials: true, + }, + transports: ["polling", "websocket"], + }); + this.client.io = io; + + io.use((socket: any, next: any) => { + const { host } = socket.request.headers; + let checkHost = false; + + for (const x of this.client.links) { + if ( + host === + this.client.parseURL(this.client.ipport(x, this.client.port)).host + ) { + checkHost = true; + break; + } + } + + if (!checkHost) { + return next(new Error("Forbidden")); + } + + next(); + }); + + let versions = await new Promise((resolve) => { + readdir("./src/websocket", (err, files) => { + resolve(files); + }); + }); + + for (const version of versions) { + const websocketFiles = await new Promise((resolve, reject) => { + readdir(`./src/websocket/${version}/`, (err, files) => { + if (err) reject(err); + resolve(files?.filter((f) => f.endsWith(".js")) || []); + }); + }); + + for (const file of websocketFiles) { + try { + const path: WebSocketPath = require( + `../websocket/${version}/${file}`, + ); + if (path.name && typeof path.run === "function") { + this.client.wspaths.set(`/${version}${path.name}`, path); + } else { + console.log(`Invalid module: ${file}`); + } + } catch (error) { + console.error(`Error loading module ${file}:`, error); + } + } + } + + for (const [name, path] of this.client.wspaths) { + const nameSpace = io.of(name); + nameSpace.on("connection", (socket: any) => { + path.run(this.client, socket, socket.request); + }); + } + this.client.logger.log("[ • ] Listening to incoming events"); + } +}; diff --git a/src/handlers/loadroutes.ts b/src/handlers/loadroutes.ts new file mode 100644 index 0000000..ce7c762 --- /dev/null +++ b/src/handlers/loadroutes.ts @@ -0,0 +1,62 @@ +"use strict"; + +import { readdir } from "fs"; + +interface Client { + routes: Map; + logger: any; +} + +interface Route { + version: string; +} + +interface Path { + name: string; + route: any; // Replace 'any' with an appropriate type based on your route structure +} + +export = class RoutesInitializer { + private client: Client; + + constructor(client: Client) { + if (!client) throw new Error(`client is required`); + this.client = client; + } + + public async start() { + let versions = await new Promise((resolve) => { + readdir("./src/routes", (err, files) => { + resolve(files); + }); + }); + + for (const version of versions) { + const dirs = await new Promise((resolve) => { + readdir(`./src/routes/${version}/`, (err, dirs) => { + resolve(dirs); + }); + }); + + for (const dir of dirs) { + const webFiles = await new Promise((resolve) => { + readdir(`./src/routes/${version}/${dir}/`, (err, files) => { + resolve(files?.filter((f) => f.endsWith(".js")) || []); + }); + }); + + for (const file of webFiles) { + const path: Path = require(`../routes/${version}/${dir}/${file}`); + + if (path.name && path.route) { + const route: Route = new path.route(this.client); + route.version = version; + this.client.routes.set(`${path.name}-${route.version}`, route); + } + } + } + } + + this.client.logger.log("[ • ] Website Routes Loaded:"); + } +}; diff --git a/src/handlers/sendSystemStatus.ts b/src/handlers/sendSystemStatus.ts new file mode 100644 index 0000000..88623c2 --- /dev/null +++ b/src/handlers/sendSystemStatus.ts @@ -0,0 +1,29 @@ +"use strict"; + +import updateSystemSpecs from "../utils/getSystemSpecs"; +import { readdir } from "fs"; +import { Client } from "./types"; // Replace './types' with the path to your types file + +export = class SystemInformation { + private client: Client; + + constructor(client: Client) { + if (!client) throw new Error(`client is required`); + this.client = client; + } + + public async start() { + const sendSystemSpecs = async () => { + if (!this.client.wsevents) return; + try { + const specs = await updateSystemSpecs(); + this.client.wsevents.emit("home", { type: "systemInfo", specs }); + } catch (error) { + console.error("Error fetching system specs:", error); + } + }; + + setInterval(sendSystemSpecs, 5000); + this.client.logger.log("[ • ] System information:"); + } +}; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..c40e66b --- /dev/null +++ b/src/index.ts @@ -0,0 +1,118 @@ +"use strict"; + +import App from "./src/structures/App"; +import colors from "colors"; +import os from "os"; +import readline from "readline"; + +const client = new App(); + +process.on("unhandledRejection", (reason: any, p: any) => { + console.log("\n\n\n\n\n=== unhandled Rejection ===".toUpperCase().yellow.dim); + console.log(reason); + console.log("=== unhandled Rejection ===\n\n\n\n\n".toUpperCase().yellow.dim); +}); + +process.on("uncaughtException", (err: Error, origin: string) => { + console.log( + "\n\n\n\n\n\n=== uncaught Exception ===".toUpperCase().yellow.dim, + ); + console.log("Exception: ", err.stack ? err.stack : err); + console.log("=== uncaught Exception ===\n\n\n\n\n".toUpperCase().yellow.dim); +}); + +process.on("uncaughtExceptionMonitor", (err: Error, origin: string) => { + console.log("=== uncaught Exception Monitor ===".toUpperCase().yellow.dim); +}); + +process.on("beforeExit", (code: number) => { + console.log("\n\n\n\n\n=== before Exit ===".toUpperCase().yellow.dim); + console.log("Code: ", code); + console.log("=== before Exit ===\n\n\n\n\n".toUpperCase().yellow.dim); +}); + +process.on("exit", (code: number) => { + console.log("\n\n\n\n\n=== exit ===".toUpperCase().yellow.dim); + console.log("Code: ", code); + console.log("=== exit ===\n\n\n\n\n".toUpperCase().yellow.dim); +}); + +process.on( + "multipleResolves", + (type: string, promise: Promise, reason: any) => { + // Do something for multipleResolves event + }, +); + +function getIPv4Addresses(): string | undefined { + const networkInterfaces = os.networkInterfaces(); + let ipv4Address: string | undefined; + + Object.keys(networkInterfaces).forEach((interfaceName) => { + const interfaceInfo = networkInterfaces[interfaceName]; + + interfaceInfo.forEach((info) => { + if (info.family === "IPv4" && info.internal === false) { + ipv4Address = info.address; + } + }); + }); + + return ipv4Address; +} + +const ipv4Address = `http://${getIPv4Addresses()}`; +const ips = [...client.config.website.links, ipv4Address, "All"]; + +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, +}); + +new Promise((resolve) => { + if (client.config.loadDefaultIps) return resolve(); + + console.log(colors.yellow.bold(`What is Your Ip: \n`)); + ips.forEach((value, i) => { + console.log( + colors.yellow.bold( + `${i + 1}.${ + value === "All" + ? `${value}` + : `${value}:${client.config.website.port}` + }`, + ), + ); + }); + console.log(colors.yellow.bold(`Or just press enter to go with env ips \n`)); + + rl.question(`Type The Number [?]: `, (userRes: string) => { + const selectedOption = parseInt(userRes, 10); + + if ( + !isNaN(selectedOption) && + selectedOption >= 1 && + selectedOption <= ips.length + ) { + const ip = ips[selectedOption - 1]; + if (ip !== "All") { + client.config.website.links = [ip]; + } else { + ips.splice(ips.indexOf("All"), 1); + client.config.website.links = ips; + } + } + + const allips = client.config.website.links.map((val) => { + return (val = `${val}:${client.config.website.port}`); + }); + + console.log(colors.yellow.bold(`Your Ips Are ${allips.join(` , `)}\n`)); + rl.close(); + resolve(); + }); +}).then(() => { + client.connect(); +}); + +export = client; diff --git a/src/routes/v1/broadcast/delete.js b/src/routes/v1/broadcast/delete.js new file mode 100644 index 0000000..e69de29 diff --git a/src/routes/v1/broadcast/get.js b/src/routes/v1/broadcast/get.js new file mode 100644 index 0000000..84aedb6 --- /dev/null +++ b/src/routes/v1/broadcast/get.js @@ -0,0 +1,58 @@ +class route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + const broadcastMessage = require("../../../schema/broadcastMessage"); + + // POST Request - Edit Role + router.get("/broadcast/:type", async (req, res) => { + const notFoundError = function (message, code) { + return res.status(code).json({ error: true, message }); + }; + + const type = req.params.type; + if (type === "public") { + try { + const publicMessages = await broadcastMessage.find({ + type: "public", + }); + res.status(200).json({ message: "Ok", messages: publicMessages }); + } catch (error) { + res + .status(500) + .json({ error: true, message: "Internal Server Error" }); + } + } else if (type === "private") { + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + try { + const tokenUserData = await client.findUser(token, req.secret); + if (!token) { + return notFoundError("Token is required", 401); + } + if (!tokenUserData) { + return notFoundError("You are not logged into the system", 400); + } + if ( + ["staff", "admin", "owner"].includes(tokenUserData.roles.roleType) + ) { + const Messages = await broadcastMessage.find({}); // Fetch all messages + res.status(200).json({ message: "Ok", messages: Messages }); + } else { + res.status(403).json({ + error: true, + message: "You don't have permission for this action", + }); + } + } catch (error) { + res + .status(500) + .json({ error: true, message: "Internal Server Error" }); + } + } + }); + + return router; + } +} +module.exports = { route: route, name: "broadcast-get" }; diff --git a/src/routes/v1/dashboard/delete.js b/src/routes/v1/dashboard/delete.js new file mode 100644 index 0000000..9862ae9 --- /dev/null +++ b/src/routes/v1/dashboard/delete.js @@ -0,0 +1,42 @@ +"use strict"; +const express = require("express"); +const router = express.Router(); +const dashboardDataDb = require("../../../schema/dashboard"); + +class route { + constructor(client) { + /**Event creatian */ + router.delete("/dashboard/:dashboardType", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + const { dashboardType } = req.params; + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError(`You are not logged to the system`, 400); + } + if (tokenUserData.roles.roleType !== dashboardType) { + return notFoundError( + "You dont have permissions to get this permissions", + 400, + ); + } + + const dashboardSchema = await dashboardDataDb.deleteOne({ + type: dashboardType, + }); + + return res.status(200).json({ message: "ok" }); + }); + + return router; + } +} +module.exports = { route: route, name: "dashboard-delete" }; diff --git a/src/routes/v1/dashboard/get.js b/src/routes/v1/dashboard/get.js new file mode 100644 index 0000000..9796c9d --- /dev/null +++ b/src/routes/v1/dashboard/get.js @@ -0,0 +1,65 @@ +"use strict"; +const express = require("express"); +const router = express.Router(); +const dashboardDataDb = require("../../../schema/dashboard"); + +class route { + constructor(client) { + /**Event creatian */ + router.get("/dashboard/:dashboardType", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + const { dashboardType } = req.params; + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + if (!tokenUserData) { + return notFoundError(`You are not logged to the system`, 400); + } + if (dashboardType === "all") { + if ( + !( + tokenUserData.roles.roleType === "admin" || + tokenUserData.roles.roleType === "owner" + ) + ) { + return notFoundError( + "You dont have permissions to get this permissions", + 400, + ); + } + + const dashboardSchema = await dashboardDataDb.find(); + + if (!dashboardSchema) { + return notFoundError(`data for current role type not found`, 404); + } + + return res.status(200).json({ message: "ok", data: dashboardSchema }); + } + if (tokenUserData.roles.roleType !== dashboardType) { + return notFoundError( + "You dont have permissions to get this permissions", + 400, + ); + } + + const dashboardSchema = await dashboardDataDb.findOne({ + type: dashboardType, + }); + + if (!dashboardSchema) { + return notFoundError(`data for current role type not found`, 404); + } + + return res.status(200).json({ message: "ok", data: dashboardSchema }); + }); + + return router; + } +} +module.exports = { route: route, name: "dashboard-get" }; diff --git a/src/routes/v1/dashboard/patch.js b/src/routes/v1/dashboard/patch.js new file mode 100644 index 0000000..a7fd005 --- /dev/null +++ b/src/routes/v1/dashboard/patch.js @@ -0,0 +1,67 @@ +"use strict"; +const express = require("express"); +const router = express.Router(); +const DashboardData = require("../../../schema/dashboard"); + +class Route { + constructor(client) { + router.patch("/dashboard/:dashboardType", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + const { dashboardData = [] } = req.body; + const { dashboardType } = req.params; + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError(`You are not logged in to the system`, 400); + } + + if ( + tokenUserData.roles.roleType !== "owner" && + tokenUserData.roles.roleType !== "admin" + ) { + return notFoundError( + "You don't have permissions to execute this command", + 400, + ); + } + + if (!dashboardData || !dashboardData.length) { + return notFoundError("You haven't entered data for navigations", 400); + } + + const existingDashboard = await DashboardData.findOne({ + type: dashboardType, + }); + + if (!existingDashboard) { + return notFoundError( + `Dashboard type '${dashboardType}' not found`, + 404, + ); + } + + // Assuming the update format is similar to the creation format + // Validate and update the received data to the existing dashboard + existingDashboard.navigationLinks = dashboardData; + + // Save the updated dashboard to the database + await existingDashboard.save(); + + return res + .status(200) + .json({ message: "Dashboard data updated successfully" }); + }); + + return router; + } +} + +module.exports = { route: Route, name: "dashboard-patch" }; diff --git a/src/routes/v1/dashboard/put.js b/src/routes/v1/dashboard/put.js new file mode 100644 index 0000000..eae4034 --- /dev/null +++ b/src/routes/v1/dashboard/put.js @@ -0,0 +1,91 @@ +"use strict"; +const express = require("express"); +const router = express.Router(); +const dashboardDataDb = require("../../../schema/dashboard"); + +class route { + constructor(client) { + /**Event creatian */ + router.put("/dashboard/:dashboardType", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + const { dashboardData } = req.body; + const { dashboardType } = req.params; + const authHeader = req.headers["authorization"]; + + const token = authHeader && authHeader.split(" ")[1]; + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError(`You are not logged to the system`, 400); + } + if ( + !( + tokenUserData.roles.roleType === "owner" || + tokenUserData.roles.roleType === "admin" + ) + ) { + return notFoundError( + "You dont have permissions to execute this command", + 400, + ); + } + // const { staff, admin, owner } = updatedData; + if (!dashboardData || !dashboardData.length) { + return notFoundError("You dont have enter data for navigations", 400); + } + for (const navigationLinkS of dashboardData) { + if (!navigationLinkS.title) + return notFoundError("title is required", 400, navigationLinkS); + if (!navigationLinkS.icon) + return notFoundError("icon is required", 400, navigationLinkS); + if (!navigationLinkS.path) + return notFoundError("icon is required", 400, navigationLinkS); + if (!navigationLinkS.url) + return notFoundError("icon is required", 400, navigationLinkS); + if (navigationLinkS.subMenu) { + for (const subMenuLinks of navigationLinkS.subMenu) { + if (!subMenuLinks.title) + return notFoundError( + "submenu title is required", + 400, + navigationLinkS, + ); + if (!subMenuLinks.icon) + return notFoundError( + "submenu icon is required", + 400, + navigationLinkS, + ); + // if (!subMenuLinks.path) + // return notFoundError( + // "submenu path is required", + // 400, + // navigationLinkS + // ); + if (!subMenuLinks.url) + return notFoundError( + "submenu url is required", + 400, + navigationLinkS, + ); + } + } + } + + const dashboardSchema = new dashboardDataDb({ + type: dashboardType, + navigationLinks: dashboardData, + }); + + await dashboardSchema.save(); + return res.status(200).json({ message: "ok" }); + }); + + return router; + } +} +module.exports = { route: route, name: "dashboard-put" }; diff --git a/src/routes/v1/events/delete.js b/src/routes/v1/events/delete.js new file mode 100644 index 0000000..f855dd9 --- /dev/null +++ b/src/routes/v1/events/delete.js @@ -0,0 +1,52 @@ +"use strict"; + +class route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + const userDataDb = require("../../../schema/userData.js"); + const eventDataDB = require("../../../schema/eventData.js"); + + /**Event Delete */ + router.delete("/events/:eventId", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + const { eventId } = req.params; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError(`You are not logged to the system`, 400); + } + if ( + !( + tokenUserData.roles.roleType === "owner" || + tokenUserData.roles.roleType === "admin" + ) + ) { + return notFoundError( + "You dont have permissions to execute this command", + 400, + ); + } + console.log(eventId); + const eventSchema = await eventDataDB + .findOneAndDelete({ _id: eventId }) + .catch((err) => { + console.log(err); + }); + if (!eventSchema) { + return notFoundError("Event Not found", 404); + } + return res.status(200).json({ message: "ok" }); + }); + + return router; + } +} +module.exports = { route: route, name: "events-delete" }; diff --git a/src/routes/v1/events/get.js b/src/routes/v1/events/get.js new file mode 100644 index 0000000..6134546 --- /dev/null +++ b/src/routes/v1/events/get.js @@ -0,0 +1,159 @@ +"use strict"; + +const CircularJSON = require("circular-json"); +const eventTypesDb = require("../../../schema/eventTypes.js"); + +class route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + const filterData = require("../../../utils/filterData.js"); + const userDataDb = require("../../../schema/userData.js"); + const eventData = require("../../../schema/eventData.js"); + const { Types } = require("mongoose"); + + router.get("/events/public", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + const events = CircularJSON.parse( + CircularJSON.stringify((await eventData.find().catch(() => {})) || {}), + ); + for (const event of events) { + const eventType = await eventTypesDb + .findOne({ _id: event.type }) + .catch(() => {}); + if (!eventType) continue; + event.type = { name: eventType.name, _id: eventType._id }; + } + if (!events) { + return notFoundError("Cannot find the events", 400); + } + return res.status(200).json({ message: "ok", events }); + }); + + /**Getting All the events */ + router.get("/events", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError(`You are not logged to the system`, 400); + } + + const events = CircularJSON.parse( + CircularJSON.stringify((await eventData.find().catch(() => {})) || {}), + ); + + if (!events) { + return notFoundError("Cannot find the events", 400); + } + return res.status(200).json({ message: "ok", events }); + }); + + router.get("/event/:eventId", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + const { eventId } = req.params; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError(`You are not logged to the system`, 400); + } + const event = CircularJSON.parse( + CircularJSON.stringify( + (await eventData.findOne({ _id: eventId }).catch(() => {})) || {}, + ), + ); + + if (!Object.keys(event).length) { + return notFoundError("Cannot find the event", 400); + } + const eventType = await eventTypesDb.findOne({ _id: event.type }); + event.type = { name: eventType.name }; + + return res.status(200).json({ message: "ok", event }); + }); + + router.get("/events/submitted", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError(`You are not logged to the system`, 400); + } + + if (tokenUserData.roles.roleType !== "owner") { + return notFoundError("You don't have permissions to access this", 400); + } + + const events = CircularJSON.parse( + CircularJSON.stringify( + (await eventData.find({ state: "pending" }).catch(() => {})) || {}, + ), + ); + + if (!events) { + return notFoundError("Cannot find the events", 400); + } + + return res.status(200).json({ message: "ok", events }); + }); + router.get("/events/approved", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError(`You are not logged to the system`, 400); + } + + if (tokenUserData.roles.roleType !== "owner") { + return notFoundError("You don't have permissions to access this", 400); + } + + const events = CircularJSON.parse( + CircularJSON.stringify( + (await eventData.find({ state: "approved" }).catch(() => {})) || {}, + ), + ); + if (!events) { + return notFoundError("Cannot find the events", 400); + } + return res.status(200).json({ message: "ok", events }); + }); + + return router; + } +} +module.exports = { route: route, name: "events-get" }; diff --git a/src/routes/v1/events/patch.js b/src/routes/v1/events/patch.js new file mode 100644 index 0000000..c05fbd1 --- /dev/null +++ b/src/routes/v1/events/patch.js @@ -0,0 +1,104 @@ +"use strict"; + +const CircularJSON = require("circular-json"); +const eventTypesDb = require("../../../schema/eventTypes.js"); + +class route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + const userDataDb = require("../../../schema/userData.js"); + const eventDataDb = require("../../../schema/eventData.js"); + /**Editing a event */ + router.patch("/events/:eventId", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + const { updatedData = {} } = req.body; + console.log(updatedData); + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + + const { eventId } = req.params; + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError(`You are not logged to the system`, 400); + } + if ( + !( + tokenUserData.roles.roleType === "owner" || + tokenUserData.roles.roleType === "admin" + ) + ) { + return notFoundError( + "You dont have permissions to execute this command", + 400, + ); + } + console.log(eventId); + const eventSchema = await eventDataDb.findOne({ _id: eventId }); + if (!eventSchema) { + return notFoundError("Cannot find the event", 400); + } + + const { name, description, places, types, inputType } = updatedData; + console.log(updatedData); + if (name) { + eventSchema.name = name; + } + if (description) { + eventSchema.description = description; + } + if (inputType) { + eventSchema.inputType = inputType; + } + if (places) { + const placesData = []; + for (const placeData of places) { + const tmpPlace = {}; + const { place, minimumMarks, _id } = placeData; + if (!place) return notFoundError("Place number Invaild"); + if (!minimumMarks) return notFoundError("Place minimumMarks Invaild"); + tmpPlace.place = place; + tmpPlace.minimumMarks = minimumMarks; + placesData.push(tmpPlace); + } + eventSchema.places = placesData; + } + if (types && types.length) { + const tmpTypes = []; + for (const type of types) { + const { _id, option } = type; + + const typeSchema = await eventTypesDb + .findOne({ _id }) + .catch(() => {}); + if (!typeSchema) return notFoundError("Type not found", 404); + + const selectedOption = typeSchema.options.find( + (opt) => opt._id.toString() === option, + ); + + if (selectedOption) { + tmpTypes.push({ + _id: _id, + option: selectedOption._id, // Assuming option here refers to option._id + selection: selectedOption.option, + }); + } + } + eventSchema.types = tmpTypes; + } + + await eventSchema.save(); + + return res.status(200).json({ message: "ok", eventSchema: eventSchema }); + }); + + return router; + } +} +module.exports = { route: route, name: "events-patch" }; diff --git a/src/routes/v1/events/post.js b/src/routes/v1/events/post.js new file mode 100644 index 0000000..405bae9 --- /dev/null +++ b/src/routes/v1/events/post.js @@ -0,0 +1,393 @@ +"use strict"; +const express = require("express"); +const router = express.Router(); +const userDataDb = require("../../../schema/userData.js"); +const eventDatadb = require("../../../schema/eventData.js"); +const memberDatadb = require("../../../schema/members.js"); +const houseDatadb = require("../../../schema/houses.js"); +const eventTypesDb = require("../../../schema/eventTypes.js"); +const CircularJSON = require("circular-json"); + +class route { + constructor(client) { + router.post("/event/:eventID", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + try { + const { submitdata = {} } = req.body; + const { eventID } = req.params; + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + + const tokenUserData = await client.findUser(token, req.secret); + if (!tokenUserData) { + return notFoundError("You are not logged into the system", 400); + } + + const { places } = submitdata; + console.log(places); + const errors = []; + for (const place of places) { + if (!place.place || !place.inputID || !place.inputType) { + return notFoundError( + "Place, InputType and inputID are required", + 400, + ); + } + } + + if (tokenUserData.roles.roleType !== "staff") { + return notFoundError( + "You don't have permissions to execute this command", + 400, + ); + } + + const eventSchema = await eventDatadb.findOne({ _id: eventID }); + if (!eventSchema) { + return notFoundError("Event not found", 400); + } + if (eventSchema.state === "pending") { + return notFoundError("Event Already submitted", 400); + } + if (eventSchema.state === "approved") { + return notFoundError("Event Already submitted and Approved", 400); + } + const submitedEvent = { + _id: eventSchema._id, + name: eventSchema.name, + description: eventSchema.description, + places: [], + inputType: eventSchema.inputType, + }; + + for (const place of places) { + if (!place.place || !place.inputID) { + errors.push({ + error: true, + message: "Place and inputID are required", + place: place.place, + }); + continue; + } + + const eventSchemaPlace = eventSchema.places.find( + (p) => p.place === place.place, + ); + if (!eventSchemaPlace) { + errors.push({ + error: true, + message: "Place not found in the event", + place: place.place, + }); + continue; + } + if (eventSchema.inputType === "MemberID") { + const memberDataSchema = await memberDatadb.findOne({ + MemberID: place.inputID, + }); + if (!memberDataSchema) { + errors.push({ + error: true, + message: "Member data not found for the submission", + place: place.place, + }); + continue; + } + + const houseDataSchema = await houseDatadb.findOne({ + _id: memberDataSchema.House, + }); + if (!houseDataSchema) { + errors.push({ + error: true, + message: "House data not found for the submission", + place: place.place, + }); + continue; + } + eventSchemaPlace.inputID = place.inputID; + eventSchemaPlace.name = memberDataSchema.Name; + eventSchemaPlace.house = houseDataSchema.Name; + } else if (eventSchema.inputType === "HouseName") { + const houseDataSchema = await houseDatadb.findOne({ + _id: place.inputID, + }); + if (!houseDataSchema) { + errors.push({ + error: true, + message: "House data not found for the submission", + place: place.place, + }); + continue; + } + eventSchemaPlace.inputID = place.inputID; + eventSchemaPlace.name = houseDataSchema.Name; + eventSchemaPlace.house = houseDataSchema.Name; + } + + submitedEvent.places.push(eventSchemaPlace); + } + + if (errors.length > 0) { + return notFoundError("Error occured", 200, errors); + } + + eventSchema.places = submitedEvent.places; + eventSchema.state = "pending"; + await eventSchema.save(); + const circularedeventSchema = CircularJSON.parse( + CircularJSON.stringify(eventSchema), + ); + console.log(circularedeventSchema); + client.wsevents.emit("home", { + type: "eventSubmits", + payload: circularedeventSchema, + }); + + return res.status(200).json({ message: "ok", submitedEvent }); + } catch (error) { + console.error(error); + return res + .status(500) + .json({ error: true, message: "Internal Server Error" }); + } + }); + + router.post("/event/approve/:eventID", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + const { token } = req.body; + console.log(token); + + try { + const { eventID } = req.params; + const tokenUserData = await client.findUser(token, req.secret); + if (!tokenUserData) { + return notFoundError("You are not logged into the system", 400); + } + + if (tokenUserData.roles.roleType !== "owner") { + return notFoundError( + "You don't have permissions to execute this command", + 400, + ); + } + + const eventSchema = await eventDatadb.findOne({ _id: eventID }); + if (!eventSchema) { + return notFoundError("Event not found", 400); + } + + eventSchema.state = "approved"; + + if (eventSchema.inputType === "MemberID") { + for (const place of eventSchema.places) { + const houseDataSchema = await houseDatadb.findOne({ + Name: place.house, + }); + houseDataSchema.houseScore += place.minimumMarks; + + const eventDataIndex = houseDataSchema.eventData.findIndex( + (data) => data.eventId === eventSchema._id.toString(), + ); + + if (eventDataIndex === -1) { + // If eventData for this eventId doesn't exist, create a new entry + const eventData = { + eventId: eventSchema._id.toString(), + participants: [ + { + userAdmissionId: place.inputID, + userName: place.name, + marks: place.minimumMarks, + place: place.place, + }, + ], + }; + houseDataSchema.eventData.push(eventData); + } else { + // If eventData for this eventId exists, add participant details + houseDataSchema.eventData[eventDataIndex].participants.push({ + userAdmissionId: place.inputID, + userName: place.name, + marks: place.minimumMarks, + place: place.place, + }); + } + + await houseDataSchema.save(); + } + } else if (eventSchema.inputType === "HouseName") { + for (const place of eventSchema.places) { + const houseDataSchema = await houseDatadb.findOne({ + _id: place.inputID, + }); + // Add the scores + houseDataSchema.houseScore += place.minimumMarks; + + const eventDataIndex = houseDataSchema.eventData.findIndex( + (data) => data.eventId === eventSchema._id.toString(), + ); + + if (eventDataIndex === -1) { + // If eventData for this eventId doesn't exist, create a new entry + const eventData = { + eventId: eventSchema._id.toString(), + }; + houseDataSchema.eventData.push(eventData); + } + await houseDataSchema.save(); + } + } + + await eventSchema.save(); + const circularedeventSchema = CircularJSON.parse( + CircularJSON.stringify(eventSchema), + ); + const AllHouseData = await houseDatadb.find(); + + client.wsevents.emit("home", { + type: "eventApproves", + payload: { type: "approved", event: circularedeventSchema }, + }); + const wsSendHouseData = []; + for (const house of AllHouseData) { + const houseData = { + _id: house._id, + houseScore: house.houseScore, + }; + wsSendHouseData.push(houseData); + } + console.log(wsSendHouseData); + + const scoreBoard = { + eventType: eventSchema.types.map((type) => ({ option: type.option })), + eventName: eventSchema.name, + inputType: eventSchema.inputType, + places: eventSchema.places.map((place) => ({ + house: place.house, + place: place.place, + score: place.minimumMarks, + member: place.name, + MemberID: place.inputID, + })), + }; + + client.wsevents.emit("public", { + type: "houseScoreUpdate", + payload: { wsSendHouseData }, + }); + + client.wsevents.emit("public", { + type: "eventUpdate", + payload: { scoreBoard }, + }); + + return res.status(200).json({ message: "ok" }); + } catch (error) { + console.error(error); + return res + .status(500) + .json({ error: true, message: "Internal Server Error" }); + } + }); + + router.post("/event/reject/:eventID", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + const { token } = req.body; + console.log(token); + + try { + const { eventID } = req.params; + + const tokenUserData = await client.findUser(token, req.secret); + if (!tokenUserData) { + return notFoundError("You are not logged into the system", 400); + } + + if (tokenUserData.roles.roleType !== "owner") { + return res.status(400).json({ + error: true, + message: "You don't have permissions to execute this command", + }); + } + + const eventSchema = await eventDatadb.findOne({ _id: eventID }); + if (!eventSchema) { + return res.status(404).json({ + error: true, + message: "Event not found", + }); + } + if (eventSchema.state === "approved") { + return notFoundError("Event Alread Approved", 400); + } + const submitedEvent = { + _id: eventSchema._id, + name: eventSchema.name, + description: eventSchema.description, + places: [], + }; + const errors = []; + for (const place of eventSchema.places) { + if (!place.place || !place.inputID) { + errors.push({ + error: true, + message: "Place and inputID are required", + place: place.place, + }); + continue; + } + + const eventSchemaPlace = eventSchema.places.find( + (p) => p.place === place.place, + ); + if (!eventSchemaPlace) { + errors.push({ + error: true, + message: "Place not found in the event", + place: place.place, + }); + continue; + } + + eventSchemaPlace.inputID = ""; + eventSchemaPlace.name = ""; + eventSchemaPlace.house = ""; + submitedEvent.places.push(eventSchemaPlace); + } + + if (errors.length > 0) { + return notFoundError("Error occured", 200, errors); + } + + eventSchema.places = submitedEvent.places; + eventSchema.state = "notSubmitted"; + await eventSchema.save(); + + client.wsevents.emit("home", { + type: "eventApproves", + payload: { type: "reject", event: eventSchema._id }, + }); + + return res.status(200).json({ message: "ok", event: eventSchema._id }); + } catch (error) { + console.error(error); + return res + .status(500) + .json({ error: true, message: "Internal Server Error" }); + } + }); + + return router; + } +} + +module.exports = { route: route, name: "events-post" }; diff --git a/src/routes/v1/events/put.js b/src/routes/v1/events/put.js new file mode 100644 index 0000000..93aa908 --- /dev/null +++ b/src/routes/v1/events/put.js @@ -0,0 +1,96 @@ +"use strict"; +const express = require("express"); +const router = express.Router(); +const userDataDb = require("../../../schema/userData.js"); +const eventDatadb = require("../../../schema/eventData.js"); +const eventTypesDb = require("../../../schema/eventTypes.js"); + +class route { + constructor(client) { + router.put("/events", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + const { eventData } = req.body; + console.log(eventData); + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + + const tokenUserData = await client.findUser(token, req.secret); + + if (!tokenUserData) { + return notFoundError(`You are not logged into the system`, 400); + } + + const { name, description, places, types, inputType } = eventData; + if (!name) return notFoundError("Name is required", 404); + if (!places || !places.length) + return notFoundError("Places are required", 404); + if (!types || !types.length) + return notFoundError("Types are required", 404); + if (!inputType) { + return notFoundError("Input Type is reaqured!", 400); + } + const tmpTypes = []; + for (const type of types) { + if (!type._id) { + return notFoundError("Type ID is required", 404); + } + const typeSchema = await eventTypesDb + .findOne({ _id: type._id }) + .catch(() => {}); + if (!typeSchema) return notFoundError("Type not found", 404); + + const selectedOption = typeSchema.options.find( + (option) => option._id.toString() === type.option, + ); + + if (selectedOption) { + tmpTypes.push({ + _id: type._id, + option: type.option, + selection: selectedOption.option, + }); + } + } + const tmpPlaces = []; + for (const place of places) { + if (!place.place || !place.minimumMarks) { + return notFoundError("Places and Minimum Marks are required", 404); + } + tmpPlaces.push({ + place: place.place, + minimumMarks: place.minimumMarks, + }); + } + + if ( + !( + tokenUserData.roles.roleType === "owner" || + tokenUserData.roles.roleType === "admin" + ) + ) { + return notFoundError( + "You don't have permissions to execute this command", + 400, + ); + } + + const eventSchema = new eventDatadb({ + name, + description, + places: tmpPlaces, + types: tmpTypes, + inputType, + }); + + await eventSchema.save(); + + return res.status(200).json({ message: "ok", eventSchema }); + }); + + return router; + } +} + +module.exports = { route: route, name: "events-put" }; diff --git a/src/routes/v1/houses/delete.js b/src/routes/v1/houses/delete.js new file mode 100644 index 0000000..5e6221e --- /dev/null +++ b/src/routes/v1/houses/delete.js @@ -0,0 +1,58 @@ +"use strict"; + +class route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + const HouseData = require("../../../schema/houses"); + + router.delete("/house/:houseId", async (req, res) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + const { houseId } = req.params; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + + if (!token) { + return notFoundError(`You are not logged into the system`, 400); + } + + if (!houseId) { + return notFoundError(`House ID not found`, 400); + } + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError("You are not logged into the system", 400); + } + if ( + !( + tokenUserData.roles.roleType === "owner" || + tokenUserData.roles.roleType === "admin" + ) + ) { + return notFoundError( + "You dont have permissions to execute this command", + 400, + ); + } + const HouseSchema = await HouseData.findOneAndRemove({ + _id: houseId, + }).catch(() => {}); + + if (!HouseSchema) { + return notFoundError("Cannot find the House", 400); + } + + return res.status(200).json({ message: "ok" }); + }); + + return router; + } +} +module.exports = { route: route, name: "house-delete" }; diff --git a/src/routes/v1/houses/get.js b/src/routes/v1/houses/get.js new file mode 100644 index 0000000..8ec4c67 --- /dev/null +++ b/src/routes/v1/houses/get.js @@ -0,0 +1,22 @@ +"use strict"; + +class route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + const HouseData = require("../../../schema/houses"); + + router.get("/houses", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + // No Auth becuase no sensitive data... + const houseDataAll = await HouseData.find(); + + return res.status(200).json({ message: "ok", HouseData: houseDataAll }); + }); + + return router; + } +} +module.exports = { route: route, name: "house-get" }; diff --git a/src/routes/v1/houses/patch.js b/src/routes/v1/houses/patch.js new file mode 100644 index 0000000..c88dfdd --- /dev/null +++ b/src/routes/v1/houses/patch.js @@ -0,0 +1,76 @@ +"use strict"; + +class route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + const HouseData = require("../../../schema/houses"); + + router.patch("/house/:houseID", async (req, res) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + const { houseID } = req.params; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + + if (!token) { + return notFoundError(`You are already logged into the system`, 400); + } + + if (!houseID) { + return notFoundError(`House ID not found`, 400); + } + + const { updatedHouseData = {} } = req.body; + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError("You are not logged into the system", 400); + } + + if ( + !( + tokenUserData.roles.roleType === "owner" || + tokenUserData.roles.roleType === "admin" + ) + ) { + return notFoundError( + "You dont have permissions to execute this command", + 400, + ); + } + const HouseSchema = await HouseData.findOne({ _id: houseID }).catch( + (err) => { + console.log(err); + }, + ); + + if (!HouseSchema) { + return notFoundError("Cannot find the House", 400); + } + if (!updatedHouseData) { + return notFoundError("Enter any House Data for Update", 400); + } + const { Name, description } = updatedHouseData; + + let editingHouse = HouseSchema; + if (Name) { + editingHouse.Name = Name; + } + if (description) { + editingHouse.description = description; + } + await editingHouse.save(); + + return res.status(200).json({ message: "ok" }); + }); + + return router; + } +} +module.exports = { route: route, name: "house-patch" }; diff --git a/src/routes/v1/houses/post.js b/src/routes/v1/houses/post.js new file mode 100644 index 0000000..41d7365 --- /dev/null +++ b/src/routes/v1/houses/post.js @@ -0,0 +1,78 @@ +"use strict"; + +class route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + const HouseData = require("../../../schema/houses"); + + router.post("/house/:houseID", async (req, res) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + const { houseID } = req.params; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + + if (!token) { + return notFoundError(`You are not logged into the system`, 400); + } + + if (!houseID) { + return notFoundError(`House ID not found`, 400); + } + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError("You are not logged into the system", 400); + } + + if (!(tokenUserData.roles.roleType === "owner")) { + return notFoundError( + "You dont have permissions to execute this command", + 400, + ); + } + const HouseSchema = await HouseData.findOne({ _id: houseID }).catch( + (err) => { + console.log(err); + }, + ); + + if (!HouseSchema) { + return notFoundError("Cannot find the House", 400); + } + + HouseSchema.eventData = []; + HouseSchema.houseScore = 0; + + await HouseSchema.save(); + + const AllHouseData = await HouseData.find(); + + const wsSendHouseData = []; + for (const house of AllHouseData) { + const houseData = { + _id: house._id, + houseScore: house.houseScore, + }; + wsSendHouseData.push(houseData); + } + console.log(wsSendHouseData); + + client.wsevents.emit("public", { + type: "houseScoreUpdate", + payload: { wsSendHouseData }, + }); + + return res.status(200).json({ message: "ok", houseData: HouseSchema }); + }); + + return router; + } +} +module.exports = { route: route, name: "house-post" }; diff --git a/src/routes/v1/houses/put.js b/src/routes/v1/houses/put.js new file mode 100644 index 0000000..bd639e4 --- /dev/null +++ b/src/routes/v1/houses/put.js @@ -0,0 +1,89 @@ +"use strict"; + +class route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + const HouseData = require("../../../schema/houses"); + + router.put("/house/add", async (req, res) => { + const notFoundError = function (message, code) { + return res.status(code).json({ error: true, message }); + }; + + try { + const { houseData = {} } = req.body; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + + if (!houseData) { + return notFoundError("Please enter data to create a house", 400); + } + + console.log(houseData); + + if (!token) { + return notFoundError(`You are not logged into the system`, 400); + } + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError(`You are not logged into the system`, 400); + } + + if ( + !( + tokenUserData.roles.roleType === "owner" || + tokenUserData.roles.roleType === "admin" + ) + ) { + return notFoundError( + "You dont have permissions to execute this command", + 400, + ); + } + const { Name, description } = houseData; + + if (!Name) { + return notFoundError(`Name for House is required`, 400); + } + + const HouseSchema = await HouseData.findOne({ Name: Name }).catch( + (err) => { + console.log(err); + }, + ); + + if (HouseSchema) { + return notFoundError(`A House with this Name is already`, 400); + } + + const HouseDataSchema = new HouseData(); + + HouseDataSchema.Name = Name; + + if (description) { + HouseDataSchema.description = description; + } + await HouseDataSchema.save(); + + return res + .status(200) + .json({ message: "ok", houseData: HouseDataSchema }); + } catch (error) { + console.error("Error", error); + return res + .status(500) + .json({ error: true, message: "Internal Server Error" }); + } + }); + + return router; + } +} + +module.exports = { route: route, name: "house-put" }; diff --git a/src/routes/v1/members/delete.js b/src/routes/v1/members/delete.js new file mode 100644 index 0000000..c29fc3c --- /dev/null +++ b/src/routes/v1/members/delete.js @@ -0,0 +1,106 @@ +class Route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + const userDataDb = require("../../../schema/userData.js"); + const memberData = require("../../../schema/members"); + const HouseData = require("../../../schema/houses.js"); + + router.delete("/member/:memId", async (req, res) => { + try { + let { memId } = req.params; + memId = parseInt(memId); // Convert memId to integer + + if (isNaN(memId)) { + return res + .status(400) + .json({ error: true, message: "Invalid Member ID format" }); + } + + if (!memId) { + return res + .status(400) + .json({ error: true, message: "Member ID not found" }); + } + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + + if (!token) { + return res.status(400).json({ + error: true, + message: "You are not logged into the system", + }); + } + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return res.status(400).json({ + error: true, + message: "You are not logged into the system", + }); + } + + if ( + !( + tokenUserData.roles.roleType === "owner" || + tokenUserData.roles.roleType === "admin" + ) + ) { + return res.status(400).json({ + error: true, + message: "You don't have permissions to execute this command", + }); + } + const memberToRemove = await memberData.findOneAndDelete({ + MemberID: memId, + }); + + if (!memberToRemove) { + return res + .status(400) + .json({ error: true, message: "Cannot find the member" }); + } + + const houseContainingMember = await HouseData.findOne({ + _id: memberToRemove.House, + }); + + if (!houseContainingMember) { + return res + .status(400) + .json({ error: true, message: "House Not Found" }); + } + + const houseMemberIndex = houseContainingMember.members.findIndex( + (member) => member.MemberID === memId, + ); + + if (houseMemberIndex === -1) { + return res + .status(404) + .json({ error: true, message: "Member Not found in the house" }); + } + + houseContainingMember.members.splice(houseMemberIndex, 1); + + // Save changes to the house containing the member + await houseContainingMember.save(); + + return res.status(200).json({ message: "ok" }); + } catch (error) { + console.log(error); + return res + .status(500) + .json({ error: true, message: "Internal server error" }); + } + }); + + return router; + } +} + +module.exports = { route: Route, name: "member-delete" }; diff --git a/src/routes/v1/members/get.js b/src/routes/v1/members/get.js new file mode 100644 index 0000000..da0ef0d --- /dev/null +++ b/src/routes/v1/members/get.js @@ -0,0 +1,96 @@ +"use strict"; + +class route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + const memberData = require("../../../schema/members"); + const houseData = require("../../../schema/houses"); + + router.get("/members/public", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + const memebrsDataAll = await memberData.find(); + const membersData = []; + + for (let member of memebrsDataAll) { + const House = await houseData.findOne({ _id: member.House }); + + membersData.push({ + Name: member.Name, + House: House.Name, + Grade: member.Grade, + MemberID: member.MemberID, + }); + } + + // interface MemberData { + // _id: string; + // Name: string; + // House: string; + // Grade: string; + // MemberID: number; + // } + + return res.status(200).json({ message: "ok", membersData }); + }); + + router.get("/members", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError("You are not logged into the system", 400); + } + const memebrsDataAll = await memberData.find(); + const membersData = []; + + for (let member of memebrsDataAll) { + const House = await houseData.findOne({ _id: member.House }); + + membersData.push({ + Name: member.Name, + House: House.Name, + Grade: member.Grade, + MemberID: member.MemberID, + }); + } + return res.status(200).json({ message: "ok", membersData }); + }); + + router.get("/members/:house", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + const { house } = req.params; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError("You are not logged into the system", 400); + } + const memebrsDataHouse = await memberData.find({ _id: house }); + + return res + .status(200) + .json({ message: "ok", membersData: memebrsDataHouse }); + }); + + return router; + } +} +module.exports = { route: route, name: "member-get" }; diff --git a/src/routes/v1/members/patch.js b/src/routes/v1/members/patch.js new file mode 100644 index 0000000..04905a3 --- /dev/null +++ b/src/routes/v1/members/patch.js @@ -0,0 +1,93 @@ +"use strict"; +const express = require("express"); +const router = express.Router(); +const userDataDb = require("../../../schema/userData.js"); +const memberData = require("../../../schema/members"); +const houseData = require("../../../schema/houses"); + +class route { + constructor(client) { + router.patch("/member/:memId", async (req, res) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + const { memId } = req.params; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + + if (!token) { + return notFoundError(`You are already logged into the system`, 400); + } + + if (!memId) { + return notFoundError(`Member ID not found`, 400); + } + + const { updatedMemberData = {} } = req.body; + console.log(updatedMemberData); + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError("You are not logged into the system", 400); + } + + if ( + !( + tokenUserData.roles.roleType === "owner" || + tokenUserData.roles.roleType === "admin" + ) + ) { + return notFoundError( + "You dont have permissions to execute this command", + 400, + ); + } + const meberSchema = await memberData + .findOne({ MemberID: memId }) + .catch(() => {}); + + if (!meberSchema) { + return notFoundError("Cannot find the member", 400); + } + const { Name, House, Grade } = updatedMemberData; + + if (Name) { + meberSchema.Name = Name; + } + if (House) { + // Remove from the current house + const currentHouseSchema = await houseData.findOne({ + _id: meberSchema.House, + }); + if (!currentHouseSchema) { + return notFoundError("Current House Not Found", 404); + } + currentHouseSchema.members.remove({ + MemberID: meberSchema.MemberID, + }); + + meberSchema.House = House; + + // Add to the new house + const newHouseSchema = await houseData.findOne({ Name: House }); + if (!newHouseSchema) { + return notFoundError("Submitted House not found", 404); + } + newHouseSchema.members.push({ MemberID: meberSchema.MemberID }); + } + if (Grade) { + meberSchema.Grade = Grade; + } + + await meberSchema.save(); + + return res.status(200).json({ message: "ok" }); + }); + + return router; + } +} +module.exports = { route: route, name: "member-patch" }; diff --git a/src/routes/v1/members/put.js b/src/routes/v1/members/put.js new file mode 100644 index 0000000..36275c3 --- /dev/null +++ b/src/routes/v1/members/put.js @@ -0,0 +1,161 @@ +"use strict"; +const express = require("express"); +const router = express.Router(); +const memberData = require("../../../schema/members"); +const HouseData = require("../../../schema/houses"); + +class route { + constructor(client) { + router.put("/members/add", async (req, res) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + try { + const { members = [] } = req.body; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + + if (!token) { + return notFoundError(`You are not logged into the system`, 400); + } + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError(`You are not logged into the system`, 400); + } + + if ( + tokenUserData.roles.roleType !== "owner" && + tokenUserData.roles.roleType !== "admin" + ) { + return notFoundError( + "You dont have permissions to execute this command", + 400, + ); + } + + if (!members || !Array.isArray(members) || members.length === 0) { + return notFoundError(`No valid member data provided`, 400); + } + const errors = []; + const membersDummyDataArray = []; + const tempIds = []; + for (const member of members) { + const { Name, House, Grade } = member; + + const MemberID = isNaN(member.MemberID) + ? parseInt(member.MemberID) + : member.MemberID; + + if (isNaN(MemberID)) { + errors.push({ + error: true, + message: `are you high nigga`, + data: MemberID, + }); + continue; + } + const isAlready = tempIds.find((id) => id === MemberID); + if (isAlready) { + errors.push({ + error: true, + message: `MemberID ${MemberID} is already in your submits`, + data: MemberID, + }); + continue; + } + tempIds.push(MemberID); + const houseSchema = await HouseData.findOne({ Name: House }); + + if (!houseSchema) { + errors.push({ + error: true, + message: `House is not found`, + data: MemberID, + }); + continue; + } + + const memberSchema = await memberData + .findOne({ MemberID }) + .catch((err) => { + console.log(err); + }); + + if (memberSchema) { + errors.push({ + error: true, + message: `MemberID ${MemberID} is already in the database`, + data: MemberID, + }); + continue; + } + + const memberDataDummy = {}; + if (!Name || !houseSchema.Name || !Grade || !MemberID) { + errors.push({ + error: true, + message: `All fields (name, house, grade, MemberID) are required`, + data: MemberID, + }); + continue; + } + + memberDataDummy.Name = Name; + memberDataDummy.House = houseSchema._id; + memberDataDummy.Grade = Grade; + memberDataDummy.MemberID = MemberID; + + membersDummyDataArray.push(memberDataDummy); + } + + if (errors.length > 0) { + return notFoundError("Error occurred", 200, errors); + } + + // Save Data If Not Any Errors + const tmpMemberArray = []; + for (const data of membersDummyDataArray) { + const memberDataSchema = new memberData(data); + const houseSchema = await HouseData.findOne({ _id: data.House }); + const houseNameUser = houseSchema.members.find( + (user) => user.MemberID === data.MemberID, + ); + tmpMemberArray.push({ + Name: data.Name, + House: houseSchema.Name, + Grade: data.Grade, + MemberID: data.MemberID, + }); + if (!houseNameUser) { + houseSchema.memberCount += 1; + houseSchema.members.push({ + MemberID: data.MemberID, + }); + } + data._id = memberDataSchema._id; + await memberDataSchema.save(); + await houseSchema.save(); + } + console.log(tmpMemberArray); + return res + .status(200) + .json({ message: "ok", memberData: tmpMemberArray }); + } catch (error) { + console.error("Error", error); + return res + .status(500) + .json({ error: true, message: "Internal Server Error" }); + } + }); + + return router; + } +} + +module.exports = { route: route, name: "member-put" }; diff --git a/src/routes/v1/public/get.js b/src/routes/v1/public/get.js new file mode 100644 index 0000000..df034b8 --- /dev/null +++ b/src/routes/v1/public/get.js @@ -0,0 +1,83 @@ +"use strict"; +const express = require("express"); +const router = express.Router(); +const dashboardDataDb = require("../../../schema/dashboard"); +const membersDataDb = require("../../../schema/members"); +const eventDataDb = require("../../../schema/eventData"); +const userData = require("../../../schema/userData"); +const houseDataDb = require("../../../schema/houses"); +const eventTypesDb = require("../../../schema/eventTypes"); + +class route { + constructor(client) { + router.get("/public/data/:type", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + const { type } = req.params; + const payload = {}; + + switch (type) { + case "info": + try { + // Get counts for members, events, houses, and accounts + const [memberCount, eventCount, housesCount, usersCount] = + await Promise.all([ + membersDataDb.count(), + eventDataDb.count(), + houseDataDb.count(), + userData.count(), + ]); + + // Prepare information object + const info = [ + { id: 1, title: "Total Members", count: memberCount }, + { id: 2, title: "Total Events", count: eventCount }, + { id: 3, title: "Total Houses", count: housesCount }, + { id: 4, title: "Total Accounts", count: usersCount }, + ]; + + payload.info = info; + return res.status(200).json({ message: "ok", payload }); + } catch (error) { + console.error(error); + return notFoundError("Error occurred", 500, error); + } + + case "scoreBoard": + try { + const eventTypes = await eventTypesDb.find(); + const eventDataSchema = await eventDataDb.find(); + const scoreBoard = eventDataSchema + .filter((event) => event.state === "approved") + .map((event) => ({ + eventType: event.types.map((type) => ({ option: type.option })), + eventName: event.name, + inputType: event.inputType, + places: event.places.map((place) => ({ + house: place.house, + place: place.place, + score: place.minimumMarks, + member: place.name, + MemberID: place.inputID, + })), + })); + + return res + .status(200) + .json({ message: "ok", payload: { scoreBoard, eventTypes } }); + } catch (error) { + console.error(error); + return notFoundError("Error occurred", 500, error); + } + + default: + return res.status(200).json({ message: "ok", payload }); + } + }); + + return router; + } +} +module.exports = { route: route, name: "public-get" }; diff --git a/src/routes/v1/roles/delete.js b/src/routes/v1/roles/delete.js new file mode 100644 index 0000000..e69de29 diff --git a/src/routes/v1/roles/get.js b/src/routes/v1/roles/get.js new file mode 100644 index 0000000..aab0ab0 --- /dev/null +++ b/src/routes/v1/roles/get.js @@ -0,0 +1,99 @@ +class route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + const userDataDb = require("../../../schema/userData"); + + // POST Request - Edit Role + router.get("/role", async (req, res) => { + const notFoundError = function (message, code) { + return res.status(code).json({ error: true, message }); + }; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + + if (!token) { + return notFoundError("Token is required", 401); + } + + try { + const tokenUserData = await client.findUser(token, req.secret); + if (!tokenUserData) { + return notFoundError("You are not logged into the system", 400); + } + + const requesterRole = tokenUserData.roles.roleIndex; + + // Query database for users with a lower roleIndex + const lowerRoleUsers = await userDataDb.find({ + "roles.roleIndex": { $gt: requesterRole }, + }); + + // Debug: Log the result + const destrucuredData = lowerRoleUsers.map((object) => ({ + id: object._id, + userName: object.userName, + name: object.name, + role: object.roles.roleType, + })); + + // Respond with the users found + res.status(200).json({ message: "Ok", lowerUsers: destrucuredData }); + } catch (error) { + console.error("Error in GET /role:", error); + res.status(500).json({ error: true, message: "Internal Server Error" }); + } + }); + + router.get("/role/access", async (req, res) => { + const notFoundError = function (message, code) { + return res.status(code).json({ error: true, message }); + }; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + + if (!token) { + return notFoundError("Token is required", 401); + } + + try { + const tokenUserData = await client.findUser(token, req.secret); + if (!tokenUserData) { + return notFoundError("You are not logged into the system", 400); + } + + const requesterRole = tokenUserData.roles.roleIndex; + + // Query database for users with a lower roleIndex + const lowerRoleUsers = await userDataDb.find({ + "roles.roleIndex": { $gt: requesterRole }, + }); + + const lowerRoles = []; + const allRoles = [ + { roleType: "Owner", roleIndex: 1 }, + { roleType: "Admin", roleIndex: 2 }, + { roleType: "Staff", roleIndex: 3 }, + ]; + for (const role of allRoles) { + console.log("role", role); + console.log("requesterRole", requesterRole); + if (role.roleIndex > requesterRole) { + lowerRoles.push(role); + } + } + // Debug: Log the result + // Respond with the users found + res.status(200).json({ message: "Ok", lowerRoles }); + } catch (error) { + console.error("Error in GET /role:", error); + res.status(500).json({ error: true, message: "Internal Server Error" }); + } + }); + + return router; + } +} +module.exports = { route: route, name: "role-get" }; diff --git a/src/routes/v1/roles/patch.js b/src/routes/v1/roles/patch.js new file mode 100644 index 0000000..e69de29 diff --git a/src/routes/v1/roles/post.js b/src/routes/v1/roles/post.js new file mode 100644 index 0000000..a57661e --- /dev/null +++ b/src/routes/v1/roles/post.js @@ -0,0 +1,86 @@ +class route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + const userDataDb = require("../../../schema/userData"); + + router.post("/role", async (req, res) => { + const { + newRole = { + targetUser: undefined, + roleType: undefined, + }, + } = req.body; + + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError("You are not logged into the system", 400); + } + + const roleHierarchy = { + staff: 3, + admin: 2, + owner: 1, + }; + + try { + const userSchema = await userDataDb.findOne({ + _id: newRole.targetUser, + }); + + if (!userSchema) { + return notFoundError( + "Fetching userSchema Error or The User With UserID not Found", + 400, + newRole.targetUser, + ); + } + if (!tokenUserData.roles) { + return notFoundError("Users Not Found in your data", 400); + } + if (!userSchema.roles) { + return notFoundError("Users Not Found in requested data", 400); + } + const requesterRoleIndex = tokenUserData.roles.roleIndex; + const targetRoleIndex = userSchema.roles.roleIndex; + + if ( + requesterRoleIndex >= targetRoleIndex || + requesterRoleIndex >= roleHierarchy[newRole.roleType] + ) { + return notFoundError( + "Insufficient permissions to edit this role.", + 400, + { + "Max Requester Role Index than target userRole": + requesterRoleIndex < targetRoleIndex, + "Max Requester Role Index than target Role": + requesterRoleIndex < roleHierarchy[newRole.roleType], + }, + ); + } + userSchema.roles.roleType = newRole.roleType; + userSchema.roles.roleIndex = roleHierarchy[newRole.roleType]; + + await userSchema.save(); + res.status(200).json({ message: "Role updated successfully" }); + } catch (error) { + console.log(error); + res.status(500).json({ error: error.message }); + } + }); + + return router; + } +} +module.exports = { route: route, name: "role-post" }; diff --git a/src/routes/v1/types/delete.js b/src/routes/v1/types/delete.js new file mode 100644 index 0000000..31b9368 --- /dev/null +++ b/src/routes/v1/types/delete.js @@ -0,0 +1,41 @@ +"use strict"; + +const CircularJSON = require("circular-json"); +const eventTypesDb = require("../../../schema/eventTypes.js"); +const express = require("express"); +const router = express.Router(); +const filterData = require("../../../utils/filterData.js"); +const userDataDb = require("../../../schema/userData.js"); +const eventData = require("../../../schema/eventData.js"); + +class route { + constructor(client) { + router.delete("/event-types/:typeId", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + const { typeId } = req.params; + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError(`You are not logged to the system`, 400); + } + + const eventsTypes = await eventTypesDb.findOne({ _id: typeId }); + + if (!eventsTypes) { + return notFoundError("Cannot find the eventTypes", 400); + } + await eventsTypes.deleteOne(); + return res.status(200).json({ message: "ok", eventsTypes }); + }); + + return router; + } +} +module.exports = { route: route, name: "event-types-delete" }; diff --git a/src/routes/v1/types/get.js b/src/routes/v1/types/get.js new file mode 100644 index 0000000..6258418 --- /dev/null +++ b/src/routes/v1/types/get.js @@ -0,0 +1,66 @@ +"use strict"; + +const CircularJSON = require("circular-json"); +const eventTypesDb = require("../../../schema/eventTypes.js"); +const express = require("express"); +const router = express.Router(); +const filterData = require("../../../utils/filterData.js"); +const userDataDb = require("../../../schema/userData.js"); +const eventData = require("../../../schema/eventData.js"); + +class route { + constructor(client) { + router.get("/event-types", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError(`You are not logged to the system`, 400); + } + + const eventsTypes = await eventTypesDb.find(); + + if (!eventsTypes) { + return notFoundError("Cannot find the eventTypes", 400); + } + + return res.status(200).json({ message: "ok", eventsTypes }); + }); + + router.get("/event-types/:typeId", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + const { typeId } = req.params; + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError(`You are not logged to the system`, 400); + } + + const eventsTypes = await eventTypesDb.findOne({ _id: typeId }); + + if (!eventsTypes) { + return notFoundError("Cannot find the eventTypes", 400); + } + + return res.status(200).json({ message: "ok", eventsTypes }); + }); + + return router; + } +} +module.exports = { route: route, name: "event-types-get" }; diff --git a/src/routes/v1/types/patch.js b/src/routes/v1/types/patch.js new file mode 100644 index 0000000..663e479 --- /dev/null +++ b/src/routes/v1/types/patch.js @@ -0,0 +1,65 @@ +"use strict"; + +const eventTypesDb = require("../../../schema/eventTypes.js"); +const express = require("express"); +const router = express.Router(); +const userDataDb = require("../../../schema/userData.js"); +const eventDataDb = require("../../../schema/eventData.js"); +class route { + constructor(client) { + /**Editing a event */ + router.patch("/event-types/:typeId", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + const { updatedData = {} } = req.body; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + + const { typeId } = req.params; + console.log(typeId); + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError(`You are not logged to the system`, 400); + } + if ( + !( + tokenUserData.roles.roleType === "owner" || + tokenUserData.roles.roleType === "admin" + ) + ) { + return notFoundError( + "You dont have permissions to execute this command", + 400, + ); + } + const typeSchema = await eventTypesDb + .findOne({ _id: typeId }) + .catch(() => {}); + + if (!typeSchema) { + return notFoundError("Cannot find the event", 400); + } + + const { name, options } = updatedData; + + if (name) { + typeSchema.name = name; + } + if (options.length) { + typeSchema.options = options; + } + + await typeSchema.save(); + + return res.status(200).json({ message: "ok", typeSchema }); + }); + + return router; + } +} +module.exports = { route: route, name: "event-types-patch" }; diff --git a/src/routes/v1/types/put.js b/src/routes/v1/types/put.js new file mode 100644 index 0000000..c3fb410 --- /dev/null +++ b/src/routes/v1/types/put.js @@ -0,0 +1,69 @@ +"use strict"; +const express = require("express"); +const router = express.Router(); +const userDataDb = require("../../../schema/userData.js"); +const eventDatadb = require("../../../schema/eventData.js"); +const eventTypesDb = require("../../../schema/eventTypes.js"); + +class route { + constructor(client) { + /**Event creatian */ + + router.put("/event-types", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + const { eventTypes = {} } = req.body; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError(`You are not logged to the system`, 400); + } + console.log(eventTypes); + const { name, options } = eventTypes; + + if (!name) return notFoundError("Name is required", 404); + if (!options.length) + return notFoundError( + "You must be add lease one option for a type", + 400, + ); + if ( + !( + tokenUserData.roles.roleType === "owner" || + tokenUserData.roles.roleType === "admin" + ) + ) { + return notFoundError( + "You dont have permissions to execute this command", + 400, + ); + } + + const optionsDummy = []; + + for (const option of options) { + if (!option || !option.option) { + return notFoundError("Option Not Found", 404); + } + optionsDummy.push({ + option: option.option, + }); + } + + const evenType = new eventTypesDb({ name, options: optionsDummy }); + console.log(evenType); + + await evenType.save(); + return res.status(200).json({ message: "ok", evenType }); + }); + return router; + } +} +module.exports = { route: route, name: "event-types-put" }; diff --git a/src/routes/v1/user/delete.js b/src/routes/v1/user/delete.js new file mode 100644 index 0000000..9386c72 --- /dev/null +++ b/src/routes/v1/user/delete.js @@ -0,0 +1,152 @@ +"use strict"; + +const { truncate } = require("fs/promises"); +const userDataDB = require("../../../schema/userData"); + +class route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + + router.delete("/user/:userId", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + + const { userId } = req.params; + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError("You are not logged into the system", 400); + } + let findingUserData; + if (userId === "@me" || String(tokenUserData._id) === userId) { + findingUserData = await userDataDB.findOne({ _id: userId }); + } else { + findingUserData = await userDataDB.findOne({ _id: userId }); + + if (!findingUserData) { + return notFoundError("Cannot find the user", 400); + } + } + + // Assuming 'delete' is a method you have defined in your schema, you should use 'deleteOne' or 'remove' + await findingUserData.deleteOne(); + + return res.status(200).json({ message: "ok" }); + }); + + // router.delete("/user/:userId/auth", async (req, res, next) => { + // const notFoundError = function (message, code, data) { + // return res.status(code).json({ error: true, message, data }); + // }; + // const { token } = req.body; + // const { userId } = req.params; + // const { tokenId } = req.query; + + // const tokenUserData = await client + // .findUser(token, req.secret) + // .catch(() => {}); + + // if (!tokenUserData) + // return notFoundError("You are not logged into the system", 400); + + // const { userSchema } = await client.users + // .getFetch(tokenUserData._id) + // .catch(() => {}); + + // if (!userSchema) { + // return notFoundError("Cannot find the user", 400); + // } + + // let editingUser; + + // switch (userId === "@me" || String(tokenUserData._id) === userId) { + // case true: { + // const findingUserData = userSchema; + // editingUser = findingUserData; + // break; + // } + // case false: { + // const findingUserData = await + // // const { userSchema: findingUserData } = await client.users + // // .getFetch(tokenUserData._id) + // // .catch(() => {}); + + // if (!findingUserData) { + // return notFoundError("Cannot find the user", 400); + // } + + // editingUser = findingUserData; + + // if (editingUser.owner) { + // return notFoundError( + // "This user is the owner of this platform", + // 400 + // ); + // } + + // if (!userSchema.owner) { + // const editingUserHeighestFlag = await new permissionCalculator() + // .getHighestFlag(editingUser) + // .catch(() => {}); + // const userSchemaHeighestFlag = await new permissionCalculator() + // .getHighestFlag(userSchema) + // .catch(() => {}); + // if ( + // editingUserHeighestFlag.flag.position <= + // userSchemaHeighestFlag.flag.position + // ) { + // return notFoundError( + // "Editing user has a higher flag than you or equal to you", + // 400 + // ); + // } + // } + + // if ( + // !(await new permissionCalculator() + // .hasPermission(userSchema, "MANAGE_USERS") + // .catch(() => {})) + // ) { + // return notFoundError( + // "You dont have permissions to execute this command", + // 400 + // ); + // } + // break; + // } + // } + + // const removingToken = + // editingUser.tokens.find( + // (tokenSchema) => String(tokenSchema._id) === tokenId + // ) || + // editingUser.tokens.find((tokenSchema) => tokenSchema.token === token); + + // editingUser.tokens = editingUser.tokens.filter( + // (tokenSchema) => tokenSchema.token !== removingToken.token + // ); + + // await editingUser.save(); + + // client + // .emitGlobalEvents("checkLogin", { + // token: removingToken.token, + // id: editingUser._id, + // }) + // .catch(() => {}); + + // return res.status(204); + // }); + + return router; + } +} +module.exports = { route: route, name: "user-delete" }; diff --git a/src/routes/v1/user/get.js b/src/routes/v1/user/get.js new file mode 100644 index 0000000..f1486fc --- /dev/null +++ b/src/routes/v1/user/get.js @@ -0,0 +1,54 @@ +"use strict"; + +class route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + const filterData = require("../../../utils/filterData.js"); + const userSchme = require("../../../schema/userData.js"); + + router.get("/user/:userId", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + const { userId } = req.params; + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError("You are not logged into the system", 400); + } + + let userData = {}; + + switch (userId) { + case "@me": { + const findingUserData = tokenUserData; + + userData = await new filterData(client).user("@me", findingUserData); + break; + } + case "@all": { + userData = await userSchme.find({}, { name: 1, _id: 1, roles: 1 }); + break; + } + default: { + userData = await userSchme.findOne( + { _id: userId }, + { name: 1, _id: 1, roles: 1, userName: 1 }, + ); + + break; + } + } + + return res.status(200).json({ message: "ok", userData }); + }); + + return router; + } +} +module.exports = { route: route, name: "user-get" }; diff --git a/src/routes/v1/user/patch.js b/src/routes/v1/user/patch.js new file mode 100644 index 0000000..5c6fe36 --- /dev/null +++ b/src/routes/v1/user/patch.js @@ -0,0 +1,581 @@ +"use strict"; + +class route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + const userDataDb = require("../../../schema/userData.js"); + + router.patch("/user/:userId", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + + const { userId } = req.params; + const { + updatedData = { + userName: undefined, + name: undefined, + role: undefined, + password: undefined, + }, + } = req.body; + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError("You are not logged into the system", 400); + } + const { userName, name, role, password } = updatedData; + + let editingUser; + + switch (userId === "@me" || String(tokenUserData._id) === userId) { + case true: { + editingUser = await userDataDb.findOne({ _id: userId }); + break; + } + case false: { + const findingUserData = await userDataDb.findOne({ _id: userId }); + + if (findingUserData.roles.roleType < tokenUserData.roles.roleType) { + return notFoundError("You Don't Have permissions", 400); + } + + break; + } + } + + if (userName) { + if (await userDataDb.findOne({ userName }).catch(() => {})) { + return notFoundError( + `This userName already exits on the database`, + 400, + ); + } else { + editingUser.userName = userName; + } + } + if (name) { + editingUser.name = name; + } + if (role) { + const roleHierarchy = { + 3: "Staff", + 2: "Admin", + 1: "Owner", + }; + + const newRoles = { + roleType: roleHierarchy[role], + roleIndex: role, + }; + editingUser.roles = newRoles; + } + if (password) { + const salt = await bcrypt.genSalt(10); + const hashedPassword = await bcrypt.hash(password, salt); + editingUser.password = hashedPassword; + } + + await editingUser.save(); + + return res.status(200).json({ message: "ok" }); + }); + + // router.patch("/user/:userId/profile", async (req, res, next) => { + // const notFoundError = function (message, code, data) { + // return res.status(code).json({ error: true, message, data }); + // }; + // const { userId } = req.params; + // const { + // token, + // updatedData = { + // email: undefined, + // userName: undefined, + // phoneNumber: undefined, + // school: undefined, + // name: undefined, + // profilePicture: undefined, + // bio: undefined, + // }, + // } = req.body; + + // const tokenUserData = await client + // .findUser(token, req.secret) + // .catch(() => {}); + + // if (!tokenUserData) { + // return notFoundError("You are not logged into the system", 400); + // } + // const { userSchema } = await client.users + // .getFetch(tokenUserData._id) + // .catch(() => {}); + + // if (!userSchema) { + // return notFoundError("Cannot find the user", 400); + // } + // const { + // email, + // userName, + // phoneNumber, + // school, + // name, + // profilePicture, + // bio, + // } = updatedData; + + // let editingUser; + + // switch (userId === "@me" || String(tokenUserData._id) === userId) { + // case true: { + // const findingUserData = userSchema; + // editingUser = findingUserData; + // break; + // } + // case false: { + // const { userSchema: findingUserData } = await client.users + // .getFetch(tokenUserData._id) + // .catch(() => {}); + + // if (!findingUserData) { + // return notFoundError("Cannot find the user", 400); + // } + + // editingUser = findingUserData; + + // if (editingUser.owner) { + // return notFoundError( + // "This user is the owner of this platform", + // 400 + // ); + // } + + // if (!userSchema.owner) { + // const editingUserHeighestFlag = await new permissionCalculator() + // .getHighestFlag(editingUser) + // .catch(() => {}); + // const userSchemaHeighestFlag = await new permissionCalculator() + // .getHighestFlag(userSchema) + // .catch(() => {}); + // if ( + // editingUserHeighestFlag.flag.position <= + // userSchemaHeighestFlag.flag.position + // ) { + // return notFoundError( + // "Editing user has a higher flag than you or equal to you", + // 400 + // ); + // } + // } + // if ( + // !(await new permissionCalculator() + // .hasPermission(userSchema, "MANAGE_USERS") + // .catch(() => {})) + // ) { + // return notFoundError( + // "You dont have permissions to execute this command", + // 400 + // ); + // } + // break; + // } + // } + + // if (email) { + // if (await userDataDb.findOne({ email }).catch(() => {})) { + // return notFoundError(`This email already exits on the database`, 400); + // } else { + // editingUser.email = email; + // } + // } + // if (userName) { + // if (await userDataDb.findOne({ userName }).catch(() => {})) { + // return notFoundError( + // `This userName already exits on the database`, + // 400 + // ); + // } else { + // editingUser.userName = userName; + // } + // } + // if (phoneNumber) { + // editingUser.phoneNumber = phoneNumber; + // } + + // if (name) { + // editingUser.name = name; + // } + // if (bio) { + // editingUser.bio = bio; + // } + // if (school) { + // editingUser.school = school; + // } + + // await editingUser.save(); + + // client.emitGlobalEvents("userUpdate", { + // id: editingUser._id, + // }); + + // return res.status(200).json({ message: "ok" }); + // }); + + // router.patch("/user/:userId/password", async (req, res, next) => { + // const notFoundError = function (message, code, data) { + // return res.status(code).json({ error: true, message, data }); + // }; + // const { userId } = req.params; + // const { + // token, + // updatedData = { + // oldPassword: undefined, + // newPassword: undefined, + // confirmPassword: undefined, + // }, + // } = req.body; + + // const tokenUserData = await client + // .findUser(token, req.secret) + // .catch(() => {}); + + // if (!tokenUserData) { + // return notFoundError("You are not logged into the system", 400); + // } + // const { userSchema } = await client.users + // .getFetch(tokenUserData._id) + // .catch(() => {}); + + // if (!userSchema) { + // return notFoundError("Cannot find the user", 400); + // } + // const { oldPassword, newPassword, confirmPassword } = updatedData; + + // let editingUser; + + // switch (userId === "@me" || String(tokenUserData._id) === userId) { + // case true: { + // const findingUserData = userSchema; + // editingUser = findingUserData; + // break; + // } + // case false: { + // const { userSchema: findingUserData } = await client.users + // .getFetch(tokenUserData._id) + // .catch(() => {}); + + // if (!findingUserData) { + // return notFoundError("Cannot find the user", 400); + // } + + // editingUser = findingUserData; + + // if (editingUser.owner) { + // return notFoundError( + // "This user is the owner of this platform", + // 400 + // ); + // } + + // if (!userSchema.owner) { + // const editingUserHeighestFlag = await new permissionCalculator() + // .getHighestFlag(editingUser) + // .catch(() => {}); + // const userSchemaHeighestFlag = await new permissionCalculator() + // .getHighestFlag(userSchema) + // .catch(() => {}); + // if ( + // editingUserHeighestFlag.flag.position <= + // userSchemaHeighestFlag.flag.position + // ) { + // return notFoundError( + // "Editing user has a higher flag than you or equal to you", + // 400 + // ); + // } + // } + + // if ( + // !(await new permissionCalculator() + // .hasPermission(userSchema, "MANAGE_USERS") + // .catch(() => {})) + // ) { + // return notFoundError( + // "You dont have permissions to execute this command", + // 400 + // ); + // } + // oldPassword = editingUser.password; + // confirmPassword = newPassword; + // break; + // } + // } + + // if (!oldPassword) { + // return notFoundError(`oldPassword is required`, 400); + // } else if (editingUser.password !== oldPassword) { + // return notFoundError( + // `oldPassword does not match to your current password`, + // 400 + // ); + // } + + // if (!newPassword) { + // return notFoundError(`newPassword is required`, 400); + // } + + // if (!confirmPassword) { + // return notFoundError(`confirmPassword is required`, 400); + // } else if (confirmPassword !== newPassword) { + // return notFoundError( + // `confirmPassword does not match to your newPassword`, + // 400 + // ); + // } + // editingUser.password = newPassword; + // await editingUser.save(); + + // client.emitGlobalEvents("userUpdate", { + // id: editingUser._id, + // internal: true, + // }); + + // return res.status(200).json({ message: "ok" }); + // }); + + // router.patch("/user/:userId/status", async (req, res, next) => { + // const notFoundError = function (message, code, data) { + // return res.status(code).json({ error: true, message, data }); + // }; + // const { userId } = req.params; + // const { token, updatedData = {} } = req.body; + + // const tokenUserData = await client + // .findUser(token, req.secret) + // .catch(() => {}); + + // if (!tokenUserData) { + // return notFoundError("You are not logged into the system", 400); + // } + // const { userSchema } = await client.users + // .getFetch(tokenUserData._id) + // .catch(() => {}); + + // if (!userSchema) { + // return notFoundError("Cannot find the user", 400); + // } + // const { status, statusMessage } = updatedData; + + // let editingUser; + + // switch (userId === "@me" || String(tokenUserData._id) === userId) { + // case true: { + // const findingUserData = userSchema; + // editingUser = findingUserData; + // break; + // } + // case false: { + // const { userSchema: findingUserData } = await client.users + // .getFetch(tokenUserData._id) + // .catch(() => {}); + + // if (!findingUserData) { + // return notFoundError("Cannot find the user", 400); + // } + + // editingUser = findingUserData; + + // if (editingUser.owner) { + // return notFoundError( + // "This user is the owner of this platform", + // 400 + // ); + // } + + // if (!userSchema.owner) { + // const editingUserHeighestFlag = await new permissionCalculator() + // .getHighestFlag(editingUser) + // .catch(() => {}); + // const userSchemaHeighestFlag = await new permissionCalculator() + // .getHighestFlag(userSchema) + // .catch(() => {}); + // if ( + // editingUserHeighestFlag.flag.position <= + // userSchemaHeighestFlag.flag.position + // ) { + // return notFoundError( + // "Editing user has a higher flag than you or equal to you", + // 400 + // ); + // } + // } + + // if ( + // !(await new permissionCalculator() + // .hasPermission(userSchema, "MANAGE_USERS") + // .catch(() => {})) + // ) { + // return notFoundError( + // "You dont have permissions to execute this command", + // 400 + // ); + // } + + // break; + // } + // } + // if (!(status === 0 || status === 1 || status === 2)) { + // return notFoundError("Status Must be 0 or 1 or 2", 400); + // } + // editingUser.statusMessage = statusMessage; + // editingUser.status = status; + // await editingUser.save(); + + // client.emitGlobalEvents("userUpdate", { + // id: editingUser._id, + // internal: true, + // }); + + // client.emitGlobalEvents("userPrecenceUpdate", { + // id: editingUser._id, + // status, + // statusMessage, + // }); + + // return res.status(200).json({ message: "ok" }); + // }); + + // router.patch("/user/:userId/flags", async (req, res, next) => { + // const notFoundError = function (message, code, data) { + // return res.status(code).json({ error: true, message, data }); + // }; + // const { userId } = req.params; + // const { + // token, + // updatedData = { + // flags: undefined, + // }, + // } = req.body; + + // const tokenUserData = await client + // .findUser(token, req.secret) + // .catch(() => {}); + + // if (!tokenUserData) { + // return notFoundError("You are not logged into the system", 400); + // } + // const { userSchema } = await client.users + // .getFetch(tokenUserData._id) + // .catch(() => {}); + + // if (!userSchema) { + // return notFoundError("Cannot find the user", 400); + // } + // const { flags } = updatedData; + + // let editingUser; + + // if ( + // !(await new permissionCalculator() + // .hasPermission(userSchema, "MANAGE_USERS") + // .catch(() => {})) + // ) { + // return notFoundError( + // "You dont have permissions to execute this command", + // 400 + // ); + // } + + // switch (userId === "@me" || String(tokenUserData._id) === userId) { + // case true: { + // const findingUserData = userSchema; + // editingUser = findingUserData; + + // break; + // } + // case false: { + // const { userSchema: findingUserData } = await client.users + // .getFetch(tokenUserData._id) + // .catch(() => {}); + + // if (!findingUserData) { + // return notFoundError("Cannot find the user", 400); + // } + + // editingUser = findingUserData; + + // if (editingUser.owner) { + // return notFoundError( + // "This user is the owner of this platform", + // 400 + // ); + // } + + // if (!userSchema.owner) { + // const editingUserHeighestFlag = await new permissionCalculator() + // .getHighestFlag(editingUser) + // .catch(() => {}); + // const userSchemaHeighestFlag = await new permissionCalculator() + // .getHighestFlag(userSchema) + // .catch(() => {}); + // if ( + // editingUserHeighestFlag.flag.position <= + // userSchemaHeighestFlag.flag.position + // ) { + // return notFoundError( + // "Editing user has a higher flag than you or equal to you", + // 400 + // ); + // } + // } + // break; + // } + // } + + // const addedFlags = []; + // const removedFlags = []; + + // for (const x of flags) { + // if (x.type === "add") { + // const flag = await new permissionCalculator().getFlag(x.id); + // if (!userSchema.owner) { + // const { flag: heighestFlag } = + // await new permissionCalculator().getHighestFlag(userSchema); + // if (flag.position <= heighestFlag) continue; + // } + // addedFlags.push(flag._id); + // } + // if (x.type === "remove") { + // const flag = await new permissionCalculator().getFlag(x.id); + // if (!userSchema.owner) { + // const { flag: heighestFlag } = + // await new permissionCalculator().getHighestFlag(userSchema); + // if (flag.position <= heighestFlag) continue; + // } + // removedFlags.push(flag._id); + // } + // } + // editingUser.flags = editingUser.flags.map( + // (val) => !removedFlags.includes(val) && val + // ); + // editingUser.flags = [...editingUser.flags, ...addedFlags]; + + // await editingUser.save(); + + // client.emitGlobalEvents("userUpdate", { + // id: editingUser._id, + // }); + + // return res.status(200).json({ message: "ok", addedFlags, removedFlags }); + // }); + + return router; + } +} +module.exports = { route: route, name: "user-patch" }; diff --git a/src/routes/v1/user/post.js b/src/routes/v1/user/post.js new file mode 100644 index 0000000..89c4041 --- /dev/null +++ b/src/routes/v1/user/post.js @@ -0,0 +1,87 @@ +"use strict"; + +class route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + const userDataDb = require("../../../schema/userData"); + const bcrypt = require("bcrypt"); + + router.post("/user/auth", async (req, res) => { + const notFoundError = function (message, code) { + return res.status(code).json({ error: true, message }); + }; + + try { + const { loginData = {} } = req.body; + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (tokenUserData) { + return notFoundError(`You are already logged into the system`, 400); + } + + const { userName, password } = loginData; + if (!userName) { + return notFoundError(`userName is required`, 400); + } + if (!password) { + return notFoundError(`password is required`, 400); + } + + // Find user by userName + const userSchema = await userDataDb + .findOne({ userName: userName }) + .catch((err) => { + console.log(err); + }); + if (!userSchema) { + return notFoundError(`userName is not found`, 400); + } + + if (userSchema.deleted) { + return notFoundError(`User account is not active`, 400); + } + // Verify the password + const isPasswordValid = await bcrypt.compare( + password, + userSchema.password, + ); + + // const isPasswordValid = (password === userSchema.password) + + if (!isPasswordValid) { + return notFoundError(`userName or password is invalid`, 400); + } + + const jwtToken = client.jwt.sign( + { + uuid: userSchema._id.toString(), + }, + client.config.website.secretKey, + ); + + userSchema.tokens.push({ + token: jwtToken, + }); + + await userSchema.save(); + + return res.status(200).json({ message: "ok", token: jwtToken }); + } catch (error) { + console.error("Error in /user/auth:", error); + return res + .status(500) + .json({ error: true, message: "Internal Server Error" }); + } + }); + + return router; + } +} + +module.exports = { route: route, name: "user-post" }; diff --git a/src/routes/v1/user/put.js b/src/routes/v1/user/put.js new file mode 100644 index 0000000..f51b238 --- /dev/null +++ b/src/routes/v1/user/put.js @@ -0,0 +1,124 @@ +"use strict"; + +class route { + constructor(client) { + const express = require("express"); + const router = express.Router(); + const dayjs = require("dayjs"); + const userDataDb = require("../../../schema/userData.js"); + const bcrypt = require("bcrypt"); + + router.put("/user", async (req, res, next) => { + const notFoundError = function (message, code, data) { + return res.status(code).json({ error: true, message, data }); + }; + const { + signupData = { + // email: undefined, + userName: undefined, + password: undefined, + // phoneNumber: undefined, + // school: undefined, + name: undefined, + role: undefined, + }, + } = req.body; + + const authHeader = req.headers["authorization"]; + const token = authHeader && authHeader.split(" ")[1]; // Bearer TOKEN_VALUE + + const tokenUserData = await client + .findUser(token, req.secret) + .catch(() => {}); + + if (!tokenUserData) { + return notFoundError(`You are not logged to the system`, 400); + } + if ( + !tokenUserData.roles || + typeof tokenUserData.roles.roleIndex === "undefined" + ) { + return notFoundError(`You're role information is incomplete`, 400); + } + + const roleHierarchy = { + 3: "Staff", + 2: "Admin", + 1: "Owner", + }; + + // Validate the role of the user to be created + + const { userName, password, name, role } = signupData; + console.log(signupData); + const userSchema = new userDataDb(); + if (!userName) { + return notFoundError(`userName is required`, 400); + } else { + if (await userDataDb.findOne({ userName }).catch(() => {})) { + return notFoundError( + `This userName already exits on the database`, + 400, + ); + } + userSchema.userName = userName; + } + if (!password) { + return notFoundError(`password is required`, 400); + } else { + const salt = await bcrypt.genSalt(10); + const hashedPassword = await bcrypt.hash(password, salt); + + userSchema.password = hashedPassword; + } + if (!name) { + return notFoundError(`name is required`, 400); + } else { + userSchema.name = name; + } + if (!role) { + return notFoundError(`role is required`, 400); + } else { + const newUserRoleIndex = roleHierarchy[role]; + + if (newUserRoleIndex <= tokenUserData.roles.roleIndex) { + return notFoundError( + "You cannot create a user with equal or higher role", + 403, + ); + } + console.log({ roleType: newUserRoleIndex, roleIndex: role }); + userSchema.roles = { + roleType: newUserRoleIndex, + roleIndex: role, + }; + } + const jwtToken = client.jwt.sign( + { + uuid: userSchema._id.toString(), + }, + client.config.website.secretKey, + ); + console.log(userSchema); + + await userSchema.save(); + + // client.emitGlobalEvents("userCreate", { + // id: editingUser._id, + // }); + const updatedUserData = { + role: userSchema.roles.roleType, + id: userSchema._id, + name: userSchema.name, + userName: userSchema.userName, + }; + + return res + .status(200) + .json({ message: "ok", userSchema: updatedUserData }); + }); + + return router; + } +} +module.exports = { route: route, name: "user-put" }; diff --git a/src/schema/broadcastMessage.ts b/src/schema/broadcastMessage.ts new file mode 100644 index 0000000..ff06a9b --- /dev/null +++ b/src/schema/broadcastMessage.ts @@ -0,0 +1,22 @@ +import { Schema, model, Document } from "mongoose"; + +// Define the sub-schema for notifications +interface IBroadcast extends Document { + title: string; + content: string; + sender: string; + sendTime: string; + type: string; +} + +const broadcastSchema: Schema = new Schema({ + title: { type: String, default: "" }, + content: { type: String, default: "" }, + sender: { type: String, default: "" }, + sendTime: { type: String, default: "" }, + type: { type: String, default: "" }, +}); + +const BroadcastModel = model("broadcast", broadcastSchema); + +export default BroadcastModel; diff --git a/src/schema/dashboard.ts b/src/schema/dashboard.ts new file mode 100644 index 0000000..226a080 --- /dev/null +++ b/src/schema/dashboard.ts @@ -0,0 +1,48 @@ +import { Schema, model, Document } from "mongoose"; + +interface ISubMenu extends Document { + url: string; + icon: string; + path: string; + title: string; +} + +const subMenuSchema: Schema = new Schema({ + url: String, + icon: String, + path: String, + title: String, +}); + +interface INavigationLink extends Document { + title: string; + icon: string; + path: string; + url: string; + subMenu: ISubMenu[]; // Embedding the sub-menu schema here +} + +const navigationLinkSchema: Schema = new Schema({ + title: String, + icon: String, + path: String, + url: String, + subMenu: [subMenuSchema], +}); + +interface IDashboardData extends Document { + type: string; + navigationLinks: INavigationLink[]; +} + +const dashboardDataSchema: Schema = new Schema({ + type: { type: String, default: "" }, + navigationLinks: [navigationLinkSchema], +}); + +const DashboardDataModel = model( + "DashboardData", + dashboardDataSchema, +); + +export default DashboardDataModel; diff --git a/src/schema/eventData.ts b/src/schema/eventData.ts new file mode 100644 index 0000000..ddd6acf --- /dev/null +++ b/src/schema/eventData.ts @@ -0,0 +1,41 @@ +import { Schema, model, Document } from "mongoose"; + +interface IPlaces extends Document { + place: number; + minimumMarks: number; + inputMarks: number; + inputID: string; + house: string; + name: string; +} + +const placesSchema: Schema = new Schema({ + place: { type: Number }, + minimumMarks: { type: Number }, + inputMarks: { type: Number }, + inputID: { type: String }, + house: { type: String }, + name: { type: String }, +}); + +interface IEvent extends Document { + name: string; + description: string; + types: any; // Define the specific type for 'types' array + places: IPlaces[]; + state: string; + inputType: "MemberID" | "HouseName"; +} + +const eventSchema: Schema = new Schema({ + name: { type: String }, + description: { type: String }, + types: { type: Array }, + places: [placesSchema], + state: { type: String, default: "notSubmitted" }, + inputType: { type: String, enum: ["MemberID", "HouseName"] }, +}); + +const EventDataModel = model("eventData", eventSchema); + +export default EventDataModel; diff --git a/src/schema/eventTypes.ts b/src/schema/eventTypes.ts new file mode 100644 index 0000000..5a26ccb --- /dev/null +++ b/src/schema/eventTypes.ts @@ -0,0 +1,23 @@ +import { Schema, model, Document } from "mongoose"; + +interface IEventTypeOptions extends Document { + option: string; +} + +const eventTypeOptionsSchema: Schema = new Schema({ + option: { type: String }, +}); + +interface IEventTypes extends Document { + name: string; + options: IEventTypeOptions[]; +} + +const eventTypesSchema: Schema = new Schema({ + name: { type: String }, + options: [eventTypeOptionsSchema], +}); + +const EventTypesModel = model("eventTypes", eventTypesSchema); + +export default EventTypesModel; diff --git a/src/schema/houses.ts b/src/schema/houses.ts new file mode 100644 index 0000000..47333eb --- /dev/null +++ b/src/schema/houses.ts @@ -0,0 +1,44 @@ +import { Schema, model, Document } from "mongoose"; + +interface IEventParticipant extends Document { + eventId: StringConstructor; + participants: any; +} + +const eventParticipantsSchema: Schema = new Schema({ + eventId: { type: String }, + participants: { + type: Array, + default: [ + { userAdmissionId: null, userName: null, marks: null, place: null }, + ], + }, +}); + +interface IHouseMember extends Document { + MemberID: number; +} + +const houseMembersSchema: Schema = new Schema({ + MemberID: { type: Number }, +}); + +interface IHouseData extends Document { + Name: string; + members: IHouseMember[]; + eventData: IEventParticipant[]; + houseScore: number; + description: string; +} + +const housesSchema: Schema = new Schema({ + Name: { type: String, required: true }, + members: [houseMembersSchema], + eventData: [eventParticipantsSchema], + houseScore: { type: Number, default: 0 }, + description: { type: String }, +}); + +const HouseDataModel = model("houseData", housesSchema); + +export default HouseDataModel; diff --git a/src/schema/members.ts b/src/schema/members.ts new file mode 100644 index 0000000..54810e6 --- /dev/null +++ b/src/schema/members.ts @@ -0,0 +1,19 @@ +import { Schema, model, Document } from "mongoose"; + +interface IMemberData extends Document { + Name: string | null; + House: string | null; + Grade: string | null; + MemberID: number | null; +} + +const memberSchema: Schema = new Schema({ + Name: { type: String, default: null }, + House: { type: String, default: null }, + Grade: { type: String, default: null }, + MemberID: { type: Number, default: null }, +}); + +const MemberDataModel = model("memberData", memberSchema); + +export default MemberDataModel; diff --git a/src/schema/userData.ts b/src/schema/userData.ts new file mode 100644 index 0000000..326ab47 --- /dev/null +++ b/src/schema/userData.ts @@ -0,0 +1,29 @@ +import { Schema, model, Document } from "mongoose"; + +interface IUser extends Document { + userName: string; + name: string; + email: string; + password: string; + roles: { + roleType: string; + roleIndex: string | null; + }; + tokens: any; // Adjust this to the specific type of your tokens array +} + +const userSchema: Schema = new Schema({ + userName: { type: String }, + name: { type: String }, + email: { type: String }, + password: { type: String }, + roles: { + roleType: { type: String, default: "" }, + roleIndex: { type: String, default: null }, + }, + tokens: { type: Array, default: [] }, +}); + +const UserDataModel = model("userData", userSchema); + +export default UserDataModel; diff --git a/src/structures/App.ts b/src/structures/App.ts new file mode 100644 index 0000000..a5f5aaf --- /dev/null +++ b/src/structures/App.ts @@ -0,0 +1,209 @@ +import * as express from "express"; +import * as config from "../config"; +import * as cookieParser from "cookie-parser"; +import * as mongoose from "mongoose"; +import * as bodyParser from "body-parser"; +import * as amqp from "amqplib"; +import * as jwt from "jsonwebtoken"; +import * as userDataDb from "../schema/userData"; +import * as cors from "cors"; +import * as CircularJSON from "circular-json"; +import * as dayjs from "dayjs"; +import { EventEmitter } from "ws"; +import { v4 as uuidv4 } from "uuid"; +import { CompressionTypes, Partitioners } from "kafkajs"; +import "ejs"; + +class App extends express.Application { + private config: any; + private express: any; + private routes: Map; + private logger: any; + private mongoose: any; + private fileCache: Map; + private linkCache: Map; + + constructor() { + super(); + this.config = config; + this.express = express; + this.routes = new Map(); + this.logger = require("../utils/logger.js"); + this.mongoose = mongoose; + this.fileCache = new Map(); + this.linkCache = new Map(); + this.getUserData = require("../utils/getuserData.js"); + this.mongoose.Promise = global.Promise; + + this.mongoose.connection.on("connected", () => { + this.logger.log("[DB] DATABASE CONNECTED", "ready"); + }); + + this.mongoose.connection.on("err", (err: any) => { + console.log(`Mongoose connection error: \n ${err.stack}`, "error"); + }); + + this.mongoose.connection.on("disconnected", () => { + console.log("Mongoose disconnected"); + }); + + this.parseURL = function (link: string) { + const parsedUrl = new URL(link); + return parsedUrl; + }; + + this.jwt = jwt; + + this.ipport = function (link: string, port: number) { + return `${link}${Number(port) === 80 ? "" : `:${port}`}`; + }; + + this._errorMiddleware = async function ( + req: express.Request, + res: express.Response, + next: express.NextFunction, + ) { + return res.status(404).json({ error: true, message: "page not found" }); + }; + + this._requirehandlers = async function () { + this.port = this.config.website.port; + this.links = this.config.website.links; + this.server = this.listen(this.port); + this.use( + cors({ + origin: this.config.website.fontendUri, + methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"], + credentials: true, + }), + ); + this.use( + async ( + req: express.Request, + res: express.Response, + next: express.NextFunction, + ) => { + let checkHost = false; + + for (const x of this.links) { + if ( + req.get("host") === this.parseURL(this.ipport(x, this.port)).host + ) + checkHost = true; + } + + if (!checkHost) { + return res.status(403).json({ error: "Forbidden" }); + } + + res.setHeader( + "Access-Control-Allow-Headers", + "Content-Type, Authorization", + ); + res.setHeader("Access-Control-Allow-Private-Network", "true"); + next(); + }, + ); + + this.use(cookieParser(this.config.website.secretKey)); + this.use(express.static(`${process.cwd()}/website`)); + this.use(bodyParser.json({ limit: "1000mb" })); + this.set("trust proxy", true); + this.set("etag", false); + this.set("view engine", "ejs"); + this.use(this._errorMiddleware); + + for (const x of [ + "loadroutes", + "loadincomingEvents", + "sendSystemStatus", + "initDatabase", + ]) { + const handler = require(`../handlers/${x}.js`); + await new handler(this).start(); + } + + this._router.stack.forEach((layer, index, layers) => { + if (layer.handle === this._errorMiddleware) { + layers.splice(index, 1); + } + }); + + for (const [id, x] of this.routes) { + this.use(`/api/${x.version}`, x); + } + + this.use(this._errorMiddleware); + }; + + this.findUser = function (token: string, secret?: string) { + return new Promise(async (resolve, reject) => { + try { + if (!token) { + reject(new Error("Token is missing.")); + return; + } + + if (secret) { + let decoded = jwt.verify(token, secret); + + if (!decoded) { + reject(new Error("Invalid token.")); + return; + } + + let data = await userDataDb.findOne({ + _id: decoded.uuid, + }); + + if (!data) { + reject(new Error("User data not found.")); + return; + } + + const tokenSchema = data.tokens.find( + (val: any) => val.token === token, + ); + + if (!tokenSchema) { + reject(new Error("Token not found for this user.")); + return; + } + + resolve(data); + } else { + let data = await userDataDb.findOne({ + _id: token, + }); + + if (!data) { + reject(new Error("User data not found.")); + return; + } + + resolve(data); + } + } catch (error) { + reject(error); + } + }); + }; + + this.connect = async function () { + this.logger.log(`[WebSite] Loading !`, "log"); + + await this.mongoose.connect(this.config.mongourl, { + useNewUrlParser: true, + autoIndex: false, + connectTimeoutMS: 10000, + family: 4, + useUnifiedTopology: true, + }); + + await this._requirehandlers(); + this.logger.log(`[WebSite] Website is now Online !`, "ready"); + }; + } +} + +export = App; diff --git a/src/utils/filterData.ts b/src/utils/filterData.ts new file mode 100644 index 0000000..07403d9 --- /dev/null +++ b/src/utils/filterData.ts @@ -0,0 +1,72 @@ +import dayjs from "dayjs"; + +interface UserData { + profilePicture: string; + bio: string; + userName: string; + _id: string; + name: string; + school: string; + email: string; + phoneNumber: string; + owner: boolean; + createdAt: string; + roles: { + roleType: string; + roleIndex: string; + }; +} + +class FilterData { + private client: any; + + constructor(client: any) { + this.client = client; + } + + async user(userType: string, findingUserData: UserData) { + const destrucuredData: any = {}; + + switch (userType === "@me") { + case true: { + this.populateDestructuredData(destrucuredData, findingUserData); + + if (findingUserData.roles.roleIndex === "1") { + destrucuredData.editAcessRoles = [ + { roleIndex: 2, roleType: "admin" }, + { roleIndex: 3, roleType: "staff" }, + ]; + } else if (findingUserData.roles.roleIndex === "2") { + destrucuredData.editAcessRoles = [ + { roleIndex: 3, roleType: "staff" }, + ]; + } else if (findingUserData.roles.roleIndex === "3") { + destrucuredData.editAcessRoles = []; + } + break; + } + case false: { + this.populateDestructuredData(destrucuredData, findingUserData); + break; + } + } + return destrucuredData; + } + + private populateDestructuredData( + destrucuredData: any, + findingUserData: UserData, + ) { + destrucuredData.profilePicture = findingUserData.profilePicture || ""; + destrucuredData.bio = findingUserData.bio || ""; + destrucuredData.userName = findingUserData.userName || ""; + destrucuredData.id = String(findingUserData._id) || ""; + destrucuredData.name = findingUserData.name || ""; + destrucuredData.school = findingUserData.school || ""; + destrucuredData.owner = findingUserData.owner || false; + destrucuredData.createdAt = dayjs(findingUserData.createdAt) || ""; + destrucuredData.role = findingUserData.roles.roleType || ""; + } +} + +export default FilterData; diff --git a/src/utils/getSystemSpecs.ts b/src/utils/getSystemSpecs.ts new file mode 100644 index 0000000..0d523fc --- /dev/null +++ b/src/utils/getSystemSpecs.ts @@ -0,0 +1,146 @@ +import os from "os"; +import diskusage from "diskusage-ng"; +import si from "systeminformation"; + +interface SystemUsage { + cpuUsage: string; + totalMemory: number; + usedMemory: number; + freeMemory: number; +} + +interface DiskUsage { + totalStorage: number; + usedStorage: number; + freeStorage: number; +} + +function getPrimaryDiskPath(): string { + if (os.platform() === "win32") { + return "C:"; + } else { + return "/"; + } +} + +function formatBytes(bytes: number): string { + if (bytes === 0) return "0 Bytes"; + + const sizes = ["Bytes", "KB", "MB", "GB", "TB"]; + const i = Math.floor(Math.log(bytes) / Math.log(1024)); + const formattedValue = (bytes / Math.pow(1024, i)).toFixed(2); + + return `${formattedValue} ${sizes[i]}`; +} + +async function getCpuUsage(): Promise { + try { + const sys = await si.currentLoad(); + return sys; + } catch (error) { + return null; + } +} + +async function getSystemUsage(): Promise { + const totalMemory = os.totalmem(); + const freeMemory = os.freemem(); + const usedMemory = totalMemory - freeMemory; + const cpuUsage = await getCpuUsage(); + + return { + cpuUsage: cpuUsage ? cpuUsage.currentLoad.toFixed(2) + "%" : "0.00%", + totalMemory: totalMemory, + usedMemory: usedMemory, + freeMemory: freeMemory, + }; +} + +function getDiskUsage(path: string): Promise { + return new Promise((resolve, reject) => { + diskusage(path, (err, usage) => { + if (err) { + reject(err); + } else { + resolve({ + totalStorage: usage.total, + usedStorage: usage.used, + freeStorage: usage.available, + }); + } + }); + }); +} + +async function updateSystemSpecs(): Promise { + try { + const systemUsage = await getSystemUsage(); + const diskUsage = await getDiskUsage(getPrimaryDiskPath()); + + return [ + { + id: 1, + type: "CPU", + usage: systemUsage.cpuUsage, + data: [ + { _id: 1, title: "No of cores", amount: os.cpus().length.toString() }, + ], + }, + { + id: 2, + type: "Memory", + usage: ((value: number, total: number) => { + if (total === 0) return "0.00%"; + return `${((value / total) * 100).toFixed(2)}%`; + })(systemUsage.usedMemory, systemUsage.totalMemory), + data: [ + { + _id: 1, + title: "Total Memory", + amount: formatBytes(systemUsage.totalMemory), + }, + { + _id: 2, + title: "Used Memory", + amount: formatBytes(systemUsage.usedMemory), + }, + { + _id: 3, + title: "Free Memory", + amount: formatBytes(systemUsage.freeMemory), + }, + ], + }, + { + id: 3, + type: "Storage", + usage: ((value: number, total: number) => { + if (total === 0) return "0.00%"; + return `${((value / total) * 100).toFixed(2)}%`; + })(diskUsage.usedStorage, diskUsage.totalStorage), + data: [ + { + _id: 1, + title: "Total Storage", + amount: formatBytes(diskUsage.totalStorage), + }, + { + _id: 2, + title: "Used Storage", + amount: formatBytes(diskUsage.usedStorage), + }, + { + _id: 3, + title: "Free Storage", + amount: formatBytes(diskUsage.freeStorage), + }, + ], + }, + ]; + } catch (error) { + console.error("Error:", error); + return []; + } +} + +export default updateSystemSpecs; diff --git a/src/utils/getuserData.ts b/src/utils/getuserData.ts new file mode 100644 index 0000000..0676ac9 --- /dev/null +++ b/src/utils/getuserData.ts @@ -0,0 +1,26 @@ +import axios from "axios"; +import uaParser from "ua-parser-js"; +import CircularJSON from "circular-json"; +import { Request } from "express"; + +class GetDetails { + static async getData(req: Request, client: any) { + const userAgent = CircularJSON.parse( + CircularJSON.stringify(uaParser(req.headers["user-agent"])), + ); + const userIP = req.ip; + + try { + const response = await axios.get( + `https://api.ipgeolocation.io/ipgeo?apiKey=${client.config.geoLocationApiKey}&ip=${userIP}`, + ); + const locationData = response.data; + return { locationData, userAgent }; + } catch (error) { + console.error("Error fetching data:", error); + return { locationData: null, userAgent }; + } + } +} + +export default GetDetails; diff --git a/src/utils/logger.ts b/src/utils/logger.ts new file mode 100644 index 0000000..1e953f7 --- /dev/null +++ b/src/utils/logger.ts @@ -0,0 +1,73 @@ +import chalk from "chalk"; +import moment from "moment"; + +export default class Logger { + static log( + content: string, + type: + | "log" + | "warn" + | "error" + | "debug" + | "cmd" + | "event" + | "ready" = "log", + ) { + const date = `${moment().format("DD-MM-YYYY hh:mm:ss")}`; + switch (type) { + case "log": { + return console.log( + `[${chalk.yellow(date)}]: [${chalk.black.bgBlue( + type.toUpperCase(), + )}] ${chalk.blue(content)}`, + ); + } + case "warn": { + return console.log( + `[${chalk.yellow(date)}]: [${chalk.black.bgYellow( + type.toUpperCase(), + )}] ${chalk.blue(content)}`, + ); + } + case "error": { + return console.log( + `[${chalk.yellow(date)}]: [${chalk.black.bgRed( + type.toUpperCase(), + )}] ${chalk.blue(content)}`, + ); + } + case "debug": { + return console.log( + `[${chalk.yellow(date)}]: [${chalk.black.bgGreen( + type.toUpperCase(), + )}] ${chalk.blue(content)}`, + ); + } + case "cmd": { + return console.log( + `[${chalk.yellow(date)}]: [${chalk.black.bgWhite( + type.toUpperCase(), + )}] ${chalk.blue(content)}`, + ); + } + case "event": { + return console.log( + `[${chalk.yellow(date)}]: [${chalk.black.bgHex("#e1f507")( + type.toUpperCase(), + )}] ${chalk.blue(content)}`, + ); + } + case "ready": { + return console.log( + `[${chalk.yellow(date)}]: [${chalk.black.bgHex("#067032")( + type.toUpperCase(), + )}] ${chalk.blue(content)}`, + ); + } + default: + throw new TypeError( + "Logger type must be either warn, debug, log, ready, cmd or error.", + ); + } + } +} diff --git a/src/utils/randomImageGenerator.ts b/src/utils/randomImageGenerator.ts new file mode 100644 index 0000000..8c904bf --- /dev/null +++ b/src/utils/randomImageGenerator.ts @@ -0,0 +1,41 @@ +import { createCanvas, Canvas } from "canvas"; +import randomColor from "randomcolor"; + +class RandomImageGenerator { + constructor() {} + + async generate(name: string): Promise { + const canvas: Canvas = createCanvas(100, 100); + const ctx = canvas.getContext("2d"); + + // Generate a random background color + const backgroundColor: string = randomColor(); + + // Set the background color + ctx.fillStyle = backgroundColor; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + // Set the text properties + ctx.font = "36px Arial"; + ctx.fillStyle = "white"; + ctx.textAlign = "center"; + ctx.textBaseline = "middle"; + + // Get the first letter of the username + const firstLetter: string = name.charAt(0).toUpperCase(); + + // Calculate the position to center the text + const x: number = canvas.width / 2; + const y: number = canvas.height / 2; + + // Draw the first letter on the canvas + ctx.fillText(firstLetter, x, y); + + // Convert the canvas to a Buffer + const buffer: Buffer = canvas.toBuffer("image/png"); + + return buffer; + } +} + +export default RandomImageGenerator; diff --git a/src/utils/wait.ts b/src/utils/wait.ts new file mode 100644 index 0000000..24e952c --- /dev/null +++ b/src/utils/wait.ts @@ -0,0 +1,7 @@ +const wait = async function (timeInMs: number): Promise { + return new Promise((resolve) => { + setTimeout(resolve, timeInMs); + }); +}; + +export default wait; diff --git a/src/webshocket/v1/home.ts b/src/webshocket/v1/home.ts new file mode 100644 index 0000000..1d08374 --- /dev/null +++ b/src/webshocket/v1/home.ts @@ -0,0 +1,165 @@ +"use strict"; +import CircularJSON from "circular-json"; +import dayjs from "dayjs"; +import userDataDb from "../../schema/userData"; +import Crypto from "node:crypto"; +import broadcastMessage from "../../schema/broadcastMessage"; +import eventDataSchema from "../../schema/eventData"; + +interface State { + authenticated: boolean | null; + id: string | null; + token: string | null; +} + +export default { + name: "/home", + async run(client: any, socket: any, req: any, params: any) { + const state: State = { authenticated: null, id: null, token: null }; + + const sendMessage = async function (data: any) { + socket.emit("server-message", data); + }; + + const sendMessageAuth = async function (data: any) { + let authenticated = false; + const sToken = + (state.id ?? "") + new Date().toString() + Crypto.randomUUID(); + sendMessage({ + type: "preflight", + payload: { sToken }, + }); + await new Promise((resolve, reject) => { + const handleReceive = function (d: any) { + const { type, payload } = d; + if (!type || !payload) return; + if (type !== "preflight") return; + if (payload.sToken !== sToken) return; + if (payload.token !== state.token) return handleClear(); + authenticated = true; + return handleClear(); + }; + const handleClear = function () { + socket.removeListener("client-message", handleReceive); + socket.removeListener("disconnect", handleClear); + resolve(); + }; + setTimeout( + () => { + handleClear(); + }, + 1000 * 60 * 2, + ); + socket.on("client-message", handleReceive); + socket.on("disconnect", handleClear); + }); + if (!authenticated) return; + socket.emit("server-message", data); + }; + + const handleIncoming = async function (d: any) { + const data = d; + switch (data.type) { + case "auth": { + const tokenUserData = await client + .findUser(data.payload, client.config.website.secretKey) + .catch(() => {}); + if (!tokenUserData) { + return await sendMessage({ + type: "auth", + payload: { success: false, message: "cannot authenticate" }, + }); + } + state.id = String(tokenUserData._id); + state.token = data.payload; + state.authenticated = true; + return await sendMessage({ + type: "auth", + payload: { success: true, message: "successfully authenticated" }, + }); + } + case "message": { + const user = await userDataDb.findOne({ _id: state.id }); + const messageData = data.payload; + const messageSchema = new broadcastMessage({ + content: messageData.content, + type: messageData.type, + sender: user?._id.toString(), + }); + await messageSchema.save(); + client.wsevents.emit("home", { + type: "message", + payload: messageData, + }); + if (messageData.type === "public") + client.wsevents.emit("public", { + type: "message", + payload: messageData, + }); + return; + } + } + }; + + const handleSend = async function ({ ...args }: any) { + if (!state.authenticated) return; + switch (args.type) { + /**Check the login if it emits to set */ + case "checkLogin": { + const { id } = args.payload; + if (id !== state.id && state.token !== state.token) return; + + await sendMessage({ + type: "checkLogin", + payload: { message: "logged out" }, + }); + + socket.disconnect(); + break; + } + case "systemInfo": { + await sendMessageAuth({ + type: "systemInfo", + payload: args.specs, + }); + break; + } + case "message": { + const messageData = args.payload; + console.log(messageData); + await sendMessageAuth({ + type: "message", + payload: messageData, + }); + break; + } + case "eventSubmits": { + const EventData = args.payload; + await sendMessageAuth({ + type: "eventSubmits", + payload: EventData, + }); + break; + } + case "eventApproves": { + const EventData = args.payload; + await sendMessageAuth({ + type: "eventApproves", + payload: EventData, + }); + break; + } + } + }; + + const handleClear = function () { + socket.removeListener("client-message", handleIncoming); + socket.removeListener("disconnect", handleClear); + client.wsevents.removeListener("home", handleSend); + }; + socket.sessionId = Date.now().toString() + Crypto.randomUUID(); + client.wsevents.on("home", handleSend); + socket.on("disconnect", handleClear); + socket.on("client-message", handleIncoming); + }, +}; diff --git a/src/webshocket/v1/public.ts b/src/webshocket/v1/public.ts new file mode 100644 index 0000000..fa32f58 --- /dev/null +++ b/src/webshocket/v1/public.ts @@ -0,0 +1,42 @@ +"use strict"; +import CircularJSON from "circular-json"; +import dayjs from "dayjs"; +import userDataDb from "../../schema/userData"; +import Crypto from "node:crypto"; +import broadcastMessage from "../../schema/broadcastMessage"; + +export default { + name: "/public", + async run(client: any, socket: any, req: any, params: any) { + const sendMessage = async function (data: any) { + socket.emit("server-message", data); + }; + + const handleSend = async function ({ ...args }: any) { + switch (args.type) { + case "message": { + const messageData = args.payload; + await sendMessage({ type: "message", payload: messageData }); + break; + } + case "houseScoreUpdate": { + const houseData = args.payload; + await sendMessage({ type: "houseScoreUpdate", payload: houseData }); + break; + } + case "eventUpdate": { + const eventData = args.payload; + await sendMessage({ type: "eventUpdate", payload: eventData }); + break; + } + } + }; + + const handleClear = function () { + socket.removeListener("disconnect", handleClear); + client.wsevents.removeListener("public", handleSend); + }; + client.wsevents.on("public", handleSend); + socket.on("disconnect", handleClear); + }, +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..208979f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es2018", // Or a target suitable for your project + "module": "commonjs", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "outDir": "./dist" // Output directory for compiled TypeScript + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "**/*.spec.ts"] + } + \ No newline at end of file