diff --git a/.husky/install.mjs b/.husky/install.mjs index 1fee59f..ec3e4ab 100644 --- a/.husky/install.mjs +++ b/.husky/install.mjs @@ -1,5 +1,5 @@ -if (process.env.NODE_ENV === 'production' || process.env.CI === 'true') { - process.exit(0) +if (process.env.NODE_ENV === "production" || process.env.CI === "true") { + process.exit(0); } -const husky = (await import('husky')).default -console.log(husky()) +const husky = (await import("husky")).default; +console.log(husky()); diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..c27d889 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +lint-staged diff --git a/.swcrc b/.swcrc index 38cf4a0..3e08dc1 100644 --- a/.swcrc +++ b/.swcrc @@ -1,14 +1,14 @@ { - "$schema": "https://json.schemastore.org/swcrc", - "sourceMaps": true, - "jsc": { - "target": "esnext", - "parser": { - "syntax": "typescript", - "decorators": true, - "dynamicImport": true - }, - "baseUrl": "./" - }, - "minify": false -} \ No newline at end of file + "$schema": "https://json.schemastore.org/swcrc", + "sourceMaps": true, + "jsc": { + "target": "esnext", + "parser": { + "syntax": "typescript", + "decorators": true, + "dynamicImport": true + }, + "baseUrl": "./" + }, + "minify": false +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json index a5824a5..16e8e66 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,5 +1,3 @@ { - "recommendations": [ - "biomejs.biome" - ] -} \ No newline at end of file + "recommendations": ["biomejs.biome"] +} diff --git a/commitlint.config.js b/commitlint.config.js index 84dcb12..26a88cb 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -1,3 +1,3 @@ module.exports = { - extends: ['@commitlint/config-conventional'], + extends: ["@commitlint/config-conventional"], }; diff --git a/nest-cli.json b/nest-cli.json index 579ca35..12c1ab8 100644 --- a/nest-cli.json +++ b/nest-cli.json @@ -1,10 +1,10 @@ { - "$schema": "https://json.schemastore.org/nest-cli", - "collection": "@nestjs/schematics", - "sourceRoot": "src", - "compilerOptions": { - "deleteOutDir": true, - "builder": "swc", - "typeCheck": true - } + "$schema": "https://json.schemastore.org/nest-cli", + "collection": "@nestjs/schematics", + "sourceRoot": "src", + "compilerOptions": { + "deleteOutDir": true, + "builder": "swc", + "typeCheck": true + } } diff --git a/package-lock.json b/package-lock.json index a09f8ba..9351075 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,6 +40,8 @@ }, "devDependencies": { "@biomejs/biome": "1.5.3", + "@commitlint/cli": "^18.6.0", + "@commitlint/config-conventional": "^18.6.0", "@nestjs/cli": "^10.0.0", "@nestjs/schematics": "^10.0.0", "@nestjs/testing": "^10.0.0", @@ -60,6 +62,7 @@ "eslint-plugin-prettier": "^5.0.0", "husky": "^9.0.7", "jest": "^29.5.0", + "lint-staged": "^15.2.1", "prettier": "^3.0.0", "source-map-support": "^0.5.21", "supertest": "^6.3.3", @@ -1857,6 +1860,393 @@ "node": ">=0.1.90" } }, + "node_modules/@commitlint/cli": { + "version": "18.6.0", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-18.6.0.tgz", + "integrity": "sha512-FiH23cr9QG8VdfbmvJJZmdfHGVMCouOOAzoXZ3Cd7czGC52RbycwNt8YCI7SA69pAl+t30vh8LMaO/N+kcel6w==", + "dev": true, + "dependencies": { + "@commitlint/format": "^18.6.0", + "@commitlint/lint": "^18.6.0", + "@commitlint/load": "^18.6.0", + "@commitlint/read": "^18.6.0", + "@commitlint/types": "^18.6.0", + "execa": "^5.0.0", + "lodash.isfunction": "^3.0.9", + "resolve-from": "5.0.0", + "resolve-global": "1.0.0", + "yargs": "^17.0.0" + }, + "bin": { + "commitlint": "cli.js" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/cli/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@commitlint/cli/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==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/cli/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/cli/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@commitlint/cli/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@commitlint/config-conventional": { + "version": "18.6.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-18.6.0.tgz", + "integrity": "sha512-CDCOf2eJz9D/TL44IBks0stM9TmdLCNE2B48owIU3YCadwzts/bobXPScagIgPQF6hhKYMEdj5zpUDlmbwuqwQ==", + "dev": true, + "dependencies": { + "conventional-changelog-conventionalcommits": "^7.0.2" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/config-validator": { + "version": "18.6.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-18.6.0.tgz", + "integrity": "sha512-Ptfa865arNozlkjxrYG3qt6wT9AlhNUHeuDyKEZiTL/l0ftncFhK/KN0t/EAMV2tec+0Mwxo0FmhbESj/bI+1g==", + "dev": true, + "dependencies": { + "@commitlint/types": "^18.6.0", + "ajv": "^8.11.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/ensure": { + "version": "18.6.0", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-18.6.0.tgz", + "integrity": "sha512-xY07NmOBJ7JuhX3tic021PaeLepZARIQyqpAQoNQZoml1keBFfB6MbA7XlWZv0ebbarUFE4yhKxOPw+WFv7/qw==", + "dev": true, + "dependencies": { + "@commitlint/types": "^18.6.0", + "lodash.camelcase": "^4.3.0", + "lodash.kebabcase": "^4.1.1", + "lodash.snakecase": "^4.1.1", + "lodash.startcase": "^4.4.0", + "lodash.upperfirst": "^4.3.1" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/execute-rule": { + "version": "18.4.4", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-18.4.4.tgz", + "integrity": "sha512-a37Nd3bDQydtg9PCLLWM9ZC+GO7X5i4zJvrggJv5jBhaHsXeQ9ZWdO6ODYR+f0LxBXXNYK3geYXJrCWUCP8JEg==", + "dev": true, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/format": { + "version": "18.6.0", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-18.6.0.tgz", + "integrity": "sha512-8UNWfs2slPPSQiiVpLGJTnPHv7Jkd5KYxfbNXbmLL583bjom4RrylvyrCVnmZReA8nNad7pPXq6mDH4FNVj6xg==", + "dev": true, + "dependencies": { + "@commitlint/types": "^18.6.0", + "chalk": "^4.1.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/is-ignored": { + "version": "18.6.0", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-18.6.0.tgz", + "integrity": "sha512-Xjx/ZyyJ4FdLuz0FcOvqiqSFgiO2yYj3QN9XlvyrxqbXTxPVC7QFEXJYBVPulUSN/gR7WXH1Udw+HYYfD17xog==", + "dev": true, + "dependencies": { + "@commitlint/types": "^18.6.0", + "semver": "7.5.4" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/lint": { + "version": "18.6.0", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-18.6.0.tgz", + "integrity": "sha512-ycbuDWfyykPmslgiHzhz8dL6F0BJYltXLVfc+M49z0c+FNITM0v+r0Vd2+Tdtq06VTc894p2+YSmZhulY8Jn3Q==", + "dev": true, + "dependencies": { + "@commitlint/is-ignored": "^18.6.0", + "@commitlint/parse": "^18.6.0", + "@commitlint/rules": "^18.6.0", + "@commitlint/types": "^18.6.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load": { + "version": "18.6.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-18.6.0.tgz", + "integrity": "sha512-RRssj7TmzT0bowoEKlgwg8uQ7ORXWkw7lYLsZZBMi9aInsJuGNLNWcMxJxRZbwxG3jkCidGUg85WmqJvRjsaDA==", + "dev": true, + "dependencies": { + "@commitlint/config-validator": "^18.6.0", + "@commitlint/execute-rule": "^18.4.4", + "@commitlint/resolve-extends": "^18.6.0", + "@commitlint/types": "^18.6.0", + "chalk": "^4.1.0", + "cosmiconfig": "^8.3.6", + "cosmiconfig-typescript-loader": "^5.0.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@commitlint/message": { + "version": "18.4.4", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-18.4.4.tgz", + "integrity": "sha512-lHF95mMDYgAI1LBXveJUyg4eLaMXyOqJccCK3v55ZOEUsMPrDi8upqDjd/NmzWmESYihaOMBTAnxm+6oD1WoDQ==", + "dev": true, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/parse": { + "version": "18.6.0", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-18.6.0.tgz", + "integrity": "sha512-Y/G++GJpATFw54O0jikc/h2ibyGHgghtPnwsOk3O/aU092ydJ5XEHYcd7xGNQYuLweLzQis2uEwRNk9AVIPbQQ==", + "dev": true, + "dependencies": { + "@commitlint/types": "^18.6.0", + "conventional-changelog-angular": "^7.0.0", + "conventional-commits-parser": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/read": { + "version": "18.6.0", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-18.6.0.tgz", + "integrity": "sha512-w39ji8VfWhPKRquPhRHB3Yd8XIHwaNHgOh28YI1QEmZ59qVpuVUQo6h/NsVb+uoC6LbXZiofTZv2iFR084jKEA==", + "dev": true, + "dependencies": { + "@commitlint/top-level": "^18.4.4", + "@commitlint/types": "^18.6.0", + "git-raw-commits": "^2.0.11", + "minimist": "^1.2.6" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "18.6.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-18.6.0.tgz", + "integrity": "sha512-k2Xp+Fxeggki2i90vGrbiLDMefPius3zGSTFFlRAPKce/SWLbZtI+uqE9Mne23mHO5lmcSV8z5m6ziiJwGpOcg==", + "dev": true, + "dependencies": { + "@commitlint/config-validator": "^18.6.0", + "@commitlint/types": "^18.6.0", + "import-fresh": "^3.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0", + "resolve-global": "^1.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/resolve-extends/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@commitlint/rules": { + "version": "18.6.0", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-18.6.0.tgz", + "integrity": "sha512-pTalvCEvuCWrBWZA/YqO/3B3nZnY3Ncc+TmQsRajBdC1tkQIm5Iovdo4Ec7f2Dw1tVvpYMUUNAgcWqsY0WckWg==", + "dev": true, + "dependencies": { + "@commitlint/ensure": "^18.6.0", + "@commitlint/message": "^18.4.4", + "@commitlint/to-lines": "^18.4.4", + "@commitlint/types": "^18.6.0", + "execa": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/rules/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@commitlint/rules/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==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/rules/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/rules/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@commitlint/to-lines": { + "version": "18.4.4", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-18.4.4.tgz", + "integrity": "sha512-mwe2Roa59NCz/krniAdCygFabg7+fQCkIhXqBHw00XQ8Y7lw4poZLLxeGI3p3bLpcEOXdqIDrEGLwHmG5lBdwQ==", + "dev": true, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/top-level": { + "version": "18.4.4", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-18.4.4.tgz", + "integrity": "sha512-PBwW1drgeavl9CadB7IPRUk6rkUP/O8jEkxjlC+ofuh3pw0bzJdAT+Kw7M1Yc9KtTb9xTaqUB8uvRtaybHa/tQ==", + "dev": true, + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/types": { + "version": "18.6.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-18.6.0.tgz", + "integrity": "sha512-oavoKLML/eJa2rJeyYSbyGAYzTxQ6voG5oeX3OrxpfrkRWhJfm4ACnhoRf5tgiybx2MZ+EVFqC1Lw3W8/uwpZA==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0" + }, + "engines": { + "node": ">=v18" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -5106,6 +5496,12 @@ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", "dev": true }, + "node_modules/@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "dev": true + }, "node_modules/@types/node": { "version": "20.11.11", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.11.tgz", @@ -5114,6 +5510,12 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true + }, "node_modules/@types/passport": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.16.tgz", @@ -5866,6 +6268,12 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true + }, "node_modules/array-timsort": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", @@ -5881,6 +6289,15 @@ "node": ">=8" } }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -6429,6 +6846,32 @@ "node": ">=6" } }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001581", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001581.tgz", @@ -6591,6 +7034,72 @@ "@colors/colors": "1.5.0" } }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/cli-width": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", @@ -6736,6 +7245,12 @@ "color-support": "bin.js" } }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -6773,6 +7288,16 @@ "node": ">= 6" } }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, "node_modules/component-emitter": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", @@ -6830,6 +7355,48 @@ "node": ">= 0.6" } }, + "node_modules/conventional-changelog-angular": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", + "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz", + "integrity": "sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-commits-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", + "dev": true, + "dependencies": { + "is-text-path": "^2.0.0", + "JSONStream": "^1.3.5", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "conventional-commits-parser": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -6898,6 +7465,23 @@ } } }, + "node_modules/cosmiconfig-typescript-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-5.0.0.tgz", + "integrity": "sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==", + "dev": true, + "dependencies": { + "jiti": "^1.19.1" + }, + "engines": { + "node": ">=v16" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=8.2", + "typescript": ">=4" + } + }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -6947,6 +7531,15 @@ "node": "*" } }, + "node_modules/dargs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", + "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -6963,6 +7556,40 @@ } } }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -7161,6 +7788,18 @@ "node": ">=6.0.0" } }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/dotenv": { "version": "16.3.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", @@ -7562,6 +8201,12 @@ "node": ">=6" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -8498,6 +9143,18 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", @@ -8530,6 +9187,80 @@ "node": ">=4" } }, + "node_modules/git-raw-commits": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", + "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", + "dev": true, + "dependencies": { + "dargs": "^7.0.0", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + }, + "bin": { + "git-raw-commits": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/git-raw-commits/node_modules/meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/git-raw-commits/node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/git-raw-commits/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/git-raw-commits/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", @@ -8577,6 +9308,18 @@ "node": ">=10" } }, + "node_modules/global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==", + "dev": true, + "dependencies": { + "ini": "^1.3.4" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", @@ -8660,6 +9403,15 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -8743,6 +9495,36 @@ "node": ">=8" } }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -8902,6 +9684,15 @@ "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -8916,6 +9707,12 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "node_modules/inquirer": { "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", @@ -9081,6 +9878,15 @@ "node": ">=0.12.0" } }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -9119,6 +9925,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-text-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", + "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", + "dev": true, + "dependencies": { + "text-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -9995,6 +10813,15 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -10085,6 +10912,31 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/jsonwebtoken": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", @@ -10199,12 +11051,299 @@ "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.3.2.tgz", "integrity": "sha512-n9wh8tvBe5sFmsqlg+XQhaQLumwpqoAUruLwjCopgTmUBjJ/fjtBsJzKleCaIGBOMXYEhp1YfKl4d7rJ5ZKJGA==" }, + "node_modules/lilconfig": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "node_modules/lint-staged": { + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.1.tgz", + "integrity": "sha512-dhwAPnM85VdshybV9FWI/9ghTvMLoQLEXgVMx+ua2DN7mdfzd/tRfoU2yhMcBac0RHkofoxdnnJUokr8s4zKmQ==", + "dev": true, + "dependencies": { + "chalk": "5.3.0", + "commander": "11.1.0", + "debug": "4.3.4", + "execa": "8.0.1", + "lilconfig": "3.0.0", + "listr2": "8.0.1", + "micromatch": "4.0.5", + "pidtree": "0.6.0", + "string-argv": "0.3.2", + "yaml": "2.3.4" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/lint-staged/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/lint-staged/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/npm-run-path": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", + "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/lint-staged/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.0.1.tgz", + "integrity": "sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==", + "dev": true, + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.0.0", + "rfdc": "^1.3.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -10234,6 +11373,12 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true + }, "node_modules/lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", @@ -10254,6 +11399,12 @@ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" }, + "node_modules/lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==", + "dev": true + }, "node_modules/lodash.isinteger": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", @@ -10274,6 +11425,12 @@ "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.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": true + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -10286,11 +11443,41 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "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/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "dev": true + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "dev": true + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "node_modules/lodash.upperfirst": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", + "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", + "dev": true + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -10307,6 +11494,193 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-update": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", + "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", + "dev": true, + "dependencies": { + "ansi-escapes": "^6.2.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^7.0.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", + "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", + "dev": true, + "dependencies": { + "type-fest": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", @@ -10374,6 +11748,18 @@ "tmpl": "1.0.5" } }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/md5": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", @@ -10404,6 +11790,18 @@ "node": ">= 4.0.0" } }, + "node_modules/meow": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", + "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", + "dev": true, + "engines": { + "node": ">=16.10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/merge-deep": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.3.tgz", @@ -10518,6 +11916,15 @@ "node": ">=4" } }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/minimatch": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", @@ -10541,6 +11948,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minimist-options/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/minipass": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", @@ -10831,6 +12261,21 @@ "node": ">=6" } }, + "node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -11253,6 +12698,18 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -11665,6 +13122,135 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -11737,6 +13323,19 @@ "node": ">= 0.10" } }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/redis-errors": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", @@ -11840,6 +13439,18 @@ "node": ">=4" } }, + "node_modules/resolve-global": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz", + "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", + "dev": true, + "dependencies": { + "global-dirs": "^0.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/resolve.exports": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", @@ -12450,6 +14061,46 @@ "node": ">=8" } }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/sonic-boom": { "version": "3.8.0", "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.0.tgz", @@ -12510,6 +14161,38 @@ "node": ">=0.10.0" } }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.4.0.tgz", + "integrity": "sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "dev": true + }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -12582,6 +14265,15 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -12674,6 +14366,18 @@ "node": ">=6" } }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "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", @@ -12996,6 +14700,18 @@ "resolved": "https://registry.npmjs.org/text-decoding/-/text-decoding-1.0.0.tgz", "integrity": "sha512-/0TJD42KDnVwKmDK6jj3xP7E2MG7SHAOG4tyTgyUCRPdHwvkquYNLEQltmdMa3owq3TkddCVcTsoctJI8VQNKA==" }, + "node_modules/text-extensions": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", + "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -13016,6 +14732,15 @@ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "dependencies": { + "readable-stream": "3" + } + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -13101,6 +14826,15 @@ "tree-kill": "cli.js" } }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/trim-repeated": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-2.0.0.tgz", @@ -13460,6 +15194,16 @@ "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", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -13699,6 +15443,15 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/package.json b/package.json index 9c7beeb..9967735 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,8 @@ }, "devDependencies": { "@biomejs/biome": "1.5.3", + "@commitlint/cli": "^18.6.0", + "@commitlint/config-conventional": "^18.6.0", "@nestjs/cli": "^10.0.0", "@nestjs/schematics": "^10.0.0", "@nestjs/testing": "^10.0.0", @@ -81,6 +83,7 @@ "eslint-plugin-prettier": "^5.0.0", "husky": "^9.0.7", "jest": "^29.5.0", + "lint-staged": "^15.2.1", "prettier": "^3.0.0", "source-map-support": "^0.5.21", "supertest": "^6.3.3", @@ -108,5 +111,8 @@ ], "coverageDirectory": "../coverage", "testEnvironment": "node" + }, + "lint-staged": { + "**.{js|ts|json}": "biome check --apply --no-errors-on-unmatched" } } diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 7199333..b3bbba1 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -92,4 +92,4 @@ model Notifications { enum NotificationType { WARNING INFO -} \ No newline at end of file +} diff --git a/src/app.module.ts b/src/app.module.ts index d7b1740..138c296 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,56 +1,56 @@ +import { FastifyMulterModule } from "@nest-lab/fastify-multer"; import { Module } from "@nestjs/common"; -import { UserModule } from "./users/users.module"; +import { ConfigModule } from "@nestjs/config"; import { APP_GUARD, APP_PIPE } from "@nestjs/core"; +import { ThrottlerGuard, ThrottlerModule } from "@nestjs/throttler"; +import { S3Module } from "nestjs-s3"; +import { ThrottlerStorageRedisService } from "nestjs-throttler-storage-redis"; import { ZodValidationPipe } from "nestjs-zod"; import { AuthModule } from "./auth/auth.module"; -import { ConfigModule } from "@nestjs/config"; import { JwtAuthGuard } from "./auth/jwt-auth.guard"; -import { ThrottlerGuard, ThrottlerModule } from "@nestjs/throttler"; -import { ThrottlerStorageRedisService } from "nestjs-throttler-storage-redis"; import { KweeksModule } from "./kweeks/kweeks.module"; -import { FastifyMulterModule } from "@nest-lab/fastify-multer"; -import { S3Module } from "nestjs-s3"; +import { UserModule } from "./users/users.module"; @Module({ - imports: [ - UserModule, - AuthModule, - ConfigModule.forRoot({ - isGlobal: true, - }), - ThrottlerModule.forRoot({ - throttlers: [{ limit: 10, ttl: 60000 }], - storage: new ThrottlerStorageRedisService( - `redis://:${process.env.REDIS_PASSWORD}@${process.env.REDIS_HOST}:${process.env.REDIS_PORT}/0`, - ), - }), - KweeksModule, - FastifyMulterModule, - S3Module.forRoot({ - config: { - credentials: { - accessKeyId: process.env.MINIO_ROOT_USER, // CHANGE WHEN PRODUCTION TO S3 - secretAccessKey: process.env.MINIO_ROOT_PASSWORD, - }, - region: "us-east-1", - endpoint: process.env.MINIO_ENDPOINT, - forcePathStyle: true, - }, - }), - ], - providers: [ - { - provide: APP_PIPE, - useClass: ZodValidationPipe, - }, - { - provide: APP_GUARD, - useClass: ThrottlerGuard, - }, - { - provide: APP_GUARD, - useClass: JwtAuthGuard, - }, - ], + imports: [ + UserModule, + AuthModule, + ConfigModule.forRoot({ + isGlobal: true, + }), + ThrottlerModule.forRoot({ + throttlers: [{ limit: 10, ttl: 60000 }], + storage: new ThrottlerStorageRedisService( + `redis://:${process.env.REDIS_PASSWORD}@${process.env.REDIS_HOST}:${process.env.REDIS_PORT}/0`, + ), + }), + KweeksModule, + FastifyMulterModule, + S3Module.forRoot({ + config: { + credentials: { + accessKeyId: process.env.MINIO_ROOT_USER, // CHANGE WHEN PRODUCTION TO S3 + secretAccessKey: process.env.MINIO_ROOT_PASSWORD, + }, + region: "us-east-1", + endpoint: process.env.MINIO_ENDPOINT, + forcePathStyle: true, + }, + }), + ], + providers: [ + { + provide: APP_PIPE, + useClass: ZodValidationPipe, + }, + { + provide: APP_GUARD, + useClass: ThrottlerGuard, + }, + { + provide: APP_GUARD, + useClass: JwtAuthGuard, + }, + ], }) export class AppModule {} diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index 8a9115a..cf9ef27 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -1,35 +1,35 @@ import { - Controller, - Request, - Post, - UseGuards, - Body, - HttpCode, + Body, + Controller, + HttpCode, + Post, + Request, + UseGuards, } from "@nestjs/common"; import { - ApiOkResponse, - ApiOperation, - ApiTags, - ApiUnauthorizedResponse, + ApiOkResponse, + ApiOperation, + ApiTags, + ApiUnauthorizedResponse, } from "@nestjs/swagger"; -import { LocalAuthGuard } from "./local-auth.guard"; +import { Public } from "src/public.decorator"; import { AuthService } from "./auth.service"; import { LoginUserDTO } from "./dto/login.dto"; -import { Public } from "src/public.decorator"; +import { LocalAuthGuard } from "./local-auth.guard"; @ApiTags("Auth") @Controller("auth") export class AuthController { - constructor(private authService: AuthService) {} + constructor(private authService: AuthService) {} - @Public() - @UseGuards(LocalAuthGuard) - @Post("/") - @ApiOperation({ summary: "Authenticates a user" }) - @ApiOkResponse({ status: 200, description: "Authenticated successfully" }) - @ApiUnauthorizedResponse({ description: "Wrong username or password" }) - @HttpCode(200) - async login(@Request() req, @Body() _: LoginUserDTO) { - return this.authService.login(req.user); - } + @Public() + @UseGuards(LocalAuthGuard) + @Post("/") + @ApiOperation({ summary: "Authenticates a user" }) + @ApiOkResponse({ status: 200, description: "Authenticated successfully" }) + @ApiUnauthorizedResponse({ description: "Wrong username or password" }) + @HttpCode(200) + async login(@Request() req, @Body() _: LoginUserDTO) { + return this.authService.login(req.user); + } } diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index 6d1e5eb..1166ea5 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -1,22 +1,22 @@ import { Module } from "@nestjs/common"; -import { AuthService } from "./auth.service"; +import { JwtModule } from "@nestjs/jwt"; import { PassportModule } from "@nestjs/passport"; -import { LocalStrategy } from "./local.strategy"; import { UserModule } from "src/users/users.module"; import { AuthController } from "./auth.controller"; -import { JwtModule } from "@nestjs/jwt"; +import { AuthService } from "./auth.service"; import { JwtStrategy } from "./jwt.strategy"; +import { LocalStrategy } from "./local.strategy"; @Module({ - controllers: [AuthController], - imports: [ - UserModule, - PassportModule, - JwtModule.register({ - secret: process.env.JWT_ACCESS_SECRET, - signOptions: { expiresIn: "1d" }, // TODO: add refresh tokens - }), - ], - providers: [AuthService, LocalStrategy, JwtStrategy], + controllers: [AuthController], + imports: [ + UserModule, + PassportModule, + JwtModule.register({ + secret: process.env.JWT_ACCESS_SECRET, + signOptions: { expiresIn: "1d" }, // TODO: add refresh tokens + }), + ], + providers: [AuthService, LocalStrategy, JwtStrategy], }) export class AuthModule {} diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index c52ee07..000e25d 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -1,46 +1,46 @@ import { Injectable } from "@nestjs/common"; -import { UserService } from "src/users/users.service"; +import { JwtService } from "@nestjs/jwt"; import * as bcrypt from "bcrypt"; import { UserModel } from "src/users/models/user.model"; -import { JwtService } from "@nestjs/jwt"; +import { UserService } from "src/users/users.service"; @Injectable() export class AuthService { - constructor( - private userService: UserService, - private jwtService: JwtService, - ) {} + constructor( + private userService: UserService, + private jwtService: JwtService, + ) {} - async validateUser( - username: string, - password: string, - ): Promise { - const user = await this.userService.auth_search(username); + async validateUser( + username: string, + password: string, + ): Promise { + const user = await this.userService.auth_search(username); - if (user === undefined) { - return null; - } + if (user === undefined) { + return null; + } - const validation = await bcrypt.compare(password, user.password); + const validation = await bcrypt.compare(password, user.password); - if (user && validation) { - const { password, ...result } = user; - return result; - } + if (user && validation) { + const { password, ...result } = user; + return result; + } - return null; - } + return null; + } - async login(user: UserModel): Promise<{ token: string }> { - const payload = { - displayName: user.displayName, - username: user.username, - profileImage: user.profileImage, - sub: user.id, - }; + async login(user: UserModel): Promise<{ token: string }> { + const payload = { + displayName: user.displayName, + username: user.username, + profileImage: user.profileImage, + sub: user.id, + }; - return { - token: this.jwtService.sign(payload), - }; - } + return { + token: this.jwtService.sign(payload), + }; + } } diff --git a/src/auth/dto/login.dto.ts b/src/auth/dto/login.dto.ts index 3d7b1d4..33a925d 100644 --- a/src/auth/dto/login.dto.ts +++ b/src/auth/dto/login.dto.ts @@ -2,28 +2,28 @@ import { createZodDto } from "nestjs-zod"; import { z } from "nestjs-zod/z"; export const LoginUserSchema = z - .object({ - username: z - .string({ - required_error: "Username is required", - }) - .regex( - /^[a-zA-Z0-9_.]{5,15}$/, - "The username must have alphanumerics characters, underscore, dots and it must be between 5 and 15 characters", - ) - .toLowerCase(), - password: z - .password({ - required_error: "Password is required", - }) - .min(8) - .max(32) - .atLeastOne("digit") - .atLeastOne("uppercase") - .atLeastOne("lowercase") - .atLeastOne("special") - .transform((value) => value.replace(/\s+/g, "")), // Removes every whitespace - }) - .required(); + .object({ + username: z + .string({ + required_error: "Username is required", + }) + .regex( + /^[a-zA-Z0-9_.]{5,15}$/, + "The username must have alphanumerics characters, underscore, dots and it must be between 5 and 15 characters", + ) + .toLowerCase(), + password: z + .password({ + required_error: "Password is required", + }) + .min(8) + .max(32) + .atLeastOne("digit") + .atLeastOne("uppercase") + .atLeastOne("lowercase") + .atLeastOne("special") + .transform((value) => value.replace(/\s+/g, "")), // Removes every whitespace + }) + .required(); export class LoginUserDTO extends createZodDto(LoginUserSchema) {} diff --git a/src/auth/jwt-auth.guard.ts b/src/auth/jwt-auth.guard.ts index 2054553..54ef454 100644 --- a/src/auth/jwt-auth.guard.ts +++ b/src/auth/jwt-auth.guard.ts @@ -6,20 +6,20 @@ import { IS_PUBLIC_KEY } from "src/public.decorator"; @Injectable() export class JwtAuthGuard extends AuthGuard("jwt") { - constructor(private reflector: Reflector) { - super(); - } + constructor(private reflector: Reflector) { + super(); + } - canActivate( - context: ExecutionContext, - ): boolean | Promise | Observable { - const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [ - context.getHandler(), - context.getClass(), - ]); - if (isPublic) { - return true; - } - return super.canActivate(context); - } + canActivate( + context: ExecutionContext, + ): boolean | Promise | Observable { + const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [ + context.getHandler(), + context.getClass(), + ]); + if (isPublic) { + return true; + } + return super.canActivate(context); + } } diff --git a/src/auth/jwt.strategy.ts b/src/auth/jwt.strategy.ts index 06989b5..bd49542 100644 --- a/src/auth/jwt.strategy.ts +++ b/src/auth/jwt.strategy.ts @@ -3,26 +3,26 @@ import { PassportStrategy } from "@nestjs/passport"; import { ExtractJwt, Strategy } from "passport-jwt"; type Payload = { - displayName: string; - username: string; - sub: string; + displayName: string; + username: string; + sub: string; }; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { - constructor() { - super({ - jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), - ignoreExpiration: false, - secretOrKey: process.env.JWT_ACCESS_SECRET, - }); - } + constructor() { + super({ + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + ignoreExpiration: false, + secretOrKey: process.env.JWT_ACCESS_SECRET, + }); + } - async validate(payload: Payload) { - return { - displayName: payload.displayName, - username: payload.username, - id: payload.sub, - }; - } + async validate(payload: Payload) { + return { + displayName: payload.displayName, + username: payload.username, + id: payload.sub, + }; + } } diff --git a/src/auth/local.strategy.ts b/src/auth/local.strategy.ts index c2cccf6..4370155 100644 --- a/src/auth/local.strategy.ts +++ b/src/auth/local.strategy.ts @@ -1,20 +1,20 @@ import { Injectable, UnauthorizedException } from "@nestjs/common"; import { PassportStrategy } from "@nestjs/passport"; import { Strategy } from "passport-local"; -import { AuthService } from "./auth.service"; import { UserModel } from "src/users/models/user.model"; +import { AuthService } from "./auth.service"; @Injectable() export class LocalStrategy extends PassportStrategy(Strategy) { - constructor(private authService: AuthService) { - super(); - } + constructor(private authService: AuthService) { + super(); + } - async validate(username: string, password: string): Promise { - const user = await this.authService.validateUser(username, password); - if (!user) { - throw new UnauthorizedException("Wrong username or password"); - } - return user; - } + async validate(username: string, password: string): Promise { + const user = await this.authService.validateUser(username, password); + if (!user) { + throw new UnauthorizedException("Wrong username or password"); + } + return user; + } } diff --git a/src/kweeks/dto/create-kweek.dto.ts b/src/kweeks/dto/create-kweek.dto.ts index 04a4ca7..87008c8 100644 --- a/src/kweeks/dto/create-kweek.dto.ts +++ b/src/kweeks/dto/create-kweek.dto.ts @@ -2,10 +2,10 @@ import { createZodDto } from "nestjs-zod"; import { z } from "nestjs-zod/z"; export const CreateKweekSchema = z - .object({ - content: z.string({ required_error: "Kweek content is required" }).max(300), - files: z.array(z.object({})), - }) - .required(); + .object({ + content: z.string({ required_error: "Kweek content is required" }).max(300), + files: z.array(z.object({})), + }) + .required(); export class CreateKweekDTO extends createZodDto(CreateKweekSchema) {} diff --git a/src/kweeks/dto/update-kweek.dto.ts b/src/kweeks/dto/update-kweek.dto.ts index 1b58478..c752e4c 100644 --- a/src/kweeks/dto/update-kweek.dto.ts +++ b/src/kweeks/dto/update-kweek.dto.ts @@ -1,4 +1,4 @@ -import { PartialType } from '@nestjs/swagger'; -import { CreateKweekDto } from './create-kweek.dto'; +import { PartialType } from "@nestjs/swagger"; +import { CreateKweekDto } from "./create-kweek.dto"; export class UpdateKweekDto extends PartialType(CreateKweekDto) {} diff --git a/src/kweeks/kweeks.controller.ts b/src/kweeks/kweeks.controller.ts index 0407f4c..026e4e0 100644 --- a/src/kweeks/kweeks.controller.ts +++ b/src/kweeks/kweeks.controller.ts @@ -37,7 +37,7 @@ export class KweeksController { @UploadedFiles() attachments: File, @Request() req, ) { - return this.kweeksService.create(createKweekDto); + return this.kweeksService.create(createKweekDto); } @Public() diff --git a/src/kweeks/kweeks.module.ts b/src/kweeks/kweeks.module.ts index 175fc3c..a2213d9 100644 --- a/src/kweeks/kweeks.module.ts +++ b/src/kweeks/kweeks.module.ts @@ -1,11 +1,11 @@ import { Module } from "@nestjs/common"; -import { KweeksService } from "./kweeks.service"; -import { KweeksController } from "./kweeks.controller"; import { PrismaModule } from "src/prisma/prisma.module"; +import { KweeksController } from "./kweeks.controller"; +import { KweeksService } from "./kweeks.service"; @Module({ - imports: [PrismaModule], - controllers: [KweeksController], - providers: [KweeksService], + imports: [PrismaModule], + controllers: [KweeksController], + providers: [KweeksService], }) export class KweeksModule {} diff --git a/src/kweeks/kweeks.service.ts b/src/kweeks/kweeks.service.ts index 6489db0..f7021a0 100644 --- a/src/kweeks/kweeks.service.ts +++ b/src/kweeks/kweeks.service.ts @@ -1,24 +1,24 @@ import { Injectable } from "@nestjs/common"; +import { PrismaService } from "src/prisma/prisma.service"; import { CreateKweekDTO } from "./dto/create-kweek.dto"; import { UpdateKweekDto } from "./dto/update-kweek.dto"; -import { PrismaService } from "src/prisma/prisma.service"; @Injectable() export class KweeksService { - constructor(private readonly prisma: PrismaService) {} - create(createKweekDto: CreateKweekDTO) { - return "This action adds a new kweek"; - } + constructor(private readonly prisma: PrismaService) {} + create(createKweekDto: CreateKweekDTO) { + return "This action adds a new kweek"; + } - findOne(id: number) { - return `This action returns a #${id} kweek`; - } + findOne(id: number) { + return `This action returns a #${id} kweek`; + } - update(id: number, updateKweekDto: UpdateKweekDto) { - return `This action updates a #${id} kweek`; - } + update(id: number, updateKweekDto: UpdateKweekDto) { + return `This action updates a #${id} kweek`; + } - remove(id: number) { - return `This action removes a #${id} kweek`; - } + remove(id: number) { + return `This action removes a #${id} kweek`; + } } diff --git a/src/main.ts b/src/main.ts index 13daf2e..0ddd49d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,51 +1,51 @@ -import { NestFactory } from "@nestjs/core"; -import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger"; -import { AppModule } from "./app.module"; -import { patchNestJsSwagger } from "nestjs-zod"; -import { - FastifyAdapter, - NestFastifyApplication, -} from "@nestjs/platform-fastify"; import * as helmet from "@fastify/helmet"; +import { NestFactory } from "@nestjs/core"; +import { + FastifyAdapter, + NestFastifyApplication, +} from "@nestjs/platform-fastify"; +import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger"; +import { patchNestJsSwagger } from "nestjs-zod"; +import { AppModule } from "./app.module"; // TODO: File Upload (Posts and User Profile Image) async function bootstrap() { - const app = await NestFactory.create( - AppModule, - new FastifyAdapter({ logger: true }), - ); + const app = await NestFactory.create( + AppModule, + new FastifyAdapter({ logger: true }), + ); - patchNestJsSwagger(); + patchNestJsSwagger(); - app.enableCors(); + app.enableCors(); - const config = new DocumentBuilder() - .setTitle("Project Knedita") - .setDescription("An open-source social media") - .setVersion("1.0") - .addBearerAuth( - { - type: "http", - scheme: "bearer", - bearerFormat: "JWT", - name: "JWT", - description: "Enter JWT Token", - in: "header", - }, - "JWT", - ) - .addTag("Auth") - .addTag("Kweeks") - .addTag("Users") - .build(); + const config = new DocumentBuilder() + .setTitle("Project Knedita") + .setDescription("An open-source social media") + .setVersion("1.0") + .addBearerAuth( + { + type: "http", + scheme: "bearer", + bearerFormat: "JWT", + name: "JWT", + description: "Enter JWT Token", + in: "header", + }, + "JWT", + ) + .addTag("Auth") + .addTag("Kweeks") + .addTag("Users") + .build(); - const document = SwaggerModule.createDocument(app, config); + const document = SwaggerModule.createDocument(app, config); - SwaggerModule.setup("/", app, document); + SwaggerModule.setup("/", app, document); - await app.register(helmet); + await app.register(helmet); - await app.listen(process.env.SERVER_PORT, process.env.SERVER_HOST); + await app.listen(process.env.SERVER_PORT, process.env.SERVER_HOST); } bootstrap(); diff --git a/src/prisma/prisma.module.ts b/src/prisma/prisma.module.ts index 5671cd6..e3bfba9 100644 --- a/src/prisma/prisma.module.ts +++ b/src/prisma/prisma.module.ts @@ -2,7 +2,7 @@ import { Module } from "@nestjs/common"; import { PrismaService } from "./prisma.service"; @Module({ - providers: [PrismaService], - exports: [PrismaService], + providers: [PrismaService], + exports: [PrismaService], }) export class PrismaModule {} diff --git a/src/prisma/prisma.service.ts b/src/prisma/prisma.service.ts index 9082f78..c2cfd4d 100644 --- a/src/prisma/prisma.service.ts +++ b/src/prisma/prisma.service.ts @@ -3,16 +3,16 @@ import { Prisma, PrismaClient } from "@prisma/client"; @Injectable() export class PrismaService - extends PrismaClient - implements OnModuleInit + extends PrismaClient + implements OnModuleInit { - async onModuleInit() { - await this.$connect(); - } + async onModuleInit() { + await this.$connect(); + } - async enableShutdownHooks(app: INestApplication) { - this.$on("beforeExit", async () => { - await app.close(); - }); - } + async enableShutdownHooks(app: INestApplication) { + this.$on("beforeExit", async () => { + await app.close(); + }); + } } diff --git a/src/users/dto/create-user.dto.ts b/src/users/dto/create-user.dto.ts index 0cda679..f2004c5 100644 --- a/src/users/dto/create-user.dto.ts +++ b/src/users/dto/create-user.dto.ts @@ -2,33 +2,33 @@ import { createZodDto } from "nestjs-zod"; import { z } from "nestjs-zod/z"; export const CreateUserSchema = z - .object({ - username: z - .string({ - required_error: "Username is required", - }) - .regex( - /^[a-zA-Z0-9_.]{5,15}$/, - "The username must have alphanumerics characters, underscore, dots and it must be between 5 and 15 characters", - ) - .toLowerCase(), - email: z - .string({ - required_error: "Email is required", - }) - .email("Invalid email"), - password: z - .password({ - required_error: "Password is required", - }) - .min(8) - .max(32) - .atLeastOne("digit") - .atLeastOne("uppercase") - .atLeastOne("lowercase") - .atLeastOne("special") - .transform((value) => value.replace(/\s+/g, "")), // Removes every whitespace - }) - .required(); + .object({ + username: z + .string({ + required_error: "Username is required", + }) + .regex( + /^[a-zA-Z0-9_.]{5,15}$/, + "The username must have alphanumerics characters, underscore, dots and it must be between 5 and 15 characters", + ) + .toLowerCase(), + email: z + .string({ + required_error: "Email is required", + }) + .email("Invalid email"), + password: z + .password({ + required_error: "Password is required", + }) + .min(8) + .max(32) + .atLeastOne("digit") + .atLeastOne("uppercase") + .atLeastOne("lowercase") + .atLeastOne("special") + .transform((value) => value.replace(/\s+/g, "")), // Removes every whitespace + }) + .required(); export class CreateUserDTO extends createZodDto(CreateUserSchema) {} diff --git a/src/users/dto/update-email.dto.ts b/src/users/dto/update-email.dto.ts index 6b2e2c1..c0093cd 100644 --- a/src/users/dto/update-email.dto.ts +++ b/src/users/dto/update-email.dto.ts @@ -2,13 +2,13 @@ import { createZodDto } from "nestjs-zod"; import { z } from "nestjs-zod/z"; export const UpdateEmailSchema = z - .object({ - email: z - .string({ - required_error: "Email is required", - }) - .email("Invalid email"), - }) - .required(); + .object({ + email: z + .string({ + required_error: "Email is required", + }) + .email("Invalid email"), + }) + .required(); export class UpdateEmailDTO extends createZodDto(UpdateEmailSchema) {} diff --git a/src/users/dto/update-name.dto.ts b/src/users/dto/update-name.dto.ts index 1395d0d..77f41fd 100644 --- a/src/users/dto/update-name.dto.ts +++ b/src/users/dto/update-name.dto.ts @@ -2,19 +2,19 @@ import { createZodDto } from "nestjs-zod"; import { z } from "nestjs-zod/z"; export const UpdateNameSchema = z - .object({ - username: z - .string() - .regex( - /^[a-zA-Z0-9_.]{5,15}$/, - "The username must have alphanumerics characters, underscore, dots and it must be between 5 and 15 characters", - ) - .toLowerCase() - .describe("New username - optional") - .optional() - .or(z.literal("")), - displayName: z.string({ required_error: "Display name is required" }), - }) - .required(); + .object({ + username: z + .string() + .regex( + /^[a-zA-Z0-9_.]{5,15}$/, + "The username must have alphanumerics characters, underscore, dots and it must be between 5 and 15 characters", + ) + .toLowerCase() + .describe("New username - optional") + .optional() + .or(z.literal("")), + displayName: z.string({ required_error: "Display name is required" }), + }) + .required(); export class UpdateNameDTO extends createZodDto(UpdateNameSchema) {} diff --git a/src/users/dto/update-password.dto.ts b/src/users/dto/update-password.dto.ts index 09709be..90231cd 100644 --- a/src/users/dto/update-password.dto.ts +++ b/src/users/dto/update-password.dto.ts @@ -4,30 +4,30 @@ import { z } from "nestjs-zod/z"; // TODO: see if it can be refactored export const UpdatePasswordSchema = z - .object({ - old_password: z - .password({ - required_error: "Password is required", - }) - .min(8) - .max(32) - .atLeastOne("digit") - .atLeastOne("uppercase") - .atLeastOne("lowercase") - .atLeastOne("special") - .transform((value) => value.replace(/\s+/g, "")), - new_password: z - .password({ - required_error: "Password is required", - }) - .min(8) - .max(32) - .atLeastOne("digit") - .atLeastOne("uppercase") - .atLeastOne("lowercase") - .atLeastOne("special") - .transform((value) => value.replace(/\s+/g, "")), - }) - .required(); + .object({ + old_password: z + .password({ + required_error: "Password is required", + }) + .min(8) + .max(32) + .atLeastOne("digit") + .atLeastOne("uppercase") + .atLeastOne("lowercase") + .atLeastOne("special") + .transform((value) => value.replace(/\s+/g, "")), + new_password: z + .password({ + required_error: "Password is required", + }) + .min(8) + .max(32) + .atLeastOne("digit") + .atLeastOne("uppercase") + .atLeastOne("lowercase") + .atLeastOne("special") + .transform((value) => value.replace(/\s+/g, "")), + }) + .required(); export class UpdatePasswordDTO extends createZodDto(UpdatePasswordSchema) {} diff --git a/src/users/models/user.model.ts b/src/users/models/user.model.ts index 775b521..13c3e23 100644 --- a/src/users/models/user.model.ts +++ b/src/users/models/user.model.ts @@ -2,21 +2,21 @@ import { createZodDto } from "nestjs-zod"; import { z } from "nestjs-zod/z"; export const UserSchema = z - .object({ - id: z.string().uuid(), - displayName: z.string().optional(), - username: z.string(), - email: z.string().email(), - password: z.password(), - kweeks: z.array(z.object({})).optional(), - profileImage: z.string().url().optional(), - likedKweeks: z.array(z.object({})).optional(), - likedComments: z.array(z.object({})).optional(), - followers: z.number(), - following: z.number(), - kweeksComments: z.array(z.object({})).optional(), - createdAt: z.date(), - }) - .required(); + .object({ + id: z.string().uuid(), + displayName: z.string().optional(), + username: z.string(), + email: z.string().email(), + password: z.password(), + kweeks: z.array(z.object({})).optional(), + profileImage: z.string().url().optional(), + likedKweeks: z.array(z.object({})).optional(), + likedComments: z.array(z.object({})).optional(), + followers: z.number(), + following: z.number(), + kweeksComments: z.array(z.object({})).optional(), + createdAt: z.date(), + }) + .required(); export class UserModel extends createZodDto(UserSchema) {} diff --git a/src/users/s3.service.ts b/src/users/s3.service.ts index 1c51e0a..01fd281 100644 --- a/src/users/s3.service.ts +++ b/src/users/s3.service.ts @@ -5,34 +5,34 @@ import sharp from "sharp"; @Injectable() export class S3Service { - constructor(@InjectS3() private readonly s3: S3) {} + constructor(@InjectS3() private readonly s3: S3) {} - /** - * Returns the image url if the upload to minio was successful. - */ - async uploadImageToMinio(userID: string, buffer: Buffer): Promise { - const compressedBuffer = await sharp(buffer) - .resize(200, 200) - .webp({ quality: 70 }) - .toBuffer(); + /** + * Returns the image url if the upload to minio was successful. + */ + async uploadImageToMinio(userID: string, buffer: Buffer): Promise { + const compressedBuffer = await sharp(buffer) + .resize(200, 200) + .webp({ quality: 70 }) + .toBuffer(); - const uploadParams: PutObjectCommandInput = { - Bucket: process.env.MINIO_DEFAULT_BUCKETS, - Key: `profile_images/${userID}.webp`, - Body: compressedBuffer, - ContentType: "image/webp", - ContentDisposition: "inline", - ACL: "public-read", - }; + const uploadParams: PutObjectCommandInput = { + Bucket: process.env.MINIO_DEFAULT_BUCKETS, + Key: `profile_images/${userID}.webp`, + Body: compressedBuffer, + ContentType: "image/webp", + ContentDisposition: "inline", + ACL: "public-read", + }; - const { ETag } = await this.s3.send(new PutObjectCommand(uploadParams)); + const { ETag } = await this.s3.send(new PutObjectCommand(uploadParams)); - if (ETag !== null) { - return `${process.env.MINIO_ENDPOINT}/${process.env.MINIO_DEFAULT_BUCKETS}/profile_images/${userID}.webp`; - } + if (ETag !== null) { + return `${process.env.MINIO_ENDPOINT}/${process.env.MINIO_DEFAULT_BUCKETS}/profile_images/${userID}.webp`; + } - throw new InternalServerErrorException( - "Failed to upload the profile image", - ); - } + throw new InternalServerErrorException( + "Failed to upload the profile image", + ); + } } diff --git a/src/users/schemas/upload-image.schema.ts b/src/users/schemas/upload-image.schema.ts index 3ec8f27..0ff1500 100644 --- a/src/users/schemas/upload-image.schema.ts +++ b/src/users/schemas/upload-image.schema.ts @@ -1,14 +1,14 @@ const UploadImageSchema = { - required: true, - schema: { - type: "object", - properties: { - image: { - type: "string", - format: "binary", - }, - }, - }, + required: true, + schema: { + type: "object", + properties: { + image: { + type: "string", + format: "binary", + }, + }, + }, }; export default UploadImageSchema; diff --git a/src/users/types/user.type.ts b/src/users/types/user.type.ts index be1d8d5..39b2e1f 100644 --- a/src/users/types/user.type.ts +++ b/src/users/types/user.type.ts @@ -1,5 +1,5 @@ export type User = { - displayName: string; - username: string; - id: string; + displayName: string; + username: string; + id: string; }; diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts index 593aea1..eabc00c 100644 --- a/src/users/users.controller.ts +++ b/src/users/users.controller.ts @@ -1,129 +1,129 @@ +import { File, FileInterceptor } from "@nest-lab/fastify-multer"; import { - Body, - Controller, - Delete, - Get, - HttpCode, - Param, - Patch, - Post, - Request, - UploadedFile, - UseInterceptors, + Body, + Controller, + Delete, + Get, + HttpCode, + Param, + Patch, + Post, + Request, + UploadedFile, + UseInterceptors, } from "@nestjs/common"; import { - ApiBadRequestResponse, - ApiBearerAuth, - ApiBody, - ApiConsumes, - ApiCreatedResponse, - ApiNotFoundResponse, - ApiOperation, - ApiTags, - ApiUnauthorizedResponse, + ApiBadRequestResponse, + ApiBearerAuth, + ApiBody, + ApiConsumes, + ApiCreatedResponse, + ApiNotFoundResponse, + ApiOperation, + ApiTags, + ApiUnauthorizedResponse, } from "@nestjs/swagger"; -import { UserService } from "./users.service"; -import { CreateUserDTO } from "./dto/create-user.dto"; import { Public } from "src/public.decorator"; -import { UpdateNameDTO } from "./dto/update-name.dto"; -import { User } from "./types/user.type"; -import { UpdateEmailDTO } from "./dto/update-email.dto"; -import { UpdatePasswordDTO } from "./dto/update-password.dto"; -import { File, FileInterceptor } from "@nest-lab/fastify-multer"; import { BufferValidator } from "src/validators/buffer-validator.pipe"; -import UploadImageSchema from "./schemas/upload-image.schema"; import UploadImageValidator from "src/validators/upload-image.validator"; +import { CreateUserDTO } from "./dto/create-user.dto"; +import { UpdateEmailDTO } from "./dto/update-email.dto"; +import { UpdateNameDTO } from "./dto/update-name.dto"; +import { UpdatePasswordDTO } from "./dto/update-password.dto"; +import UploadImageSchema from "./schemas/upload-image.schema"; +import { User } from "./types/user.type"; +import { UserService } from "./users.service"; @ApiTags("Users") @Controller("users") export class UserController { - constructor(private readonly userService: UserService) {} - // POST - @Public() - @Post() - @ApiOperation({ summary: "Creates a new account" }) - @ApiCreatedResponse({ description: "Account created successfully" }) - @ApiBadRequestResponse({ - description: - "Missing field / Invalid username / Invalid email / Weak password", - }) - create(@Body() createUserDTO: CreateUserDTO) { - return this.userService.create(createUserDTO); - } + constructor(private readonly userService: UserService) {} + // POST + @Public() + @Post() + @ApiOperation({ summary: "Creates a new account" }) + @ApiCreatedResponse({ description: "Account created successfully" }) + @ApiBadRequestResponse({ + description: + "Missing field / Invalid username / Invalid email / Weak password", + }) + create(@Body() createUserDTO: CreateUserDTO) { + return this.userService.create(createUserDTO); + } - // GET - @Get("/profile") - @ApiOperation({ summary: "Returns information about the logged user" }) - @ApiBearerAuth("JWT") - @ApiUnauthorizedResponse({ - description: "Not authenticated / Invalid JWT Token", - }) - me(@Request() req) { - return req.user; - } + // GET + @Get("/profile") + @ApiOperation({ summary: "Returns information about the logged user" }) + @ApiBearerAuth("JWT") + @ApiUnauthorizedResponse({ + description: "Not authenticated / Invalid JWT Token", + }) + me(@Request() req) { + return req.user; + } - @Public() - @Get(":username") - @ApiOperation({ summary: "Returns information about a user" }) - @ApiNotFoundResponse({ description: "User not found" }) - @HttpCode(200) - info(@Param("username") username: string) { - return this.userService.info(username); - } + @Public() + @Get(":username") + @ApiOperation({ summary: "Returns information about a user" }) + @ApiNotFoundResponse({ description: "User not found" }) + @HttpCode(200) + info(@Param("username") username: string) { + return this.userService.info(username); + } - // PATCH - @Patch() - @ApiOperation({ - summary: "Updates the username or display name of a logged user", - }) - @ApiBearerAuth("JWT") - updateName(@Body() { displayName, username }: UpdateNameDTO, @Request() req) { - return this.userService.updateName(req.user as User, username, displayName); - } + // PATCH + @Patch() + @ApiOperation({ + summary: "Updates the username or display name of a logged user", + }) + @ApiBearerAuth("JWT") + updateName(@Body() { displayName, username }: UpdateNameDTO, @Request() req) { + return this.userService.updateName(req.user as User, username, displayName); + } - @Patch("/email") - @ApiOperation({ summary: "Updates the email of a logged user" }) - @ApiBearerAuth("JWT") - updateEmail(@Body() body: UpdateEmailDTO, @Request() req) { - return this.userService.updateEmail(req.user as User, body.email); - } + @Patch("/email") + @ApiOperation({ summary: "Updates the email of a logged user" }) + @ApiBearerAuth("JWT") + updateEmail(@Body() body: UpdateEmailDTO, @Request() req) { + return this.userService.updateEmail(req.user as User, body.email); + } - @Patch("/password") - @ApiOperation({ summary: "Updates the password of a logged user" }) - @ApiBearerAuth("JWT") - updatePassword( - @Body() { old_password, new_password }: UpdatePasswordDTO, - @Request() req, - ) { - return this.userService.updatePassword( - req.user as User, - old_password, - new_password, - ); - } + @Patch("/password") + @ApiOperation({ summary: "Updates the password of a logged user" }) + @ApiBearerAuth("JWT") + updatePassword( + @Body() { old_password, new_password }: UpdatePasswordDTO, + @Request() req, + ) { + return this.userService.updatePassword( + req.user as User, + old_password, + new_password, + ); + } - @Patch("/image") - @ApiOperation({ - summary: "Add a profile image", - }) - @ApiBearerAuth("JWT") - @UseInterceptors(FileInterceptor("image")) - @ApiConsumes("multipart/form-data") - @ApiBody(UploadImageSchema) - uploadProfileImage( - @UploadedFile( - UploadImageValidator, - new BufferValidator(), // Magic number validation - ) - image: File, - @Request() req, - ) { - return this.userService.uploadImage(req.user, image); - } + @Patch("/image") + @ApiOperation({ + summary: "Add a profile image", + }) + @ApiBearerAuth("JWT") + @UseInterceptors(FileInterceptor("image")) + @ApiConsumes("multipart/form-data") + @ApiBody(UploadImageSchema) + uploadProfileImage( + @UploadedFile( + UploadImageValidator, + new BufferValidator(), // Magic number validation + ) + image: File, + @Request() req, + ) { + return this.userService.uploadImage(req.user, image); + } - // DELETE - @Delete() - @ApiOperation({ summary: "Deletes the account of a logged user" }) - @ApiBearerAuth("JWT") - remove() {} + // DELETE + @Delete() + @ApiOperation({ summary: "Deletes the account of a logged user" }) + @ApiBearerAuth("JWT") + remove() {} } diff --git a/src/users/users.module.ts b/src/users/users.module.ts index 16502f8..72a2381 100644 --- a/src/users/users.module.ts +++ b/src/users/users.module.ts @@ -1,13 +1,13 @@ import { Module } from "@nestjs/common"; -import { UserController } from "./users.controller"; -import { UserService } from "./users.service"; import { PrismaModule } from "src/prisma/prisma.module"; import { S3Service } from "./s3.service"; +import { UserController } from "./users.controller"; +import { UserService } from "./users.service"; @Module({ - imports: [PrismaModule], - controllers: [UserController], - providers: [UserService, S3Service], - exports: [UserService], + imports: [PrismaModule], + controllers: [UserController], + providers: [UserService, S3Service], + exports: [UserService], }) export class UserModule {} diff --git a/src/users/users.service.ts b/src/users/users.service.ts index cbc7845..0656c4c 100644 --- a/src/users/users.service.ts +++ b/src/users/users.service.ts @@ -1,221 +1,221 @@ -import { - BadRequestException, - Injectable, - NotFoundException, -} from "@nestjs/common"; -import { CreateUserDTO } from "./dto/create-user.dto"; -import { PrismaService } from "src/prisma/prisma.service"; -import { UserModel } from "./models/user.model"; -import * as bcrypt from "bcrypt"; -import { User } from "./types/user.type"; import { File } from "@nest-lab/fastify-multer"; +import { + BadRequestException, + Injectable, + NotFoundException, +} from "@nestjs/common"; +import * as bcrypt from "bcrypt"; +import { PrismaService } from "src/prisma/prisma.service"; +import { CreateUserDTO } from "./dto/create-user.dto"; +import { UserModel } from "./models/user.model"; import { S3Service } from "./s3.service"; +import { User } from "./types/user.type"; @Injectable() export class UserService { - constructor( - private readonly prisma: PrismaService, - private readonly s3: S3Service, - ) {} - async auth_search(username: string): Promise { - const user = await this.prisma.user.findFirst({ - where: { - username, - }, - select: { - id: true, - profileImage: true, - displayName: true, - username: true, - password: true, - }, - }); + constructor( + private readonly prisma: PrismaService, + private readonly s3: S3Service, + ) {} + async auth_search(username: string): Promise { + const user = await this.prisma.user.findFirst({ + where: { + username, + }, + select: { + id: true, + profileImage: true, + displayName: true, + username: true, + password: true, + }, + }); - if (user == null) { - return undefined; - } + if (user == null) { + return undefined; + } - return user; - } + return user; + } - async info(username: string): Promise { - const user = await this.prisma.user.findFirst({ - where: { username }, - select: { - id: true, - profileImage: true, - displayName: true, - username: true, - createdAt: true, - followers: true, - following: true, - kweeks: { - select: { - id: true, - content: true, - createdAt: true, - updatedAt: true, - }, - }, - }, - }); + async info(username: string): Promise { + const user = await this.prisma.user.findFirst({ + where: { username }, + select: { + id: true, + profileImage: true, + displayName: true, + username: true, + createdAt: true, + followers: true, + following: true, + kweeks: { + select: { + id: true, + content: true, + createdAt: true, + updatedAt: true, + }, + }, + }, + }); - if (user === null) { - throw new NotFoundException("User not found"); - } + if (user === null) { + throw new NotFoundException("User not found"); + } - return { - ...user, - followers: user.followers.length, - following: user.following.length, - }; - } + return { + ...user, + followers: user.followers.length, + following: user.following.length, + }; + } - async create({ - username, - email, - password, - }: CreateUserDTO): Promise< - Pick - > { - if ((await this.prisma.user.findFirst({ where: { username } })) != null) { - throw new BadRequestException("Username already in use"); - } + async create({ + username, + email, + password, + }: CreateUserDTO): Promise< + Pick + > { + if ((await this.prisma.user.findFirst({ where: { username } })) != null) { + throw new BadRequestException("Username already in use"); + } - if ((await this.prisma.user.findFirst({ where: { email } })) != null) { - throw new BadRequestException("Email already in use"); - } + if ((await this.prisma.user.findFirst({ where: { email } })) != null) { + throw new BadRequestException("Email already in use"); + } - // Password encryption - const salt = await bcrypt.genSalt(15); - const hash = await bcrypt.hash(password, salt); + // Password encryption + const salt = await bcrypt.genSalt(15); + const hash = await bcrypt.hash(password, salt); - const user = await this.prisma.user.create({ - data: { - username, - email, - password: hash, - }, - select: { - displayName: true, - username: true, - createdAt: true, - }, - }); + const user = await this.prisma.user.create({ + data: { + username, + email, + password: hash, + }, + select: { + displayName: true, + username: true, + createdAt: true, + }, + }); - return user; - } + return user; + } - async updateEmail( - loggedUser: User, - email: string, - ): Promise<{ message: string }> { - const user = await this.prisma.user.findFirst({ - where: { id: loggedUser.id }, - }); + async updateEmail( + loggedUser: User, + email: string, + ): Promise<{ message: string }> { + const user = await this.prisma.user.findFirst({ + where: { id: loggedUser.id }, + }); - if (email !== undefined && email.trim() !== user.email) { - const isAlreadyInUse = await this.prisma.user.findFirst({ - where: { email }, - }); - if (isAlreadyInUse != null && isAlreadyInUse.email !== user.email) { - throw new BadRequestException("Email already in use"); - } + if (email !== undefined && email.trim() !== user.email) { + const isAlreadyInUse = await this.prisma.user.findFirst({ + where: { email }, + }); + if (isAlreadyInUse != null && isAlreadyInUse.email !== user.email) { + throw new BadRequestException("Email already in use"); + } - await this.prisma.user.update({ - where: { - id: loggedUser.id, - }, - data: { - email: email ?? user.email, - }, - }); + await this.prisma.user.update({ + where: { + id: loggedUser.id, + }, + data: { + email: email ?? user.email, + }, + }); - return { message: "Email updated successfully" }; - } - } + return { message: "Email updated successfully" }; + } + } - async updateName( - loggedUser: User, - username: string | undefined, - displayName: string, - ): Promise> { - const user = await this.prisma.user.findFirst({ - where: { id: loggedUser.id }, - }); + async updateName( + loggedUser: User, + username: string | undefined, + displayName: string, + ): Promise> { + const user = await this.prisma.user.findFirst({ + where: { id: loggedUser.id }, + }); - if (username !== undefined && username.trim() !== user.username) { - const isAlreadyInUse = await this.prisma.user.findFirst({ - where: { username }, - }); - if (isAlreadyInUse != null && isAlreadyInUse.username !== user.username) { - throw new BadRequestException("Username already in use"); - } - } + if (username !== undefined && username.trim() !== user.username) { + const isAlreadyInUse = await this.prisma.user.findFirst({ + where: { username }, + }); + if (isAlreadyInUse != null && isAlreadyInUse.username !== user.username) { + throw new BadRequestException("Username already in use"); + } + } - return await this.prisma.user.update({ - where: { - id: loggedUser.id, - }, - data: { - displayName, - username: username ?? user.username, - }, - select: { - displayName: true, - username: true, - }, - }); - } + return await this.prisma.user.update({ + where: { + id: loggedUser.id, + }, + data: { + displayName, + username: username ?? user.username, + }, + select: { + displayName: true, + username: true, + }, + }); + } - async updatePassword( - loggedUser: User, - old_password: string, - new_password: string, - ): Promise<{ message: string }> { - const id = loggedUser.id; + async updatePassword( + loggedUser: User, + old_password: string, + new_password: string, + ): Promise<{ message: string }> { + const id = loggedUser.id; - const user = await this.prisma.user.findFirst({ - where: { id }, - }); + const user = await this.prisma.user.findFirst({ + where: { id }, + }); - const validatePassword = await bcrypt.compare(old_password, user.password); + const validatePassword = await bcrypt.compare(old_password, user.password); - if (!validatePassword) { - throw new BadRequestException("Wrong password"); - } + if (!validatePassword) { + throw new BadRequestException("Wrong password"); + } - const salt = await bcrypt.genSalt(15); - const hash = await bcrypt.hash(new_password, salt); + const salt = await bcrypt.genSalt(15); + const hash = await bcrypt.hash(new_password, salt); - await this.prisma.user.update({ - where: { - id, - }, - data: { - password: hash, - }, - }); + await this.prisma.user.update({ + where: { + id, + }, + data: { + password: hash, + }, + }); - return { message: "Password updated successfully" }; - } + return { message: "Password updated successfully" }; + } - async uploadImage(authenticatedUser: User, image: File) { - const url = await this.s3.uploadImageToMinio( - authenticatedUser.id, - image.buffer, - ); + async uploadImage(authenticatedUser: User, image: File) { + const url = await this.s3.uploadImageToMinio( + authenticatedUser.id, + image.buffer, + ); - return await this.prisma.user.update({ - where: { - id: authenticatedUser.id, - }, - data: { - profileImage: url, - }, - select: { - profileImage: true, - }, - }); - } + return await this.prisma.user.update({ + where: { + id: authenticatedUser.id, + }, + data: { + profileImage: url, + }, + select: { + profileImage: true, + }, + }); + } } diff --git a/src/validators/buffer-validator.pipe.ts b/src/validators/buffer-validator.pipe.ts index cc59248..589194d 100644 --- a/src/validators/buffer-validator.pipe.ts +++ b/src/validators/buffer-validator.pipe.ts @@ -6,20 +6,20 @@ import { BadRequestException, Injectable, PipeTransform } from "@nestjs/common"; */ @Injectable() export class BufferValidator implements PipeTransform { - async transform(value: File) { - const { fileTypeFromBuffer } = await (eval( - 'import("file-type")', - ) as Promise); + async transform(value: File) { + const { fileTypeFromBuffer } = await (eval( + 'import("file-type")', + ) as Promise); - const ALLOWED_MIMES = ["image/jpeg", "image/png", "image/webp"]; - const Type = await fileTypeFromBuffer(value.buffer); + const ALLOWED_MIMES = ["image/jpeg", "image/png", "image/webp"]; + const Type = await fileTypeFromBuffer(value.buffer); - if (!Type || !ALLOWED_MIMES.includes(Type.mime)) { - throw new BadRequestException( - "Invalid file type. Should be jpeg, png or webp", - ); - } + if (!Type || !ALLOWED_MIMES.includes(Type.mime)) { + throw new BadRequestException( + "Invalid file type. Should be jpeg, png or webp", + ); + } - return value; - } + return value; + } } diff --git a/src/validators/upload-image.validator.ts b/src/validators/upload-image.validator.ts index 36004b0..b3b9c3f 100644 --- a/src/validators/upload-image.validator.ts +++ b/src/validators/upload-image.validator.ts @@ -1,17 +1,17 @@ import { - FileTypeValidator, - MaxFileSizeValidator, - ParseFilePipe, + FileTypeValidator, + MaxFileSizeValidator, + ParseFilePipe, } from "@nestjs/common"; const UploadImageValidator = new ParseFilePipe({ - validators: [ - new MaxFileSizeValidator({ - maxSize: 15 * 1024 * 1024, - message: "File too big. Max 1MB.", - }), - new FileTypeValidator({ fileType: /^image\/(jpeg|png|webp)$/ }), // File extension validation - ], + validators: [ + new MaxFileSizeValidator({ + maxSize: 15 * 1024 * 1024, + message: "File too big. Max 1MB.", + }), + new FileTypeValidator({ fileType: /^image\/(jpeg|png|webp)$/ }), // File extension validation + ], }); export default UploadImageValidator; diff --git a/test/app.e2e-spec.ts b/test/app.e2e-spec.ts index 50cda62..23c007e 100644 --- a/test/app.e2e-spec.ts +++ b/test/app.e2e-spec.ts @@ -1,24 +1,24 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { INestApplication } from '@nestjs/common'; -import * as request from 'supertest'; -import { AppModule } from './../src/app.module'; +import { INestApplication } from "@nestjs/common"; +import { Test, TestingModule } from "@nestjs/testing"; +import * as request from "supertest"; +import { AppModule } from "./../src/app.module"; -describe('AppController (e2e)', () => { - let app: INestApplication; +describe("AppController (e2e)", () => { + let app: INestApplication; - beforeEach(async () => { - const moduleFixture: TestingModule = await Test.createTestingModule({ - imports: [AppModule], - }).compile(); + beforeEach(async () => { + const moduleFixture: TestingModule = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); - app = moduleFixture.createNestApplication(); - await app.init(); - }); + app = moduleFixture.createNestApplication(); + await app.init(); + }); - it('/ (GET)', () => { - return request(app.getHttpServer()) - .get('/') - .expect(200) - .expect('Hello World!'); - }); + it("/ (GET)", () => { + return request(app.getHttpServer()) + .get("/") + .expect(200) + .expect("Hello World!"); + }); }); diff --git a/test/jest-e2e.json b/test/jest-e2e.json index e9d912f..f43e8a6 100644 --- a/test/jest-e2e.json +++ b/test/jest-e2e.json @@ -1,9 +1,9 @@ { - "moduleFileExtensions": ["js", "json", "ts"], - "rootDir": ".", - "testEnvironment": "node", - "testRegex": ".e2e-spec.ts$", - "transform": { - "^.+\\.(t|j)s$": "ts-jest" - } + "moduleFileExtensions": ["js", "json", "ts"], + "rootDir": ".", + "testEnvironment": "node", + "testRegex": ".e2e-spec.ts$", + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + } } diff --git a/tsconfig.build.json b/tsconfig.build.json index 64f86c6..4491981 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,4 +1,4 @@ { - "extends": "./tsconfig.json", - "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] + "extends": "./tsconfig.json", + "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] }