From 43d39309c88436e0e4812e1a421363268176689a Mon Sep 17 00:00:00 2001 From: Thomas Karanikiotis Date: Tue, 29 Oct 2024 11:39:07 +0200 Subject: [PATCH 01/18] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6b7bcc9..95b46fc 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "dev": "nodemon server.js --watch .", "lint": "eslint . --cache", "start": "cross-env NODE_ENV=production node server.js", - "test": "npm run lint && ava -s" + "test": "echo 'No tests specified!' & exit 0" }, "nodemonConfig": { "env": { From d94bf06f024cd2bc326c8bdf50e9f05c62c3bbab Mon Sep 17 00:00:00 2001 From: Thomas Karanikiotis Date: Tue, 29 Oct 2024 11:53:44 +0200 Subject: [PATCH 02/18] Create cicd.yml --- .github/workflows/cicd.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/cicd.yml diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml new file mode 100644 index 0000000..3b20b33 --- /dev/null +++ b/.github/workflows/cicd.yml @@ -0,0 +1,21 @@ +name: cicd + +on: push + +jobs: + ci: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + + - name: Setup nodejs + uses: actions/setup-node@v2 + with: + node-version: 16 + + - name: Download dependencies + run: npm install + + - name: Run tests + run: npm run test From abadcc908e3263c756d277c289a713af5a6e6671 Mon Sep 17 00:00:00 2001 From: Thomas Karanikiotis Date: Tue, 29 Oct 2024 11:55:57 +0200 Subject: [PATCH 03/18] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 95b46fc..d525fe0 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "dev": "nodemon server.js --watch .", "lint": "eslint . --cache", "start": "cross-env NODE_ENV=production node server.js", - "test": "echo 'No tests specified!' & exit 0" + "test": "echo 'No tests specified!' & exit 1" }, "nodemonConfig": { "env": { From 7ccd95c30e8b38e9b64bc425fc9fbbf8ab9236ab Mon Sep 17 00:00:00 2001 From: Thomas Karanikiotis Date: Tue, 29 Oct 2024 12:26:56 +0200 Subject: [PATCH 04/18] Update cicd.yml --- .github/workflows/cicd.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index 3b20b33..c922460 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -19,3 +19,13 @@ jobs: - name: Run tests run: npm run test + + cd: + runs-on: ubuntu-latest + needs: ci + steps: + - name: Deploy to Render + uses: johnbeynon/render-deploy-action@v0.0.8 + with: + service-id: ${{ secrets.RENDER_SERVICE_ID }} + api-key: ${{ secrets.RENDER_API_KEY }} From 451f418dbee2fc19f4f1a425a4d967ce8ef2716b Mon Sep 17 00:00:00 2001 From: Thomas Karanikiotis Date: Tue, 29 Oct 2024 12:28:00 +0200 Subject: [PATCH 05/18] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d525fe0..95b46fc 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "dev": "nodemon server.js --watch .", "lint": "eslint . --cache", "start": "cross-env NODE_ENV=production node server.js", - "test": "echo 'No tests specified!' & exit 1" + "test": "echo 'No tests specified!' & exit 0" }, "nodemonConfig": { "env": { From bcd6a0f58c144ea4eb378a4e6c19b7d4965f044d Mon Sep 17 00:00:00 2001 From: Thomas Karanikiotis Date: Tue, 29 Oct 2024 12:37:33 +0200 Subject: [PATCH 06/18] Update server.js --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index 52bad49..fc5f048 100644 --- a/server.js +++ b/server.js @@ -42,7 +42,7 @@ app.use(express.urlencoded({ extended: true, limit: "5mb" })); app.use(favicon(path.join(path.dirname(fileURLToPath(import.meta.url)), "src", "assets", "images", "favicon.ico"))); app.use("/api", routes); -app.all("/*", (_, res) => res.json({ body: "It works!" })); +app.all("/*", (_, res) => res.json({ body: "Render deployed!" })); app.use(Sentry.Handlers.errorHandler()); From 0e865c3578b18f9d7677e8e2cfbbaab28373cf78 Mon Sep 17 00:00:00 2001 From: karanikiotis Date: Tue, 5 Nov 2024 13:55:56 +0200 Subject: [PATCH 07/18] Testing --- package-lock.json | 708 ++++++++++++++++++++++++++++++++++++++++++--- package.json | 7 +- server.js | 5 +- tests/init.test.js | 43 ++- 4 files changed, 712 insertions(+), 51 deletions(-) diff --git a/package-lock.json b/package-lock.json index 82103b5..5a2856d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,6 @@ "cross-env": "^7.0.3", "dotenv": "^16.0.3", "express": "^4.18.2", - "got": "^12.5.2", "helmet": "^6.0.1", "jsonwebtoken": "^9.0.0", "mongoose": "^6.9.2", @@ -29,9 +28,11 @@ }, "devDependencies": { "@iamnapo/prettier-config": "^1.0.3", - "ava": "^5.2.0", + "ava": "^5.3.1", + "c8": "^10.1.2", "eslint": "^8.34.0", "eslint-config-iamnapo": "^28.2.0", + "got": "^14.4.3", "nodemon": "^2.0.20", "test-listen": "^1.1.0" }, @@ -856,6 +857,13 @@ "node": ">=0.8.0" } }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, "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", @@ -964,6 +972,80 @@ "prettier": ">=2" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@mongodb-js/saslprep": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz", @@ -1012,6 +1094,17 @@ "node": ">= 8" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -1026,6 +1119,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true, + "license": "MIT" + }, "node_modules/@sendgrid/client": { "version": "7.7.0", "resolved": "https://registry.npmjs.org/@sendgrid/client/-/client-7.7.0.tgz", @@ -1144,12 +1244,13 @@ } }, "node_modules/@sindresorhus/is": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", - "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.0.1.tgz", + "integrity": "sha512-QWLl2P+rsCJeofkDNIT3WFmb6NrRud1SUYW8dIhXK/46XFV8Q/g7Bsvib0Askb0reRLe+WYPeeE+l5cH7SlkuQ==", + "dev": true, "license": "MIT", "engines": { - "node": ">=14.16" + "node": ">=18" }, "funding": { "url": "https://github.com/sindresorhus/is?sponsor=1" @@ -1751,6 +1852,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, "license": "MIT", "dependencies": { "defer-to-connect": "^2.0.1" @@ -1763,6 +1865,14 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, "license": "MIT" }, "node_modules/@types/json-schema": { @@ -2749,31 +2859,67 @@ "node": ">= 0.8" } }, + "node_modules/c8": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/c8/-/c8-10.1.2.tgz", + "integrity": "sha512-Qr6rj76eSshu5CgRYvktW0uM0CFY0yi4Fd5D0duDXO6sYinyopmftUiJVuzBQxQcwQLor7JWDVRP+dUfCmzgJw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^3.1.1", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.6", + "test-exclude": "^7.0.1", + "v8-to-istanbul": "^9.0.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" + }, + "bin": { + "c8": "bin/c8.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "monocart-coverage-reports": "^2" + }, + "peerDependenciesMeta": { + "monocart-coverage-reports": { + "optional": true + } + } + }, "node_modules/cacheable-lookup": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true, "license": "MIT", "engines": { "node": ">=14.16" } }, "node_modules/cacheable-request": { - "version": "10.2.14", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", - "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-12.0.1.tgz", + "integrity": "sha512-Yo9wGIQUaAfIbk+qY0X4cDQgCosecfBe3V9NSyeY4qPC2SAkbCS4Xj79VP8WOzitpJUZKc/wsRCYF5ariDIwkg==", + "dev": true, "license": "MIT", "dependencies": { - "@types/http-cache-semantics": "^4.0.2", - "get-stream": "^6.0.1", + "@types/http-cache-semantics": "^4.0.4", + "get-stream": "^9.0.1", "http-cache-semantics": "^4.1.1", - "keyv": "^4.5.3", + "keyv": "^4.5.4", "mimic-response": "^4.0.0", - "normalize-url": "^8.0.0", + "normalize-url": "^8.0.1", "responselike": "^3.0.0" }, "engines": { - "node": ">=14.16" + "node": ">=18" } }, "node_modules/call-bind": { @@ -3194,6 +3340,13 @@ "node": ">= 0.6" } }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, "node_modules/convert-to-spaces": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz", @@ -3372,6 +3525,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, "license": "MIT", "dependencies": { "mimic-response": "^3.1.0" @@ -3387,6 +3541,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -3448,6 +3603,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -4870,13 +5026,31 @@ "is-callable": "^1.1.3" } }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data-encoder": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", - "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-4.0.2.tgz", + "integrity": "sha512-KQVhvhK8ZkWzxKxOr56CPulAhH3dobtuQ4+hNQ+HekH/Wp5gSOafqRAeTphQUJAIk0GBvHZgJ2ZGRWd5kphMuw==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 14.17" + "node": ">= 18" } }, "node_modules/forwarded": { @@ -4987,12 +5161,17 @@ } }, "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -5117,30 +5296,44 @@ } }, "node_modules/got": { - "version": "12.6.1", - "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", - "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "version": "14.4.3", + "resolved": "https://registry.npmjs.org/got/-/got-14.4.3.tgz", + "integrity": "sha512-iTC0Z87yxSijWTh/IpvGpwOhIQK7+GgWkYrMRoN/hB9qeRj9RPuLGODwevs0p5idUf7nrxCVa5IlOmK3b8z+KA==", + "dev": true, "license": "MIT", "dependencies": { - "@sindresorhus/is": "^5.2.0", + "@sindresorhus/is": "^7.0.1", "@szmarczak/http-timer": "^5.0.1", "cacheable-lookup": "^7.0.0", - "cacheable-request": "^10.2.8", + "cacheable-request": "^12.0.1", "decompress-response": "^6.0.0", - "form-data-encoder": "^2.1.2", - "get-stream": "^6.0.1", - "http2-wrapper": "^2.1.10", + "form-data-encoder": "^4.0.2", + "http2-wrapper": "^2.2.1", "lowercase-keys": "^3.0.0", - "p-cancelable": "^3.0.0", - "responselike": "^3.0.0" + "p-cancelable": "^4.0.1", + "responselike": "^3.0.0", + "type-fest": "^4.26.1" }, "engines": { - "node": ">=14.16" + "node": ">=20" }, "funding": { "url": "https://github.com/sindresorhus/got?sponsor=1" } }, + "node_modules/got/node_modules/type-fest": { + "version": "4.26.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.1.tgz", + "integrity": "sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -5248,10 +5441,18 @@ "dev": true, "license": "ISC" }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true, "license": "BSD-2-Clause" }, "node_modules/http-errors": { @@ -5274,6 +5475,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, "license": "MIT", "dependencies": { "quick-lru": "^5.1.1", @@ -5843,6 +6045,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", @@ -5960,6 +6175,68 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/iterator.prototype": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.3.tgz", @@ -5977,6 +6254,22 @@ "node": ">= 0.4" } }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", @@ -6030,6 +6323,7 @@ "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, "license": "MIT" }, "node_modules/json-parse-even-better-errors": { @@ -6138,6 +6432,7 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, "license": "MIT", "dependencies": { "json-buffer": "3.0.1" @@ -6304,6 +6599,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -6312,6 +6608,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/map-age-cleaner": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", @@ -6508,6 +6827,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true, "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -6549,6 +6869,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mongodb": { "version": "4.17.2", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.17.2.tgz", @@ -6807,6 +7137,7 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "dev": true, "license": "MIT", "engines": { "node": ">=14.16" @@ -6999,12 +7330,13 @@ } }, "node_modules/p-cancelable": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", - "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-4.0.1.tgz", + "integrity": "sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==", + "dev": true, "license": "MIT", "engines": { - "node": ">=12.20" + "node": ">=14.16" } }, "node_modules/p-defer": { @@ -7104,6 +7436,13 @@ "node": ">=6" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -7204,6 +7543,23 @@ "dev": true, "license": "MIT" }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/path-to-regexp": { "version": "0.1.10", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", @@ -7524,6 +7880,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -7810,6 +8167,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true, "license": "MIT" }, "node_modules/resolve-cwd": { @@ -7839,6 +8197,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, "license": "MIT", "dependencies": { "lowercase-keys": "^3.0.0" @@ -8382,6 +8741,62 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/string.prototype.includes": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz", @@ -8499,6 +8914,30 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -8625,6 +9064,68 @@ "node": ">=14.16" } }, + "node_modules/test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/test-exclude/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/test-listen": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/test-listen/-/test-listen-1.1.0.tgz", @@ -8865,9 +9366,9 @@ } }, "node_modules/typescript": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", - "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -8876,7 +9377,7 @@ "tsserver": "bin/tsserver" }, "engines": { - "node": ">=14.17" + "node": ">=4.2.0" } }, "node_modules/unbox-primitive": { @@ -8950,6 +9451,21 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -9128,6 +9644,116 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrap-ansi/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", diff --git a/package.json b/package.json index 95b46fc..87075b6 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "dev": "nodemon server.js --watch .", "lint": "eslint . --cache", "start": "cross-env NODE_ENV=production node server.js", - "test": "echo 'No tests specified!' & exit 0" + "test": "c8 ava" }, "nodemonConfig": { "env": { @@ -53,9 +53,11 @@ }, "devDependencies": { "@iamnapo/prettier-config": "^1.0.3", - "ava": "^5.2.0", + "ava": "^5.3.1", + "c8": "^10.1.2", "eslint": "^8.34.0", "eslint-config-iamnapo": "^28.2.0", + "got": "^14.4.3", "nodemon": "^2.0.20", "test-listen": "^1.1.0" }, @@ -69,7 +71,6 @@ "cross-env": "^7.0.3", "dotenv": "^16.0.3", "express": "^4.18.2", - "got": "^12.5.2", "helmet": "^6.0.1", "jsonwebtoken": "^9.0.0", "mongoose": "^6.9.2", diff --git a/server.js b/server.js index fc5f048..edc466b 100644 --- a/server.js +++ b/server.js @@ -47,6 +47,9 @@ app.all("/*", (_, res) => res.json({ body: "Render deployed!" })); app.use(Sentry.Handlers.errorHandler()); const port = PORT || 4000; -server.listen(port, () => NODE_ENV !== "test" && console.log(chalk.bold.cyan(`>>> Live at http://localhost:${port}`))); + +if (NODE_ENV !== "test") { + server.listen(port, () => NODE_ENV !== "test" && console.log(chalk.bold.cyan(`>>> Live at http://localhost:${port}`))); +} export default app; diff --git a/tests/init.test.js b/tests/init.test.js index 70f8326..02ca997 100644 --- a/tests/init.test.js +++ b/tests/init.test.js @@ -1,24 +1,55 @@ -import "dotenv/config"; - import http from "node:http"; import test from "ava"; import got from "got"; -import listen from "test-listen"; import app from "../server.js"; +// test("Test passes", (t) => { +// t.pass(); +// }); + +// test("Test fails", (t) => { +// t.fail(); +// }); + +// test("Test throws", (t) => { +// t.throws(() => { +// throw new Error("Test failed"); +// }); +// }); + +// const addNumbers = (a,b) => a + b; + +// test('Add numbers', t => { +// t.is(addNumbers(1,2), 3); +// t.is(addNumbers(3,5), 8); +// t.is(addNumbers(-1,2), 1); +// t.is(addNumbers(0,0), 0); +// t.is(addNumbers(0,2), 2); +// t.is(addNumbers("1", "2"), "12"); +// t.is(addNumbers("1", 2), "12"); +// t.is(addNumbers(undefined, 2), NaN); +// t.is(addNumbers(), NaN); +// }); + +// test('Async', async t => { +// const res = Promise.resolve('test'); +// t.is(await res, 'test'); +// }); + test.before(async (t) => { t.context.server = http.createServer(app); - t.context.prefixUrl = await listen(t.context.server); - t.context.got = got.extend({ http2: true, throwHttpErrors: false, responseType: "json", prefixUrl: t.context.prefixUrl }); + const server = t.context.server.listen(); + const { port } = server.address(); + t.context.got = got.extend({ responseType: "json", prefixUrl: `http://localhost:${port}` }); }); test.after.always((t) => { t.context.server.close(); }); -test("GET / returns correct response and status code", async (t) => { +test("GET /api returns correct response and status code", async (t) => { const { body, statusCode } = await t.context.got("api"); t.is(body.message, "It works!"); t.is(statusCode, 200); From d0d6da1a58b420c66103f433bc3f3feb5184419a Mon Sep 17 00:00:00 2001 From: Thomas Karanikiotis Date: Sat, 9 Nov 2024 21:52:12 +0200 Subject: [PATCH 08/18] Update server.js --- server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index edc466b..9e7cf7d 100644 --- a/server.js +++ b/server.js @@ -15,7 +15,7 @@ import helmet from "helmet"; import routes from "./src/routes/index.js"; import { setServerTimeout } from "./src/middleware/index.js"; -import { init } from "./src/utils/index.js"; +import {init} from "./src/utils/index.js"; const { NODE_ENV, PORT } = process.env; @@ -37,7 +37,7 @@ if (NODE_ENV === "development") app.use(morgan("dev", { skip: (req) => req.metho app.use(cors({ credentials: true, origin: true })); app.use(compression()); app.use(express.json({ limit: "1mb" })); -app.use((req, _, next) => { req.body ||= {}; next(); }); +app.use((req, _, next) => {req.body ||= {}; next();}); app.use(express.urlencoded({ extended: true, limit: "5mb" })); app.use(favicon(path.join(path.dirname(fileURLToPath(import.meta.url)), "src", "assets", "images", "favicon.ico"))); From fa0b93127f5e62bcbdd9255b0ff3e811bea4025a Mon Sep 17 00:00:00 2001 From: Thomas Karanikiotis Date: Sat, 9 Nov 2024 21:56:16 +0200 Subject: [PATCH 09/18] Update index.js --- src/middleware/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/middleware/index.js b/src/middleware/index.js index 4e74be9..a2a2656 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -1,5 +1,6 @@ +// This function changes the default server timeout export const setServerTimeout = (millis = 5 * 60 * 1000) => (req, res, next) => { - req.setTimeout(millis, () => res.status(408).json({ message: "Request Timeout" })); - res.setTimeout(millis, () => res.status(503).json({ message: "Service Unavailable" })); + req.setTimeout(millis, () => res.status(408).json({ message: "Request Timeout" })); // Set timeout in request object + res.setTimeout(millis, () => res.status(503).json({ message: "Service Unavailable" })); // Set timeout in response object next(); }; From 9c46cc443f32de9fefd5ade2b635cce27222d770 Mon Sep 17 00:00:00 2001 From: Thomas Karanikiotis Date: Sat, 9 Nov 2024 21:59:41 +0200 Subject: [PATCH 10/18] Update data.js --- src/routes/data.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/routes/data.js b/src/routes/data.js index 14017b7..25d9d75 100644 --- a/src/routes/data.js +++ b/src/routes/data.js @@ -3,16 +3,19 @@ import Sentry from "@sentry/node"; const router = express.Router({ mergeParams: true }); +// Generate a random number in the range [min,max] const generateRandomData = (min = 0, max = 10) => Math.random() * (max - min) + min; router.get("/", async (req, res) => { try { + // Generate random data for localFoodCropProduction const localFoodCropProduction = { March: Array.from({ length: 100 }, () => generateRandomData(0, 10)), April: Array.from({ length: 100 }, () => generateRandomData(0, 10)), May: Array.from({ length: 100 }, () => generateRandomData(0, 10)), }; + // Generate random data for comparisonOfIrrigationWaterVsNeeds const comparisonOfIrrigationWaterVsNeeds = { March: { etc: generateRandomData(0, 100), irrigation: generateRandomData(0, 100), rainfall: generateRandomData(0, 100) }, April: { etc: generateRandomData(0, 100), irrigation: generateRandomData(0, 100), rainfall: generateRandomData(0, 100) }, @@ -22,6 +25,7 @@ router.get("/", async (req, res) => { August: { etc: generateRandomData(0, 100), irrigation: generateRandomData(0, 100), rainfall: generateRandomData(0, 100) }, }; + // Generate random data for timePlot const timePlot = { meteo: Array.from({ length: 20 }, () => generateRandomData(0, 100)), inSitu: Array.from({ length: 20 }, () => generateRandomData(0, 100)), From c7e0bc7cdb5049b3471b2eccf2f2c7b41ffa0138 Mon Sep 17 00:00:00 2001 From: karanikiotis Date: Sun, 17 Nov 2024 12:37:34 +0200 Subject: [PATCH 11/18] Test --- server.js | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/server.js b/server.js index 9e7cf7d..6ae71a2 100644 --- a/server.js +++ b/server.js @@ -1,21 +1,23 @@ -import "dotenv/config"; +import "dotenv/config" -import path from "node:path"; -import { fileURLToPath } from "node:url"; -import http from "node:http"; +import path from "node:path" +import { fileURLToPath } from "node:url" +import http from "node:http" -import express from "express"; -import morgan from "morgan"; -import compression from "compression"; -import favicon from "serve-favicon"; -import cors from "cors"; -import chalk from "chalk"; -import Sentry from "@sentry/node"; -import helmet from "helmet"; +import express from "express" +import morgan from "morgan" +import compression from "compression" +import favicon from "serve-favicon" +import cors from "cors" +import chalk from "chalk" +import Sentry from "@sentry/node" +import helmet from "helmet" -import routes from "./src/routes/index.js"; -import { setServerTimeout } from "./src/middleware/index.js"; -import {init} from "./src/utils/index.js"; +import routes from "./src/routes/index.js" +import { setServerTimeout } from "./src/middleware/index.js" +import { init } from "./src/utils/index.js" + +const unusedVariable = "I am not used"; const { NODE_ENV, PORT } = process.env; @@ -37,7 +39,7 @@ if (NODE_ENV === "development") app.use(morgan("dev", { skip: (req) => req.metho app.use(cors({ credentials: true, origin: true })); app.use(compression()); app.use(express.json({ limit: "1mb" })); -app.use((req, _, next) => {req.body ||= {}; next();}); +app.use((req, _, next) => {req.body ||= {}; req = null; next();}); app.use(express.urlencoded({ extended: true, limit: "5mb" })); app.use(favicon(path.join(path.dirname(fileURLToPath(import.meta.url)), "src", "assets", "images", "favicon.ico"))); @@ -46,10 +48,16 @@ app.all("/*", (_, res) => res.json({ body: "Render deployed!" })); app.use(Sentry.Handlers.errorHandler()); -const port = PORT || 4000; - +const port = 3000; if (NODE_ENV !== "test") { - server.listen(port, () => NODE_ENV !== "test" && console.log(chalk.bold.cyan(`>>> Live at http://localhost:${port}`))); + const port = PORT || 4000; + server.listen(port, () => console.log(chalk.bold.cyan(`>>> Live at http://localhost:${port}`))); } -export default app; +const serverStart = () => console.log("Server started"); +serverStart(); + +return; +console.log("This will never execute"); + +export default app; \ No newline at end of file From 3770f14a78a60dbac7c875bec31aa08f12d51958 Mon Sep 17 00:00:00 2001 From: karanikiotis Date: Sun, 17 Nov 2024 12:49:58 +0200 Subject: [PATCH 12/18] Minor fix --- server.js | 1 - 1 file changed, 1 deletion(-) diff --git a/server.js b/server.js index 6ae71a2..0f7149a 100644 --- a/server.js +++ b/server.js @@ -57,7 +57,6 @@ if (NODE_ENV !== "test") { const serverStart = () => console.log("Server started"); serverStart(); -return; console.log("This will never execute"); export default app; \ No newline at end of file From afb210765fe8d50dcbd09f52f806893ed46677fc Mon Sep 17 00:00:00 2001 From: karanikiotis Date: Sun, 17 Nov 2024 12:55:20 +0200 Subject: [PATCH 13/18] Test violations --- server.js | 7 +- src/routes/user-system.js | 268 +++++++++++--------------------------- 2 files changed, 80 insertions(+), 195 deletions(-) diff --git a/server.js b/server.js index 0f7149a..e6f88c9 100644 --- a/server.js +++ b/server.js @@ -54,9 +54,4 @@ if (NODE_ENV !== "test") { server.listen(port, () => console.log(chalk.bold.cyan(`>>> Live at http://localhost:${port}`))); } -const serverStart = () => console.log("Server started"); -serverStart(); - -console.log("This will never execute"); - -export default app; \ No newline at end of file +export default app; diff --git a/src/routes/user-system.js b/src/routes/user-system.js index e9dccc1..fef1ce5 100644 --- a/src/routes/user-system.js +++ b/src/routes/user-system.js @@ -1,198 +1,88 @@ -import express from "express"; +import express from "express"; // Unused import violation -import { validations, email } from "../utils/index.js"; -import { User, Reset, Invitation } from "../models/index.js"; +import { validations, email } from "../utils/index.js"; // Trailing comma violation +import { User, Reset, Invitation } from "../models/index.js"; // Import grouping order violation const router = express.Router(); router.post("/createUser", - (req, res, next) => validations.validate(req, res, next, "register"), - async (req, res, next) => { - const { username, password, email: userEmail } = req.body; - try { - const user = await User.findOne({ $or: [{ username }, { email: userEmail }] }); - if (user) { - return res.json({ - status: 409, - message: "Registration Error: A user with that e-mail or username already exists.", - }); - } - - await new User({ - username, - password, - email: userEmail, - }).save(); - return res.json({ - success: true, - message: "User created successfully", - }); - } catch (error) { - return next(error); - } - }); + (req, res, next) => validations.validate(req, res, next, "register"), // Arrow function parentheses violation + async (req, res, next) => { // Missing return type for async function violation + const { username, password, email: userEmail } = req.body + try { // No newline after try violation + const user = await User.findOne({ $or: [{ username }, { email: userEmail }] }); + if (user) { + return res.json({ + status: 409, + message: "Registration Error: A user with that e-mail or username already exists." + }) // Missing semicolon violation + } + + await new User({ username, password, email: userEmail }).save(); // Line too long violation + return res.json({ + success: true, + message: "User created successfully" + }); + } catch (error) { + return next(error) + } + }); router.post("/createUserInvited", - (req, res, next) => validations.validate(req, res, next, "register"), - async (req, res, next) => { - const { username, password, email: userEmail, token } = req.body; - try { - const invitation = await Invitation.findOne({ token }); - - if (!invitation) { - return res.json({ - success: false, - message: "Invalid token", - }); - } - - const user = await User.findOne({ $or: [{ username }, { email: userEmail }] }); - if (user) { - return res.json({ - status: 409, - message: "Registration Error: A user with that e-mail or username already exists.", - }); - } - - await new User({ - username, - password, - email: userEmail, - }).save(); - - await Invitation.deleteOne({ token }); - - return res.json({ - success: true, - message: "User created successfully", - }); - } catch (error) { - return next(error); - } - }); + (req, res, next) => validations.validate(req, res, next, "register"), + async (req, res, next) => { + const { username, password, email: userEmail, token } = req.body; + try { + const invitation = await Invitation.findOne({ token }) + + if (!invitation) return res.json({ success: false, message: "Invalid token" }); // No block for if statement violation + + const user = await User.findOne({ $or: [{ username }, { email: userEmail }] }); + if (user) { + return res.json({ + status: 409, + message: "Registration Error: A user with that e-mail or username already exists.", + }); + } + + await new User({ username, password, email: userEmail }).save(); // Line too long violation + + await Invitation.deleteOne({ token }); + + return res.json({ + success: true, + message: "User created successfully", + }); + } catch (error) { + return next(error); + } + } +); router.post("/authenticate", - (req, res, next) => validations.validate(req, res, next, "authenticate"), - async (req, res, next) => { - const { username, password } = req.body; - try { - const user = await User.findOne({ username }).select("+password"); - if (!user) { - return res.json({ - success: false, - status: 401, - message: "Authentication Error: User not found.", - }); - } - - if (!user.comparePassword(password, user.password)) { - return res.json({ - success: false, - status: 401, - message: "Authentication Error: Password does not match!", - }); - } - - return res.json({ - success: true, - user: { - username, - id: user._id, - email: user.email, - role: user.role, - }, - token: validations.jwtSign({ username, id: user._id, email: user.email, role: user.role }), - }); - } catch (error) { - return next(error); - } - }); - -router.post("/forgotpassword", - (req, res, next) => validations.validate(req, res, next, "request"), - async (req, res) => { - try { - const { username } = req.body; - - const user = await User.findOne({ username }).select("+password"); - if (!user) { - return res.json({ - status: 404, - message: "Resource Error: User not found.", - }); - } - - if (!user?.password) { - return res.json({ - status: 404, - message: "User has logged in with google", - }); - } - - const token = validations.jwtSign({ username }); - await Reset.findOneAndRemove({ username }); - await new Reset({ - username, - token, - }).save(); - - await email.forgotPassword(user.email, token); - return res.json({ - success: true, - message: "Forgot password e-mail sent.", - }); - } catch (error) { - return res.json({ - success: false, - message: error.body, - }); - } - }); - -router.post("/resetpassword", async (req, res) => { - const { token, password } = req.body; - - try { - const reset = await Reset.findOne({ token }); - - if (!reset) { - return res.json({ - status: 400, - message: "Invalid Token!", - }); - } - - const today = new Date(); - - if (reset.expireAt < today) { - return res.json({ - success: false, - message: "Token expired", - }); - } - - const user = await User.findOne({ username: reset.username }); - if (!user) { - return res.json({ - success: false, - message: "User does not exist", - }); - } - - user.password = password; - await user.save(); - await Reset.deleteOne({ _id: reset._id }); - - return res.json({ - success: true, - message: "Password updated succesfully", - }); - } catch (error) { - return res.json({ - success: false, - message: error, - }); - } -}); - -export default router; + (req, res, next) => validations.validate(req, res, next, "authenticate"), + async(req, res, next) => { // Missing space after async keyword violation + const { username, password } = req.body; + try { + const user = await User.findOne({ username }).select("+password"); // No await wrap violation + if (!user) { + return res.json({ // Arrow body style violation + success: false, + status: 401, + message: "Authentication Error: User not found.", + }); + } + + if (!user.comparePassword(password, user.password)) { + return res.json({ + success: false, + status: 401, + message: "Authentication Error: Password does not match!" + }); + } + + return res.json({ success: true, user: { username, id: user._id, email: user.email, role: user.role }, token: validations.jwtSign({ username, id: user._id, email: user.email, role: user.role }) }) // Object literal formatting violation + } catch (error) { + return next(error) + } + }); \ No newline at end of file From d8c4e9d443906477f42237aa22c19204bcc50403 Mon Sep 17 00:00:00 2001 From: karanikiotis Date: Sun, 17 Nov 2024 13:05:29 +0200 Subject: [PATCH 14/18] More violations --- server.js | 5 ++--- src/routes/public.js | 2 +- src/routes/user-system.js | 7 +++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/server.js b/server.js index e6f88c9..50aee0d 100644 --- a/server.js +++ b/server.js @@ -39,7 +39,7 @@ if (NODE_ENV === "development") app.use(morgan("dev", { skip: (req) => req.metho app.use(cors({ credentials: true, origin: true })); app.use(compression()); app.use(express.json({ limit: "1mb" })); -app.use((req, _, next) => {req.body ||= {}; req = null; next();}); +app.use((req,_,next) => {req.body ||= {}; req = null; next();}); app.use(express.urlencoded({ extended: true, limit: "5mb" })); app.use(favicon(path.join(path.dirname(fileURLToPath(import.meta.url)), "src", "assets", "images", "favicon.ico"))); @@ -48,9 +48,8 @@ app.all("/*", (_, res) => res.json({ body: "Render deployed!" })); app.use(Sentry.Handlers.errorHandler()); -const port = 3000; if (NODE_ENV !== "test") { - const port = PORT || 4000; + var port = PORT || 4000; server.listen(port, () => console.log(chalk.bold.cyan(`>>> Live at http://localhost:${port}`))); } diff --git a/src/routes/public.js b/src/routes/public.js index d6aba5e..bd44f35 100644 --- a/src/routes/public.js +++ b/src/routes/public.js @@ -3,7 +3,7 @@ import express from "express"; const router = express.Router({ mergeParams: true }); -router.get("/", (req, res) => { +router.get("/", (req,res) => { try { return res.json({ message: "It works!" }); } catch (error) { diff --git a/src/routes/user-system.js b/src/routes/user-system.js index fef1ce5..700257b 100644 --- a/src/routes/user-system.js +++ b/src/routes/user-system.js @@ -10,7 +10,7 @@ router.post("/createUser", async (req, res, next) => { // Missing return type for async function violation const { username, password, email: userEmail } = req.body try { // No newline after try violation - const user = await User.findOne({ $or: [{ username }, { email: userEmail }] }); + var user = await User.findOne({ $or: [{ username }, { email: userEmail }] }); if (user) { return res.json({ status: 409, @@ -59,12 +59,15 @@ router.post("/createUserInvited", } ); + + + router.post("/authenticate", (req, res, next) => validations.validate(req, res, next, "authenticate"), async(req, res, next) => { // Missing space after async keyword violation const { username, password } = req.body; try { - const user = await User.findOne({ username }).select("+password"); // No await wrap violation + var user = await User.findOne({ username }).select("+password"); // No await wrap violation if (!user) { return res.json({ // Arrow body style violation success: false, From df6094c8ea74a7a9af778f8651bc80a724685d1a Mon Sep 17 00:00:00 2001 From: karanikiotis Date: Sun, 17 Nov 2024 13:10:56 +0200 Subject: [PATCH 15/18] Test --- src/routes/user-system.js | 271 ++++++++++++++++++++++++++------------ 1 file changed, 190 insertions(+), 81 deletions(-) diff --git a/src/routes/user-system.js b/src/routes/user-system.js index 700257b..b3dbc3d 100644 --- a/src/routes/user-system.js +++ b/src/routes/user-system.js @@ -1,91 +1,200 @@ -import express from "express"; // Unused import violation +import express from "express"; -import { validations, email } from "../utils/index.js"; // Trailing comma violation -import { User, Reset, Invitation } from "../models/index.js"; // Import grouping order violation +import { validations, email } from "../utils/index.js"; +import { User, Reset, Invitation } from "../models/index.js"; const router = express.Router(); router.post("/createUser", - (req, res, next) => validations.validate(req, res, next, "register"), // Arrow function parentheses violation - async (req, res, next) => { // Missing return type for async function violation - const { username, password, email: userEmail } = req.body - try { // No newline after try violation - var user = await User.findOne({ $or: [{ username }, { email: userEmail }] }); - if (user) { - return res.json({ - status: 409, - message: "Registration Error: A user with that e-mail or username already exists." - }) // Missing semicolon violation - } - - await new User({ username, password, email: userEmail }).save(); // Line too long violation - return res.json({ - success: true, - message: "User created successfully" - }); - } catch (error) { - return next(error) - } - }); - -router.post("/createUserInvited", - (req, res, next) => validations.validate(req, res, next, "register"), - async (req, res, next) => { - const { username, password, email: userEmail, token } = req.body; - try { - const invitation = await Invitation.findOne({ token }) - - if (!invitation) return res.json({ success: false, message: "Invalid token" }); // No block for if statement violation - - const user = await User.findOne({ $or: [{ username }, { email: userEmail }] }); - if (user) { - return res.json({ - status: 409, - message: "Registration Error: A user with that e-mail or username already exists.", - }); - } - - await new User({ username, password, email: userEmail }).save(); // Line too long violation - - await Invitation.deleteOne({ token }); - - return res.json({ - success: true, - message: "User created successfully", - }); - } catch (error) { - return next(error); - } - } -); + (req, res, next) => validations.validate(req, res, next, "register"), + async (req, res, next) => { + const { username, password, email: userEmail } = req.body; + try { + const user = await User.findOne({ $or: [{ username }, { email: userEmail }] }); + if (user) { + return res.json({ + status: 409, + message: "Registration Error: A user with that e-mail or username already exists.", + }); + } + + await new User({ + username, + password, + email: userEmail, + }).save(); + return res.json({ + success: true, + message: "User created successfully", + }); + } catch (error) { + return next(error); + } + }); +router.post("/createUserInvited", + (req,res,next) => validations.validate(req, res, next, "register"), + async (req, res, next) => { + const { username, password, email: userEmail, token } = req.body; + try { + const invitation = await Invitation.findOne({ token }); + + if (!invitation) { + return res.json({ + success: false, + message: "Invalid token", + }); + } + + const user = await User.findOne({ $or: [{ username }, { email: userEmail }] }); + if (user) { + return res.json({ + status: 409, + message: "Registration Error: A user with that e-mail or username already exists.", + }); + } + + await new User({ + username, + password, + email: userEmail, + }).save(); + + await Invitation.deleteOne({ token }); + + return res.json({ + success: true, + message: "User created successfully", + }); + } catch (error) { + return next(error); + } + }); router.post("/authenticate", - (req, res, next) => validations.validate(req, res, next, "authenticate"), - async(req, res, next) => { // Missing space after async keyword violation - const { username, password } = req.body; - try { - var user = await User.findOne({ username }).select("+password"); // No await wrap violation - if (!user) { - return res.json({ // Arrow body style violation - success: false, - status: 401, - message: "Authentication Error: User not found.", - }); - } - - if (!user.comparePassword(password, user.password)) { - return res.json({ - success: false, - status: 401, - message: "Authentication Error: Password does not match!" - }); - } - - return res.json({ success: true, user: { username, id: user._id, email: user.email, role: user.role }, token: validations.jwtSign({ username, id: user._id, email: user.email, role: user.role }) }) // Object literal formatting violation - } catch (error) { - return next(error) - } - }); \ No newline at end of file + (req, res, next) => validations.validate(req, res, next, "authenticate"), + async (req, res, next) => { + const { username, password } = req.body; + try { + const user = await User.findOne({ username }).select("+password"); + if (!user) { + return res.json({ + success: false, + status: 401, + message: "Authentication Error: User not found.", + }); + } + + if (!user.comparePassword(password, user.password)) { + return res.json({ + success: false, + status: 401, + message: "Authentication Error: Password does not match!", + }); + } + + return res.json({ + success: true, + user: { + username, + id: user._id, + email: user.email, + role: user.role, + }, + token: validations.jwtSign({ username, id: user._id, email: user.email, role: user.role }), + }); + } catch (error) { + return next(error); + } + }); + +router.post("/forgotpassword", + (req, res, next) => validations.validate(req, res, next, "request"), + async (req, res) => { + try { + const { username } = req.body; + + const user = await User.findOne({ username }).select("+password"); + if (!user) { + return res.json({ + status: 404, + message: "Resource Error: User not found.", + }); + } + + if (!user?.password) { + return res.json({ + status: 404, + message: "User has logged in with google", + }); + } + + const token = validations.jwtSign({ username }); + await Reset.findOneAndRemove({ username }); + await new Reset({ + username, + token, + }).save(); + + await email.forgotPassword(user.email, token); + return res.json({ + success: true, + message: "Forgot password e-mail sent.", + }); + } catch (error) { + return res.json({ + success: false, + message: error.body, + }); + } + }); + +router.post("/resetpassword", async (req, res) => { + const { token, password } = req.body; + + try { + const reset = await Reset.findOne({ token }); + + if (!reset) { + return res.json({ + status: 400, + message: "Invalid Token!", + }); + } + + const today = new Date(); + + if (reset.expireAt < today) { + return res.json({ + success: false, + message: "Token expired", + }); + } + + const user = await User.findOne({ username: reset.username }); + if (!user) { + return res.json({ + success: false, + message: "User does not exist", + }); + } + + user.password = password; + await user.save(); + await Reset.deleteOne({ _id: reset._id }); + + return res.json({ + success: true, + message: "Password updated succesfully", + }); + } catch (error) { + return res.json({ + success: false, + message: error, + }); + } +}); + +export default router; From d1435cce1910ab962c3e2d1aaf24928db5d94831 Mon Sep 17 00:00:00 2001 From: karanikiotis Date: Sun, 17 Nov 2024 13:16:21 +0200 Subject: [PATCH 16/18] Test --- src/routes/user-system.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/user-system.js b/src/routes/user-system.js index b3dbc3d..1abc868 100644 --- a/src/routes/user-system.js +++ b/src/routes/user-system.js @@ -62,12 +62,12 @@ router.post("/createUserInvited", email: userEmail, }).save(); - await Invitation.deleteOne({ token }); - return res.json({ success: true, message: "User created successfully", }); + + await Invitation.deleteOne({ token }); } catch (error) { return next(error); } From 8b2ea80159f6048e5ebe574c04b09082cf8db82a Mon Sep 17 00:00:00 2001 From: karanikiotis Date: Sun, 17 Nov 2024 13:24:47 +0200 Subject: [PATCH 17/18] Minor fixes --- .github/workflows/cicd.yml | 12 +----------- server.js | 34 +++++++++++++++++----------------- src/middleware/index.js | 6 ++---- src/routes/data.js | 4 ---- 4 files changed, 20 insertions(+), 36 deletions(-) diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index c922460..f1d888e 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -18,14 +18,4 @@ jobs: run: npm install - name: Run tests - run: npm run test - - cd: - runs-on: ubuntu-latest - needs: ci - steps: - - name: Deploy to Render - uses: johnbeynon/render-deploy-action@v0.0.8 - with: - service-id: ${{ secrets.RENDER_SERVICE_ID }} - api-key: ${{ secrets.RENDER_API_KEY }} + run: npm run test \ No newline at end of file diff --git a/server.js b/server.js index 50aee0d..871d65a 100644 --- a/server.js +++ b/server.js @@ -1,21 +1,21 @@ -import "dotenv/config" +import "dotenv/config"; -import path from "node:path" -import { fileURLToPath } from "node:url" -import http from "node:http" +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import http from "node:http"; -import express from "express" -import morgan from "morgan" -import compression from "compression" -import favicon from "serve-favicon" -import cors from "cors" -import chalk from "chalk" -import Sentry from "@sentry/node" -import helmet from "helmet" +import express from "express"; +import morgan from "morgan"; +import compression from "compression"; +import favicon from "serve-favicon"; +import cors from "cors"; +import chalk from "chalk"; +import Sentry from "@sentry/node"; +import helmet from "helmet"; -import routes from "./src/routes/index.js" -import { setServerTimeout } from "./src/middleware/index.js" -import { init } from "./src/utils/index.js" +import routes from "./src/routes/index.js"; +import { setServerTimeout } from "./src/middleware/index.js"; +import { init } from "./src/utils/index.js"; const unusedVariable = "I am not used"; @@ -39,12 +39,12 @@ if (NODE_ENV === "development") app.use(morgan("dev", { skip: (req) => req.metho app.use(cors({ credentials: true, origin: true })); app.use(compression()); app.use(express.json({ limit: "1mb" })); -app.use((req,_,next) => {req.body ||= {}; req = null; next();}); +app.use((req, _, next) => { req.body ||= {}; next(); }); app.use(express.urlencoded({ extended: true, limit: "5mb" })); app.use(favicon(path.join(path.dirname(fileURLToPath(import.meta.url)), "src", "assets", "images", "favicon.ico"))); app.use("/api", routes); -app.all("/*", (_, res) => res.json({ body: "Render deployed!" })); +app.all("/*", (_, res) => res.json({ body: "It works!" })); app.use(Sentry.Handlers.errorHandler()); diff --git a/src/middleware/index.js b/src/middleware/index.js index a2a2656..d1dbae6 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -1,6 +1,4 @@ -// This function changes the default server timeout export const setServerTimeout = (millis = 5 * 60 * 1000) => (req, res, next) => { - req.setTimeout(millis, () => res.status(408).json({ message: "Request Timeout" })); // Set timeout in request object - res.setTimeout(millis, () => res.status(503).json({ message: "Service Unavailable" })); // Set timeout in response object - next(); + req.setTimeout(millis, () => res.status(408).json({ message: "Request Timeout" })); + res.setTimeout(millis, () => res.status(503).json({ message: "Service Unavailable" })); }; diff --git a/src/routes/data.js b/src/routes/data.js index 25d9d75..14017b7 100644 --- a/src/routes/data.js +++ b/src/routes/data.js @@ -3,19 +3,16 @@ import Sentry from "@sentry/node"; const router = express.Router({ mergeParams: true }); -// Generate a random number in the range [min,max] const generateRandomData = (min = 0, max = 10) => Math.random() * (max - min) + min; router.get("/", async (req, res) => { try { - // Generate random data for localFoodCropProduction const localFoodCropProduction = { March: Array.from({ length: 100 }, () => generateRandomData(0, 10)), April: Array.from({ length: 100 }, () => generateRandomData(0, 10)), May: Array.from({ length: 100 }, () => generateRandomData(0, 10)), }; - // Generate random data for comparisonOfIrrigationWaterVsNeeds const comparisonOfIrrigationWaterVsNeeds = { March: { etc: generateRandomData(0, 100), irrigation: generateRandomData(0, 100), rainfall: generateRandomData(0, 100) }, April: { etc: generateRandomData(0, 100), irrigation: generateRandomData(0, 100), rainfall: generateRandomData(0, 100) }, @@ -25,7 +22,6 @@ router.get("/", async (req, res) => { August: { etc: generateRandomData(0, 100), irrigation: generateRandomData(0, 100), rainfall: generateRandomData(0, 100) }, }; - // Generate random data for timePlot const timePlot = { meteo: Array.from({ length: 20 }, () => generateRandomData(0, 100)), inSitu: Array.from({ length: 20 }, () => generateRandomData(0, 100)), From 77bd1b8ace01df80bfce726d7fd755588aa1589e Mon Sep 17 00:00:00 2001 From: karanikiotis Date: Sun, 17 Nov 2024 13:26:21 +0200 Subject: [PATCH 18/18] Oops --- src/middleware/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/middleware/index.js b/src/middleware/index.js index d1dbae6..4e74be9 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -1,4 +1,5 @@ export const setServerTimeout = (millis = 5 * 60 * 1000) => (req, res, next) => { req.setTimeout(millis, () => res.status(408).json({ message: "Request Timeout" })); res.setTimeout(millis, () => res.status(503).json({ message: "Service Unavailable" })); + next(); };