From ad33c532ca02f543b1da2c4b27696cf59f71adb4 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 16 Nov 2023 15:11:47 +0900 Subject: [PATCH 001/170] =?UTF-8?q?setting:=20=EC=84=9C=EB=B2=84=20?= =?UTF-8?q?=EB=B0=B0=ED=8F=AC=20=EC=9E=90=EB=8F=99=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit github actions와 Docker를 사용한 배포 자동화 Co-authored-by: Yong --- .github/workflows/BE-deploy.yml | 33 +++++++++++++++++++++++++++++++++ nestjs-BE/.dockerignore | 10 ++++++++++ nestjs-BE/Dockerfile | 13 +++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 .github/workflows/BE-deploy.yml create mode 100644 nestjs-BE/.dockerignore create mode 100644 nestjs-BE/Dockerfile diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml new file mode 100644 index 00000000..6e4b5072 --- /dev/null +++ b/.github/workflows/BE-deploy.yml @@ -0,0 +1,33 @@ +name: BE-deploy +on: + push: + branches: + - "BE-develop" +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + run: | + git clone https://github.com/boostcampwm2023/and07-MindSync.git mindsync + cd mindSync/nestjs-BE + - name: Login to github Packages + run: echo ${{ secrets.PACKAGE_ACCESS_TOKEN }} | docker login ghcr.io -u ${{ secrets.PACKAGE_USERNAME }} --password-stdin + - name: Build and push Docker image + run: | + docker build -t ghcr.io/${{ secrets.PACKGE_USERNAME }}/mindsync . + docker push ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync:latest + + deploy: + runs-on: ubuntu-latest + step: + - name: Pull Docker image + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.REMOTE_HOST }} + username: ${{ secrets.REMOTE_USER }} + key: ${{ secrets.REMOTE_SSH_KEY }} + script: | + echo ${{ secrets.PACKAGE_ACCESS_TOKEN }} | docker login ghcr.io -u ${{ secrets.PACKAGE_USERNAME }} --password-stdin + docker pull ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync + docker run -p 3000:3000 ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync diff --git a/nestjs-BE/.dockerignore b/nestjs-BE/.dockerignore new file mode 100644 index 00000000..56296465 --- /dev/null +++ b/nestjs-BE/.dockerignore @@ -0,0 +1,10 @@ +README.md +/node_modules +/test + +.eslintrc.js +.gitignore +.prettierrc +nest-cli.json + +*.spec.ts diff --git a/nestjs-BE/Dockerfile b/nestjs-BE/Dockerfile new file mode 100644 index 00000000..9b939a5c --- /dev/null +++ b/nestjs-BE/Dockerfile @@ -0,0 +1,13 @@ +FROM node:20.4.0-alpine + +WORKDIR /server + +COPY package.json package-lock.json ./ + +RUN npm ci + +COPY ./ ./ + +EXPOSE 3000 + +CMD ["npm", "start"] From aa492c37101c1cc559d577e03af56630b4568fe5 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 16 Nov 2023 15:14:59 +0900 Subject: [PATCH 002/170] =?UTF-8?q?fix:=20=EC=98=A4=ED=83=88=EC=9E=90=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yong --- .github/workflows/BE-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index 6e4b5072..5ac53a80 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -20,7 +20,7 @@ jobs: deploy: runs-on: ubuntu-latest - step: + steps: - name: Pull Docker image uses: appleboy/ssh-action@master with: From 8cd9cf6693b1f83a605608cf4589610e6c5f18d0 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 16 Nov 2023 15:40:04 +0900 Subject: [PATCH 003/170] =?UTF-8?q?fix:=20=EB=B0=B0=ED=8F=AC=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=ED=99=94=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit actions/checkout 사용 Co-authored-by: Yong --- .github/workflows/BE-deploy.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index 5ac53a80..ae93d2a0 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -7,24 +7,25 @@ jobs: build: runs-on: ubuntu-latest steps: - - name: Checkout code - run: | - git clone https://github.com/boostcampwm2023/and07-MindSync.git mindsync - cd mindSync/nestjs-BE + - uses: actions/checkout@v4 + with: + sparse-checkout: nestjs-BE - name: Login to github Packages run: echo ${{ secrets.PACKAGE_ACCESS_TOKEN }} | docker login ghcr.io -u ${{ secrets.PACKAGE_USERNAME }} --password-stdin - name: Build and push Docker image run: | - docker build -t ghcr.io/${{ secrets.PACKGE_USERNAME }}/mindsync . + docker build -t ghcr.io/${{ secrets.PACKGE_USERNAME }}/mindsync ./nestjs-BE docker push ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync:latest deploy: + needs: build runs-on: ubuntu-latest steps: - name: Pull Docker image uses: appleboy/ssh-action@master with: host: ${{ secrets.REMOTE_HOST }} + port: ${{ secrets.REMOTE_PORT }} username: ${{ secrets.REMOTE_USER }} key: ${{ secrets.REMOTE_SSH_KEY }} script: | From 68ae3f29a82b51fa1c4b4cc993a225412c4876e3 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 16 Nov 2023 15:45:42 +0900 Subject: [PATCH 004/170] =?UTF-8?q?fix(#16):=20=EC=98=A4=ED=83=88=EC=9E=90?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/BE-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index ae93d2a0..3f9dbd2f 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -14,7 +14,7 @@ jobs: run: echo ${{ secrets.PACKAGE_ACCESS_TOKEN }} | docker login ghcr.io -u ${{ secrets.PACKAGE_USERNAME }} --password-stdin - name: Build and push Docker image run: | - docker build -t ghcr.io/${{ secrets.PACKGE_USERNAME }}/mindsync ./nestjs-BE + docker build -t ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync ./nestjs-BE docker push ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync:latest deploy: From 6cbccb88c1c80ebe3672702c790c2e2003420735 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 16 Nov 2023 17:41:57 +0900 Subject: [PATCH 005/170] =?UTF-8?q?fix(#16):=20ssh=20=EC=A0=91=EC=86=8D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yong --- .github/workflows/BE-deploy.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index 3f9dbd2f..3eeaf278 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -31,4 +31,6 @@ jobs: script: | echo ${{ secrets.PACKAGE_ACCESS_TOKEN }} | docker login ghcr.io -u ${{ secrets.PACKAGE_USERNAME }} --password-stdin docker pull ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync - docker run -p 3000:3000 ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync + docker stop mindsync_server || true + docker rm mindsync_server || true + docker run -d --name mindsync_server -p 3000:3000 ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync From f3f3584d06ab1ff8c50dc9b3ad8d482da50b42fc Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 16 Nov 2023 18:03:40 +0900 Subject: [PATCH 006/170] =?UTF-8?q?fix(#16):=20=ED=8F=AC=ED=8A=B8=20?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=EB=B3=80=EC=88=98=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yong --- .github/workflows/BE-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index 3eeaf278..acd61ccb 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -33,4 +33,4 @@ jobs: docker pull ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync docker stop mindsync_server || true docker rm mindsync_server || true - docker run -d --name mindsync_server -p 3000:3000 ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync + docker run -d --name mindsync_server -p ${{ secrets.SERVER_PORT }}:${{ secrets.CONTAINER_PORT }} ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync \ No newline at end of file From 0fe86a9c57e3bcdacf740ff20f36e261accd5735 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 21 Nov 2023 18:32:43 +0900 Subject: [PATCH 007/170] =?UTF-8?q?chore(#58):=20cache=20=EC=84=9C?= =?UTF-8?q?=EB=B2=84=20=EC=B4=88=EA=B8=B0=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/cache-server/.eslintrc.js | 29 + nestjs-BE/cache-server/.gitignore | 35 + nestjs-BE/cache-server/.prettierrc | 6 + nestjs-BE/cache-server/README.md | 73 + nestjs-BE/cache-server/nest-cli.json | 8 + nestjs-BE/cache-server/package-lock.json | 8873 +++++++++++++++++ nestjs-BE/cache-server/package.json | 70 + .../cache-server/src/app.controller.spec.ts | 22 + nestjs-BE/cache-server/src/app.controller.ts | 12 + nestjs-BE/cache-server/src/app.module.ts | 11 + nestjs-BE/cache-server/src/app.service.ts | 8 + nestjs-BE/cache-server/src/main.ts | 8 + nestjs-BE/cache-server/test/app.e2e-spec.ts | 24 + nestjs-BE/cache-server/test/jest-e2e.json | 9 + nestjs-BE/cache-server/tsconfig.build.json | 4 + nestjs-BE/cache-server/tsconfig.json | 21 + 16 files changed, 9213 insertions(+) create mode 100644 nestjs-BE/cache-server/.eslintrc.js create mode 100644 nestjs-BE/cache-server/.gitignore create mode 100644 nestjs-BE/cache-server/.prettierrc create mode 100644 nestjs-BE/cache-server/README.md create mode 100644 nestjs-BE/cache-server/nest-cli.json create mode 100644 nestjs-BE/cache-server/package-lock.json create mode 100644 nestjs-BE/cache-server/package.json create mode 100644 nestjs-BE/cache-server/src/app.controller.spec.ts create mode 100644 nestjs-BE/cache-server/src/app.controller.ts create mode 100644 nestjs-BE/cache-server/src/app.module.ts create mode 100644 nestjs-BE/cache-server/src/app.service.ts create mode 100644 nestjs-BE/cache-server/src/main.ts create mode 100644 nestjs-BE/cache-server/test/app.e2e-spec.ts create mode 100644 nestjs-BE/cache-server/test/jest-e2e.json create mode 100644 nestjs-BE/cache-server/tsconfig.build.json create mode 100644 nestjs-BE/cache-server/tsconfig.json diff --git a/nestjs-BE/cache-server/.eslintrc.js b/nestjs-BE/cache-server/.eslintrc.js new file mode 100644 index 00000000..64cb21cf --- /dev/null +++ b/nestjs-BE/cache-server/.eslintrc.js @@ -0,0 +1,29 @@ +module.exports = { + parser: '@typescript-eslint/parser', + parserOptions: { + project: 'tsconfig.json', + tsconfigRootDir: __dirname, + sourceType: 'module', + }, + plugins: ['@typescript-eslint/eslint-plugin'], + extends: [ + 'plugin:@typescript-eslint/recommended', + 'plugin:prettier/recommended', + ], + root: true, + env: { + node: true, + jest: true, + }, + ignorePatterns: ['.eslintrc.js'], + rules: { + '@typescript-eslint/interface-name-prefix': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-explicit-any': 'off', + 'max-depth': ['error', 3], + 'no-magic-numbers': ['error', { ignore: [-1, 0, 1] }], + curly: ['error', 'multi-line', 'consistent'], + 'max-params': ['error', 3], + }, +}; diff --git a/nestjs-BE/cache-server/.gitignore b/nestjs-BE/cache-server/.gitignore new file mode 100644 index 00000000..22f55adc --- /dev/null +++ b/nestjs-BE/cache-server/.gitignore @@ -0,0 +1,35 @@ +# compiled output +/dist +/node_modules + +# Logs +logs +*.log +npm-debug.log* +pnpm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# OS +.DS_Store + +# Tests +/coverage +/.nyc_output + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json \ No newline at end of file diff --git a/nestjs-BE/cache-server/.prettierrc b/nestjs-BE/cache-server/.prettierrc new file mode 100644 index 00000000..cb17f298 --- /dev/null +++ b/nestjs-BE/cache-server/.prettierrc @@ -0,0 +1,6 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "endOfLine": "auto" +} + diff --git a/nestjs-BE/cache-server/README.md b/nestjs-BE/cache-server/README.md new file mode 100644 index 00000000..00a13b11 --- /dev/null +++ b/nestjs-BE/cache-server/README.md @@ -0,0 +1,73 @@ +

+ Nest Logo +

+ +[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 +[circleci-url]: https://circleci.com/gh/nestjs/nest + +

A progressive Node.js framework for building efficient and scalable server-side applications.

+

+NPM Version +Package License +NPM Downloads +CircleCI +Coverage +Discord +Backers on Open Collective +Sponsors on Open Collective + + Support us + +

+ + +## Description + +[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. + +## Installation + +```bash +$ npm install +``` + +## Running the app + +```bash +# development +$ npm run start + +# watch mode +$ npm run start:dev + +# production mode +$ npm run start:prod +``` + +## Test + +```bash +# unit tests +$ npm run test + +# e2e tests +$ npm run test:e2e + +# test coverage +$ npm run test:cov +``` + +## Support + +Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). + +## Stay in touch + +- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com) +- Website - [https://nestjs.com](https://nestjs.com/) +- Twitter - [@nestframework](https://twitter.com/nestframework) + +## License + +Nest is [MIT licensed](LICENSE). diff --git a/nestjs-BE/cache-server/nest-cli.json b/nestjs-BE/cache-server/nest-cli.json new file mode 100644 index 00000000..f9aa683b --- /dev/null +++ b/nestjs-BE/cache-server/nest-cli.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/nest-cli", + "collection": "@nestjs/schematics", + "sourceRoot": "src", + "compilerOptions": { + "deleteOutDir": true + } +} diff --git a/nestjs-BE/cache-server/package-lock.json b/nestjs-BE/cache-server/package-lock.json new file mode 100644 index 00000000..311ad10b --- /dev/null +++ b/nestjs-BE/cache-server/package-lock.json @@ -0,0 +1,8873 @@ +{ + "name": "cache-server", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "cache-server", + "version": "0.0.1", + "license": "UNLICENSED", + "dependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/core": "^10.0.0", + "@nestjs/mapped-types": "*", + "@nestjs/platform-express": "^10.0.0", + "reflect-metadata": "^0.1.13", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@nestjs/cli": "^10.0.0", + "@nestjs/schematics": "^10.0.0", + "@nestjs/testing": "^10.0.0", + "@types/express": "^4.17.17", + "@types/jest": "^29.5.2", + "@types/node": "^20.3.1", + "@types/supertest": "^2.0.12", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.42.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.5.0", + "prettier": "^3.0.0", + "source-map-support": "^0.5.21", + "supertest": "^6.3.3", + "ts-jest": "^29.1.0", + "ts-loader": "^9.4.3", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.1.3" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@angular-devkit/core": { + "version": "16.2.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.8.tgz", + "integrity": "sha512-PTGozYvh1Bin5lB15PwcXa26Ayd17bWGLS3H8Rs0s+04mUDvfNofmweaX1LgumWWy3nCUTDuwHxX10M3G0wE2g==", + "dev": true, + "dependencies": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.0", + "picomatch": "2.3.1", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "16.2.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.8.tgz", + "integrity": "sha512-MBiKZOlR9/YMdflALr7/7w/BGAfo/BGTrlkqsIB6rDWV1dYiCgxI+033HsiNssLS6RQyCFx/e7JA2aBBzu9zEg==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "16.2.8", + "jsonc-parser": "3.2.0", + "magic-string": "0.30.1", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics-cli": { + "version": "16.2.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-16.2.8.tgz", + "integrity": "sha512-EXURJCzWTVYCipiTT4vxQQOrF63asOUDbeOy3OtiSh7EwIUvxm3BPG6hquJqngEnI/N6bA75NJ1fBhU6Hrh7eA==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "16.2.8", + "@angular-devkit/schematics": "16.2.8", + "ansi-colors": "4.1.3", + "inquirer": "8.2.4", + "symbol-observable": "4.0.0", + "yargs-parser": "21.1.1" + }, + "bin": { + "schematics": "bin/schematics.js" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.4.tgz", + "integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", + "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz", + "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.2", + "@babel/parser": "^7.23.3", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.3", + "@babel/types": "^7.23.3", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.4.tgz", + "integrity": "sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.4", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.4.tgz", + "integrity": "sha512-HfcMizYz10cr3h29VqyfGL6ZWIjTwWfvYBMsBVGwpcbhNGe3wQ1ZXZRPzZoAHhd9OqHadHqjQ89iVKINXnbzuw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.4", + "@babel/types": "^7.23.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.4.tgz", + "integrity": "sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", + "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.4.tgz", + "integrity": "sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.4", + "@babel/generator": "^7.23.4", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.4", + "@babel/types": "^7.23.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.4.tgz", + "integrity": "sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "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", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", + "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/@eslint/js": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz", + "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "dev": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.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/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/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/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/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/@istanbuljs/load-nyc-config/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/@istanbuljs/load-nyc-config/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/@istanbuljs/load-nyc-config/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/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@nestjs/cli": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-10.2.1.tgz", + "integrity": "sha512-CAJAQwmxFZfB3RTvqz/eaXXWpyU+mZ4QSqfBYzjneTsPgF+uyOAW3yQpaLNn9Dfcv39R9UxSuAhayv6yuFd+Jg==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "16.2.8", + "@angular-devkit/schematics": "16.2.8", + "@angular-devkit/schematics-cli": "16.2.8", + "@nestjs/schematics": "^10.0.1", + "chalk": "4.1.2", + "chokidar": "3.5.3", + "cli-table3": "0.6.3", + "commander": "4.1.1", + "fork-ts-checker-webpack-plugin": "9.0.2", + "glob": "10.3.10", + "inquirer": "8.2.6", + "node-emoji": "1.11.0", + "ora": "5.4.1", + "os-name": "4.0.1", + "rimraf": "4.4.1", + "shelljs": "0.8.5", + "source-map-support": "0.5.21", + "tree-kill": "1.2.2", + "tsconfig-paths": "4.2.0", + "tsconfig-paths-webpack-plugin": "4.1.0", + "typescript": "5.2.2", + "webpack": "5.89.0", + "webpack-node-externals": "3.0.0" + }, + "bin": { + "nest": "bin/nest.js" + }, + "engines": { + "node": ">= 16.14" + }, + "peerDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.62" + }, + "peerDependenciesMeta": { + "@swc/cli": { + "optional": true + }, + "@swc/core": { + "optional": true + } + } + }, + "node_modules/@nestjs/cli/node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@nestjs/common": { + "version": "10.2.10", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.2.10.tgz", + "integrity": "sha512-fwAk931rjW8CNH2Mgwawq/7HWHH1dxkOLdcgs7U52ddLk8CtHXjejm1cbNahewlSbNhvlOl7y1STLHutE6sUqw==", + "dependencies": { + "iterare": "1.2.1", + "tslib": "2.6.2", + "uid": "2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "class-transformer": "*", + "class-validator": "*", + "reflect-metadata": "^0.1.12", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, + "node_modules/@nestjs/core": { + "version": "10.2.10", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.2.10.tgz", + "integrity": "sha512-+ckOI6BPi2ZMHikT9MCG4ctHDc4OnjhoIytrn7f2AYMMXI4bnutJhqyQKc30VDka5x3Wq6QAD57pgSP7y+JjJg==", + "hasInstallScript": true, + "dependencies": { + "@nuxtjs/opencollective": "0.3.2", + "fast-safe-stringify": "2.1.1", + "iterare": "1.2.1", + "path-to-regexp": "3.2.0", + "tslib": "2.6.2", + "uid": "2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/microservices": "^10.0.0", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/websockets": "^10.0.0", + "reflect-metadata": "^0.1.12", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "@nestjs/microservices": { + "optional": true + }, + "@nestjs/platform-express": { + "optional": true + }, + "@nestjs/websockets": { + "optional": true + } + } + }, + "node_modules/@nestjs/mapped-types": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.0.4.tgz", + "integrity": "sha512-xl+gUSp0B+ln1VSNoUftlglk8dfpUes3DHGxKZ5knuBxS5g2H/8p9/DSBOYWUfO5f4u9s6ffBPZ71WO+tbe5SA==", + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "class-transformer": "^0.4.0 || ^0.5.0", + "class-validator": "^0.13.0 || ^0.14.0", + "reflect-metadata": "^0.1.12" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, + "node_modules/@nestjs/platform-express": { + "version": "10.2.10", + "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.2.10.tgz", + "integrity": "sha512-U4KDgtMjH8TqEvt0RzC/POP8ABvL9bYoCScvlGtFSKgVGaMLBKkZ4+jHtbQx6qItYSlBBRUuz/dveMZCObfrkQ==", + "dependencies": { + "body-parser": "1.20.2", + "cors": "2.8.5", + "express": "4.18.2", + "multer": "1.4.4-lts.1", + "tslib": "2.6.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/core": "^10.0.0" + } + }, + "node_modules/@nestjs/schematics": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-10.0.3.tgz", + "integrity": "sha512-2BRujK0GqGQ7j1Zpz+obVfskDnnOeVKt5aXoSaVngKo8Oczy8uYCY+R547TQB+Kf35epdfFER2pVnQrX3/It5A==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "16.2.8", + "@angular-devkit/schematics": "16.2.8", + "comment-json": "4.2.3", + "jsonc-parser": "3.2.0", + "pluralize": "8.0.0" + }, + "peerDependencies": { + "typescript": ">=4.8.2" + } + }, + "node_modules/@nestjs/testing": { + "version": "10.2.10", + "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.2.10.tgz", + "integrity": "sha512-IVLUnPz/+fkBtPATYfqTIP+phN9yjkXejmj+JyhmcfPJZpxBmD1i9VSMqa4u54l37j0xkGPscQ0IXpbhqMYUKw==", + "dev": true, + "dependencies": { + "tslib": "2.6.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/core": "^10.0.0", + "@nestjs/microservices": "^10.0.0", + "@nestjs/platform-express": "^10.0.0" + }, + "peerDependenciesMeta": { + "@nestjs/microservices": { + "optional": true + }, + "@nestjs/platform-express": { + "optional": true + } + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nuxtjs/opencollective": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz", + "integrity": "sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==", + "dependencies": { + "chalk": "^4.1.0", + "consola": "^2.15.0", + "node-fetch": "^2.6.1" + }, + "bin": { + "opencollective": "bin/opencollective.js" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/utils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", + "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "fast-glob": "^3.3.0", + "is-glob": "^4.0.3", + "open": "^9.1.0", + "picocolors": "^1.0.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", + "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookiejar": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", + "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", + "dev": true + }, + "node_modules/@types/eslint": { + "version": "8.44.7", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.7.tgz", + "integrity": "sha512-f5ORu2hcBbKei97U73mf+l9t4zTGl74IqZ0GQk4oVea/VS8tQZYkUveSYojk+frraAVYId0V2WC9O4PTNru2FQ==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.41", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz", + "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.9", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.9.tgz", + "integrity": "sha512-zJeWhqBwVoPm83sP8h1/SVntwWTu5lZbKQGCvBjxQOyEWnKnsaomt2y7SlV4KfwlrHAHHAn00Sh4IAWaIsGOgQ==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.9.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.3.tgz", + "integrity": "sha512-nk5wXLAXGBKfrhLB0cyHGbSqopS+nz0BUgZkUQqSHSSgdee0kssp1IAqlQOu333bW+gMNs2QREx7iynm19Abxw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/qs": { + "version": "6.9.10", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", + "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true + }, + "node_modules/@types/superagent": { + "version": "4.1.22", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.22.tgz", + "integrity": "sha512-GMaOrnnUsjChvH8zlzdDPARRXky8bU3E8xsU/fOclgqsINekbwDu1+wzJzJaGzZP91SGpOutf5Te5pm5M/qCWg==", + "dev": true, + "dependencies": { + "@types/cookiejar": "*", + "@types/node": "*" + } + }, + "node_modules/@types/supertest": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.16.tgz", + "integrity": "sha512-6c2ogktZ06tr2ENoZivgm7YnprnhYE4ZoXGMY+oA7IuAf17M8FWvujXZGmxLv8y0PTyts4x5A+erSwVUFA8XSg==", + "dev": true, + "dependencies": { + "@types/superagent": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.12.0.tgz", + "integrity": "sha512-XOpZ3IyJUIV1b15M7HVOpgQxPPF7lGXgsfcEIu3yDxFPaf/xZKt7s9QO/pbk7vpWQyVulpJbu4E5LwpZiQo4kA==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/type-utils": "6.12.0", + "@typescript-eslint/utils": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.12.0.tgz", + "integrity": "sha512-s8/jNFPKPNRmXEnNXfuo1gemBdVmpQsK1pcu+QIvuNJuhFzGrpD7WjOcvDc/+uEdfzSYpNu7U/+MmbScjoQ6vg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/typescript-estree": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.12.0.tgz", + "integrity": "sha512-5gUvjg+XdSj8pcetdL9eXJzQNTl3RD7LgUiYTl8Aabdi8hFkaGSYnaS6BLc0BGNaDH+tVzVwmKtWvu0jLgWVbw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.12.0.tgz", + "integrity": "sha512-WWmRXxhm1X8Wlquj+MhsAG4dU/Blvf1xDgGaYCzfvStP2NwPQh6KBvCDbiOEvaE0filhranjIlK/2fSTVwtBng==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.12.0", + "@typescript-eslint/utils": "6.12.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.12.0.tgz", + "integrity": "sha512-MA16p/+WxM5JG/F3RTpRIcuOghWO30//VEOvzubM8zuOOBYXsP+IfjoCXXiIfy2Ta8FRh9+IO9QLlaFQUU+10Q==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.12.0.tgz", + "integrity": "sha512-vw9E2P9+3UUWzhgjyyVczLWxZ3GuQNT7QpnIY3o5OMeLO/c8oHljGc8ZpryBMIyympiAAaKgw9e5Hl9dCWFOYw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.12.0.tgz", + "integrity": "sha512-LywPm8h3tGEbgfyjYnu3dauZ0U7R60m+miXgKcZS8c7QALO9uWJdvNoP+duKTk2XMWc7/Q3d/QiCuLN9X6SWyQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/typescript-estree": "6.12.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.12.0.tgz", + "integrity": "sha512-rg3BizTZHF1k3ipn8gfrzDXXSFKyOEB5zxYXInQ6z0hUvmQlhaZQzK+YmHmNViMA9HzW5Q9+bPPt90bU6GQwyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.12.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", + "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.44" + }, + "engines": { + "node": ">= 5.10.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/bundle-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "dev": true, + "dependencies": { + "run-applescript": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001563", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001563.tgz", + "integrity": "sha512-na2WUmOxnwIZtwnFI2CZ/3er0wdNzU7hN+cPYz/z2ajHThnkWjNBOpEPP4n+4r2WPM847JaMotaJE3bnfzjyKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.1.tgz", + "integrity": "sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/comment-json": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.3.tgz", + "integrity": "sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw==", + "dev": true, + "dependencies": { + "array-timsort": "^1.0.3", + "core-util-is": "^1.0.3", + "esprima": "^4.0.1", + "has-own-prop": "^2.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/consola": { + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", + "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "dev": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "dev": true, + "dependencies": { + "bundle-name": "^3.0.0", + "default-browser-id": "^3.0.0", + "execa": "^7.1.1", + "titleize": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "dev": true, + "dependencies": { + "bplist-parser": "^0.2.0", + "untildify": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/default-browser/node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/default-browser/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/default-browser/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/default-browser/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "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/default-browser/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/default-browser/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/default-browser/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/default-browser/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/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.589", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.589.tgz", + "integrity": "sha512-zF6y5v/YfoFIgwf2dDfAqVlPPsyQeWNpEWXbAlDUS8Ax4Z2VoiiZpAPC0Jm9hXEkJm2vIZpwB6rc4KnLTQffbQ==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz", + "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.3", + "@eslint/js": "8.54.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz", + "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.5" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "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/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/express/node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.0.2.tgz", + "integrity": "sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^8.2.0", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">=12.13.0", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "typescript": ">3.6.0", + "webpack": "^5.11.0" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formidable": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", + "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", + "dev": true, + "dependencies": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "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/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-own-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz", + "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/inquirer": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/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/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-wsl/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz", + "integrity": "sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/iterare": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", + "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-runner/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/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/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/macos-release": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.5.1.tgz", + "integrity": "sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/magic-string": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz", + "integrity": "sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/multer": { + "version": "1.4.4-lts.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz", + "integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "dev": true + }, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "dev": true, + "dependencies": { + "default-browser": "^4.0.0", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-name": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-4.0.1.tgz", + "integrity": "sha512-xl9MAoU97MH1Xt5K9ERft2YfCAoaO6msy1OBA0ozxEC0x0TmIoE6K3QvgJMMZA9yKGLmHXNY/YZoDbiGDj4zYw==", + "dev": true, + "dependencies": { + "macos-release": "^2.5.0", + "windows-release": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.3.tgz", + "integrity": "sha512-B7gr+F6MkqB3uzINHXNctGieGsRTMwIBgxkp0yq/5BwcuDzD4A8wQpHQW6vDAm1uKSLQghmRdD9sKqf2vJ1cEg==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-to-regexp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.2.0.tgz", + "integrity": "sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/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/pkg-dir/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/pkg-dir/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/pkg-dir/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/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", + "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", + "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/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/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", + "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", + "dev": true, + "dependencies": { + "glob": "^9.2.0" + }, + "bin": { + "rimraf": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/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/semver/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/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/shelljs/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superagent": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", + "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==", + "dev": true, + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.1.2", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=6.4.0 <13 || >=14" + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/supertest": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.3.tgz", + "integrity": "sha512-EMCG6G8gDu5qEqRQ3JjjPs6+FYT1a7Hv5ApHvtSghmOFJYtsU5S+pSb6Y2EUeCEY3CmEL3mmQ8YWlPOzQomabA==", + "dev": true, + "dependencies": { + "methods": "^1.1.2", + "superagent": "^8.0.5" + }, + "engines": { + "node": ">=6.4.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/synckit": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", + "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "dev": true, + "dependencies": { + "@pkgr/utils": "^2.3.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz", + "integrity": "sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-jest": { + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", + "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "^7.5.3", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-loader": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tsconfig-paths-webpack-plugin": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.1.0.tgz", + "integrity": "sha512-xWFISjviPydmtmgeUAuXp4N1fky+VCtfhOkDUFIv5ea7p4wuTomI4QTrXvFBX2S4jZsmyTSrStQl+E+4w+RzxA==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.7.0", + "tsconfig-paths": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "node_modules/typescript": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", + "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uid": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", + "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", + "dependencies": { + "@lukeed/csprng": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", + "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/webpack": { + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", + "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-node-externals": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz", + "integrity": "sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/windows-release": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-4.0.0.tgz", + "integrity": "sha512-OxmV4wzDKB1x7AZaZgXMVsdJ1qER1ed83ZrTYd5Bwq2HfJVg3DJS8nqlAG4sMoJ7mu8cuRmLEYyU13BKwctRAg==", + "dev": true, + "dependencies": { + "execa": "^4.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/windows-release/node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/windows-release/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/windows-release/node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/windows-release/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/nestjs-BE/cache-server/package.json b/nestjs-BE/cache-server/package.json new file mode 100644 index 00000000..e7bd2e3e --- /dev/null +++ b/nestjs-BE/cache-server/package.json @@ -0,0 +1,70 @@ +{ + "name": "cache-server", + "version": "0.0.1", + "description": "", + "author": "", + "private": true, + "license": "UNLICENSED", + "scripts": { + "build": "nest build", + "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", + "start": "nest start", + "start:dev": "nest start --watch", + "start:debug": "nest start --debug --watch", + "start:prod": "node dist/main", + "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", + "test": "jest", + "test:watch": "jest --watch", + "test:cov": "jest --coverage", + "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", + "test:e2e": "jest --config ./test/jest-e2e.json" + }, + "dependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/core": "^10.0.0", + "@nestjs/mapped-types": "*", + "@nestjs/platform-express": "^10.0.0", + "reflect-metadata": "^0.1.13", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@nestjs/cli": "^10.0.0", + "@nestjs/schematics": "^10.0.0", + "@nestjs/testing": "^10.0.0", + "@types/express": "^4.17.17", + "@types/jest": "^29.5.2", + "@types/node": "^20.3.1", + "@types/supertest": "^2.0.12", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.42.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.5.0", + "prettier": "^3.0.0", + "source-map-support": "^0.5.21", + "supertest": "^6.3.3", + "ts-jest": "^29.1.0", + "ts-loader": "^9.4.3", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.1.3" + }, + "jest": { + "moduleFileExtensions": [ + "js", + "json", + "ts" + ], + "rootDir": "src", + "testRegex": ".*\\.spec\\.ts$", + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + }, + "collectCoverageFrom": [ + "**/*.(t|j)s" + ], + "coverageDirectory": "../coverage", + "testEnvironment": "node" + } +} diff --git a/nestjs-BE/cache-server/src/app.controller.spec.ts b/nestjs-BE/cache-server/src/app.controller.spec.ts new file mode 100644 index 00000000..d22f3890 --- /dev/null +++ b/nestjs-BE/cache-server/src/app.controller.spec.ts @@ -0,0 +1,22 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { AppController } from './app.controller'; +import { AppService } from './app.service'; + +describe('AppController', () => { + let appController: AppController; + + beforeEach(async () => { + const app: TestingModule = await Test.createTestingModule({ + controllers: [AppController], + providers: [AppService], + }).compile(); + + appController = app.get(AppController); + }); + + describe('root', () => { + it('should return "Hello World!"', () => { + expect(appController.getHello()).toBe('Hello World!'); + }); + }); +}); diff --git a/nestjs-BE/cache-server/src/app.controller.ts b/nestjs-BE/cache-server/src/app.controller.ts new file mode 100644 index 00000000..cce879ee --- /dev/null +++ b/nestjs-BE/cache-server/src/app.controller.ts @@ -0,0 +1,12 @@ +import { Controller, Get } from '@nestjs/common'; +import { AppService } from './app.service'; + +@Controller() +export class AppController { + constructor(private readonly appService: AppService) {} + + @Get() + getHello(): string { + return this.appService.getHello(); + } +} diff --git a/nestjs-BE/cache-server/src/app.module.ts b/nestjs-BE/cache-server/src/app.module.ts new file mode 100644 index 00000000..02ae1fe4 --- /dev/null +++ b/nestjs-BE/cache-server/src/app.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { AppController } from './app.controller'; +import { AppService } from './app.service'; +import { TemporaryDatabaseModule } from './temporary-database/temporary-database.module'; + +@Module({ + imports: [TemporaryDatabaseModule], + controllers: [AppController], + providers: [AppService], +}) +export class AppModule {} diff --git a/nestjs-BE/cache-server/src/app.service.ts b/nestjs-BE/cache-server/src/app.service.ts new file mode 100644 index 00000000..927d7cca --- /dev/null +++ b/nestjs-BE/cache-server/src/app.service.ts @@ -0,0 +1,8 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class AppService { + getHello(): string { + return 'Hello World!'; + } +} diff --git a/nestjs-BE/cache-server/src/main.ts b/nestjs-BE/cache-server/src/main.ts new file mode 100644 index 00000000..13cad38c --- /dev/null +++ b/nestjs-BE/cache-server/src/main.ts @@ -0,0 +1,8 @@ +import { NestFactory } from '@nestjs/core'; +import { AppModule } from './app.module'; + +async function bootstrap() { + const app = await NestFactory.create(AppModule); + await app.listen(3000); +} +bootstrap(); diff --git a/nestjs-BE/cache-server/test/app.e2e-spec.ts b/nestjs-BE/cache-server/test/app.e2e-spec.ts new file mode 100644 index 00000000..50cda623 --- /dev/null +++ b/nestjs-BE/cache-server/test/app.e2e-spec.ts @@ -0,0 +1,24 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { INestApplication } from '@nestjs/common'; +import * as request from 'supertest'; +import { AppModule } from './../src/app.module'; + +describe('AppController (e2e)', () => { + let app: INestApplication; + + beforeEach(async () => { + const moduleFixture: TestingModule = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); + + app = moduleFixture.createNestApplication(); + await app.init(); + }); + + it('/ (GET)', () => { + return request(app.getHttpServer()) + .get('/') + .expect(200) + .expect('Hello World!'); + }); +}); diff --git a/nestjs-BE/cache-server/test/jest-e2e.json b/nestjs-BE/cache-server/test/jest-e2e.json new file mode 100644 index 00000000..e9d912f3 --- /dev/null +++ b/nestjs-BE/cache-server/test/jest-e2e.json @@ -0,0 +1,9 @@ +{ + "moduleFileExtensions": ["js", "json", "ts"], + "rootDir": ".", + "testEnvironment": "node", + "testRegex": ".e2e-spec.ts$", + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + } +} diff --git a/nestjs-BE/cache-server/tsconfig.build.json b/nestjs-BE/cache-server/tsconfig.build.json new file mode 100644 index 00000000..64f86c6b --- /dev/null +++ b/nestjs-BE/cache-server/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] +} diff --git a/nestjs-BE/cache-server/tsconfig.json b/nestjs-BE/cache-server/tsconfig.json new file mode 100644 index 00000000..95f5641c --- /dev/null +++ b/nestjs-BE/cache-server/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "module": "commonjs", + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "target": "ES2021", + "sourceMap": true, + "outDir": "./dist", + "baseUrl": "./", + "incremental": true, + "skipLibCheck": true, + "strictNullChecks": false, + "noImplicitAny": false, + "strictBindCallApply": false, + "forceConsistentCasingInFileNames": false, + "noFallthroughCasesInSwitch": false + } +} From 9a8d7906941b1f2c5f92033110c72a7a78460998 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 21 Nov 2023 19:09:04 +0900 Subject: [PATCH 008/170] =?UTF-8?q?feat(#58):=20lru-cache=20prototype=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/cache-server/src/utils/lru-cache.ts | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 nestjs-BE/cache-server/src/utils/lru-cache.ts diff --git a/nestjs-BE/cache-server/src/utils/lru-cache.ts b/nestjs-BE/cache-server/src/utils/lru-cache.ts new file mode 100644 index 00000000..1ef5b0bd --- /dev/null +++ b/nestjs-BE/cache-server/src/utils/lru-cache.ts @@ -0,0 +1,83 @@ +class LRUNode { + key: string; + value: any; + prev: LRUNode | null; + next: LRUNode | null; + + constructor(key: string, value: any) { + this.key = key; + this.value = value; + this.prev = null; + this.next = null; + } +} + +export default class LRUCache { + capacity: number; + hashmap: { [key: string]: LRUNode }; + head: LRUNode; + tail: LRUNode; + + constructor(capacity: number) { + this.capacity = capacity; + this.hashmap = {}; + this.head = new LRUNode('0', 0); + this.tail = new LRUNode('0', 0); + this.head.next = this.tail; + this.tail.prev = this.head; + } + + get(key: string): any { + if (this.hashmap[key]) { + const node = this.hashmap[key]; + this.remove(node); + this.add(node); + return node.value; + } + return -1; + } + + put(key: string, value: any): void { + if (this.hashmap[key]) this.remove(this.hashmap[key]); + + const node = new LRUNode(key, value); + this.add(node); + this.hashmap[key] = node; + if (Object.keys(this.hashmap).length > this.capacity) { + const oldestNode = this.head.next; + if (oldestNode) { + this.remove(oldestNode); + delete this.hashmap[oldestNode.key]; + } + } + } + + private remove(node: LRUNode): void { + const prev = node.prev; + const next = node.next; + if (prev) prev.next = next; + if (next) next.prev = prev; + } + + private add(node: LRUNode): void { + const prev = this.tail.prev; + if (prev) prev.next = node; + this.tail.prev = node; + node.prev = prev; + node.next = this.tail; + } + + removeOldest(count: number): void { + for (let i = 0; i < count; i++) { + if (this.head.next !== this.tail) { + const node = this.head.next; + if (node) { + this.remove(node); + delete this.hashmap[node.key]; + } + } else { + break; + } + } + } +} From 8d14661ef0eb2c033ebf74bb6e3bdc4afbd99e19 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Tue, 21 Nov 2023 22:35:30 +0900 Subject: [PATCH 009/170] =?UTF-8?q?feat(#71):=20Timestamp=20=EB=85=BC?= =?UTF-8?q?=EB=A6=AC=EC=A0=81=20=EC=8B=9C=EA=B3=84=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/crdt/lww-map.ts | 2 +- nestjs-BE/crdt/lww-register.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nestjs-BE/crdt/lww-map.ts b/nestjs-BE/crdt/lww-map.ts index 52fb9bde..458c86be 100644 --- a/nestjs-BE/crdt/lww-map.ts +++ b/nestjs-BE/crdt/lww-map.ts @@ -37,7 +37,7 @@ export class LWWMap { key, new LWWRegister(this.id, { id: this.id, - timestamp: Date.now(), + timestamp: 1, value, }), ); diff --git a/nestjs-BE/crdt/lww-register.ts b/nestjs-BE/crdt/lww-register.ts index b7c020e2..ccb74cb9 100644 --- a/nestjs-BE/crdt/lww-register.ts +++ b/nestjs-BE/crdt/lww-register.ts @@ -18,7 +18,7 @@ export class LWWRegister { } setValue(value: T): void { - this.state = { id: this.id, timestamp: Date.now(), value }; + this.state = { id: this.id, timestamp: this.state.timestamp + 1, value }; } merge(state: lwwRegisterState): void { From 4ad2ac1b4f2537530adf797124bbbcf9880fdef4 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Tue, 21 Nov 2023 22:38:01 +0900 Subject: [PATCH 010/170] =?UTF-8?q?rename:=20lww=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=EC=97=90=EC=84=9C=20=EB=B9=BC=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/crdt/{lww-map.ts => map.ts} | 2 +- nestjs-BE/crdt/{lww-register.ts => register.ts} | 0 nestjs-BE/src/mindmap/mindmap.service.ts | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename nestjs-BE/crdt/{lww-map.ts => map.ts} (96%) rename nestjs-BE/crdt/{lww-register.ts => register.ts} (100%) diff --git a/nestjs-BE/crdt/lww-map.ts b/nestjs-BE/crdt/map.ts similarity index 96% rename from nestjs-BE/crdt/lww-map.ts rename to nestjs-BE/crdt/map.ts index 458c86be..3a7cf31c 100644 --- a/nestjs-BE/crdt/lww-map.ts +++ b/nestjs-BE/crdt/map.ts @@ -1,4 +1,4 @@ -import { LWWRegister, lwwRegisterState } from './lww-register'; +import { LWWRegister, lwwRegisterState } from './register'; export type lwwMapState = { [key: string]: lwwRegisterState; diff --git a/nestjs-BE/crdt/lww-register.ts b/nestjs-BE/crdt/register.ts similarity index 100% rename from nestjs-BE/crdt/lww-register.ts rename to nestjs-BE/crdt/register.ts diff --git a/nestjs-BE/src/mindmap/mindmap.service.ts b/nestjs-BE/src/mindmap/mindmap.service.ts index 14b24730..1794b188 100644 --- a/nestjs-BE/src/mindmap/mindmap.service.ts +++ b/nestjs-BE/src/mindmap/mindmap.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@nestjs/common'; -import { LWWMap, lwwMapState } from 'crdt/lww-map'; +import { LWWMap, lwwMapState } from 'crdt/map'; @Injectable() export class MindmapService { From e77f41744c3454668f211439f043e703fcaa8f7c Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Wed, 22 Nov 2023 23:44:05 +0900 Subject: [PATCH 011/170] =?UTF-8?q?delete:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=20=ED=8C=8C=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/crdt/map.ts | 66 -------------------------------------- nestjs-BE/crdt/register.ts | 31 ------------------ 2 files changed, 97 deletions(-) delete mode 100644 nestjs-BE/crdt/map.ts delete mode 100644 nestjs-BE/crdt/register.ts diff --git a/nestjs-BE/crdt/map.ts b/nestjs-BE/crdt/map.ts deleted file mode 100644 index 3a7cf31c..00000000 --- a/nestjs-BE/crdt/map.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { LWWRegister, lwwRegisterState } from './register'; - -export type lwwMapState = { - [key: string]: lwwRegisterState; -}; - -export class LWWMap { - readonly id: string; - private data = new Map>(); - - constructor(id: string, state: lwwMapState = {}) { - this.id = id; - this.initializeData(state); - } - - private initializeData(state: lwwMapState): void { - for (const [key, register] of Object.entries(state)) - this.data.set(key, new LWWRegister(this.id, register)); - } - - getState(): lwwMapState { - const state: lwwMapState = {}; - for (const [key, register] of this.data.entries()) - if (register) state[key] = register.state; - return state; - } - - get(key: string): T | null | undefined { - return this.data.get(key)?.getValue(); - } - - set(key: string, value: T): void { - const register = this.data.get(key); - if (register) register.setValue(value); - else - this.data.set( - key, - new LWWRegister(this.id, { - id: this.id, - timestamp: 1, - value, - }), - ); - } - - delete(key: string): void { - this.data.get(key)?.setValue(null); - } - - has(key: string): boolean { - return !!this.data.get(key)?.getValue(); - } - - clear(): void { - for (const [key, register] of this.data.entries()) - if (register) this.delete(key); - } - - merge(state: lwwMapState): void { - for (const [key, remoteRegister] of Object.entries(state)) { - const local = this.data.get(key); - if (local) local.merge(remoteRegister); - else this.data.set(key, new LWWRegister(this.id, remoteRegister)); - } - } -} diff --git a/nestjs-BE/crdt/register.ts b/nestjs-BE/crdt/register.ts deleted file mode 100644 index ccb74cb9..00000000 --- a/nestjs-BE/crdt/register.ts +++ /dev/null @@ -1,31 +0,0 @@ -export interface lwwRegisterState { - id: string; - timestamp: number; - value: T; -} - -export class LWWRegister { - readonly id: string; - state: lwwRegisterState; - - constructor(id: string, state: lwwRegisterState) { - this.id = id; - this.state = state; - } - - getValue(): T { - return this.state.value; - } - - setValue(value: T): void { - this.state = { id: this.id, timestamp: this.state.timestamp + 1, value }; - } - - merge(state: lwwRegisterState): void { - const { id: remoteId, timestamp: remoteTimestamp } = state; - const { id: localId, timestamp: localTimestamp } = this.state; - if (localTimestamp > remoteTimestamp) return; - if (localTimestamp === remoteTimestamp && localId > remoteId) return; - this.state = state; - } -} From 4cd6050cee8019e75a2bd2e08904ce91e564971a Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Wed, 22 Nov 2023 23:45:39 +0900 Subject: [PATCH 012/170] =?UTF-8?q?feat(#76):=20=ED=8A=B8=EB=A6=AC=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/crdt/node.ts | 9 +++++++ nestjs-BE/crdt/tree.ts | 58 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 nestjs-BE/crdt/node.ts create mode 100644 nestjs-BE/crdt/tree.ts diff --git a/nestjs-BE/crdt/node.ts b/nestjs-BE/crdt/node.ts new file mode 100644 index 00000000..bf9c94a9 --- /dev/null +++ b/nestjs-BE/crdt/node.ts @@ -0,0 +1,9 @@ +export class Node { + parentId: string; + content: T; + + constructor(parentId: string = '0', content: T | null = null) { + this.parentId = parentId; + this.content = content; + } +} diff --git a/nestjs-BE/crdt/tree.ts b/nestjs-BE/crdt/tree.ts new file mode 100644 index 00000000..3be39393 --- /dev/null +++ b/nestjs-BE/crdt/tree.ts @@ -0,0 +1,58 @@ +import { Node } from './node'; + +export class Tree { + nodes = new Map>(); + children = new Map>(); + + constructor() { + this.nodes.set('root', new Node()); + } + + get(id: string): Node | undefined { + return this.nodes.get(id); + } + + addNode(targetId: string, parentId: string, content: T) { + const newNode = new Node(parentId, content); + + const parentNode = this.nodes.get(parentId); + if (!parentNode) return; + + let childrenSet = this.children.get(parentId); + if (!childrenSet) { + childrenSet = new Set(); + this.children.set(parentId, childrenSet); + } + + childrenSet.add(targetId); + this.nodes.set(targetId, newNode); + } + + attachNode(targetId: string, parentId: string) { + const targetNode = this.nodes.get(targetId); + if (!targetNode) return; + + const parentNode = this.nodes.get(parentId); + if (!parentNode) return; + + let childrenSet = this.children.get(parentId); + if (!childrenSet) { + childrenSet = new Set(); + this.children.set(parentId, childrenSet); + } + + childrenSet.add(targetId); + targetNode.parentId = parentId; + } + + removeNode(targetId: string): Node { + const targetNode = this.nodes.get(targetId); + if (!targetNode) return; + + const parentChildren = this.children.get(targetNode.parentId); + if (!parentChildren) return; + parentChildren.delete(targetId); + + return this.nodes.get(targetId); + } +} From 4cfd580793c9b552e8e3067804703b23d74f981d Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Wed, 22 Nov 2023 23:46:32 +0900 Subject: [PATCH 013/170] =?UTF-8?q?feat(#76):=20=EB=85=BC=EB=A6=AC?= =?UTF-8?q?=EC=A0=81=20=EC=8B=9C=EA=B3=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/crdt/clock.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 nestjs-BE/crdt/clock.ts diff --git a/nestjs-BE/crdt/clock.ts b/nestjs-BE/crdt/clock.ts new file mode 100644 index 00000000..4a78508d --- /dev/null +++ b/nestjs-BE/crdt/clock.ts @@ -0,0 +1,33 @@ +export enum COMPARE { + GREATER, + LESS, +} + +export class Clock { + id: string; + counter: number; + + constructor(id: string, counter: number = 0) { + this.id = id; + this.counter = counter; + } + + increment() { + this.counter++; + } + + copy(): Clock { + return new Clock(this.id, this.counter); + } + + merge(remoteClock: Clock): Clock { + return new Clock(this.id, Math.max(this.counter, remoteClock.counter)); + } + + compare(remoteClock: Clock): COMPARE { + if (this.counter > remoteClock.counter) return COMPARE.GREATER; + if (this.counter === remoteClock.counter && this.id > remoteClock.id) + return COMPARE.GREATER; + return COMPARE.LESS; + } +} From bdcaa1cd1455488080065a6b01a85dd654a5f04f Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 23 Nov 2023 00:43:44 +0900 Subject: [PATCH 014/170] =?UTF-8?q?chore(#58):=20schedule=EA=B3=BC=20prism?= =?UTF-8?q?a=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/cache-server/package-lock.json | 99 ++++++++++++++++++++++++ nestjs-BE/cache-server/package.json | 3 + 2 files changed, 102 insertions(+) diff --git a/nestjs-BE/cache-server/package-lock.json b/nestjs-BE/cache-server/package-lock.json index 311ad10b..622d4089 100644 --- a/nestjs-BE/cache-server/package-lock.json +++ b/nestjs-BE/cache-server/package-lock.json @@ -13,6 +13,8 @@ "@nestjs/core": "^10.0.0", "@nestjs/mapped-types": "*", "@nestjs/platform-express": "^10.0.0", + "@nestjs/schedule": "^4.0.0", + "@prisma/client": "^5.6.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1" }, @@ -31,6 +33,7 @@ "eslint-plugin-prettier": "^5.0.0", "jest": "^29.5.0", "prettier": "^3.0.0", + "prisma": "^5.6.0", "source-map-support": "^0.5.21", "supertest": "^6.3.3", "ts-jest": "^29.1.0", @@ -1698,6 +1701,20 @@ "@nestjs/core": "^10.0.0" } }, + "node_modules/@nestjs/schedule": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@nestjs/schedule/-/schedule-4.0.0.tgz", + "integrity": "sha512-zz4h54m/F/1qyQKvMJCRphmuwGqJltDAkFxUXCVqJBXEs5kbPt93Pza3heCQOcMH22MZNhGlc9DmDMLXVHmgVQ==", + "dependencies": { + "cron": "3.1.3", + "uuid": "9.0.1" + }, + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0", + "reflect-metadata": "^0.1.12" + } + }, "node_modules/@nestjs/schematics": { "version": "10.0.3", "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-10.0.3.tgz", @@ -1823,6 +1840,38 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@prisma/client": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.6.0.tgz", + "integrity": "sha512-mUDefQFa1wWqk4+JhKPYq8BdVoFk9NFMBXUI8jAkBfQTtgx8WPx02U2HB/XbAz3GSUJpeJOKJQtNvaAIDs6sug==", + "hasInstallScript": true, + "dependencies": { + "@prisma/engines-version": "5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee" + }, + "engines": { + "node": ">=16.13" + }, + "peerDependencies": { + "prisma": "*" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + } + } + }, + "node_modules/@prisma/engines": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.6.0.tgz", + "integrity": "sha512-Mt2q+GNJpU2vFn6kif24oRSBQv1KOkYaterQsi0k2/lA+dLvhRX6Lm26gon6PYHwUM8/h8KRgXIUMU0PCLB6bw==", + "devOptional": true, + "hasInstallScript": true + }, + "node_modules/@prisma/engines-version": { + "version": "5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee.tgz", + "integrity": "sha512-UoFgbV1awGL/3wXuUK3GDaX2SolqczeeJ5b4FVec9tzeGbSWJboPSbT0psSrmgYAKiKnkOPFSLlH6+b+IyOwAw==" + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -2042,6 +2091,11 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, + "node_modules/@types/luxon": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.5.tgz", + "integrity": "sha512-1cyf6Ge/94zlaWIZA2ei1pE6SZ8xpad2hXaYa5JEFiaUH0YS494CZwyi4MXNpXD9oEuv6ZH0Bmh0e7F9sPhmZA==" + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -3508,6 +3562,15 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "node_modules/cron": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/cron/-/cron-3.1.3.tgz", + "integrity": "sha512-KVxeKTKYj2eNzN4ElnT6nRSbjbfhyxR92O/Jdp6SH3pc05CDJws59jBrZWEMQlxevCiE6QUTrXy+Im3vC3oD3A==", + "dependencies": { + "@types/luxon": "~3.3.0", + "luxon": "~3.4.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -6228,6 +6291,14 @@ "yallist": "^3.0.2" } }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "engines": { + "node": ">=12" + } + }, "node_modules/macos-release": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.5.1.tgz", @@ -6983,6 +7054,22 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/prisma": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.6.0.tgz", + "integrity": "sha512-EEaccku4ZGshdr2cthYHhf7iyvCcXqwJDvnoQRAJg5ge2Tzpv0e2BaMCp+CbbDUwoVTzwgOap9Zp+d4jFa2O9A==", + "devOptional": true, + "hasInstallScript": true, + "dependencies": { + "@prisma/engines": "5.6.0" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=16.13" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -8498,6 +8585,18 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", diff --git a/nestjs-BE/cache-server/package.json b/nestjs-BE/cache-server/package.json index e7bd2e3e..2fb01361 100644 --- a/nestjs-BE/cache-server/package.json +++ b/nestjs-BE/cache-server/package.json @@ -24,6 +24,8 @@ "@nestjs/core": "^10.0.0", "@nestjs/mapped-types": "*", "@nestjs/platform-express": "^10.0.0", + "@nestjs/schedule": "^4.0.0", + "@prisma/client": "^5.6.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1" }, @@ -42,6 +44,7 @@ "eslint-plugin-prettier": "^5.0.0", "jest": "^29.5.0", "prettier": "^3.0.0", + "prisma": "^5.6.0", "source-map-support": "^0.5.21", "supertest": "^6.3.3", "ts-jest": "^29.1.0", From 660d6881253fe2cd1c277f6f24228f86db11f4f0 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 23 Nov 2023 02:58:37 +0900 Subject: [PATCH 015/170] =?UTF-8?q?feat(#58):=20=EC=9E=84=EC=8B=9C=20DB=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../temporary-database.module.ts | 9 + .../temporary-database.service.spec.ts | 18 ++ .../temporary-database.service.ts | 155 ++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 nestjs-BE/cache-server/src/temporary-database/temporary-database.module.ts create mode 100644 nestjs-BE/cache-server/src/temporary-database/temporary-database.service.spec.ts create mode 100644 nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts diff --git a/nestjs-BE/cache-server/src/temporary-database/temporary-database.module.ts b/nestjs-BE/cache-server/src/temporary-database/temporary-database.module.ts new file mode 100644 index 00000000..d3a2f58a --- /dev/null +++ b/nestjs-BE/cache-server/src/temporary-database/temporary-database.module.ts @@ -0,0 +1,9 @@ +import { Global, Module } from '@nestjs/common'; +import { TemporaryDatabaseService } from './temporary-database.service'; + +@Global() +@Module({ + providers: [TemporaryDatabaseService], + exports: [TemporaryDatabaseService], +}) +export class TemporaryDatabaseModule {} diff --git a/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.spec.ts b/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.spec.ts new file mode 100644 index 00000000..b76bc582 --- /dev/null +++ b/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { TemporaryDatabaseService } from './temporary-database.service'; + +describe('TemporaryDatabaseService', () => { + let service: TemporaryDatabaseService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [TemporaryDatabaseService], + }).compile(); + + service = module.get(TemporaryDatabaseService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts b/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts new file mode 100644 index 00000000..3b29795b --- /dev/null +++ b/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts @@ -0,0 +1,155 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { Cron } from '@nestjs/schedule'; +import { writeFileSync, readFileSync, existsSync, readdirSync } from 'fs'; +import { join } from 'path'; + +interface OperationData { + service: string; + uniqueKey: string; + command: string; + data: any; +} + +@Injectable() +export class TemporaryDatabaseService { + private database: Map>> = new Map(); + private readonly FOLDER_NAME = 'operations'; + + constructor(private readonly prisma: PrismaService) { + this.initializeDatabase(); + this.readDataFromFiles(); + } + + private initializeDatabase() { + const services = ['user', 'space', 'board']; + const operations = ['insert', 'update', 'delete']; + + services.forEach((service) => { + const serviceMap = new Map(); + this.database.set(service, serviceMap); + operations.forEach((operation) => { + serviceMap.set(operation, new Map()); + }); + }); + } + + private readDataFromFiles() { + const files = readdirSync(this.FOLDER_NAME); + files.forEach((file) => { + if (file.endsWith('.csv')) { + this.readDataFromFile(file); + } + }); + } + + private readDataFromFile(file: string) { + const [service, commandWithExtension] = file.split('-'); + const command = commandWithExtension.replace('.csv', ''); + const fileData = readFileSync(join(this.FOLDER_NAME, file), 'utf8'); + fileData.split('\n').forEach((line) => { + if (line.trim() !== '') { + const [uniqueKey, ...dataParts] = line.split(','); + const data = dataParts.join(','); + this.database + .get(service) + .get(command) + .set(uniqueKey, JSON.parse(data)); + } + }); + } + + get(service: string, uniqueKey: string, command: string): any { + return this.database.get(service).get(command).get(uniqueKey); + } + + create(service: string, uniqueKey: string, data: any) { + this.operation({ service, uniqueKey, command: 'insert', data }); + } + + update(service: string, uniqueKey: string, data: any) { + this.operation({ service, uniqueKey, command: 'update', data }); + } + + remove(service: string, uniqueKey: string, data: any) { + this.operation({ service, uniqueKey, command: 'delete', data }); + } + + delete(service: string, uniqueKey: string, command: string) { + this.database.get(service).get(command).delete(uniqueKey); + } + + operation({ service, uniqueKey, command, data }: OperationData) { + const filePath = join(this.FOLDER_NAME, `${service}-${command}.csv`); + let fileData = existsSync(filePath) ? readFileSync(filePath, 'utf8') : ''; + fileData += `${uniqueKey},${JSON.stringify(data)}\n`; + writeFileSync(filePath, fileData); + this.database.get(service).get(command).set(uniqueKey, data); + } + + @Cron('0 */10 * * * *') + async executeBulkOperations() { + for (const service of this.database.keys()) { + const serviceMap = this.database.get(service); + await this.performInsert(service, serviceMap.get('insert')); + await this.performUpdate(service, serviceMap.get('update')); + await this.performDelete(service, serviceMap.get('delete')); + } + } + + private async performInsert(service: string, dataMap: Map) { + const data = this.prepareData(service, 'insert', dataMap); + if (!data.length) return; + await this.prisma[service].createMany({ + data: data, + skipDuplicates: true, + }); + } + + private async performUpdate(service: string, dataMap: Map) { + const data = this.prepareData(service, 'update', dataMap); + if (!data.length) return; + await Promise.all( + data.map((item) => { + const keyField = item.field; + const keyValue = item.value[keyField]; + return this.prisma[service].update({ + where: { [keyField]: keyValue }, + data: item.value, + }); + }), + ); + } + + private async performDelete(service: string, dataMap: Map) { + const data = this.prepareData(service, 'delete', dataMap); + if (!data.length) return; + await Promise.all( + data.map(async (item) => { + const existing = await this.prisma[service].findUnique({ + where: { [item.field]: item.value }, + }); + if (existing) { + return this.prisma[service].delete({ + where: { [item.field]: item.value }, + }); + } + }), + ); + } + + private prepareData( + service: string, + operation: string, + dataMap: Map, + ) { + const data = Array.from(dataMap.values()); + this.clearFile(`${service}-${operation}.csv`); + dataMap.clear(); + return data; + } + + private clearFile(filename: string) { + writeFileSync(join(this.FOLDER_NAME, filename), '', 'utf8'); + } +} From 44d890fffcb730d56112bb0f43f4b9bc0260d0d8 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 23 Nov 2023 02:59:21 +0900 Subject: [PATCH 016/170] =?UTF-8?q?fix(#58):=20return=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20=EB=B0=8F=20delete=20=ED=95=A8=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/cache-server/src/utils/lru-cache.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/nestjs-BE/cache-server/src/utils/lru-cache.ts b/nestjs-BE/cache-server/src/utils/lru-cache.ts index 1ef5b0bd..5e70d557 100644 --- a/nestjs-BE/cache-server/src/utils/lru-cache.ts +++ b/nestjs-BE/cache-server/src/utils/lru-cache.ts @@ -34,21 +34,24 @@ export default class LRUCache { this.add(node); return node.value; } - return -1; + return null; } put(key: string, value: any): void { - if (this.hashmap[key]) this.remove(this.hashmap[key]); + if (this.hashmap[key]) this.delete(key); const node = new LRUNode(key, value); this.add(node); this.hashmap[key] = node; - if (Object.keys(this.hashmap).length > this.capacity) { - const oldestNode = this.head.next; - if (oldestNode) { - this.remove(oldestNode); - delete this.hashmap[oldestNode.key]; - } + + if (Object.keys(this.hashmap).length > this.capacity) this.removeOldest(1); + } + + delete(key: string): void { + if (this.hashmap[key]) { + const node = this.hashmap[key]; + this.remove(node); + delete this.hashmap[key]; } } From c2737978b9f47b267a1f80c5889aa697d820199a Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 23 Nov 2023 18:39:14 +0900 Subject: [PATCH 017/170] =?UTF-8?q?feat(#76):=20CRDT=20=EC=9E=91=EC=97=85?= =?UTF-8?q?=20=EC=B2=98=EB=A6=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/crdt/crdt-tree.ts | 168 ++++++++++++++++++++++++++++++++++++ nestjs-BE/crdt/operation.ts | 119 +++++++++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 nestjs-BE/crdt/crdt-tree.ts create mode 100644 nestjs-BE/crdt/operation.ts diff --git a/nestjs-BE/crdt/crdt-tree.ts b/nestjs-BE/crdt/crdt-tree.ts new file mode 100644 index 00000000..59758a08 --- /dev/null +++ b/nestjs-BE/crdt/crdt-tree.ts @@ -0,0 +1,168 @@ +import { Clock, COMPARE } from './clock'; +import { + Operation, + OperationAdd, + OperationDelete, + OperationInput, + OperationLog, + OperationMove, + SerializedOperation, +} from './operation'; +import { Tree } from './tree'; +import { Node } from './node'; + +export class CrdtTree { + operationLog: OperationLog[] = []; + clock: Clock; + tree = new Tree(); + + constructor(id: string) { + this.clock = new Clock(id); + } + + get(id: string): Node | undefined { + return this.tree.get(id); + } + + addLog(log: OperationLog) { + this.operationLog.push(log); + } + + generateOperationAdd( + targetId: string, + parentId: string, + content: T, + ): OperationAdd { + this.clock.increment(); + const clock = this.clock.copy(); + const input: OperationInput = { + id: targetId, + parentId, + content, + clock, + }; + return new OperationAdd(input); + } + + generateOperationDelete(targetId: string): OperationDelete { + this.clock.increment(); + const clock = this.clock.copy(); + const input: OperationInput = { + id: targetId, + clock, + }; + return new OperationDelete(input); + } + + generateOperationMove(targetId: string, parentId: string): OperationMove { + this.clock.increment(); + const clock = this.clock.copy(); + const input: OperationInput = { + id: targetId, + parentId, + clock, + }; + return new OperationMove(input); + } + + serializeOperationAdd(operation: OperationAdd): SerializedOperation { + const serializedOperation: SerializedOperation = { + operationType: 'add', + id: operation.id, + clock: { id: operation.clock.id, counter: operation.clock.counter }, + content: operation.content, + parentId: operation.parentId, + }; + return serializedOperation; + } + + serializeOperationDelete( + operation: OperationDelete, + ): SerializedOperation { + const serializedOperation: SerializedOperation = { + operationType: 'delete', + id: operation.id, + clock: { id: operation.clock.id, counter: operation.clock.counter }, + }; + return serializedOperation; + } + + serializeOperationMove(operation: OperationMove): SerializedOperation { + const serializedOperation: SerializedOperation = { + operationType: 'move', + id: operation.id, + clock: { id: operation.clock.id, counter: operation.clock.counter }, + parentId: operation.parentId, + }; + return serializedOperation; + } + + deserializeOperationAdd( + serializedOperation: SerializedOperation, + ): OperationAdd { + const input: OperationInput = { + id: serializedOperation.id, + parentId: serializedOperation.parentId, + content: serializedOperation.content, + clock: new Clock( + serializedOperation.clock.id, + serializedOperation.clock.counter, + ), + }; + return new OperationAdd(input); + } + + deserializeOperationDelete( + serializedOperation: SerializedOperation, + ): OperationDelete { + const input: OperationInput = { + id: serializedOperation.id, + clock: new Clock( + serializedOperation.clock.id, + serializedOperation.clock.counter, + ), + }; + return new OperationDelete(input); + } + + deserializeOperationMove( + serializedOperation: SerializedOperation, + ): OperationMove { + const input: OperationInput = { + id: serializedOperation.id, + parentId: serializedOperation.parentId, + clock: new Clock( + serializedOperation.clock.id, + serializedOperation.clock.counter, + ), + }; + return new OperationMove(input); + } + + applyOperation(operation: Operation) { + this.clock = this.clock.merge(operation.clock); + + if (this.operationLog.length === 0) { + const log = operation.doOperation(this.tree); + this.addLog(log); + return; + } + + const lastOperation = + this.operationLog[this.operationLog.length - 1].operation; + if (operation.clock.compare(lastOperation.clock) === COMPARE.LESS) { + const prevLog = this.operationLog.pop(); + prevLog.operation.undoOperation(this.tree, prevLog); + this.applyOperation(operation); + const redoLog = prevLog.operation.redoOperation(this.tree, prevLog); + this.addLog(redoLog); + } else { + const log = operation.doOperation(this.tree); + this.addLog(log); + } + } + + applyOperations(operations: Operation[]) { + for (const operation of operations) this.applyOperation(operation); + } +} diff --git a/nestjs-BE/crdt/operation.ts b/nestjs-BE/crdt/operation.ts new file mode 100644 index 00000000..7bf2255f --- /dev/null +++ b/nestjs-BE/crdt/operation.ts @@ -0,0 +1,119 @@ +import { Clock } from './clock'; +import { Tree } from './tree'; + +export interface OperationLog { + operation: Operation; + oldParentId?: string; + oldContent?: T; +} + +export interface OperationInput { + id: string; + clock: Clock; + content?: T; + parentId?: string; +} + +interface ClockInterface { + id: string; + counter: number; +} + +export interface SerializedOperation { + operationType: string; + id: string; + clock: ClockInterface; + content?: T; + parentId?: string; +} + +export abstract class Operation { + operationType: string; + id: string; + clock: Clock; + + constructor(operationType: string, id: string, clock: Clock) { + this.operationType = operationType; + this.id = id; + this.clock = clock; + } + + abstract doOperation(tree: Tree): OperationLog; + abstract undoOperation(tree: Tree, log: OperationLog): void; + abstract redoOperation(tree: Tree, log: OperationLog): OperationLog; +} + +export class OperationAdd extends Operation { + content: T; + parentId: string; + + constructor(input: OperationInput) { + super('add', input.id, input.clock); + this.content = input.content; + this.parentId = input.parentId; + } + + doOperation(tree: Tree): OperationLog { + tree.addNode(this.id, this.parentId, this.content); + return { operation: this }; + } + + undoOperation(tree: Tree, log: OperationLog): void { + tree.removeNode(log.operation.id); + } + + redoOperation(tree: Tree, log?: OperationLog): OperationLog { + tree.attachNode(log.operation.id, this.parentId); + return { operation: this }; + } +} + +export class OperationDelete extends Operation { + constructor(input: OperationInput) { + super('delete', input.id, input.clock); + } + + doOperation(tree: Tree): OperationLog { + const node = tree.get(this.id); + const oldParentId = node.parentId; + tree.removeNode(this.id); + return { operation: this, oldParentId: oldParentId }; + } + + undoOperation(tree: Tree, log: OperationLog): void { + tree.attachNode(log.operation.id, log.oldParentId); + } + + redoOperation(tree: Tree, log?: OperationLog): OperationLog { + const redoLog = log.operation.doOperation(tree); + return redoLog; + } +} + +export class OperationMove extends Operation { + parentId: string; + + constructor(input: OperationInput) { + super('move', input.id, input.clock); + this.parentId = input.parentId; + } + + doOperation(tree: Tree): OperationLog { + const node = tree.get(this.id); + const oldParentId = node.parentId; + + tree.removeNode(this.id); + tree.attachNode(this.id, this.parentId); + return { operation: this, oldParentId }; + } + + undoOperation(tree: Tree, log: OperationLog): void { + tree.removeNode(log.operation.id); + tree.attachNode(log.operation.id, log.oldParentId); + } + + redoOperation(tree: Tree, log?: OperationLog): OperationLog { + const redoLog = log.operation.doOperation(tree); + return redoLog; + } +} From c1962c213dce491d4b254173430b413949989bde Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 23 Nov 2023 18:40:22 +0900 Subject: [PATCH 018/170] =?UTF-8?q?feat(#76):=20=ED=8A=B8=EB=A6=AC=20?= =?UTF-8?q?=EB=85=B8=EB=93=9C=20update=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/crdt/crdt-tree.ts | 38 +++++++++++++++++++++++++++++++++++++ nestjs-BE/crdt/operation.ts | 25 ++++++++++++++++++++++++ nestjs-BE/crdt/tree.ts | 7 +++++++ 3 files changed, 70 insertions(+) diff --git a/nestjs-BE/crdt/crdt-tree.ts b/nestjs-BE/crdt/crdt-tree.ts index 59758a08..e4ce4192 100644 --- a/nestjs-BE/crdt/crdt-tree.ts +++ b/nestjs-BE/crdt/crdt-tree.ts @@ -6,6 +6,7 @@ import { OperationInput, OperationLog, OperationMove, + OperationUpdate, SerializedOperation, } from './operation'; import { Tree } from './tree'; @@ -65,6 +66,17 @@ export class CrdtTree { return new OperationMove(input); } + generateOperationUpdate(targetId: string, content: T): OperationUpdate { + this.clock.increment(); + const clock = this.clock.copy(); + const input: OperationInput = { + id: targetId, + content, + clock, + }; + return new OperationUpdate(input); + } + serializeOperationAdd(operation: OperationAdd): SerializedOperation { const serializedOperation: SerializedOperation = { operationType: 'add', @@ -97,6 +109,18 @@ export class CrdtTree { return serializedOperation; } + serializeOperationUpdate( + operation: OperationUpdate, + ): SerializedOperation { + const serializedOperation: SerializedOperation = { + operationType: 'update', + id: operation.id, + clock: { id: operation.clock.id, counter: operation.clock.counter }, + content: operation.content, + }; + return serializedOperation; + } + deserializeOperationAdd( serializedOperation: SerializedOperation, ): OperationAdd { @@ -139,6 +163,20 @@ export class CrdtTree { return new OperationMove(input); } + deserializeOperationUpdate( + serializedOperation: SerializedOperation, + ): OperationUpdate { + const input: OperationInput = { + id: serializedOperation.id, + content: serializedOperation.content, + clock: new Clock( + serializedOperation.clock.id, + serializedOperation.clock.counter, + ), + }; + return new OperationUpdate(input); + } + applyOperation(operation: Operation) { this.clock = this.clock.merge(operation.clock); diff --git a/nestjs-BE/crdt/operation.ts b/nestjs-BE/crdt/operation.ts index 7bf2255f..644206f2 100644 --- a/nestjs-BE/crdt/operation.ts +++ b/nestjs-BE/crdt/operation.ts @@ -117,3 +117,28 @@ export class OperationMove extends Operation { return redoLog; } } + +export class OperationUpdate extends Operation { + content: T; + + constructor(input: OperationInput) { + super('update', input.id, input.clock); + this.content = input.content; + } + + doOperation(tree: Tree): OperationLog { + const node = tree.get(this.id); + const oldContent = node.content; + tree.updateNode(this.id, this.content); + return { operation: this, oldContent }; + } + + undoOperation(tree: Tree, log: OperationLog): void { + tree.updateNode(log.operation.id, log.oldContent); + } + + redoOperation(tree: Tree, log?: OperationLog): OperationLog { + const redoLog = log.operation.doOperation(tree); + return redoLog; + } +} diff --git a/nestjs-BE/crdt/tree.ts b/nestjs-BE/crdt/tree.ts index 3be39393..3e1cf36e 100644 --- a/nestjs-BE/crdt/tree.ts +++ b/nestjs-BE/crdt/tree.ts @@ -55,4 +55,11 @@ export class Tree { return this.nodes.get(targetId); } + + updateNode(targetId: string, content: T) { + const targetNode = this.nodes.get(targetId); + if (!targetNode) return; + + targetNode.content = content; + } } From 1cbff5fafea7ffaac13cc8efbb063a301017b449 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Fri, 24 Nov 2023 01:00:55 +0900 Subject: [PATCH 019/170] =?UTF-8?q?feat(#58):=20=EA=B3=B5=ED=86=B5?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=82=AC=EC=9A=A9=20=ED=95=A0=20base=20cl?= =?UTF-8?q?ass=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cache-server/src/base/base.service.ts | 130 ++++++++++++++++++ nestjs-BE/cache-server/src/utils/uuid.ts | 6 + 2 files changed, 136 insertions(+) create mode 100644 nestjs-BE/cache-server/src/base/base.service.ts create mode 100644 nestjs-BE/cache-server/src/utils/uuid.ts diff --git a/nestjs-BE/cache-server/src/base/base.service.ts b/nestjs-BE/cache-server/src/base/base.service.ts new file mode 100644 index 00000000..062c4e56 --- /dev/null +++ b/nestjs-BE/cache-server/src/base/base.service.ts @@ -0,0 +1,130 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { TemporaryDatabaseService } from '../temporary-database/temporary-database.service'; +import LRUCache from '../utils/lru-cache'; +import generateUuid from '../utils/uuid'; + +interface BaseServiceOptions { + prisma: PrismaService; + temporaryDatabaseService: TemporaryDatabaseService; + cacheSize: number; + className: string; + field: string; +} + +export interface HasUuid { + uuid?: string; +} + +@Injectable() +export abstract class BaseService { + protected cache: LRUCache; + protected className: string; + protected field: string; + protected prisma: PrismaService; + protected temporaryDatabaseService: TemporaryDatabaseService; + + constructor(options: BaseServiceOptions) { + this.cache = new LRUCache(options.cacheSize); + this.className = options.className; + this.field = options.field; + this.prisma = options.prisma; + this.temporaryDatabaseService = options.temporaryDatabaseService; + } + + abstract generateKey(data: T): string; + + async create(data: T): Promise { + data.uuid = generateUuid(); + const key = this.generateKey(data); + const storeData = await this.getDataFromCacheOrDB(key); + if (storeData) return 'data already exists.'; + + this.temporaryDatabaseService.create(this.className, key, data); + this.cache.put(key, data); + return data; + } + + async findOne(key: string): Promise { + const data = await this.getDataFromCacheOrDB(key); + + const deleteCommand = this.temporaryDatabaseService.get( + this.className, + key, + 'delete', + ); + if (deleteCommand) return null; + if (data) { + const mergedData = this.mergeWithUpdateCommand(data, key); + this.cache.put(key, mergedData); + return mergedData; + } + + return data; + } + + async update(key: string, updateData: any) { + const data = await this.getDataFromCacheOrDB(key); + + if (data) { + const updatedData = { + field: this.field, + value: { ...data, ...updateData }, + }; + if (this.temporaryDatabaseService.get(this.className, key, 'insert')) { + this.temporaryDatabaseService.create( + this.className, + key, + updatedData.value, + ); + } else { + this.temporaryDatabaseService.update(this.className, key, updatedData); + } + + this.cache.put(key, updatedData.value); + } + } + + async remove(key: string) { + this.cache.delete(key); + const insertTemporaryData = this.temporaryDatabaseService.get( + this.className, + key, + 'insert', + ); + if (insertTemporaryData) { + this.temporaryDatabaseService.delete(this.className, key, 'insert'); + } else { + this.temporaryDatabaseService.remove(this.className, key, { + field: this.field, + value: key, + }); + } + } + + async getDataFromCacheOrDB(key: string): Promise { + const cacheData = this.cache.get(key); + if (cacheData) return cacheData; + const temporaryDatabaseData = this.temporaryDatabaseService.get( + this.className, + key, + 'insert', + ); + if (temporaryDatabaseData) return temporaryDatabaseData; + const databaseData = await this.prisma[this.className].findUnique({ + where: { [this.field]: key }, + }); + return databaseData; + } + + private mergeWithUpdateCommand(data: any, key: string): T { + const updateCommand = this.temporaryDatabaseService.get( + this.className, + key, + 'update', + ); + if (updateCommand) return { ...data, ...updateCommand }; + + return data; + } +} diff --git a/nestjs-BE/cache-server/src/utils/uuid.ts b/nestjs-BE/cache-server/src/utils/uuid.ts new file mode 100644 index 00000000..bd4eea80 --- /dev/null +++ b/nestjs-BE/cache-server/src/utils/uuid.ts @@ -0,0 +1,6 @@ +import { v1 as uuid1 } from 'uuid'; + +export default function generateUuid(): string { + const [first, second, third, fourth, fifth] = uuid1().split('-'); + return third + second + first + fourth + fifth; +} From 53636f6a286d181c5e27f504301e74bc4fc558ab Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Fri, 24 Nov 2023 01:04:15 +0900 Subject: [PATCH 020/170] =?UTF-8?q?chore(#58):=20uuid=20=EC=84=A4=EC=B9=98?= =?UTF-8?q?=20=EB=B0=8F=20gitignore=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/cache-server/.gitignore | 8 +++++++- nestjs-BE/cache-server/package-lock.json | 3 ++- nestjs-BE/cache-server/package.json | 3 ++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/nestjs-BE/cache-server/.gitignore b/nestjs-BE/cache-server/.gitignore index 22f55adc..48a804b7 100644 --- a/nestjs-BE/cache-server/.gitignore +++ b/nestjs-BE/cache-server/.gitignore @@ -32,4 +32,10 @@ lerna-debug.log* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json -!.vscode/extensions.json \ No newline at end of file +!.vscode/extensions.json + +# 환경 변수 +.env + +# csv +/operations \ No newline at end of file diff --git a/nestjs-BE/cache-server/package-lock.json b/nestjs-BE/cache-server/package-lock.json index 622d4089..e8148d14 100644 --- a/nestjs-BE/cache-server/package-lock.json +++ b/nestjs-BE/cache-server/package-lock.json @@ -16,7 +16,8 @@ "@nestjs/schedule": "^4.0.0", "@prisma/client": "^5.6.0", "reflect-metadata": "^0.1.13", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "uuid": "^9.0.1" }, "devDependencies": { "@nestjs/cli": "^10.0.0", diff --git a/nestjs-BE/cache-server/package.json b/nestjs-BE/cache-server/package.json index 2fb01361..fb5ba9e6 100644 --- a/nestjs-BE/cache-server/package.json +++ b/nestjs-BE/cache-server/package.json @@ -27,7 +27,8 @@ "@nestjs/schedule": "^4.0.0", "@prisma/client": "^5.6.0", "reflect-metadata": "^0.1.13", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "uuid": "^9.0.1" }, "devDependencies": { "@nestjs/cli": "^10.0.0", From 6746643f26a2250780dca6b6d1584a6e50cc8000 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Fri, 24 Nov 2023 01:04:57 +0900 Subject: [PATCH 021/170] =?UTF-8?q?feat(#58):=20prisma=20=EC=8A=A4?= =?UTF-8?q?=ED=82=A4=EB=A7=88=20=EB=B0=8F=20=EB=AA=A8=EB=93=88=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/cache-server/prisma/schema.prisma | 40 +++++++++++++++++++ .../cache-server/src/prisma/prisma.module.ts | 9 +++++ .../src/prisma/prisma.service.spec.ts | 18 +++++++++ .../cache-server/src/prisma/prisma.service.ts | 9 +++++ 4 files changed, 76 insertions(+) create mode 100644 nestjs-BE/cache-server/prisma/schema.prisma create mode 100644 nestjs-BE/cache-server/src/prisma/prisma.module.ts create mode 100644 nestjs-BE/cache-server/src/prisma/prisma.service.spec.ts create mode 100644 nestjs-BE/cache-server/src/prisma/prisma.service.ts diff --git a/nestjs-BE/cache-server/prisma/schema.prisma b/nestjs-BE/cache-server/prisma/schema.prisma new file mode 100644 index 00000000..60e97088 --- /dev/null +++ b/nestjs-BE/cache-server/prisma/schema.prisma @@ -0,0 +1,40 @@ +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "mysql" + url = env("DATABASE_URL") +} + +model USER_TB { + uuid String @id @db.VarChar(32) + email String @unique + password String + profiles PROFILE_TB[] +} + +model PROFILE_TB { + uuid String @id @db.VarChar(32) + user_id String @db.VarChar(32) + image String + nickname String + user USER_TB @relation(fields: [user_id], references: [uuid]) + spaces PROFILE_SPACE_TB[] + @@index([user_id]) +} + +model SPACE_TB { + uuid String @id @db.VarChar(32) + name String + icon String + profiles PROFILE_SPACE_TB[] +} + +model PROFILE_SPACE_TB { + space_uuid String @db.VarChar(32) + profile_uuid String @db.VarChar(32) + space SPACE_TB @relation(fields: [space_uuid], references: [uuid]) + profile PROFILE_TB @relation(fields: [profile_uuid], references: [uuid]) + @@id([space_uuid, profile_uuid]) +} \ No newline at end of file diff --git a/nestjs-BE/cache-server/src/prisma/prisma.module.ts b/nestjs-BE/cache-server/src/prisma/prisma.module.ts new file mode 100644 index 00000000..7207426f --- /dev/null +++ b/nestjs-BE/cache-server/src/prisma/prisma.module.ts @@ -0,0 +1,9 @@ +import { Global, Module } from '@nestjs/common'; +import { PrismaService } from './prisma.service'; + +@Global() +@Module({ + providers: [PrismaService], + exports: [PrismaService], +}) +export class PrismaModule {} diff --git a/nestjs-BE/cache-server/src/prisma/prisma.service.spec.ts b/nestjs-BE/cache-server/src/prisma/prisma.service.spec.ts new file mode 100644 index 00000000..a68cb9e3 --- /dev/null +++ b/nestjs-BE/cache-server/src/prisma/prisma.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { PrismaService } from './prisma.service'; + +describe('PrismaService', () => { + let service: PrismaService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [PrismaService], + }).compile(); + + service = module.get(PrismaService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/nestjs-BE/cache-server/src/prisma/prisma.service.ts b/nestjs-BE/cache-server/src/prisma/prisma.service.ts new file mode 100644 index 00000000..359f950b --- /dev/null +++ b/nestjs-BE/cache-server/src/prisma/prisma.service.ts @@ -0,0 +1,9 @@ +import { Injectable, OnModuleInit } from '@nestjs/common'; +import { PrismaClient } from '@prisma/client'; + +@Injectable() +export class PrismaService extends PrismaClient implements OnModuleInit { + async onModuleInit() { + await this.$connect(); + } +} From f2f1ff9140438d01f18879bb24efecaf713ade8e Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Fri, 24 Nov 2023 01:06:19 +0900 Subject: [PATCH 022/170] =?UTF-8?q?feat(#58):=20=ED=9A=8C=EC=9B=90=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/users/dto/create-user.dto.ts | 4 ++ .../src/users/dto/update-user.dto.ts | 4 ++ .../src/users/entities/user.entity.ts | 1 + .../src/users/users.controller.spec.ts | 20 +++++++ .../src/users/users.controller.ts | 42 +++++++++++++ .../cache-server/src/users/users.module.ts | 9 +++ .../src/users/users.service.spec.ts | 18 ++++++ .../cache-server/src/users/users.service.ts | 59 +++++++++++++++++++ 8 files changed, 157 insertions(+) create mode 100644 nestjs-BE/cache-server/src/users/dto/create-user.dto.ts create mode 100644 nestjs-BE/cache-server/src/users/dto/update-user.dto.ts create mode 100644 nestjs-BE/cache-server/src/users/entities/user.entity.ts create mode 100644 nestjs-BE/cache-server/src/users/users.controller.spec.ts create mode 100644 nestjs-BE/cache-server/src/users/users.controller.ts create mode 100644 nestjs-BE/cache-server/src/users/users.module.ts create mode 100644 nestjs-BE/cache-server/src/users/users.service.spec.ts create mode 100644 nestjs-BE/cache-server/src/users/users.service.ts diff --git a/nestjs-BE/cache-server/src/users/dto/create-user.dto.ts b/nestjs-BE/cache-server/src/users/dto/create-user.dto.ts new file mode 100644 index 00000000..16baaf2d --- /dev/null +++ b/nestjs-BE/cache-server/src/users/dto/create-user.dto.ts @@ -0,0 +1,4 @@ +export class CreateUserDto { + email: string; + password: string; +} diff --git a/nestjs-BE/cache-server/src/users/dto/update-user.dto.ts b/nestjs-BE/cache-server/src/users/dto/update-user.dto.ts new file mode 100644 index 00000000..dfd37fb1 --- /dev/null +++ b/nestjs-BE/cache-server/src/users/dto/update-user.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateUserDto } from './create-user.dto'; + +export class UpdateUserDto extends PartialType(CreateUserDto) {} diff --git a/nestjs-BE/cache-server/src/users/entities/user.entity.ts b/nestjs-BE/cache-server/src/users/entities/user.entity.ts new file mode 100644 index 00000000..4f82c145 --- /dev/null +++ b/nestjs-BE/cache-server/src/users/entities/user.entity.ts @@ -0,0 +1 @@ +export class User {} diff --git a/nestjs-BE/cache-server/src/users/users.controller.spec.ts b/nestjs-BE/cache-server/src/users/users.controller.spec.ts new file mode 100644 index 00000000..a76d3103 --- /dev/null +++ b/nestjs-BE/cache-server/src/users/users.controller.spec.ts @@ -0,0 +1,20 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { UsersController } from './users.controller'; +import { UsersService } from './users.service'; + +describe('UsersController', () => { + let controller: UsersController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [UsersController], + providers: [UsersService], + }).compile(); + + controller = module.get(UsersController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/nestjs-BE/cache-server/src/users/users.controller.ts b/nestjs-BE/cache-server/src/users/users.controller.ts new file mode 100644 index 00000000..28f7de55 --- /dev/null +++ b/nestjs-BE/cache-server/src/users/users.controller.ts @@ -0,0 +1,42 @@ +import { + Controller, + Get, + Post, + Body, + Patch, + Param, + Delete, +} from '@nestjs/common'; +import { UsersService } from './users.service'; +import { CreateUserDto } from './dto/create-user.dto'; +import { UpdateUserDto } from './dto/update-user.dto'; + +@Controller('users') +export class UsersController { + constructor(private readonly usersService: UsersService) {} + + @Post() + create(@Body() createUserDto: CreateUserDto) { + return this.usersService.create(createUserDto); + } + + @Get(':email') + findOne(@Param('email') email: string) { + return this.usersService.findOne(email); + } + + @Patch(':email') + update(@Param('email') email: string, @Body() updateUserDto: UpdateUserDto) { + return this.usersService.update(email, updateUserDto); + } + + @Delete(':email') + remove(@Param('email') email: string) { + return this.usersService.remove(email); + } + + @Get('profiles/:email') + findProfiles(@Param('email') email: string) { + return this.usersService.getProfiles(email); + } +} diff --git a/nestjs-BE/cache-server/src/users/users.module.ts b/nestjs-BE/cache-server/src/users/users.module.ts new file mode 100644 index 00000000..ecca17ad --- /dev/null +++ b/nestjs-BE/cache-server/src/users/users.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { UsersService } from './users.service'; +import { UsersController } from './users.controller'; + +@Module({ + controllers: [UsersController], + providers: [UsersService], +}) +export class UsersModule {} diff --git a/nestjs-BE/cache-server/src/users/users.service.spec.ts b/nestjs-BE/cache-server/src/users/users.service.spec.ts new file mode 100644 index 00000000..62815ba6 --- /dev/null +++ b/nestjs-BE/cache-server/src/users/users.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { UsersService } from './users.service'; + +describe('UsersService', () => { + let service: UsersService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [UsersService], + }).compile(); + + service = module.get(UsersService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/nestjs-BE/cache-server/src/users/users.service.ts b/nestjs-BE/cache-server/src/users/users.service.ts new file mode 100644 index 00000000..e93a1044 --- /dev/null +++ b/nestjs-BE/cache-server/src/users/users.service.ts @@ -0,0 +1,59 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { TemporaryDatabaseService } from '../temporary-database/temporary-database.service'; +import { BaseService } from '../base/base.service'; +import { USER_CACHE_SIZE } from '../config/magic-number'; + +export interface User { + uuid?: string; + email: string; + password: string; +} + +@Injectable() +export class UsersService extends BaseService { + constructor( + protected prisma: PrismaService, + protected temporaryDatabaseService: TemporaryDatabaseService, + ) { + super({ + prisma, + temporaryDatabaseService, + cacheSize: USER_CACHE_SIZE, + className: 'USER_TB', + field: 'email', + }); + } + + generateKey(data: any): string { + return data.email; + } + + async getProfiles(email: string) { + let user = await this.prisma[this.className].findUnique({ + where: { email }, + include: { profiles: true }, + }); + + if (!user) user = await super.getDataFromCacheOrDB(email); + if (!user) return null; + + const profiles = user.profiles || []; + const temporaryProfilesUuids = + this.temporaryDatabaseService.getUserProfiles(user.uuid); + const temporaryProfiles = temporaryProfilesUuids.map((uuid) => + this.temporaryDatabaseService.get('PROFILE_TB', uuid, 'insert'), + ); + const combinedProfiles = [...profiles, ...temporaryProfiles]; + const mergedData = combinedProfiles.map((data) => { + const updateOperation = this.temporaryDatabaseService.get( + 'PROFILE_TB', + data.uuid, + 'update', + ); + if (updateOperation) return { ...data, ...updateOperation.value }; + return data; + }); + return mergedData; + } +} From e43258183c0593148821fe48b25cce237357d60b Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Fri, 24 Nov 2023 01:06:52 +0900 Subject: [PATCH 023/170] =?UTF-8?q?fix(#58):=20=EC=BB=A8=EB=B2=A4=EC=85=98?= =?UTF-8?q?=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../temporary-database.service.ts | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts b/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts index 3b29795b..ae19f645 100644 --- a/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts +++ b/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts @@ -14,6 +14,7 @@ interface OperationData { @Injectable() export class TemporaryDatabaseService { private database: Map>> = new Map(); + private userProfilesMap: Map = new Map(); private readonly FOLDER_NAME = 'operations'; constructor(private readonly prisma: PrismaService) { @@ -22,7 +23,7 @@ export class TemporaryDatabaseService { } private initializeDatabase() { - const services = ['user', 'space', 'board']; + const services = ['USER_TB', 'PROFILE_TB', 'SPACE_TB', 'BOARD_TB']; const operations = ['insert', 'update', 'delete']; services.forEach((service) => { @@ -99,6 +100,7 @@ export class TemporaryDatabaseService { private async performInsert(service: string, dataMap: Map) { const data = this.prepareData(service, 'insert', dataMap); + this.userProfilesMap.clear(); if (!data.length) return; await this.prisma[service].createMany({ data: data, @@ -152,4 +154,23 @@ export class TemporaryDatabaseService { private clearFile(filename: string) { writeFileSync(join(this.FOLDER_NAME, filename), '', 'utf8'); } + + getUserProfiles(user_id: string): string[] { + return this.userProfilesMap.get(user_id) || []; + } + + addUserProfile(user_id: string, profile_uuid: string): void { + const profiles = this.getUserProfiles(user_id); + profiles.push(profile_uuid); + this.userProfilesMap.set(user_id, profiles); + } + + removeUserProfile(user_id: string, profile_uuid: string): void { + const profiles = this.getUserProfiles(user_id); + const index = profiles.indexOf(profile_uuid); + if (index > -1) { + profiles.splice(index, 1); + this.userProfilesMap.set(user_id, profiles); + } + } } From e2925d22867d2c8461975dc1bcfe03c7cf50edcc Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Fri, 24 Nov 2023 01:07:25 +0900 Subject: [PATCH 024/170] =?UTF-8?q?feat(#58):=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=95=84=20=EB=93=B1=EB=A1=9D=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cache-server/src/config/magic-number.ts | 3 ++ .../src/profiles/dto/create-profile.dto.ts | 5 ++ .../src/profiles/dto/update-profile.dto.ts | 4 ++ .../src/profiles/entities/profile.entity.ts | 1 + .../src/profiles/profiles.controller.spec.ts | 20 ++++++++ .../src/profiles/profiles.controller.ts | 40 +++++++++++++++ .../src/profiles/profiles.module.ts | 9 ++++ .../src/profiles/profiles.service.spec.ts | 18 +++++++ .../src/profiles/profiles.service.ts | 51 +++++++++++++++++++ 9 files changed, 151 insertions(+) create mode 100644 nestjs-BE/cache-server/src/config/magic-number.ts create mode 100644 nestjs-BE/cache-server/src/profiles/dto/create-profile.dto.ts create mode 100644 nestjs-BE/cache-server/src/profiles/dto/update-profile.dto.ts create mode 100644 nestjs-BE/cache-server/src/profiles/entities/profile.entity.ts create mode 100644 nestjs-BE/cache-server/src/profiles/profiles.controller.spec.ts create mode 100644 nestjs-BE/cache-server/src/profiles/profiles.controller.ts create mode 100644 nestjs-BE/cache-server/src/profiles/profiles.module.ts create mode 100644 nestjs-BE/cache-server/src/profiles/profiles.service.spec.ts create mode 100644 nestjs-BE/cache-server/src/profiles/profiles.service.ts diff --git a/nestjs-BE/cache-server/src/config/magic-number.ts b/nestjs-BE/cache-server/src/config/magic-number.ts new file mode 100644 index 00000000..e2790d04 --- /dev/null +++ b/nestjs-BE/cache-server/src/config/magic-number.ts @@ -0,0 +1,3 @@ +export const USER_CACHE_SIZE = 1000; +export const PROFILE_CACHE_SIZE = 5000; +export const SPACE_CACHE_SIZE = 10000; diff --git a/nestjs-BE/cache-server/src/profiles/dto/create-profile.dto.ts b/nestjs-BE/cache-server/src/profiles/dto/create-profile.dto.ts new file mode 100644 index 00000000..a3222cff --- /dev/null +++ b/nestjs-BE/cache-server/src/profiles/dto/create-profile.dto.ts @@ -0,0 +1,5 @@ +export class CreateProfileDto { + user_id: string; + image: string; + nickname: string; +} diff --git a/nestjs-BE/cache-server/src/profiles/dto/update-profile.dto.ts b/nestjs-BE/cache-server/src/profiles/dto/update-profile.dto.ts new file mode 100644 index 00000000..d5a658ae --- /dev/null +++ b/nestjs-BE/cache-server/src/profiles/dto/update-profile.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateProfileDto } from './create-profile.dto'; + +export class UpdateProfileDto extends PartialType(CreateProfileDto) {} diff --git a/nestjs-BE/cache-server/src/profiles/entities/profile.entity.ts b/nestjs-BE/cache-server/src/profiles/entities/profile.entity.ts new file mode 100644 index 00000000..b4a8829d --- /dev/null +++ b/nestjs-BE/cache-server/src/profiles/entities/profile.entity.ts @@ -0,0 +1 @@ +export class Profile {} diff --git a/nestjs-BE/cache-server/src/profiles/profiles.controller.spec.ts b/nestjs-BE/cache-server/src/profiles/profiles.controller.spec.ts new file mode 100644 index 00000000..752ac281 --- /dev/null +++ b/nestjs-BE/cache-server/src/profiles/profiles.controller.spec.ts @@ -0,0 +1,20 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ProfilesController } from './profiles.controller'; +import { ProfilesService } from './profiles.service'; + +describe('ProfilesController', () => { + let controller: ProfilesController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [ProfilesController], + providers: [ProfilesService], + }).compile(); + + controller = module.get(ProfilesController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/nestjs-BE/cache-server/src/profiles/profiles.controller.ts b/nestjs-BE/cache-server/src/profiles/profiles.controller.ts new file mode 100644 index 00000000..92c1d6ee --- /dev/null +++ b/nestjs-BE/cache-server/src/profiles/profiles.controller.ts @@ -0,0 +1,40 @@ +import { + Controller, + Get, + Post, + Body, + Patch, + Param, + Delete, +} from '@nestjs/common'; +import { ProfilesService } from './profiles.service'; +import { CreateProfileDto } from './dto/create-profile.dto'; +import { UpdateProfileDto } from './dto/update-profile.dto'; + +@Controller('profiles') +export class ProfilesController { + constructor(private readonly profilesService: ProfilesService) {} + + @Post() + create(@Body() createProfileDto: CreateProfileDto) { + return this.profilesService.create(createProfileDto); + } + + @Get(':uuid') + findOne(@Param('uuid') uuid: string) { + return this.profilesService.findOne(uuid); + } + + @Patch(':uuid') + update( + @Param('uuid') uuid: string, + @Body() updateProfileDto: UpdateProfileDto, + ) { + return this.profilesService.update(uuid, updateProfileDto); + } + + @Delete(':uuid') + remove(@Param('uuid') uuid: string) { + return this.profilesService.remove(uuid); + } +} diff --git a/nestjs-BE/cache-server/src/profiles/profiles.module.ts b/nestjs-BE/cache-server/src/profiles/profiles.module.ts new file mode 100644 index 00000000..7459a790 --- /dev/null +++ b/nestjs-BE/cache-server/src/profiles/profiles.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { ProfilesService } from './profiles.service'; +import { ProfilesController } from './profiles.controller'; + +@Module({ + controllers: [ProfilesController], + providers: [ProfilesService], +}) +export class ProfilesModule {} diff --git a/nestjs-BE/cache-server/src/profiles/profiles.service.spec.ts b/nestjs-BE/cache-server/src/profiles/profiles.service.spec.ts new file mode 100644 index 00000000..29cbe78f --- /dev/null +++ b/nestjs-BE/cache-server/src/profiles/profiles.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ProfilesService } from './profiles.service'; + +describe('ProfilesService', () => { + let service: ProfilesService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ProfilesService], + }).compile(); + + service = module.get(ProfilesService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/nestjs-BE/cache-server/src/profiles/profiles.service.ts b/nestjs-BE/cache-server/src/profiles/profiles.service.ts new file mode 100644 index 00000000..e73a2322 --- /dev/null +++ b/nestjs-BE/cache-server/src/profiles/profiles.service.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { TemporaryDatabaseService } from '../temporary-database/temporary-database.service'; +import { BaseService } from '../base/base.service'; +import { PROFILE_CACHE_SIZE } from 'src/config/magic-number'; + +export interface Profile { + uuid?: string; + user_id: string; + image: string; + nickname: string; +} + +@Injectable() +export class ProfilesService extends BaseService { + constructor( + protected prisma: PrismaService, + protected temporaryDatabaseService: TemporaryDatabaseService, + ) { + super({ + prisma, + temporaryDatabaseService, + cacheSize: PROFILE_CACHE_SIZE, + className: 'PROFILE_TB', + field: 'uuid', + }); + } + + generateKey(data: any): string { + return data.uuid; + } + + async create(data: Profile): Promise { + const createdProfile = await super.create(data); + if (typeof createdProfile !== 'string') { + this.temporaryDatabaseService.addUserProfile( + data.user_id, + createdProfile.uuid, + ); + } + return createdProfile; + } + + async remove(key: string) { + const profile = await super.getDataFromCacheOrDB(key); + if (profile) { + this.temporaryDatabaseService.removeUserProfile(profile.user_id, key); + } + await super.remove(key); + } +} From 3d3bb0d409d60cf440c35e41324e266f2636c591 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Fri, 24 Nov 2023 01:08:14 +0900 Subject: [PATCH 025/170] =?UTF-8?q?feat(#58):=20=EC=8A=A4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80,?= =?UTF-8?q?=20=EB=B0=A9=20=EC=A0=91=EC=86=8D=20=EB=B0=8F=20=EB=82=98?= =?UTF-8?q?=EA=B0=80=EA=B8=B0=EB=8A=94=20=EC=88=98=EC=A0=95=20=ED=95=84?= =?UTF-8?q?=EC=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/spaces/dto/create-space.dto.ts | 4 ++ .../src/spaces/dto/update-space.dto.ts | 4 ++ .../src/spaces/entities/space.entity.ts | 1 + .../src/spaces/spaces.controller.spec.ts | 20 ++++++++ .../src/spaces/spaces.controller.ts | 37 ++++++++++++++ .../cache-server/src/spaces/spaces.module.ts | 9 ++++ .../src/spaces/spaces.service.spec.ts | 18 +++++++ .../cache-server/src/spaces/spaces.service.ts | 50 +++++++++++++++++++ 8 files changed, 143 insertions(+) create mode 100644 nestjs-BE/cache-server/src/spaces/dto/create-space.dto.ts create mode 100644 nestjs-BE/cache-server/src/spaces/dto/update-space.dto.ts create mode 100644 nestjs-BE/cache-server/src/spaces/entities/space.entity.ts create mode 100644 nestjs-BE/cache-server/src/spaces/spaces.controller.spec.ts create mode 100644 nestjs-BE/cache-server/src/spaces/spaces.controller.ts create mode 100644 nestjs-BE/cache-server/src/spaces/spaces.module.ts create mode 100644 nestjs-BE/cache-server/src/spaces/spaces.service.spec.ts create mode 100644 nestjs-BE/cache-server/src/spaces/spaces.service.ts diff --git a/nestjs-BE/cache-server/src/spaces/dto/create-space.dto.ts b/nestjs-BE/cache-server/src/spaces/dto/create-space.dto.ts new file mode 100644 index 00000000..db6d9a92 --- /dev/null +++ b/nestjs-BE/cache-server/src/spaces/dto/create-space.dto.ts @@ -0,0 +1,4 @@ +export class CreateSpaceDto { + name: string; + icon: string; +} diff --git a/nestjs-BE/cache-server/src/spaces/dto/update-space.dto.ts b/nestjs-BE/cache-server/src/spaces/dto/update-space.dto.ts new file mode 100644 index 00000000..f474d438 --- /dev/null +++ b/nestjs-BE/cache-server/src/spaces/dto/update-space.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateSpaceDto } from './create-space.dto'; + +export class UpdateSpaceDto extends PartialType(CreateSpaceDto) {} diff --git a/nestjs-BE/cache-server/src/spaces/entities/space.entity.ts b/nestjs-BE/cache-server/src/spaces/entities/space.entity.ts new file mode 100644 index 00000000..c75a03e4 --- /dev/null +++ b/nestjs-BE/cache-server/src/spaces/entities/space.entity.ts @@ -0,0 +1 @@ +export class Space {} diff --git a/nestjs-BE/cache-server/src/spaces/spaces.controller.spec.ts b/nestjs-BE/cache-server/src/spaces/spaces.controller.spec.ts new file mode 100644 index 00000000..bc7556ae --- /dev/null +++ b/nestjs-BE/cache-server/src/spaces/spaces.controller.spec.ts @@ -0,0 +1,20 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { SpacesController } from './spaces.controller'; +import { SpacesService } from './spaces.service'; + +describe('SpacesController', () => { + let controller: SpacesController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [SpacesController], + providers: [SpacesService], + }).compile(); + + controller = module.get(SpacesController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/nestjs-BE/cache-server/src/spaces/spaces.controller.ts b/nestjs-BE/cache-server/src/spaces/spaces.controller.ts new file mode 100644 index 00000000..e4440b3a --- /dev/null +++ b/nestjs-BE/cache-server/src/spaces/spaces.controller.ts @@ -0,0 +1,37 @@ +import { + Controller, + Get, + Post, + Body, + Patch, + Param, + Delete, +} from '@nestjs/common'; +import { SpacesService } from './spaces.service'; +import { CreateSpaceDto } from './dto/create-space.dto'; +import { UpdateSpaceDto } from './dto/update-space.dto'; + +@Controller('spaces') +export class SpacesController { + constructor(private readonly spacesService: SpacesService) {} + + @Post() + create(@Body() createSpaceDto: CreateSpaceDto) { + return this.spacesService.create(createSpaceDto); + } + + @Get(':uuid') + findOne(@Param('uuid') uuid: string) { + return this.spacesService.findOne(uuid); + } + + @Patch(':uuid') + update(@Param('uuid') uuid: string, @Body() updateSpaceDto: UpdateSpaceDto) { + return this.spacesService.update(uuid, updateSpaceDto); + } + + @Delete(':uuid') + remove(@Param('uuid') uuid: string) { + return this.spacesService.remove(uuid); + } +} diff --git a/nestjs-BE/cache-server/src/spaces/spaces.module.ts b/nestjs-BE/cache-server/src/spaces/spaces.module.ts new file mode 100644 index 00000000..5a9b68c9 --- /dev/null +++ b/nestjs-BE/cache-server/src/spaces/spaces.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { SpacesService } from './spaces.service'; +import { SpacesController } from './spaces.controller'; + +@Module({ + controllers: [SpacesController], + providers: [SpacesService], +}) +export class SpacesModule {} diff --git a/nestjs-BE/cache-server/src/spaces/spaces.service.spec.ts b/nestjs-BE/cache-server/src/spaces/spaces.service.spec.ts new file mode 100644 index 00000000..6b9d4876 --- /dev/null +++ b/nestjs-BE/cache-server/src/spaces/spaces.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { SpacesService } from './spaces.service'; + +describe('SpacesService', () => { + let service: SpacesService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [SpacesService], + }).compile(); + + service = module.get(SpacesService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/nestjs-BE/cache-server/src/spaces/spaces.service.ts b/nestjs-BE/cache-server/src/spaces/spaces.service.ts new file mode 100644 index 00000000..032dfe0f --- /dev/null +++ b/nestjs-BE/cache-server/src/spaces/spaces.service.ts @@ -0,0 +1,50 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { TemporaryDatabaseService } from '../temporary-database/temporary-database.service'; +import { BaseService } from '../base/base.service'; +import { SPACE_CACHE_SIZE } from 'src/config/magic-number'; + +export interface Space { + uuid?: string; + name: string; + icon: string; +} + +@Injectable() +export class SpacesService extends BaseService { + constructor( + protected prisma: PrismaService, + protected temporaryDatabaseService: TemporaryDatabaseService, + ) { + super({ + prisma, + temporaryDatabaseService, + cacheSize: SPACE_CACHE_SIZE, + className: 'SPACE_TB', + field: 'uuid', + }); + } + + generateKey(data: any): string { + return data.uuid; + } + + async joinSpace(profileUuid: string, spaceUuid: string) { + const profileSpace = { + space_uuid: spaceUuid, + profile_uuid: profileUuid, + }; + + await this.prisma['PROFILE_SPACE_TB'].create({ + data: profileSpace, + }); + + return profileSpace; + } + + async leaveSpace(profileUuid: string, spaceUuid: string) { + await this.prisma['PROFILE_SPACE_TB'].delete({ + where: { space_uuid: spaceUuid, profile_uuid: profileUuid }, + }); + } +} From 8d41262e3183cb6a40f0f1b2d1e67d6c277660e3 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Fri, 24 Nov 2023 01:08:40 +0900 Subject: [PATCH 026/170] =?UTF-8?q?fix(#58):=20=EA=B8=B0=EB=8A=A5=EC=9D=B4?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20=EB=90=A8=EC=97=90=20=EB=94=B0=EB=9D=BC?= =?UTF-8?q?=20=EB=AA=A8=EB=93=88=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/cache-server/src/app.module.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/nestjs-BE/cache-server/src/app.module.ts b/nestjs-BE/cache-server/src/app.module.ts index 02ae1fe4..f046876e 100644 --- a/nestjs-BE/cache-server/src/app.module.ts +++ b/nestjs-BE/cache-server/src/app.module.ts @@ -1,10 +1,22 @@ import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; +import { UsersModule } from './users/users.module'; +import { PrismaModule } from './prisma/prisma.module'; import { TemporaryDatabaseModule } from './temporary-database/temporary-database.module'; +import { ScheduleModule } from '@nestjs/schedule'; +import { ProfilesModule } from './profiles/profiles.module'; +import { SpacesModule } from './spaces/spaces.module'; @Module({ - imports: [TemporaryDatabaseModule], + imports: [ + UsersModule, + PrismaModule, + TemporaryDatabaseModule, + ScheduleModule.forRoot(), + ProfilesModule, + SpacesModule, + ], controllers: [AppController], providers: [AppService], }) From 17ab13fb33c4f7c149704a95f7ffb9d6c220dc1d Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Fri, 24 Nov 2023 20:34:03 +0900 Subject: [PATCH 027/170] =?UTF-8?q?fix(#58):=20any=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/cache-server/src/base/base.service.ts | 4 ++-- .../src/profiles/dto/update-profile.dto.ts | 4 +++- .../cache-server/src/profiles/profiles.service.ts | 13 ++++--------- .../cache-server/src/spaces/dto/update-space.dto.ts | 4 +++- nestjs-BE/cache-server/src/spaces/spaces.service.ts | 9 ++------- .../cache-server/src/users/dto/update-user.dto.ts | 4 +++- nestjs-BE/cache-server/src/users/users.service.ts | 9 ++------- 7 files changed, 19 insertions(+), 28 deletions(-) diff --git a/nestjs-BE/cache-server/src/base/base.service.ts b/nestjs-BE/cache-server/src/base/base.service.ts index 062c4e56..b1d27ac4 100644 --- a/nestjs-BE/cache-server/src/base/base.service.ts +++ b/nestjs-BE/cache-server/src/base/base.service.ts @@ -63,7 +63,7 @@ export abstract class BaseService { return data; } - async update(key: string, updateData: any) { + async update(key: string, updateData: T) { const data = await this.getDataFromCacheOrDB(key); if (data) { @@ -117,7 +117,7 @@ export abstract class BaseService { return databaseData; } - private mergeWithUpdateCommand(data: any, key: string): T { + private mergeWithUpdateCommand(data: T, key: string): T { const updateCommand = this.temporaryDatabaseService.get( this.className, key, diff --git a/nestjs-BE/cache-server/src/profiles/dto/update-profile.dto.ts b/nestjs-BE/cache-server/src/profiles/dto/update-profile.dto.ts index d5a658ae..a715da8d 100644 --- a/nestjs-BE/cache-server/src/profiles/dto/update-profile.dto.ts +++ b/nestjs-BE/cache-server/src/profiles/dto/update-profile.dto.ts @@ -1,4 +1,6 @@ import { PartialType } from '@nestjs/mapped-types'; import { CreateProfileDto } from './create-profile.dto'; -export class UpdateProfileDto extends PartialType(CreateProfileDto) {} +export class UpdateProfileDto extends PartialType(CreateProfileDto) { + uuid?: string; +} diff --git a/nestjs-BE/cache-server/src/profiles/profiles.service.ts b/nestjs-BE/cache-server/src/profiles/profiles.service.ts index e73a2322..26d0ef82 100644 --- a/nestjs-BE/cache-server/src/profiles/profiles.service.ts +++ b/nestjs-BE/cache-server/src/profiles/profiles.service.ts @@ -3,16 +3,11 @@ import { PrismaService } from '../prisma/prisma.service'; import { TemporaryDatabaseService } from '../temporary-database/temporary-database.service'; import { BaseService } from '../base/base.service'; import { PROFILE_CACHE_SIZE } from 'src/config/magic-number'; - -export interface Profile { - uuid?: string; - user_id: string; - image: string; - nickname: string; -} +import { UpdateProfileDto } from './dto/update-profile.dto'; +import { CreateProfileDto } from './dto/create-profile.dto'; @Injectable() -export class ProfilesService extends BaseService { +export class ProfilesService extends BaseService { constructor( protected prisma: PrismaService, protected temporaryDatabaseService: TemporaryDatabaseService, @@ -30,7 +25,7 @@ export class ProfilesService extends BaseService { return data.uuid; } - async create(data: Profile): Promise { + async create(data: CreateProfileDto): Promise { const createdProfile = await super.create(data); if (typeof createdProfile !== 'string') { this.temporaryDatabaseService.addUserProfile( diff --git a/nestjs-BE/cache-server/src/spaces/dto/update-space.dto.ts b/nestjs-BE/cache-server/src/spaces/dto/update-space.dto.ts index f474d438..a1e7bb48 100644 --- a/nestjs-BE/cache-server/src/spaces/dto/update-space.dto.ts +++ b/nestjs-BE/cache-server/src/spaces/dto/update-space.dto.ts @@ -1,4 +1,6 @@ import { PartialType } from '@nestjs/mapped-types'; import { CreateSpaceDto } from './create-space.dto'; -export class UpdateSpaceDto extends PartialType(CreateSpaceDto) {} +export class UpdateSpaceDto extends PartialType(CreateSpaceDto) { + uuid?: string; +} diff --git a/nestjs-BE/cache-server/src/spaces/spaces.service.ts b/nestjs-BE/cache-server/src/spaces/spaces.service.ts index 032dfe0f..25ef860b 100644 --- a/nestjs-BE/cache-server/src/spaces/spaces.service.ts +++ b/nestjs-BE/cache-server/src/spaces/spaces.service.ts @@ -3,15 +3,10 @@ import { PrismaService } from '../prisma/prisma.service'; import { TemporaryDatabaseService } from '../temporary-database/temporary-database.service'; import { BaseService } from '../base/base.service'; import { SPACE_CACHE_SIZE } from 'src/config/magic-number'; - -export interface Space { - uuid?: string; - name: string; - icon: string; -} +import { UpdateSpaceDto } from './dto/update-space.dto'; @Injectable() -export class SpacesService extends BaseService { +export class SpacesService extends BaseService { constructor( protected prisma: PrismaService, protected temporaryDatabaseService: TemporaryDatabaseService, diff --git a/nestjs-BE/cache-server/src/users/dto/update-user.dto.ts b/nestjs-BE/cache-server/src/users/dto/update-user.dto.ts index dfd37fb1..361e7ba5 100644 --- a/nestjs-BE/cache-server/src/users/dto/update-user.dto.ts +++ b/nestjs-BE/cache-server/src/users/dto/update-user.dto.ts @@ -1,4 +1,6 @@ import { PartialType } from '@nestjs/mapped-types'; import { CreateUserDto } from './create-user.dto'; -export class UpdateUserDto extends PartialType(CreateUserDto) {} +export class UpdateUserDto extends PartialType(CreateUserDto) { + uuid?: string; +} diff --git a/nestjs-BE/cache-server/src/users/users.service.ts b/nestjs-BE/cache-server/src/users/users.service.ts index e93a1044..c3fd626d 100644 --- a/nestjs-BE/cache-server/src/users/users.service.ts +++ b/nestjs-BE/cache-server/src/users/users.service.ts @@ -3,15 +3,10 @@ import { PrismaService } from '../prisma/prisma.service'; import { TemporaryDatabaseService } from '../temporary-database/temporary-database.service'; import { BaseService } from '../base/base.service'; import { USER_CACHE_SIZE } from '../config/magic-number'; - -export interface User { - uuid?: string; - email: string; - password: string; -} +import { UpdateUserDto } from './dto/update-user.dto'; @Injectable() -export class UsersService extends BaseService { +export class UsersService extends BaseService { constructor( protected prisma: PrismaService, protected temporaryDatabaseService: TemporaryDatabaseService, From 3b6846a714d9bfa579a9e462c38b009c877d6355 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Sun, 26 Nov 2023 22:28:56 +0900 Subject: [PATCH 028/170] =?UTF-8?q?delete:=20crdt=20map=EC=9D=84=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/src/board/board.gateway.ts | 21 ++++++------------- nestjs-BE/src/mindmap/mindmap.service.ts | 26 ------------------------ 2 files changed, 6 insertions(+), 41 deletions(-) delete mode 100644 nestjs-BE/src/mindmap/mindmap.service.ts diff --git a/nestjs-BE/src/board/board.gateway.ts b/nestjs-BE/src/board/board.gateway.ts index cd6229ea..2c555bcc 100644 --- a/nestjs-BE/src/board/board.gateway.ts +++ b/nestjs-BE/src/board/board.gateway.ts @@ -4,33 +4,24 @@ import { WebSocketServer, } from '@nestjs/websockets'; import { Server, Socket } from 'socket.io'; -import { MindmapService } from '../mindmap/mindmap.service'; -interface BoardDataPayload { +interface MindmapDataPayload { message: any; boardId: string; } @WebSocketGateway({ namespace: 'board' }) export class BoardGateway { - constructor(private readonly mindmapService: MindmapService) {} - @WebSocketServer() server: Server; - @SubscribeMessage('joinRoom') - handleJoinRoom(client: Socket, payload: { boardId: string }): void { + @SubscribeMessage('joinBoard') + handleJoinBoard(client: Socket, payload: { boardId: string }): void { client.join(payload.boardId); } - @SubscribeMessage('pushData') - handlePushNode(client: Socket, payload: BoardDataPayload): void { - this.mindmapService.updateMindmap(payload.boardId, payload.message); - client.broadcast - .to(payload.boardId) - .emit( - 'messageFromServer', - this.mindmapService.getEncodedState(payload.boardId), - ); + @SubscribeMessage('updateMindmap') + handleUpdateMindmap(client: Socket, payload: MindmapDataPayload) { + client.broadcast.to(payload.boardId).emit('stateFromServer', payload); } } diff --git a/nestjs-BE/src/mindmap/mindmap.service.ts b/nestjs-BE/src/mindmap/mindmap.service.ts deleted file mode 100644 index 1794b188..00000000 --- a/nestjs-BE/src/mindmap/mindmap.service.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { LWWMap, lwwMapState } from 'crdt/map'; - -@Injectable() -export class MindmapService { - private boards = new Map>(); - - updateMindmap(boardId: string, message: any): void { - const board = this.getMindmap(boardId); - board.merge(message); - } - - getEncodedState(boardId: string): lwwMapState { - const board = this.getMindmap(boardId); - return board.getState(); - } - - private getMindmap(boardId: string) { - let board = this.boards.get(boardId); - if (!board) { - board = new LWWMap(boardId); // boardId 대신에 서버 아이디??? - this.boards.set(boardId, board); - } - return board; - } -} From a98a0a37e95f9f9df0f1ba4142fd444e525e181e Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Mon, 27 Nov 2023 10:10:31 +0900 Subject: [PATCH 029/170] =?UTF-8?q?feat:=20=EB=85=B8=EB=93=9C=EC=97=90?= =?UTF-8?q?=EC=84=9C=20children=20=EA=B0=80=EC=A7=80=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/crdt/node.ts | 1 + nestjs-BE/crdt/tree.ts | 33 +++++++++++++++------------------ 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/nestjs-BE/crdt/node.ts b/nestjs-BE/crdt/node.ts index bf9c94a9..ca09556c 100644 --- a/nestjs-BE/crdt/node.ts +++ b/nestjs-BE/crdt/node.ts @@ -1,6 +1,7 @@ export class Node { parentId: string; content: T; + children = new Set(); constructor(parentId: string = '0', content: T | null = null) { this.parentId = parentId; diff --git a/nestjs-BE/crdt/tree.ts b/nestjs-BE/crdt/tree.ts index 3e1cf36e..fc72bc87 100644 --- a/nestjs-BE/crdt/tree.ts +++ b/nestjs-BE/crdt/tree.ts @@ -2,7 +2,6 @@ import { Node } from './node'; export class Tree { nodes = new Map>(); - children = new Map>(); constructor() { this.nodes.set('root', new Node()); @@ -12,19 +11,22 @@ export class Tree { return this.nodes.get(id); } + getNodeChildren(id: string): Array | null { + const node = this.get(id); + if (!node) return null; + + const childrenArray = Array.from(node.children); + childrenArray.sort(); + return childrenArray; + } + addNode(targetId: string, parentId: string, content: T) { const newNode = new Node(parentId, content); const parentNode = this.nodes.get(parentId); if (!parentNode) return; - let childrenSet = this.children.get(parentId); - if (!childrenSet) { - childrenSet = new Set(); - this.children.set(parentId, childrenSet); - } - - childrenSet.add(targetId); + parentNode.children.add(targetId); this.nodes.set(targetId, newNode); } @@ -35,13 +37,7 @@ export class Tree { const parentNode = this.nodes.get(parentId); if (!parentNode) return; - let childrenSet = this.children.get(parentId); - if (!childrenSet) { - childrenSet = new Set(); - this.children.set(parentId, childrenSet); - } - - childrenSet.add(targetId); + parentNode.children.add(targetId); targetNode.parentId = parentId; } @@ -49,9 +45,10 @@ export class Tree { const targetNode = this.nodes.get(targetId); if (!targetNode) return; - const parentChildren = this.children.get(targetNode.parentId); - if (!parentChildren) return; - parentChildren.delete(targetId); + const parentNode = this.nodes.get(targetNode.parentId); + if (!parentNode) return; + + parentNode.children.delete(targetId); return this.nodes.get(targetId); } From 3574292ce152a15f557815bfac10d8587ae9ad07 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Mon, 27 Nov 2023 10:14:42 +0900 Subject: [PATCH 030/170] =?UTF-8?q?delete:=20=EB=8F=99=EC=9E=91=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/src/app.module.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nestjs-BE/src/app.module.ts b/nestjs-BE/src/app.module.ts index fe6f5f38..b919faf3 100644 --- a/nestjs-BE/src/app.module.ts +++ b/nestjs-BE/src/app.module.ts @@ -2,11 +2,10 @@ import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { BoardGateway } from './board/board.gateway'; -import { MindmapService } from './mindmap/mindmap.service'; @Module({ imports: [], controllers: [AppController], - providers: [AppService, BoardGateway, MindmapService], + providers: [AppService, BoardGateway], }) export class AppModule {} From 28e9529149b485268719598ab260e15b17dad0e1 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 27 Nov 2023 10:30:22 +0900 Subject: [PATCH 031/170] =?UTF-8?q?fix(#58):=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=ED=96=89=EB=8F=99=20try-catch=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/temporary-database/temporary-database.service.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts b/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts index ae19f645..5946274a 100644 --- a/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts +++ b/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts @@ -128,13 +128,12 @@ export class TemporaryDatabaseService { if (!data.length) return; await Promise.all( data.map(async (item) => { - const existing = await this.prisma[service].findUnique({ - where: { [item.field]: item.value }, - }); - if (existing) { + try { return this.prisma[service].delete({ where: { [item.field]: item.value }, }); + } catch (error) { + return; } }), ); From 95203278cde1288b1a321b189ccb161bb59622b8 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 27 Nov 2023 16:36:11 +0900 Subject: [PATCH 032/170] =?UTF-8?q?fix(#58):=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=9D=BD=EA=B3=A0=20=EC=93=B0=EA=B8=B0=20=EB=B9=84=EB=8F=99?= =?UTF-8?q?=EA=B8=B0=20=EC=B2=98=EB=A6=AC=20=EB=B0=8F=20=EC=9D=BC=EB=B6=80?= =?UTF-8?q?=20any=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/profiles/profiles.service.ts | 2 +- .../cache-server/src/spaces/spaces.service.ts | 2 +- .../temporary-database.service.ts | 21 ++++++++++--------- .../cache-server/src/users/users.service.ts | 2 +- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/nestjs-BE/cache-server/src/profiles/profiles.service.ts b/nestjs-BE/cache-server/src/profiles/profiles.service.ts index 26d0ef82..b06866d3 100644 --- a/nestjs-BE/cache-server/src/profiles/profiles.service.ts +++ b/nestjs-BE/cache-server/src/profiles/profiles.service.ts @@ -21,7 +21,7 @@ export class ProfilesService extends BaseService { }); } - generateKey(data: any): string { + generateKey(data: UpdateProfileDto): string { return data.uuid; } diff --git a/nestjs-BE/cache-server/src/spaces/spaces.service.ts b/nestjs-BE/cache-server/src/spaces/spaces.service.ts index 25ef860b..8294e8b4 100644 --- a/nestjs-BE/cache-server/src/spaces/spaces.service.ts +++ b/nestjs-BE/cache-server/src/spaces/spaces.service.ts @@ -20,7 +20,7 @@ export class SpacesService extends BaseService { }); } - generateKey(data: any): string { + generateKey(data: UpdateSpaceDto): string { return data.uuid; } diff --git a/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts b/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts index 5946274a..4ef8f7f3 100644 --- a/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts +++ b/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { PrismaService } from '../prisma/prisma.service'; import { Cron } from '@nestjs/schedule'; -import { writeFileSync, readFileSync, existsSync, readdirSync } from 'fs'; +import { promises as fs } from 'fs'; import { join } from 'path'; interface OperationData { @@ -35,8 +35,8 @@ export class TemporaryDatabaseService { }); } - private readDataFromFiles() { - const files = readdirSync(this.FOLDER_NAME); + private async readDataFromFiles() { + const files = await fs.readdir(this.FOLDER_NAME); files.forEach((file) => { if (file.endsWith('.csv')) { this.readDataFromFile(file); @@ -44,10 +44,10 @@ export class TemporaryDatabaseService { }); } - private readDataFromFile(file: string) { + private async readDataFromFile(file: string) { const [service, commandWithExtension] = file.split('-'); const command = commandWithExtension.replace('.csv', ''); - const fileData = readFileSync(join(this.FOLDER_NAME, file), 'utf8'); + const fileData = await fs.readFile(join(this.FOLDER_NAME, file), 'utf8'); fileData.split('\n').forEach((line) => { if (line.trim() !== '') { const [uniqueKey, ...dataParts] = line.split(','); @@ -82,10 +82,11 @@ export class TemporaryDatabaseService { operation({ service, uniqueKey, command, data }: OperationData) { const filePath = join(this.FOLDER_NAME, `${service}-${command}.csv`); - let fileData = existsSync(filePath) ? readFileSync(filePath, 'utf8') : ''; - fileData += `${uniqueKey},${JSON.stringify(data)}\n`; - writeFileSync(filePath, fileData); - this.database.get(service).get(command).set(uniqueKey, data); + fs.readFile(filePath, 'utf8').then((fileData) => { + fileData += `${uniqueKey},${JSON.stringify(data)}\n`; + fs.writeFile(filePath, fileData); + this.database.get(service).get(command).set(uniqueKey, data); + }); } @Cron('0 */10 * * * *') @@ -151,7 +152,7 @@ export class TemporaryDatabaseService { } private clearFile(filename: string) { - writeFileSync(join(this.FOLDER_NAME, filename), '', 'utf8'); + fs.writeFile(join(this.FOLDER_NAME, filename), '', 'utf8'); } getUserProfiles(user_id: string): string[] { diff --git a/nestjs-BE/cache-server/src/users/users.service.ts b/nestjs-BE/cache-server/src/users/users.service.ts index c3fd626d..3eac8ed7 100644 --- a/nestjs-BE/cache-server/src/users/users.service.ts +++ b/nestjs-BE/cache-server/src/users/users.service.ts @@ -20,7 +20,7 @@ export class UsersService extends BaseService { }); } - generateKey(data: any): string { + generateKey(data: UpdateUserDto): string { return data.email; } From 64f6dc61650e85d5cf5cbf3d46b4e7265f9226f2 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Mon, 27 Nov 2023 18:46:29 +0900 Subject: [PATCH 033/170] =?UTF-8?q?feat:=20Node=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD,=20children?= =?UTF-8?q?=20=EC=9E=90=EB=A3=8C=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/crdt/node.ts | 10 ++++++++-- nestjs-BE/crdt/tree.ts | 20 ++++++-------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/nestjs-BE/crdt/node.ts b/nestjs-BE/crdt/node.ts index ca09556c..7014afc6 100644 --- a/nestjs-BE/crdt/node.ts +++ b/nestjs-BE/crdt/node.ts @@ -1,9 +1,15 @@ export class Node { + targetId: string; parentId: string; content: T; - children = new Set(); + children = new Array(); - constructor(parentId: string = '0', content: T | null = null) { + constructor( + targetId: string, + parentId: string = '0', + content: T | null = null, + ) { + this.targetId = targetId; this.parentId = parentId; this.content = content; } diff --git a/nestjs-BE/crdt/tree.ts b/nestjs-BE/crdt/tree.ts index fc72bc87..afdca07f 100644 --- a/nestjs-BE/crdt/tree.ts +++ b/nestjs-BE/crdt/tree.ts @@ -4,29 +4,20 @@ export class Tree { nodes = new Map>(); constructor() { - this.nodes.set('root', new Node()); + this.nodes.set('root', new Node('root')); } get(id: string): Node | undefined { return this.nodes.get(id); } - getNodeChildren(id: string): Array | null { - const node = this.get(id); - if (!node) return null; - - const childrenArray = Array.from(node.children); - childrenArray.sort(); - return childrenArray; - } - addNode(targetId: string, parentId: string, content: T) { - const newNode = new Node(parentId, content); + const newNode = new Node(targetId, parentId, content); const parentNode = this.nodes.get(parentId); if (!parentNode) return; - parentNode.children.add(targetId); + parentNode.children.push(targetId); this.nodes.set(targetId, newNode); } @@ -37,7 +28,7 @@ export class Tree { const parentNode = this.nodes.get(parentId); if (!parentNode) return; - parentNode.children.add(targetId); + parentNode.children.push(targetId); targetNode.parentId = parentId; } @@ -48,7 +39,8 @@ export class Tree { const parentNode = this.nodes.get(targetNode.parentId); if (!parentNode) return; - parentNode.children.delete(targetId); + const targetIndex = parentNode.children.indexOf(targetId); + if (targetIndex !== -1) parentNode.children.splice(targetIndex, 1); return this.nodes.get(targetId); } From 11e84b089b02da0d9cfd8a0d88640bb42d1a4621 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Mon, 27 Nov 2023 18:46:56 +0900 Subject: [PATCH 034/170] =?UTF-8?q?fix:=20=EB=A7=A4=EA=B0=9C=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/crdt/operation.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nestjs-BE/crdt/operation.ts b/nestjs-BE/crdt/operation.ts index 644206f2..561c786b 100644 --- a/nestjs-BE/crdt/operation.ts +++ b/nestjs-BE/crdt/operation.ts @@ -62,7 +62,7 @@ export class OperationAdd extends Operation { tree.removeNode(log.operation.id); } - redoOperation(tree: Tree, log?: OperationLog): OperationLog { + redoOperation(tree: Tree, log: OperationLog): OperationLog { tree.attachNode(log.operation.id, this.parentId); return { operation: this }; } @@ -84,7 +84,7 @@ export class OperationDelete extends Operation { tree.attachNode(log.operation.id, log.oldParentId); } - redoOperation(tree: Tree, log?: OperationLog): OperationLog { + redoOperation(tree: Tree, log: OperationLog): OperationLog { const redoLog = log.operation.doOperation(tree); return redoLog; } @@ -112,7 +112,7 @@ export class OperationMove extends Operation { tree.attachNode(log.operation.id, log.oldParentId); } - redoOperation(tree: Tree, log?: OperationLog): OperationLog { + redoOperation(tree: Tree, log: OperationLog): OperationLog { const redoLog = log.operation.doOperation(tree); return redoLog; } @@ -137,7 +137,7 @@ export class OperationUpdate extends Operation { tree.updateNode(log.operation.id, log.oldContent); } - redoOperation(tree: Tree, log?: OperationLog): OperationLog { + redoOperation(tree: Tree, log: OperationLog): OperationLog { const redoLog = log.operation.doOperation(tree); return redoLog; } From 1eec5c9eaf7e5ff6513873570590ea40d57d0444 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Mon, 27 Nov 2023 18:58:50 +0900 Subject: [PATCH 035/170] =?UTF-8?q?fix:=20=EB=B3=80=EC=88=98=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/crdt/crdt-tree.ts | 19 +++++++++++-------- nestjs-BE/crdt/node.ts | 6 +++--- nestjs-BE/crdt/operation.ts | 24 ++++++++++++------------ nestjs-BE/crdt/tree.ts | 8 ++++---- 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/nestjs-BE/crdt/crdt-tree.ts b/nestjs-BE/crdt/crdt-tree.ts index e4ce4192..ce6b18ae 100644 --- a/nestjs-BE/crdt/crdt-tree.ts +++ b/nestjs-BE/crdt/crdt-tree.ts @@ -32,14 +32,14 @@ export class CrdtTree { generateOperationAdd( targetId: string, parentId: string, - content: T, + description: T, ): OperationAdd { this.clock.increment(); const clock = this.clock.copy(); const input: OperationInput = { id: targetId, parentId, - content, + description, clock, }; return new OperationAdd(input); @@ -66,12 +66,15 @@ export class CrdtTree { return new OperationMove(input); } - generateOperationUpdate(targetId: string, content: T): OperationUpdate { + generateOperationUpdate( + targetId: string, + description: T, + ): OperationUpdate { this.clock.increment(); const clock = this.clock.copy(); const input: OperationInput = { id: targetId, - content, + description, clock, }; return new OperationUpdate(input); @@ -82,7 +85,7 @@ export class CrdtTree { operationType: 'add', id: operation.id, clock: { id: operation.clock.id, counter: operation.clock.counter }, - content: operation.content, + description: operation.description, parentId: operation.parentId, }; return serializedOperation; @@ -116,7 +119,7 @@ export class CrdtTree { operationType: 'update', id: operation.id, clock: { id: operation.clock.id, counter: operation.clock.counter }, - content: operation.content, + description: operation.description, }; return serializedOperation; } @@ -127,7 +130,7 @@ export class CrdtTree { const input: OperationInput = { id: serializedOperation.id, parentId: serializedOperation.parentId, - content: serializedOperation.content, + description: serializedOperation.description, clock: new Clock( serializedOperation.clock.id, serializedOperation.clock.counter, @@ -168,7 +171,7 @@ export class CrdtTree { ): OperationUpdate { const input: OperationInput = { id: serializedOperation.id, - content: serializedOperation.content, + description: serializedOperation.description, clock: new Clock( serializedOperation.clock.id, serializedOperation.clock.counter, diff --git a/nestjs-BE/crdt/node.ts b/nestjs-BE/crdt/node.ts index 7014afc6..7a334ce8 100644 --- a/nestjs-BE/crdt/node.ts +++ b/nestjs-BE/crdt/node.ts @@ -1,16 +1,16 @@ export class Node { targetId: string; parentId: string; - content: T; + description: T; children = new Array(); constructor( targetId: string, parentId: string = '0', - content: T | null = null, + description: T | null = null, ) { this.targetId = targetId; this.parentId = parentId; - this.content = content; + this.description = description; } } diff --git a/nestjs-BE/crdt/operation.ts b/nestjs-BE/crdt/operation.ts index 561c786b..006a94d0 100644 --- a/nestjs-BE/crdt/operation.ts +++ b/nestjs-BE/crdt/operation.ts @@ -4,13 +4,13 @@ import { Tree } from './tree'; export interface OperationLog { operation: Operation; oldParentId?: string; - oldContent?: T; + oldDescription?: T; } export interface OperationInput { id: string; clock: Clock; - content?: T; + description?: T; parentId?: string; } @@ -23,7 +23,7 @@ export interface SerializedOperation { operationType: string; id: string; clock: ClockInterface; - content?: T; + description?: T; parentId?: string; } @@ -44,17 +44,17 @@ export abstract class Operation { } export class OperationAdd extends Operation { - content: T; + description: T; parentId: string; constructor(input: OperationInput) { super('add', input.id, input.clock); - this.content = input.content; + this.description = input.description; this.parentId = input.parentId; } doOperation(tree: Tree): OperationLog { - tree.addNode(this.id, this.parentId, this.content); + tree.addNode(this.id, this.parentId, this.description); return { operation: this }; } @@ -119,22 +119,22 @@ export class OperationMove extends Operation { } export class OperationUpdate extends Operation { - content: T; + description: T; constructor(input: OperationInput) { super('update', input.id, input.clock); - this.content = input.content; + this.description = input.description; } doOperation(tree: Tree): OperationLog { const node = tree.get(this.id); - const oldContent = node.content; - tree.updateNode(this.id, this.content); - return { operation: this, oldContent }; + const oldDescription = node.description; + tree.updateNode(this.id, this.description); + return { operation: this, oldDescription: oldDescription }; } undoOperation(tree: Tree, log: OperationLog): void { - tree.updateNode(log.operation.id, log.oldContent); + tree.updateNode(log.operation.id, log.oldDescription); } redoOperation(tree: Tree, log: OperationLog): OperationLog { diff --git a/nestjs-BE/crdt/tree.ts b/nestjs-BE/crdt/tree.ts index afdca07f..a183ceb4 100644 --- a/nestjs-BE/crdt/tree.ts +++ b/nestjs-BE/crdt/tree.ts @@ -11,8 +11,8 @@ export class Tree { return this.nodes.get(id); } - addNode(targetId: string, parentId: string, content: T) { - const newNode = new Node(targetId, parentId, content); + addNode(targetId: string, parentId: string, description: T) { + const newNode = new Node(targetId, parentId, description); const parentNode = this.nodes.get(parentId); if (!parentNode) return; @@ -45,10 +45,10 @@ export class Tree { return this.nodes.get(targetId); } - updateNode(targetId: string, content: T) { + updateNode(targetId: string, description: T) { const targetNode = this.nodes.get(targetId); if (!targetNode) return; - targetNode.content = content; + targetNode.description = description; } } From d71ff02f82c26db7ef2bf9be90cbb26681c862a6 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 27 Nov 2023 20:04:20 +0900 Subject: [PATCH 036/170] =?UTF-8?q?fix(#101):=20=EB=8F=99=EC=A0=81?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=82=AC=EC=9A=A9=ED=95=98=EA=B8=B0=20?= =?UTF-8?q?=EC=9C=84=ED=95=98=EC=97=AC=20=ED=95=A8=EC=88=98=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../temporary-database.service.ts | 41 +++++++++++-------- .../cache-server/src/users/users.service.ts | 5 ++- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts b/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts index 4ef8f7f3..494250c2 100644 --- a/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts +++ b/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts @@ -14,7 +14,7 @@ interface OperationData { @Injectable() export class TemporaryDatabaseService { private database: Map>> = new Map(); - private userProfilesMap: Map = new Map(); + private entriesMap: Map = new Map(); private readonly FOLDER_NAME = 'operations'; constructor(private readonly prisma: PrismaService) { @@ -23,7 +23,13 @@ export class TemporaryDatabaseService { } private initializeDatabase() { - const services = ['USER_TB', 'PROFILE_TB', 'SPACE_TB', 'BOARD_TB']; + const services = [ + 'USER_TB', + 'PROFILE_TB', + 'SPACE_TB', + 'BOARD_TB', + 'PROFILE_SPACE_TB', + ]; const operations = ['insert', 'update', 'delete']; services.forEach((service) => { @@ -89,7 +95,7 @@ export class TemporaryDatabaseService { }); } - @Cron('0 */10 * * * *') + @Cron('* * * * * *') async executeBulkOperations() { for (const service of this.database.keys()) { const serviceMap = this.database.get(service); @@ -101,7 +107,7 @@ export class TemporaryDatabaseService { private async performInsert(service: string, dataMap: Map) { const data = this.prepareData(service, 'insert', dataMap); - this.userProfilesMap.clear(); + this.entriesMap.clear(); if (!data.length) return; await this.prisma[service].createMany({ data: data, @@ -130,10 +136,11 @@ export class TemporaryDatabaseService { await Promise.all( data.map(async (item) => { try { - return this.prisma[service].delete({ + await this.prisma[service].delete({ where: { [item.field]: item.value }, }); - } catch (error) { + } catch { + } finally { return; } }), @@ -155,22 +162,22 @@ export class TemporaryDatabaseService { fs.writeFile(join(this.FOLDER_NAME, filename), '', 'utf8'); } - getUserProfiles(user_id: string): string[] { - return this.userProfilesMap.get(user_id) || []; + getEntries(key: string): string[] { + return this.entriesMap.get(key) || []; } - addUserProfile(user_id: string, profile_uuid: string): void { - const profiles = this.getUserProfiles(user_id); - profiles.push(profile_uuid); - this.userProfilesMap.set(user_id, profiles); + addEntry(key: string, value: string): void { + const entries = this.getEntries(key); + entries.push(value); + this.entriesMap.set(key, entries); } - removeUserProfile(user_id: string, profile_uuid: string): void { - const profiles = this.getUserProfiles(user_id); - const index = profiles.indexOf(profile_uuid); + removeEntry(key: string, value: string): void { + const entries = this.getEntries(key); + const index = entries.indexOf(value); if (index > -1) { - profiles.splice(index, 1); - this.userProfilesMap.set(user_id, profiles); + entries.splice(index, 1); + this.entriesMap.set(key, entries); } } } diff --git a/nestjs-BE/cache-server/src/users/users.service.ts b/nestjs-BE/cache-server/src/users/users.service.ts index 3eac8ed7..49c0f4ed 100644 --- a/nestjs-BE/cache-server/src/users/users.service.ts +++ b/nestjs-BE/cache-server/src/users/users.service.ts @@ -34,8 +34,9 @@ export class UsersService extends BaseService { if (!user) return null; const profiles = user.profiles || []; - const temporaryProfilesUuids = - this.temporaryDatabaseService.getUserProfiles(user.uuid); + const temporaryProfilesUuids = this.temporaryDatabaseService.getEntries( + user.uuid, + ); const temporaryProfiles = temporaryProfilesUuids.map((uuid) => this.temporaryDatabaseService.get('PROFILE_TB', uuid, 'insert'), ); From 70792521ac6d127c4f8a96e442bf16eaeb9e1593 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 27 Nov 2023 20:05:39 +0900 Subject: [PATCH 037/170] =?UTF-8?q?feat(#101):=20=EC=8A=A4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EB=93=A4=EC=96=B4=EA=B0=80=EA=B8=B0=20?= =?UTF-8?q?=EB=82=98=EA=B0=80=EA=B8=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/profiles/dto/profile-space.dto.ts | 4 ++ .../src/profiles/profiles.controller.ts | 14 ++++++ .../src/profiles/profiles.module.ts | 4 +- .../src/profiles/profiles.service.ts | 44 ++++++++++++++++--- 4 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 nestjs-BE/cache-server/src/profiles/dto/profile-space.dto.ts diff --git a/nestjs-BE/cache-server/src/profiles/dto/profile-space.dto.ts b/nestjs-BE/cache-server/src/profiles/dto/profile-space.dto.ts new file mode 100644 index 00000000..4c93c418 --- /dev/null +++ b/nestjs-BE/cache-server/src/profiles/dto/profile-space.dto.ts @@ -0,0 +1,4 @@ +export class ProfileSpaceDto { + profile_uuid: string; + space_uuid: string; +} diff --git a/nestjs-BE/cache-server/src/profiles/profiles.controller.ts b/nestjs-BE/cache-server/src/profiles/profiles.controller.ts index 92c1d6ee..cffb4142 100644 --- a/nestjs-BE/cache-server/src/profiles/profiles.controller.ts +++ b/nestjs-BE/cache-server/src/profiles/profiles.controller.ts @@ -10,6 +10,7 @@ import { import { ProfilesService } from './profiles.service'; import { CreateProfileDto } from './dto/create-profile.dto'; import { UpdateProfileDto } from './dto/update-profile.dto'; +import { ProfileSpaceDto } from './dto/profile-space.dto'; @Controller('profiles') export class ProfilesController { @@ -37,4 +38,17 @@ export class ProfilesController { remove(@Param('uuid') uuid: string) { return this.profilesService.remove(uuid); } + + @Post('/spaces') + joinSpace(@Body() profileSpaceDto: ProfileSpaceDto) { + return this.profilesService.joinSpace(profileSpaceDto); + } + + @Delete(':profile_uuid/spaces/:space_uuid') + leaveSpace( + @Param('profile_uuid') profileUuid: string, + @Param('space_uuid') spaceUuid: string, + ) { + return this.profilesService.leaveSpace(profileUuid, spaceUuid); + } } diff --git a/nestjs-BE/cache-server/src/profiles/profiles.module.ts b/nestjs-BE/cache-server/src/profiles/profiles.module.ts index 7459a790..65a9fe50 100644 --- a/nestjs-BE/cache-server/src/profiles/profiles.module.ts +++ b/nestjs-BE/cache-server/src/profiles/profiles.module.ts @@ -1,9 +1,9 @@ import { Module } from '@nestjs/common'; import { ProfilesService } from './profiles.service'; import { ProfilesController } from './profiles.controller'; - +import { SpacesService } from '../spaces/spaces.service'; @Module({ controllers: [ProfilesController], - providers: [ProfilesService], + providers: [ProfilesService, SpacesService], }) export class ProfilesModule {} diff --git a/nestjs-BE/cache-server/src/profiles/profiles.service.ts b/nestjs-BE/cache-server/src/profiles/profiles.service.ts index b06866d3..3cfcbfb6 100644 --- a/nestjs-BE/cache-server/src/profiles/profiles.service.ts +++ b/nestjs-BE/cache-server/src/profiles/profiles.service.ts @@ -5,12 +5,15 @@ import { BaseService } from '../base/base.service'; import { PROFILE_CACHE_SIZE } from 'src/config/magic-number'; import { UpdateProfileDto } from './dto/update-profile.dto'; import { CreateProfileDto } from './dto/create-profile.dto'; +import { SpacesService } from '../spaces/spaces.service'; +import { ProfileSpaceDto } from './dto/profile-space.dto'; @Injectable() export class ProfilesService extends BaseService { constructor( protected prisma: PrismaService, protected temporaryDatabaseService: TemporaryDatabaseService, + protected spacesService: SpacesService, ) { super({ prisma, @@ -28,10 +31,7 @@ export class ProfilesService extends BaseService { async create(data: CreateProfileDto): Promise { const createdProfile = await super.create(data); if (typeof createdProfile !== 'string') { - this.temporaryDatabaseService.addUserProfile( - data.user_id, - createdProfile.uuid, - ); + this.temporaryDatabaseService.addEntry(data.user_id, createdProfile.uuid); } return createdProfile; } @@ -39,8 +39,42 @@ export class ProfilesService extends BaseService { async remove(key: string) { const profile = await super.getDataFromCacheOrDB(key); if (profile) { - this.temporaryDatabaseService.removeUserProfile(profile.user_id, key); + this.temporaryDatabaseService.removeEntry(profile.user_id, key); } await super.remove(key); } + + async joinSpace(data: ProfileSpaceDto) { + const { profile_uuid: profileUuid, space_uuid: spaceUuid } = data; + const result = await this.getProfileAndSpace(profileUuid, spaceUuid); + if (typeof result === 'string') return result; + + this.temporaryDatabaseService.create('PROFILE_SPACE_TB', profileUuid, data); + this.temporaryDatabaseService.addEntry(profileUuid, spaceUuid); + this.temporaryDatabaseService.addEntry(spaceUuid, profileUuid); + } + + async leaveSpace(profileUuid: string, spaceUuid: string) { + const result = await this.getProfileAndSpace(profileUuid, spaceUuid); + if (typeof result === 'string') return result; + + const data = { + field: 'space_uuid_profile_uuid', + value: { + space_uuid: spaceUuid, + profile_uuid: profileUuid, + }, + }; + this.temporaryDatabaseService.remove('PROFILE_SPACE_TB', profileUuid, data); + this.temporaryDatabaseService.removeEntry(profileUuid, spaceUuid); + this.temporaryDatabaseService.removeEntry(spaceUuid, profileUuid); + } + + private async getProfileAndSpace(profileUuid: string, spaceUuid: string) { + const profile = await super.getDataFromCacheOrDB(profileUuid); + if (!profile) return `Profile not found: ${profileUuid}`; + const space = await this.spacesService.getDataFromCacheOrDB(spaceUuid); + if (!space) return `Space not found: ${spaceUuid}`; + return { profile, space }; + } } From 9a0c561065afa5e550ac48945fe291742c6c6f54 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 27 Nov 2023 20:13:42 +0900 Subject: [PATCH 038/170] =?UTF-8?q?fix(#102):=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=95=84=20=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8A=94=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cache-server/src/users/users.service.ts | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/nestjs-BE/cache-server/src/users/users.service.ts b/nestjs-BE/cache-server/src/users/users.service.ts index 49c0f4ed..e3dd50de 100644 --- a/nestjs-BE/cache-server/src/users/users.service.ts +++ b/nestjs-BE/cache-server/src/users/users.service.ts @@ -25,22 +25,38 @@ export class UsersService extends BaseService { } async getProfiles(email: string) { + const user = await this.getUser(email); + if (!user) return; + + const profiles = user.profiles || []; + const temporaryProfiles = this.getTemporaryProfiles(user); + const combinedProfiles = [...profiles, ...temporaryProfiles]; + const mergedData = this.mergeProfileData(combinedProfiles); + + return mergedData; + } + + async getUser(email: string) { let user = await this.prisma[this.className].findUnique({ where: { email }, include: { profiles: true }, }); if (!user) user = await super.getDataFromCacheOrDB(email); - if (!user) return null; + return user; + } - const profiles = user.profiles || []; + getTemporaryProfiles(user: UpdateUserDto) { const temporaryProfilesUuids = this.temporaryDatabaseService.getEntries( user.uuid, ); const temporaryProfiles = temporaryProfilesUuids.map((uuid) => this.temporaryDatabaseService.get('PROFILE_TB', uuid, 'insert'), ); - const combinedProfiles = [...profiles, ...temporaryProfiles]; + return temporaryProfiles; + } + + mergeProfileData(combinedProfiles: UpdateUserDto[]) { const mergedData = combinedProfiles.map((data) => { const updateOperation = this.temporaryDatabaseService.get( 'PROFILE_TB', From c30f5ea95cfc2bcab2431557fe06c3254bea578c Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 27 Nov 2023 20:40:18 +0900 Subject: [PATCH 039/170] =?UTF-8?q?fix(#101):=20delete=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EB=A7=A4=EC=A7=81?= =?UTF-8?q?=20=EC=8A=A4=ED=8A=B8=EB=A7=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/profiles/profiles.service.ts | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/nestjs-BE/cache-server/src/profiles/profiles.service.ts b/nestjs-BE/cache-server/src/profiles/profiles.service.ts index 3cfcbfb6..c6859d6a 100644 --- a/nestjs-BE/cache-server/src/profiles/profiles.service.ts +++ b/nestjs-BE/cache-server/src/profiles/profiles.service.ts @@ -10,6 +10,7 @@ import { ProfileSpaceDto } from './dto/profile-space.dto'; @Injectable() export class ProfilesService extends BaseService { + joinTable = 'PROFILE_SPACE_TB'; constructor( protected prisma: PrismaService, protected temporaryDatabaseService: TemporaryDatabaseService, @@ -49,7 +50,7 @@ export class ProfilesService extends BaseService { const result = await this.getProfileAndSpace(profileUuid, spaceUuid); if (typeof result === 'string') return result; - this.temporaryDatabaseService.create('PROFILE_SPACE_TB', profileUuid, data); + this.temporaryDatabaseService.create(this.joinTable, profileUuid, data); this.temporaryDatabaseService.addEntry(profileUuid, spaceUuid); this.temporaryDatabaseService.addEntry(spaceUuid, profileUuid); } @@ -58,16 +59,29 @@ export class ProfilesService extends BaseService { const result = await this.getProfileAndSpace(profileUuid, spaceUuid); if (typeof result === 'string') return result; - const data = { - field: 'space_uuid_profile_uuid', - value: { - space_uuid: spaceUuid, - profile_uuid: profileUuid, - }, - }; - this.temporaryDatabaseService.remove('PROFILE_SPACE_TB', profileUuid, data); - this.temporaryDatabaseService.removeEntry(profileUuid, spaceUuid); - this.temporaryDatabaseService.removeEntry(spaceUuid, profileUuid); + const insertTemporaryData = this.temporaryDatabaseService.get( + this.joinTable, + profileUuid, + 'insert', + ); + if (insertTemporaryData) { + this.temporaryDatabaseService.delete( + this.joinTable, + profileUuid, + 'insert', + ); + this.temporaryDatabaseService.removeEntry(profileUuid, spaceUuid); + this.temporaryDatabaseService.removeEntry(spaceUuid, profileUuid); + } else { + const data = { + field: 'space_uuid_profile_uuid', + value: { + space_uuid: spaceUuid, + profile_uuid: profileUuid, + }, + }; + this.temporaryDatabaseService.remove(this.joinTable, profileUuid, data); + } } private async getProfileAndSpace(profileUuid: string, spaceUuid: string) { From 987440ec83975ea6c5f24c958d11b4678a6b959d Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 28 Nov 2023 02:38:59 +0900 Subject: [PATCH 040/170] =?UTF-8?q?fix(#101):=20delete=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20csv=20=ED=8C=8C=EC=9D=BC=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../temporary-database/temporary-database.service.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts b/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts index 494250c2..4e4d6f1e 100644 --- a/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts +++ b/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts @@ -84,6 +84,14 @@ export class TemporaryDatabaseService { delete(service: string, uniqueKey: string, command: string) { this.database.get(service).get(command).delete(uniqueKey); + const filePath = join(this.FOLDER_NAME, `${service}-${command}.csv`); + fs.readFile(filePath, 'utf8').then((fileData) => { + const lines = fileData.split('\n'); + const updatedFileData = lines + .filter((line) => !line.startsWith(`${uniqueKey},`)) + .join('\n'); + fs.writeFile(filePath, updatedFileData); + }); } operation({ service, uniqueKey, command, data }: OperationData) { @@ -95,7 +103,7 @@ export class TemporaryDatabaseService { }); } - @Cron('* * * * * *') + @Cron('0 */10 * * * *') async executeBulkOperations() { for (const service of this.database.keys()) { const serviceMap = this.database.get(service); From 5b6992e5b3a5058a3ebd3c640c563457799eaf07 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 28 Nov 2023 02:40:07 +0900 Subject: [PATCH 041/170] =?UTF-8?q?fix(#101):=20=EC=8A=A4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EC=9E=85=EC=9E=A5=EC=8B=9C=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/profiles/profiles.service.ts | 54 ++++++++++++++++--- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/nestjs-BE/cache-server/src/profiles/profiles.service.ts b/nestjs-BE/cache-server/src/profiles/profiles.service.ts index c6859d6a..c739501c 100644 --- a/nestjs-BE/cache-server/src/profiles/profiles.service.ts +++ b/nestjs-BE/cache-server/src/profiles/profiles.service.ts @@ -10,7 +10,7 @@ import { ProfileSpaceDto } from './dto/profile-space.dto'; @Injectable() export class ProfilesService extends BaseService { - joinTable = 'PROFILE_SPACE_TB'; + profileSpaceTable = 'PROFILE_SPACE_TB'; constructor( protected prisma: PrismaService, protected temporaryDatabaseService: TemporaryDatabaseService, @@ -49,8 +49,11 @@ export class ProfilesService extends BaseService { const { profile_uuid: profileUuid, space_uuid: spaceUuid } = data; const result = await this.getProfileAndSpace(profileUuid, spaceUuid); if (typeof result === 'string') return result; + const key = `${profileUuid}_${spaceUuid}`; + const isExists = await this.isDataExists(key, spaceUuid, profileUuid); + if (typeof isExists === 'string') return isExists; - this.temporaryDatabaseService.create(this.joinTable, profileUuid, data); + this.temporaryDatabaseService.create(this.profileSpaceTable, key, data); this.temporaryDatabaseService.addEntry(profileUuid, spaceUuid); this.temporaryDatabaseService.addEntry(spaceUuid, profileUuid); } @@ -58,16 +61,16 @@ export class ProfilesService extends BaseService { async leaveSpace(profileUuid: string, spaceUuid: string) { const result = await this.getProfileAndSpace(profileUuid, spaceUuid); if (typeof result === 'string') return result; - + const key = `${profileUuid}_${spaceUuid}`; const insertTemporaryData = this.temporaryDatabaseService.get( - this.joinTable, - profileUuid, + this.profileSpaceTable, + key, 'insert', ); if (insertTemporaryData) { this.temporaryDatabaseService.delete( - this.joinTable, - profileUuid, + this.profileSpaceTable, + key, 'insert', ); this.temporaryDatabaseService.removeEntry(profileUuid, spaceUuid); @@ -80,7 +83,7 @@ export class ProfilesService extends BaseService { profile_uuid: profileUuid, }, }; - this.temporaryDatabaseService.remove(this.joinTable, profileUuid, data); + this.temporaryDatabaseService.remove(this.profileSpaceTable, key, data); } } @@ -91,4 +94,39 @@ export class ProfilesService extends BaseService { if (!space) return `Space not found: ${spaceUuid}`; return { profile, space }; } + + async isDataExists(key: string, space_uuid: string, profile_uuid: string) { + const existingEntry = await this.prisma[this.profileSpaceTable].findUnique({ + where: { + space_uuid_profile_uuid: { + space_uuid, + profile_uuid, + }, + }, + }); + + const existingTempEntry = this.temporaryDatabaseService.get( + this.profileSpaceTable, + key, + 'insert', + ); + + const deleteTemporaryData = this.temporaryDatabaseService.get( + this.profileSpaceTable, + key, + 'delete', + ); + if (deleteTemporaryData) { + this.temporaryDatabaseService.delete( + this.profileSpaceTable, + key, + 'delete', + ); + return 'Removed the data scheduled for deletion and re-joined the room.'; + } + if (existingEntry || existingTempEntry) { + return 'Data already exists.'; + } + return; + } } From 9062bb8754931b7d5f6487e601c197eb81bb52be Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 28 Nov 2023 02:40:36 +0900 Subject: [PATCH 042/170] =?UTF-8?q?fix(#101):=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cache-server/src/spaces/spaces.service.ts | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/nestjs-BE/cache-server/src/spaces/spaces.service.ts b/nestjs-BE/cache-server/src/spaces/spaces.service.ts index 8294e8b4..5e4c45aa 100644 --- a/nestjs-BE/cache-server/src/spaces/spaces.service.ts +++ b/nestjs-BE/cache-server/src/spaces/spaces.service.ts @@ -23,23 +23,4 @@ export class SpacesService extends BaseService { generateKey(data: UpdateSpaceDto): string { return data.uuid; } - - async joinSpace(profileUuid: string, spaceUuid: string) { - const profileSpace = { - space_uuid: spaceUuid, - profile_uuid: profileUuid, - }; - - await this.prisma['PROFILE_SPACE_TB'].create({ - data: profileSpace, - }); - - return profileSpace; - } - - async leaveSpace(profileUuid: string, spaceUuid: string) { - await this.prisma['PROFILE_SPACE_TB'].delete({ - where: { space_uuid: spaceUuid, profile_uuid: profileUuid }, - }); - } } From e3ce9ef6ee9d4339492361e30309796622bcf474 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 28 Nov 2023 02:41:30 +0900 Subject: [PATCH 043/170] =?UTF-8?q?feat(#102):=20=EC=9C=A0=EC=A0=80?= =?UTF-8?q?=EA=B0=80=20=EB=93=A4=EC=96=B4=EA=B0=84=20=EB=B0=A9=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=B6=9C=EB=A0=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/users/users.controller.ts | 7 +- .../cache-server/src/users/users.module.ts | 3 +- .../cache-server/src/users/users.service.ts | 118 ++++++++++++++++-- 3 files changed, 119 insertions(+), 9 deletions(-) diff --git a/nestjs-BE/cache-server/src/users/users.controller.ts b/nestjs-BE/cache-server/src/users/users.controller.ts index 28f7de55..3080e688 100644 --- a/nestjs-BE/cache-server/src/users/users.controller.ts +++ b/nestjs-BE/cache-server/src/users/users.controller.ts @@ -37,6 +37,11 @@ export class UsersController { @Get('profiles/:email') findProfiles(@Param('email') email: string) { - return this.usersService.getProfiles(email); + return this.usersService.findProfiles(email); + } + + @Get('rooms/:email') + findRooms(@Param('email') email: string) { + return this.usersService.findRooms(email); } } diff --git a/nestjs-BE/cache-server/src/users/users.module.ts b/nestjs-BE/cache-server/src/users/users.module.ts index ecca17ad..d2a63d80 100644 --- a/nestjs-BE/cache-server/src/users/users.module.ts +++ b/nestjs-BE/cache-server/src/users/users.module.ts @@ -1,9 +1,10 @@ import { Module } from '@nestjs/common'; import { UsersService } from './users.service'; import { UsersController } from './users.controller'; +import { SpacesService } from 'src/spaces/spaces.service'; @Module({ controllers: [UsersController], - providers: [UsersService], + providers: [UsersService, SpacesService], }) export class UsersModule {} diff --git a/nestjs-BE/cache-server/src/users/users.service.ts b/nestjs-BE/cache-server/src/users/users.service.ts index e3dd50de..899f8596 100644 --- a/nestjs-BE/cache-server/src/users/users.service.ts +++ b/nestjs-BE/cache-server/src/users/users.service.ts @@ -4,12 +4,41 @@ import { TemporaryDatabaseService } from '../temporary-database/temporary-databa import { BaseService } from '../base/base.service'; import { USER_CACHE_SIZE } from '../config/magic-number'; import { UpdateUserDto } from './dto/update-user.dto'; +import { ProfileSpaceDto } from 'src/profiles/dto/profile-space.dto'; +import { SpacesService } from 'src/spaces/spaces.service'; + +interface Profile { + spaces: ProfileSpaceDto[]; +} + +type IncludeObject = { + profiles: + | boolean + | { + include?: { + spaces: + | boolean + | { + include?: { + space: boolean; + }; + }; + }; + }; +}; + +interface Item extends ProfileSpaceDto { + uuid?: string; +} @Injectable() export class UsersService extends BaseService { + profileTable = 'PROFILE_TB'; + profileSpaceTable = 'PROFILE_SPACE_TB'; constructor( protected prisma: PrismaService, protected temporaryDatabaseService: TemporaryDatabaseService, + protected spacesService: SpacesService, ) { super({ prisma, @@ -24,8 +53,8 @@ export class UsersService extends BaseService { return data.email; } - async getProfiles(email: string) { - const user = await this.getUser(email); + async findProfiles(email: string, includeSpaces = false) { + const user = await this.getUser(email, includeSpaces); if (!user) return; const profiles = user.profiles || []; @@ -36,22 +65,64 @@ export class UsersService extends BaseService { return mergedData; } - async getUser(email: string) { + async getUser(email: string, includeSpaces = false) { + const includeObject: IncludeObject = { profiles: true }; + + if (includeSpaces) { + includeObject.profiles = { + include: { + spaces: { + include: { + space: true, + }, + }, + }, + }; + } let user = await this.prisma[this.className].findUnique({ where: { email }, - include: { profiles: true }, + include: includeObject, }); - if (!user) user = await super.getDataFromCacheOrDB(email); + if (user && user.profiles) { + user.profiles = this.filterNotDeleted(this.profileTable, user.profiles); + + if (includeSpaces) { + user.profiles.forEach((profile: Profile) => { + if (profile.spaces) { + profile.spaces = this.filterNotDeleted( + this.profileSpaceTable, + profile.spaces, + ); + } + }); + } + } return user; } + filterNotDeleted(tableName: string, items: Item[]) { + return items.filter((item) => { + let key = item.uuid; + if (item.profile_uuid && item.space_uuid) { + key = `${item.profile_uuid}_${item.space_uuid}`; + } + + const deleteOperation = this.temporaryDatabaseService.get( + tableName, + key, + 'delete', + ); + return !deleteOperation; + }); + } + getTemporaryProfiles(user: UpdateUserDto) { const temporaryProfilesUuids = this.temporaryDatabaseService.getEntries( user.uuid, ); const temporaryProfiles = temporaryProfilesUuids.map((uuid) => - this.temporaryDatabaseService.get('PROFILE_TB', uuid, 'insert'), + this.temporaryDatabaseService.get(this.profileTable, uuid, 'insert'), ); return temporaryProfiles; } @@ -59,7 +130,7 @@ export class UsersService extends BaseService { mergeProfileData(combinedProfiles: UpdateUserDto[]) { const mergedData = combinedProfiles.map((data) => { const updateOperation = this.temporaryDatabaseService.get( - 'PROFILE_TB', + this.profileTable, data.uuid, 'update', ); @@ -68,4 +139,37 @@ export class UsersService extends BaseService { }); return mergedData; } + + async findRooms(email: string) { + const profiles = await this.findProfiles(email, true); + if (!profiles) return; + const spaceList = await profiles.reduce(async (listPromise, profile) => { + const list = await listPromise; + const spaceUuidsFromTempDB = this.temporaryDatabaseService.getEntries( + profile.uuid, + ); + profile.spaces = profile.spaces.filter((profileSpace) => { + const deleteTempData = this.temporaryDatabaseService.get( + this.profileSpaceTable, + `${profileSpace.profile_uuid}_${profileSpace.space_uuid}`, + 'delete', + ); + return !deleteTempData; + }); + const updatedSpaces = await Promise.all( + spaceUuidsFromTempDB.map(async (spaceUuid) => { + const space = + await this.spacesService.getDataFromCacheOrDB(spaceUuid); + return { space_uuid: spaceUuid, profile_uuid: profile.uuid, space }; + }), + ); + profile.spaces = [...profile.spaces, ...updatedSpaces]; + const spaces = profile.spaces + .filter((profileSpace) => profileSpace.space) + .map((profileSpace) => profileSpace.space); + + return list.concat(spaces); + }, Promise.resolve([])); + return spaceList; + } } From 98e978f152b97e28c61ef6620c04552764be9cb0 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 28 Nov 2023 02:42:06 +0900 Subject: [PATCH 044/170] =?UTF-8?q?fix(#101):=20=EB=A9=94=EC=84=B8?= =?UTF-8?q?=EC=A7=80=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/cache-server/src/base/base.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nestjs-BE/cache-server/src/base/base.service.ts b/nestjs-BE/cache-server/src/base/base.service.ts index b1d27ac4..d60e4266 100644 --- a/nestjs-BE/cache-server/src/base/base.service.ts +++ b/nestjs-BE/cache-server/src/base/base.service.ts @@ -38,7 +38,7 @@ export abstract class BaseService { data.uuid = generateUuid(); const key = this.generateKey(data); const storeData = await this.getDataFromCacheOrDB(key); - if (storeData) return 'data already exists.'; + if (storeData) return 'Data already exists.'; this.temporaryDatabaseService.create(this.className, key, data); this.cache.put(key, data); From f98247300e454b067c96485d98f894be840a3518 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 28 Nov 2023 03:26:55 +0900 Subject: [PATCH 045/170] =?UTF-8?q?feat(#102):=20=EB=B0=A9=EC=97=90=20?= =?UTF-8?q?=EC=9E=88=EB=8A=94=20=EC=9C=A0=EC=A0=80=20=EC=9E=84=EC=8B=9C=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/profiles/profiles.controller.ts | 5 +++ .../src/profiles/profiles.service.ts | 39 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/nestjs-BE/cache-server/src/profiles/profiles.controller.ts b/nestjs-BE/cache-server/src/profiles/profiles.controller.ts index cffb4142..c0516f74 100644 --- a/nestjs-BE/cache-server/src/profiles/profiles.controller.ts +++ b/nestjs-BE/cache-server/src/profiles/profiles.controller.ts @@ -51,4 +51,9 @@ export class ProfilesController { ) { return this.profilesService.leaveSpace(profileUuid, spaceUuid); } + + @Get('users/:uuid') + findUsers(@Param('uuid') uuid: string) { + return this.profilesService.findUsers(uuid); + } } diff --git a/nestjs-BE/cache-server/src/profiles/profiles.service.ts b/nestjs-BE/cache-server/src/profiles/profiles.service.ts index c739501c..bb62bac4 100644 --- a/nestjs-BE/cache-server/src/profiles/profiles.service.ts +++ b/nestjs-BE/cache-server/src/profiles/profiles.service.ts @@ -129,4 +129,43 @@ export class ProfilesService extends BaseService { } return; } + + async findUsers(uuid: string) { + const space = await this.prisma['SPACE_TB'].findUnique({ + where: { + uuid, + }, + include: { + profiles: { include: { profile: true } }, + }, + }); + + space.profiles = space.profiles.filter((profileSpace) => { + const deleteTempData = this.temporaryDatabaseService.get( + 'PROFILE_SPACE_TB', + `${profileSpace.profile_uuid}_${profileSpace.space_uuid}`, + 'delete', + ); + return !deleteTempData; + }); + + const spaceUuidsFromTempDB = this.temporaryDatabaseService.getEntries(uuid); + for (const spaceUuid of spaceUuidsFromTempDB) { + const insertTempData = this.temporaryDatabaseService.get( + 'PROFILE_SPACE_TB', + `${spaceUuid}_${uuid}`, + 'insert', + ); + if (insertTempData) { + const userProfile = await super.getDataFromCacheOrDB(spaceUuid); + if (userProfile) { + space.profiles.push({ + profile_uuid: spaceUuid, + profile: userProfile, + }); + } + } + } + return space.profiles.map((profileSpace) => profileSpace.profile); + } } From a35a42501f9ec505485f49aeb29af8a702d3bae6 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Tue, 28 Nov 2023 11:22:47 +0900 Subject: [PATCH 046/170] =?UTF-8?q?rename:=20server=20=ED=8F=B4=EB=8D=94?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/{ => server}/.dockerignore | 0 nestjs-BE/{ => server}/.eslintrc.js | 0 nestjs-BE/{ => server}/.gitignore | 0 nestjs-BE/{ => server}/.prettierrc | 0 nestjs-BE/{ => server}/Dockerfile | 0 nestjs-BE/{ => server}/README.md | 0 nestjs-BE/{ => server}/nest-cli.json | 0 nestjs-BE/{ => server}/package-lock.json | 0 nestjs-BE/{ => server}/package.json | 0 nestjs-BE/{ => server}/src/app.controller.spec.ts | 0 nestjs-BE/{ => server}/src/app.controller.ts | 0 nestjs-BE/{ => server}/src/app.module.ts | 0 nestjs-BE/{ => server}/src/app.service.ts | 0 nestjs-BE/{ => server}/src/board/board.gateway.ts | 0 nestjs-BE/{ => server}/src/main.ts | 0 nestjs-BE/{ => server}/test/app.e2e-spec.ts | 0 nestjs-BE/{ => server}/test/jest-e2e.json | 0 nestjs-BE/{ => server}/tsconfig.build.json | 0 nestjs-BE/{ => server}/tsconfig.json | 0 19 files changed, 0 insertions(+), 0 deletions(-) rename nestjs-BE/{ => server}/.dockerignore (100%) rename nestjs-BE/{ => server}/.eslintrc.js (100%) rename nestjs-BE/{ => server}/.gitignore (100%) rename nestjs-BE/{ => server}/.prettierrc (100%) rename nestjs-BE/{ => server}/Dockerfile (100%) rename nestjs-BE/{ => server}/README.md (100%) rename nestjs-BE/{ => server}/nest-cli.json (100%) rename nestjs-BE/{ => server}/package-lock.json (100%) rename nestjs-BE/{ => server}/package.json (100%) rename nestjs-BE/{ => server}/src/app.controller.spec.ts (100%) rename nestjs-BE/{ => server}/src/app.controller.ts (100%) rename nestjs-BE/{ => server}/src/app.module.ts (100%) rename nestjs-BE/{ => server}/src/app.service.ts (100%) rename nestjs-BE/{ => server}/src/board/board.gateway.ts (100%) rename nestjs-BE/{ => server}/src/main.ts (100%) rename nestjs-BE/{ => server}/test/app.e2e-spec.ts (100%) rename nestjs-BE/{ => server}/test/jest-e2e.json (100%) rename nestjs-BE/{ => server}/tsconfig.build.json (100%) rename nestjs-BE/{ => server}/tsconfig.json (100%) diff --git a/nestjs-BE/.dockerignore b/nestjs-BE/server/.dockerignore similarity index 100% rename from nestjs-BE/.dockerignore rename to nestjs-BE/server/.dockerignore diff --git a/nestjs-BE/.eslintrc.js b/nestjs-BE/server/.eslintrc.js similarity index 100% rename from nestjs-BE/.eslintrc.js rename to nestjs-BE/server/.eslintrc.js diff --git a/nestjs-BE/.gitignore b/nestjs-BE/server/.gitignore similarity index 100% rename from nestjs-BE/.gitignore rename to nestjs-BE/server/.gitignore diff --git a/nestjs-BE/.prettierrc b/nestjs-BE/server/.prettierrc similarity index 100% rename from nestjs-BE/.prettierrc rename to nestjs-BE/server/.prettierrc diff --git a/nestjs-BE/Dockerfile b/nestjs-BE/server/Dockerfile similarity index 100% rename from nestjs-BE/Dockerfile rename to nestjs-BE/server/Dockerfile diff --git a/nestjs-BE/README.md b/nestjs-BE/server/README.md similarity index 100% rename from nestjs-BE/README.md rename to nestjs-BE/server/README.md diff --git a/nestjs-BE/nest-cli.json b/nestjs-BE/server/nest-cli.json similarity index 100% rename from nestjs-BE/nest-cli.json rename to nestjs-BE/server/nest-cli.json diff --git a/nestjs-BE/package-lock.json b/nestjs-BE/server/package-lock.json similarity index 100% rename from nestjs-BE/package-lock.json rename to nestjs-BE/server/package-lock.json diff --git a/nestjs-BE/package.json b/nestjs-BE/server/package.json similarity index 100% rename from nestjs-BE/package.json rename to nestjs-BE/server/package.json diff --git a/nestjs-BE/src/app.controller.spec.ts b/nestjs-BE/server/src/app.controller.spec.ts similarity index 100% rename from nestjs-BE/src/app.controller.spec.ts rename to nestjs-BE/server/src/app.controller.spec.ts diff --git a/nestjs-BE/src/app.controller.ts b/nestjs-BE/server/src/app.controller.ts similarity index 100% rename from nestjs-BE/src/app.controller.ts rename to nestjs-BE/server/src/app.controller.ts diff --git a/nestjs-BE/src/app.module.ts b/nestjs-BE/server/src/app.module.ts similarity index 100% rename from nestjs-BE/src/app.module.ts rename to nestjs-BE/server/src/app.module.ts diff --git a/nestjs-BE/src/app.service.ts b/nestjs-BE/server/src/app.service.ts similarity index 100% rename from nestjs-BE/src/app.service.ts rename to nestjs-BE/server/src/app.service.ts diff --git a/nestjs-BE/src/board/board.gateway.ts b/nestjs-BE/server/src/board/board.gateway.ts similarity index 100% rename from nestjs-BE/src/board/board.gateway.ts rename to nestjs-BE/server/src/board/board.gateway.ts diff --git a/nestjs-BE/src/main.ts b/nestjs-BE/server/src/main.ts similarity index 100% rename from nestjs-BE/src/main.ts rename to nestjs-BE/server/src/main.ts diff --git a/nestjs-BE/test/app.e2e-spec.ts b/nestjs-BE/server/test/app.e2e-spec.ts similarity index 100% rename from nestjs-BE/test/app.e2e-spec.ts rename to nestjs-BE/server/test/app.e2e-spec.ts diff --git a/nestjs-BE/test/jest-e2e.json b/nestjs-BE/server/test/jest-e2e.json similarity index 100% rename from nestjs-BE/test/jest-e2e.json rename to nestjs-BE/server/test/jest-e2e.json diff --git a/nestjs-BE/tsconfig.build.json b/nestjs-BE/server/tsconfig.build.json similarity index 100% rename from nestjs-BE/tsconfig.build.json rename to nestjs-BE/server/tsconfig.build.json diff --git a/nestjs-BE/tsconfig.json b/nestjs-BE/server/tsconfig.json similarity index 100% rename from nestjs-BE/tsconfig.json rename to nestjs-BE/server/tsconfig.json From 6aeb526f372665f179f70ed10f94da43474a449a Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Tue, 28 Nov 2023 11:23:08 +0900 Subject: [PATCH 047/170] =?UTF-8?q?fix:=20checkout=20action=20=EB=B8=8C?= =?UTF-8?q?=EB=9E=9C=EC=B9=98=20=EC=A7=80=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/BE-deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index acd61ccb..fac8a088 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -9,6 +9,7 @@ jobs: steps: - uses: actions/checkout@v4 with: + ref: BE-develop sparse-checkout: nestjs-BE - name: Login to github Packages run: echo ${{ secrets.PACKAGE_ACCESS_TOKEN }} | docker login ghcr.io -u ${{ secrets.PACKAGE_USERNAME }} --password-stdin From b6df8f6a49403ad0da0200bba1a63ce0ec07c6f7 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Tue, 28 Nov 2023 11:24:52 +0900 Subject: [PATCH 048/170] =?UTF-8?q?fix:=20=EB=8F=84=EC=BB=A4=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EB=B9=8C=EB=93=9C=20=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/BE-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index fac8a088..056c798b 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -15,7 +15,7 @@ jobs: run: echo ${{ secrets.PACKAGE_ACCESS_TOKEN }} | docker login ghcr.io -u ${{ secrets.PACKAGE_USERNAME }} --password-stdin - name: Build and push Docker image run: | - docker build -t ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync ./nestjs-BE + docker build -t ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync ./nestjs-BE/server docker push ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync:latest deploy: From 3c2f22050829787f92d307eb7b79778f6b5f70d0 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Tue, 28 Nov 2023 11:44:23 +0900 Subject: [PATCH 049/170] =?UTF-8?q?rename:=20crdt=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/{ => server}/crdt/clock.ts | 0 nestjs-BE/{ => server}/crdt/crdt-tree.ts | 0 nestjs-BE/{ => server}/crdt/node.ts | 0 nestjs-BE/{ => server}/crdt/operation.ts | 0 nestjs-BE/{ => server}/crdt/tree.ts | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename nestjs-BE/{ => server}/crdt/clock.ts (100%) rename nestjs-BE/{ => server}/crdt/crdt-tree.ts (100%) rename nestjs-BE/{ => server}/crdt/node.ts (100%) rename nestjs-BE/{ => server}/crdt/operation.ts (100%) rename nestjs-BE/{ => server}/crdt/tree.ts (100%) diff --git a/nestjs-BE/crdt/clock.ts b/nestjs-BE/server/crdt/clock.ts similarity index 100% rename from nestjs-BE/crdt/clock.ts rename to nestjs-BE/server/crdt/clock.ts diff --git a/nestjs-BE/crdt/crdt-tree.ts b/nestjs-BE/server/crdt/crdt-tree.ts similarity index 100% rename from nestjs-BE/crdt/crdt-tree.ts rename to nestjs-BE/server/crdt/crdt-tree.ts diff --git a/nestjs-BE/crdt/node.ts b/nestjs-BE/server/crdt/node.ts similarity index 100% rename from nestjs-BE/crdt/node.ts rename to nestjs-BE/server/crdt/node.ts diff --git a/nestjs-BE/crdt/operation.ts b/nestjs-BE/server/crdt/operation.ts similarity index 100% rename from nestjs-BE/crdt/operation.ts rename to nestjs-BE/server/crdt/operation.ts diff --git a/nestjs-BE/crdt/tree.ts b/nestjs-BE/server/crdt/tree.ts similarity index 100% rename from nestjs-BE/crdt/tree.ts rename to nestjs-BE/server/crdt/tree.ts From 1e52de4fab2c03033bdbdb1916dd3f35e3572aa5 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Tue, 28 Nov 2023 11:47:25 +0900 Subject: [PATCH 050/170] =?UTF-8?q?fix:=20=EC=9D=98=EB=AF=B8=EC=97=90=20?= =?UTF-8?q?=EB=A7=9E=EA=B2=8C=20=EB=B3=80=EC=88=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/board/board.gateway.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/nestjs-BE/server/src/board/board.gateway.ts b/nestjs-BE/server/src/board/board.gateway.ts index 2c555bcc..e51570d2 100644 --- a/nestjs-BE/server/src/board/board.gateway.ts +++ b/nestjs-BE/server/src/board/board.gateway.ts @@ -3,10 +3,11 @@ import { WebSocketGateway, WebSocketServer, } from '@nestjs/websockets'; +import { SerializedOperation } from 'crdt/operation'; import { Server, Socket } from 'socket.io'; interface MindmapDataPayload { - message: any; + operation: SerializedOperation; boardId: string; } @@ -22,6 +23,8 @@ export class BoardGateway { @SubscribeMessage('updateMindmap') handleUpdateMindmap(client: Socket, payload: MindmapDataPayload) { - client.broadcast.to(payload.boardId).emit('stateFromServer', payload); + client.broadcast + .to(payload.boardId) + .emit('operationFromServer', payload.operation); } } From a74f904fda14e91c25907497c4d69ee59560174b Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 28 Nov 2023 13:50:55 +0900 Subject: [PATCH 051/170] =?UTF-8?q?fix(#102):=20for=EB=AC=B8=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/profiles/profiles.service.ts | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/nestjs-BE/cache-server/src/profiles/profiles.service.ts b/nestjs-BE/cache-server/src/profiles/profiles.service.ts index bb62bac4..1642a39e 100644 --- a/nestjs-BE/cache-server/src/profiles/profiles.service.ts +++ b/nestjs-BE/cache-server/src/profiles/profiles.service.ts @@ -150,22 +150,29 @@ export class ProfilesService extends BaseService { }); const spaceUuidsFromTempDB = this.temporaryDatabaseService.getEntries(uuid); - for (const spaceUuid of spaceUuidsFromTempDB) { - const insertTempData = this.temporaryDatabaseService.get( - 'PROFILE_SPACE_TB', - `${spaceUuid}_${uuid}`, - 'insert', - ); - if (insertTempData) { - const userProfile = await super.getDataFromCacheOrDB(spaceUuid); - if (userProfile) { - space.profiles.push({ - profile_uuid: spaceUuid, - profile: userProfile, - }); + const addedProfiles = await Promise.all( + spaceUuidsFromTempDB.map(async (spaceUuid) => { + const insertTempData = this.temporaryDatabaseService.get( + 'PROFILE_SPACE_TB', + `${spaceUuid}_${uuid}`, + 'insert', + ); + if (insertTempData) { + const userProfile = await super.getDataFromCacheOrDB(spaceUuid); + if (userProfile) { + return { + profile_uuid: spaceUuid, + profile: userProfile, + }; + } } - } - } + return null; + }), + ); + space.profiles = [ + ...space.profiles, + ...addedProfiles.filter((profile) => profile), + ]; return space.profiles.map((profileSpace) => profileSpace.profile); } } From 323088f144bc8cfb9624d73e3c92f2ee57a2fca8 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Tue, 28 Nov 2023 16:57:39 +0900 Subject: [PATCH 052/170] =?UTF-8?q?fix:=20JSON=20=EB=AC=B8=EC=9E=90?= =?UTF-8?q?=EC=97=B4=EB=A1=9C=20=EB=B0=9B=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/board/board.gateway.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/nestjs-BE/server/src/board/board.gateway.ts b/nestjs-BE/server/src/board/board.gateway.ts index e51570d2..cf3411f7 100644 --- a/nestjs-BE/server/src/board/board.gateway.ts +++ b/nestjs-BE/server/src/board/board.gateway.ts @@ -3,28 +3,24 @@ import { WebSocketGateway, WebSocketServer, } from '@nestjs/websockets'; -import { SerializedOperation } from 'crdt/operation'; import { Server, Socket } from 'socket.io'; -interface MindmapDataPayload { - operation: SerializedOperation; - boardId: string; -} - @WebSocketGateway({ namespace: 'board' }) export class BoardGateway { @WebSocketServer() server: Server; @SubscribeMessage('joinBoard') - handleJoinBoard(client: Socket, payload: { boardId: string }): void { - client.join(payload.boardId); + handleJoinBoard(client: Socket, payload: string): void { + const payloadObject = JSON.parse(payload); + client.join(payloadObject.boardId); } @SubscribeMessage('updateMindmap') - handleUpdateMindmap(client: Socket, payload: MindmapDataPayload) { + handleUpdateMindmap(client: Socket, payload: string) { + const payloadObject = JSON.parse(payload); client.broadcast - .to(payload.boardId) - .emit('operationFromServer', payload.operation); + .to(payloadObject.boardId) + .emit('operationFromServer', payloadObject.operation); } } From 01446d26988fab1b5fa9baf9bef32616bc62d784 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 28 Nov 2023 18:57:10 +0900 Subject: [PATCH 053/170] =?UTF-8?q?fix(#104):=20=EB=AA=BD=EA=B3=A0=20DB?= =?UTF-8?q?=EB=A5=BC=20=EC=9C=84=ED=95=9C=20=EC=8A=A4=ED=82=A4=EB=A7=88=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cache-server/prisma/mongodb.schema.prisma | 14 +++++++ .../cache-server/prisma/mysql.schema.prisma | 41 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 nestjs-BE/cache-server/prisma/mongodb.schema.prisma create mode 100644 nestjs-BE/cache-server/prisma/mysql.schema.prisma diff --git a/nestjs-BE/cache-server/prisma/mongodb.schema.prisma b/nestjs-BE/cache-server/prisma/mongodb.schema.prisma new file mode 100644 index 00000000..7fbb0264 --- /dev/null +++ b/nestjs-BE/cache-server/prisma/mongodb.schema.prisma @@ -0,0 +1,14 @@ +generator client { + provider = "prisma-client-js" + output = "./generated/mongodb" +} + +datasource db { + provider = "mongodb" + url = env("MONGODB_DATABASE_URL") +} + +model BoardCollection { + uuid String @id @map("_id") + data Json +} \ No newline at end of file diff --git a/nestjs-BE/cache-server/prisma/mysql.schema.prisma b/nestjs-BE/cache-server/prisma/mysql.schema.prisma new file mode 100644 index 00000000..d01cfb9d --- /dev/null +++ b/nestjs-BE/cache-server/prisma/mysql.schema.prisma @@ -0,0 +1,41 @@ +generator client { + provider = "prisma-client-js" + output = "./generated/mysql" +} + +datasource db { + provider = "mysql" + url = env("MYSQL_DATABASE_URL") +} + +model USER_TB { + uuid String @id @db.VarChar(32) + email String @unique + password String + profiles PROFILE_TB[] +} + +model PROFILE_TB { + uuid String @id @db.VarChar(32) + user_id String @db.VarChar(32) + image String + nickname String + user USER_TB @relation(fields: [user_id], references: [uuid]) + spaces PROFILE_SPACE_TB[] + @@index([user_id]) +} + +model SPACE_TB { + uuid String @id @db.VarChar(32) + name String + icon String + profiles PROFILE_SPACE_TB[] +} + +model PROFILE_SPACE_TB { + space_uuid String @db.VarChar(32) + profile_uuid String @db.VarChar(32) + space SPACE_TB @relation(fields: [space_uuid], references: [uuid]) + profile PROFILE_TB @relation(fields: [profile_uuid], references: [uuid]) + @@id([space_uuid, profile_uuid]) +} \ No newline at end of file From b47678628d0a5d8b4c924b988d93b71d16202442 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 28 Nov 2023 18:58:22 +0900 Subject: [PATCH 054/170] =?UTF-8?q?fix(#104):=20mongoDB=20client=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=B0=8F=20import=20=EB=AA=85=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cache-server/src/prisma/prisma.module.ts | 7 ++++--- .../cache-server/src/prisma/prisma.service.ts | 18 ++++++++++++++++-- .../src/profiles/profiles.service.ts | 4 ++-- .../cache-server/src/spaces/spaces.service.ts | 4 ++-- .../cache-server/src/users/users.service.ts | 4 ++-- 5 files changed, 26 insertions(+), 11 deletions(-) diff --git a/nestjs-BE/cache-server/src/prisma/prisma.module.ts b/nestjs-BE/cache-server/src/prisma/prisma.module.ts index 7207426f..01b27f2d 100644 --- a/nestjs-BE/cache-server/src/prisma/prisma.module.ts +++ b/nestjs-BE/cache-server/src/prisma/prisma.module.ts @@ -1,9 +1,10 @@ import { Global, Module } from '@nestjs/common'; -import { PrismaService } from './prisma.service'; +import { PrismaServiceMySQL } from './prisma.service'; +import { PrismaServiceMongoDB } from './prisma.service'; @Global() @Module({ - providers: [PrismaService], - exports: [PrismaService], + providers: [PrismaServiceMySQL, PrismaServiceMongoDB], + exports: [PrismaServiceMySQL, PrismaServiceMongoDB], }) export class PrismaModule {} diff --git a/nestjs-BE/cache-server/src/prisma/prisma.service.ts b/nestjs-BE/cache-server/src/prisma/prisma.service.ts index 359f950b..5559b4ea 100644 --- a/nestjs-BE/cache-server/src/prisma/prisma.service.ts +++ b/nestjs-BE/cache-server/src/prisma/prisma.service.ts @@ -1,8 +1,22 @@ import { Injectable, OnModuleInit } from '@nestjs/common'; -import { PrismaClient } from '@prisma/client'; +import { PrismaClient as PrismaClientMySQL } from '../../prisma/generated/mysql'; +import { PrismaClient as PrismaClientMongoDB } from '../../prisma/generated/mongodb'; @Injectable() -export class PrismaService extends PrismaClient implements OnModuleInit { +export class PrismaServiceMySQL + extends PrismaClientMySQL + implements OnModuleInit +{ + async onModuleInit() { + await this.$connect(); + } +} + +@Injectable() +export class PrismaServiceMongoDB + extends PrismaClientMongoDB + implements OnModuleInit +{ async onModuleInit() { await this.$connect(); } diff --git a/nestjs-BE/cache-server/src/profiles/profiles.service.ts b/nestjs-BE/cache-server/src/profiles/profiles.service.ts index 1642a39e..21ac9194 100644 --- a/nestjs-BE/cache-server/src/profiles/profiles.service.ts +++ b/nestjs-BE/cache-server/src/profiles/profiles.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@nestjs/common'; -import { PrismaService } from '../prisma/prisma.service'; +import { PrismaServiceMySQL } from '../prisma/prisma.service'; import { TemporaryDatabaseService } from '../temporary-database/temporary-database.service'; import { BaseService } from '../base/base.service'; import { PROFILE_CACHE_SIZE } from 'src/config/magic-number'; @@ -12,7 +12,7 @@ import { ProfileSpaceDto } from './dto/profile-space.dto'; export class ProfilesService extends BaseService { profileSpaceTable = 'PROFILE_SPACE_TB'; constructor( - protected prisma: PrismaService, + protected prisma: PrismaServiceMySQL, protected temporaryDatabaseService: TemporaryDatabaseService, protected spacesService: SpacesService, ) { diff --git a/nestjs-BE/cache-server/src/spaces/spaces.service.ts b/nestjs-BE/cache-server/src/spaces/spaces.service.ts index 5e4c45aa..eff278c6 100644 --- a/nestjs-BE/cache-server/src/spaces/spaces.service.ts +++ b/nestjs-BE/cache-server/src/spaces/spaces.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@nestjs/common'; -import { PrismaService } from '../prisma/prisma.service'; +import { PrismaServiceMySQL } from '../prisma/prisma.service'; import { TemporaryDatabaseService } from '../temporary-database/temporary-database.service'; import { BaseService } from '../base/base.service'; import { SPACE_CACHE_SIZE } from 'src/config/magic-number'; @@ -8,7 +8,7 @@ import { UpdateSpaceDto } from './dto/update-space.dto'; @Injectable() export class SpacesService extends BaseService { constructor( - protected prisma: PrismaService, + protected prisma: PrismaServiceMySQL, protected temporaryDatabaseService: TemporaryDatabaseService, ) { super({ diff --git a/nestjs-BE/cache-server/src/users/users.service.ts b/nestjs-BE/cache-server/src/users/users.service.ts index 899f8596..7bb4ae4e 100644 --- a/nestjs-BE/cache-server/src/users/users.service.ts +++ b/nestjs-BE/cache-server/src/users/users.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@nestjs/common'; -import { PrismaService } from '../prisma/prisma.service'; +import { PrismaServiceMySQL } from '../prisma/prisma.service'; import { TemporaryDatabaseService } from '../temporary-database/temporary-database.service'; import { BaseService } from '../base/base.service'; import { USER_CACHE_SIZE } from '../config/magic-number'; @@ -36,7 +36,7 @@ export class UsersService extends BaseService { profileTable = 'PROFILE_TB'; profileSpaceTable = 'PROFILE_SPACE_TB'; constructor( - protected prisma: PrismaService, + protected prisma: PrismaServiceMySQL, protected temporaryDatabaseService: TemporaryDatabaseService, protected spacesService: SpacesService, ) { From def142ffc017a9ad1ca94f950877f9f5c44dbb50 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 28 Nov 2023 18:59:14 +0900 Subject: [PATCH 055/170] =?UTF-8?q?feat(#104):=20boards=20=EC=95=B1=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=B0=8F=20DB=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cache-server/src/base/base.service.ts | 14 +++---- .../src/boards/boards.controller.spec.ts | 20 ++++++++++ .../src/boards/boards.controller.ts | 37 +++++++++++++++++++ .../cache-server/src/boards/boards.module.ts | 9 +++++ .../src/boards/boards.service.spec.ts | 18 +++++++++ .../cache-server/src/boards/boards.service.ts | 25 +++++++++++++ .../src/boards/dto/create-board.dto.ts | 1 + .../src/boards/dto/update-board.dto.ts | 6 +++ .../src/boards/entities/board.entity.ts | 1 + .../cache-server/src/config/magic-number.ts | 2 + 10 files changed, 126 insertions(+), 7 deletions(-) create mode 100644 nestjs-BE/cache-server/src/boards/boards.controller.spec.ts create mode 100644 nestjs-BE/cache-server/src/boards/boards.controller.ts create mode 100644 nestjs-BE/cache-server/src/boards/boards.module.ts create mode 100644 nestjs-BE/cache-server/src/boards/boards.service.spec.ts create mode 100644 nestjs-BE/cache-server/src/boards/boards.service.ts create mode 100644 nestjs-BE/cache-server/src/boards/dto/create-board.dto.ts create mode 100644 nestjs-BE/cache-server/src/boards/dto/update-board.dto.ts create mode 100644 nestjs-BE/cache-server/src/boards/entities/board.entity.ts diff --git a/nestjs-BE/cache-server/src/base/base.service.ts b/nestjs-BE/cache-server/src/base/base.service.ts index d60e4266..8ba5272a 100644 --- a/nestjs-BE/cache-server/src/base/base.service.ts +++ b/nestjs-BE/cache-server/src/base/base.service.ts @@ -1,11 +1,14 @@ import { Injectable } from '@nestjs/common'; -import { PrismaService } from '../prisma/prisma.service'; +import { + PrismaServiceMySQL, + PrismaServiceMongoDB, +} from '../prisma/prisma.service'; import { TemporaryDatabaseService } from '../temporary-database/temporary-database.service'; import LRUCache from '../utils/lru-cache'; import generateUuid from '../utils/uuid'; interface BaseServiceOptions { - prisma: PrismaService; + prisma: PrismaServiceMySQL | PrismaServiceMongoDB; temporaryDatabaseService: TemporaryDatabaseService; cacheSize: number; className: string; @@ -21,7 +24,7 @@ export abstract class BaseService { protected cache: LRUCache; protected className: string; protected field: string; - protected prisma: PrismaService; + protected prisma: PrismaServiceMySQL | PrismaServiceMongoDB; protected temporaryDatabaseService: TemporaryDatabaseService; constructor(options: BaseServiceOptions) { @@ -47,7 +50,6 @@ export abstract class BaseService { async findOne(key: string): Promise { const data = await this.getDataFromCacheOrDB(key); - const deleteCommand = this.temporaryDatabaseService.get( this.className, key, @@ -65,7 +67,6 @@ export abstract class BaseService { async update(key: string, updateData: T) { const data = await this.getDataFromCacheOrDB(key); - if (data) { const updatedData = { field: this.field, @@ -80,7 +81,6 @@ export abstract class BaseService { } else { this.temporaryDatabaseService.update(this.className, key, updatedData); } - this.cache.put(key, updatedData.value); } } @@ -123,7 +123,7 @@ export abstract class BaseService { key, 'update', ); - if (updateCommand) return { ...data, ...updateCommand }; + if (updateCommand) return { ...data, ...updateCommand.value }; return data; } diff --git a/nestjs-BE/cache-server/src/boards/boards.controller.spec.ts b/nestjs-BE/cache-server/src/boards/boards.controller.spec.ts new file mode 100644 index 00000000..f6de507d --- /dev/null +++ b/nestjs-BE/cache-server/src/boards/boards.controller.spec.ts @@ -0,0 +1,20 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { BoardsController } from './boards.controller'; +import { BoardsService } from './boards.service'; + +describe('BoardsController', () => { + let controller: BoardsController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [BoardsController], + providers: [BoardsService], + }).compile(); + + controller = module.get(BoardsController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/nestjs-BE/cache-server/src/boards/boards.controller.ts b/nestjs-BE/cache-server/src/boards/boards.controller.ts new file mode 100644 index 00000000..8a32b04f --- /dev/null +++ b/nestjs-BE/cache-server/src/boards/boards.controller.ts @@ -0,0 +1,37 @@ +import { + Controller, + Get, + Post, + Body, + Patch, + Param, + Delete, +} from '@nestjs/common'; +import { BoardsService } from './boards.service'; +import { CreateBoardDto } from './dto/create-board.dto'; +import { UpdateBoardDto } from './dto/update-board.dto'; + +@Controller('boards') +export class BoardsController { + constructor(private readonly boardsService: BoardsService) {} + + @Post() + create(@Body() createBoardDto: CreateBoardDto) { + return this.boardsService.create(createBoardDto); + } + + @Get(':uuid') + findOne(@Param('uuid') uuid: string) { + return this.boardsService.findOne(uuid); + } + + @Patch(':uuid') + update(@Param('uuid') uuid: string, @Body() updateBoardDto: UpdateBoardDto) { + return this.boardsService.update(uuid, updateBoardDto); + } + + @Delete(':uuid') + remove(@Param('uuid') uuid: string) { + return this.boardsService.remove(uuid); + } +} diff --git a/nestjs-BE/cache-server/src/boards/boards.module.ts b/nestjs-BE/cache-server/src/boards/boards.module.ts new file mode 100644 index 00000000..16204c29 --- /dev/null +++ b/nestjs-BE/cache-server/src/boards/boards.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { BoardsService } from './boards.service'; +import { BoardsController } from './boards.controller'; + +@Module({ + controllers: [BoardsController], + providers: [BoardsService], +}) +export class BoardsModule {} diff --git a/nestjs-BE/cache-server/src/boards/boards.service.spec.ts b/nestjs-BE/cache-server/src/boards/boards.service.spec.ts new file mode 100644 index 00000000..a1da1cdb --- /dev/null +++ b/nestjs-BE/cache-server/src/boards/boards.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { BoardsService } from './boards.service'; + +describe('BoardsService', () => { + let service: BoardsService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [BoardsService], + }).compile(); + + service = module.get(BoardsService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/nestjs-BE/cache-server/src/boards/boards.service.ts b/nestjs-BE/cache-server/src/boards/boards.service.ts new file mode 100644 index 00000000..d9c63142 --- /dev/null +++ b/nestjs-BE/cache-server/src/boards/boards.service.ts @@ -0,0 +1,25 @@ +import { Injectable } from '@nestjs/common'; +import { UpdateBoardDto } from './dto/update-board.dto'; +import { PrismaServiceMongoDB } from 'src/prisma/prisma.service'; +import { BOARD_CACHE_SIZE } from 'src/config/magic-number'; +import { BaseService } from 'src/base/base.service'; +import { TemporaryDatabaseService } from 'src/temporary-database/temporary-database.service'; +@Injectable() +export class BoardsService extends BaseService { + constructor( + protected prisma: PrismaServiceMongoDB, + protected temporaryDatabaseService: TemporaryDatabaseService, + ) { + super({ + prisma, + temporaryDatabaseService, + cacheSize: BOARD_CACHE_SIZE, + className: 'BoardCollection', + field: 'uuid', + }); + } + + generateKey(data: UpdateBoardDto): string { + return data.uuid; + } +} diff --git a/nestjs-BE/cache-server/src/boards/dto/create-board.dto.ts b/nestjs-BE/cache-server/src/boards/dto/create-board.dto.ts new file mode 100644 index 00000000..463a2541 --- /dev/null +++ b/nestjs-BE/cache-server/src/boards/dto/create-board.dto.ts @@ -0,0 +1 @@ +export class CreateBoardDto {} diff --git a/nestjs-BE/cache-server/src/boards/dto/update-board.dto.ts b/nestjs-BE/cache-server/src/boards/dto/update-board.dto.ts new file mode 100644 index 00000000..67fc4bfb --- /dev/null +++ b/nestjs-BE/cache-server/src/boards/dto/update-board.dto.ts @@ -0,0 +1,6 @@ +import { PartialType } from '@nestjs/swagger'; +import { CreateBoardDto } from './create-board.dto'; + +export class UpdateBoardDto extends PartialType(CreateBoardDto) { + uuid?: string; +} diff --git a/nestjs-BE/cache-server/src/boards/entities/board.entity.ts b/nestjs-BE/cache-server/src/boards/entities/board.entity.ts new file mode 100644 index 00000000..555916ba --- /dev/null +++ b/nestjs-BE/cache-server/src/boards/entities/board.entity.ts @@ -0,0 +1 @@ +export class Board {} diff --git a/nestjs-BE/cache-server/src/config/magic-number.ts b/nestjs-BE/cache-server/src/config/magic-number.ts index e2790d04..825d7d4e 100644 --- a/nestjs-BE/cache-server/src/config/magic-number.ts +++ b/nestjs-BE/cache-server/src/config/magic-number.ts @@ -1,3 +1,5 @@ export const USER_CACHE_SIZE = 1000; export const PROFILE_CACHE_SIZE = 5000; export const SPACE_CACHE_SIZE = 10000; +export const BOARD_CACHE_SIZE = 10000; +export const PORT = 3000; From 1d80cfc9be74901a106a7e77597527463e50ce23 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 28 Nov 2023 18:59:43 +0900 Subject: [PATCH 056/170] =?UTF-8?q?fix(#104):=20mongoDB=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0=20=ED=95=98=EB=A9=B4=EC=84=9C=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../temporary-database.service.ts | 64 +++++++++++++------ 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts b/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts index 4e4d6f1e..52ef7906 100644 --- a/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts +++ b/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts @@ -1,5 +1,8 @@ import { Injectable } from '@nestjs/common'; -import { PrismaService } from '../prisma/prisma.service'; +import { + PrismaServiceMySQL, + PrismaServiceMongoDB, +} from '../prisma/prisma.service'; import { Cron } from '@nestjs/schedule'; import { promises as fs } from 'fs'; import { join } from 'path'; @@ -17,7 +20,10 @@ export class TemporaryDatabaseService { private entriesMap: Map = new Map(); private readonly FOLDER_NAME = 'operations'; - constructor(private readonly prisma: PrismaService) { + constructor( + private readonly prismaMysql: PrismaServiceMySQL, + private readonly prismaMongoDB: PrismaServiceMongoDB, + ) { this.initializeDatabase(); this.readDataFromFiles(); } @@ -27,7 +33,7 @@ export class TemporaryDatabaseService { 'USER_TB', 'PROFILE_TB', 'SPACE_TB', - 'BOARD_TB', + 'BoardCollection', 'PROFILE_SPACE_TB', ]; const operations = ['insert', 'update', 'delete']; @@ -103,51 +109,73 @@ export class TemporaryDatabaseService { }); } - @Cron('0 */10 * * * *') + @Cron('* */10 * * * *') async executeBulkOperations() { for (const service of this.database.keys()) { const serviceMap = this.database.get(service); - await this.performInsert(service, serviceMap.get('insert')); - await this.performUpdate(service, serviceMap.get('update')); - await this.performDelete(service, serviceMap.get('delete')); + const prisma = + service === 'BoardCollection' ? this.prismaMongoDB : this.prismaMysql; + await this.performInsert(service, serviceMap.get('insert'), prisma); + await this.performUpdate(service, serviceMap.get('update'), prisma); + await this.performDelete(service, serviceMap.get('delete'), prisma); } } - private async performInsert(service: string, dataMap: Map) { + private async performInsert( + service: string, + dataMap: Map, + prisma: PrismaServiceMongoDB | PrismaServiceMySQL, + ) { const data = this.prepareData(service, 'insert', dataMap); this.entriesMap.clear(); if (!data.length) return; - await this.prisma[service].createMany({ - data: data, - skipDuplicates: true, - }); + if (prisma instanceof PrismaServiceMySQL) { + await prisma[service].createMany({ + data: data, + skipDuplicates: true, + }); + } else { + await prisma[service].createMany({ + data: data, + }); + } } - private async performUpdate(service: string, dataMap: Map) { + private async performUpdate( + service: string, + dataMap: Map, + prisma: PrismaServiceMongoDB | PrismaServiceMySQL, + ) { const data = this.prepareData(service, 'update', dataMap); if (!data.length) return; await Promise.all( data.map((item) => { const keyField = item.field; const keyValue = item.value[keyField]; - return this.prisma[service].update({ + const updatedValue = Object.fromEntries( + Object.entries(item.value).filter(([key]) => key !== 'uuid'), + ); + return prisma[service].update({ where: { [keyField]: keyValue }, - data: item.value, + data: updatedValue, }); }), ); } - private async performDelete(service: string, dataMap: Map) { + private async performDelete( + service: string, + dataMap: Map, + prisma: PrismaServiceMongoDB | PrismaServiceMySQL, + ) { const data = this.prepareData(service, 'delete', dataMap); if (!data.length) return; await Promise.all( data.map(async (item) => { try { - await this.prisma[service].delete({ + await prisma[service].delete({ where: { [item.field]: item.value }, }); - } catch { } finally { return; } From 2efa47dec41eb3e60fada9c60059fc9412965159 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 28 Nov 2023 19:00:46 +0900 Subject: [PATCH 057/170] =?UTF-8?q?chore(#104):=20=EC=9E=84=EC=8B=9C=20swa?= =?UTF-8?q?gger=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/cache-server/.gitignore | 5 +- nestjs-BE/cache-server/package-lock.json | 63 ++++++++++++++++++-- nestjs-BE/cache-server/package.json | 1 + nestjs-BE/cache-server/src/app.module.ts | 2 + nestjs-BE/cache-server/src/config/swagger.ts | 6 ++ nestjs-BE/cache-server/src/main.ts | 8 ++- 6 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 nestjs-BE/cache-server/src/config/swagger.ts diff --git a/nestjs-BE/cache-server/.gitignore b/nestjs-BE/cache-server/.gitignore index 48a804b7..fbd14d32 100644 --- a/nestjs-BE/cache-server/.gitignore +++ b/nestjs-BE/cache-server/.gitignore @@ -37,5 +37,6 @@ lerna-debug.log* # 환경 변수 .env -# csv -/operations \ No newline at end of file +# csv, prisma +/operations +/prisma/generated \ No newline at end of file diff --git a/nestjs-BE/cache-server/package-lock.json b/nestjs-BE/cache-server/package-lock.json index e8148d14..9eb2d308 100644 --- a/nestjs-BE/cache-server/package-lock.json +++ b/nestjs-BE/cache-server/package-lock.json @@ -14,6 +14,7 @@ "@nestjs/mapped-types": "*", "@nestjs/platform-express": "^10.0.0", "@nestjs/schedule": "^4.0.0", + "@nestjs/swagger": "^7.1.16", "@prisma/client": "^5.6.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", @@ -1732,6 +1733,56 @@ "typescript": ">=4.8.2" } }, + "node_modules/@nestjs/swagger": { + "version": "7.1.16", + "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-7.1.16.tgz", + "integrity": "sha512-f9KBk/BX9MUKPTj7tQNYJ124wV/jP5W2lwWHLGwe/4qQXixuDOo39zP55HIJ44LE7S04B7BOeUOo9GBJD/vRcw==", + "dependencies": { + "@nestjs/mapped-types": "2.0.3", + "js-yaml": "4.1.0", + "lodash": "4.17.21", + "path-to-regexp": "3.2.0", + "swagger-ui-dist": "5.9.1" + }, + "peerDependencies": { + "@fastify/static": "^6.0.0", + "@nestjs/common": "^9.0.0 || ^10.0.0", + "@nestjs/core": "^9.0.0 || ^10.0.0", + "class-transformer": "*", + "class-validator": "*", + "reflect-metadata": "^0.1.12" + }, + "peerDependenciesMeta": { + "@fastify/static": { + "optional": true + }, + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, + "node_modules/@nestjs/swagger/node_modules/@nestjs/mapped-types": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.0.3.tgz", + "integrity": "sha512-40Zdqg98lqoF0+7ThWIZFStxgzisK6GG22+1ABO4kZiGF/Tu2FE+DYLw+Q9D94vcFWizJ+MSjNN4ns9r6hIGxw==", + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "class-transformer": "^0.4.0 || ^0.5.0", + "class-validator": "^0.13.0 || ^0.14.0", + "reflect-metadata": "^0.1.12" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, "node_modules/@nestjs/testing": { "version": "10.2.10", "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.2.10.tgz", @@ -2714,8 +2765,7 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/array-flatten": { "version": "1.1.1", @@ -6105,7 +6155,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -6252,8 +6301,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.memoize": { "version": "4.1.2", @@ -8028,6 +8076,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swagger-ui-dist": { + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.9.1.tgz", + "integrity": "sha512-5zAx+hUwJb9T3EAntc7TqYkV716CMqG6sZpNlAAMOMWkNXRYxGkN8ADIvD55dQZ10LxN90ZM/TQmN7y1gpICnw==" + }, "node_modules/symbol-observable": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", diff --git a/nestjs-BE/cache-server/package.json b/nestjs-BE/cache-server/package.json index fb5ba9e6..2b297eff 100644 --- a/nestjs-BE/cache-server/package.json +++ b/nestjs-BE/cache-server/package.json @@ -25,6 +25,7 @@ "@nestjs/mapped-types": "*", "@nestjs/platform-express": "^10.0.0", "@nestjs/schedule": "^4.0.0", + "@nestjs/swagger": "^7.1.16", "@prisma/client": "^5.6.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", diff --git a/nestjs-BE/cache-server/src/app.module.ts b/nestjs-BE/cache-server/src/app.module.ts index f046876e..70b5f4ab 100644 --- a/nestjs-BE/cache-server/src/app.module.ts +++ b/nestjs-BE/cache-server/src/app.module.ts @@ -7,6 +7,7 @@ import { TemporaryDatabaseModule } from './temporary-database/temporary-database import { ScheduleModule } from '@nestjs/schedule'; import { ProfilesModule } from './profiles/profiles.module'; import { SpacesModule } from './spaces/spaces.module'; +import { BoardsModule } from './boards/boards.module'; @Module({ imports: [ @@ -16,6 +17,7 @@ import { SpacesModule } from './spaces/spaces.module'; ScheduleModule.forRoot(), ProfilesModule, SpacesModule, + BoardsModule, ], controllers: [AppController], providers: [AppService], diff --git a/nestjs-BE/cache-server/src/config/swagger.ts b/nestjs-BE/cache-server/src/config/swagger.ts new file mode 100644 index 00000000..a8e44ab0 --- /dev/null +++ b/nestjs-BE/cache-server/src/config/swagger.ts @@ -0,0 +1,6 @@ +import { DocumentBuilder } from '@nestjs/swagger'; +export const swaggerConfig = new DocumentBuilder() + .setTitle('mind-sync db-api') + .setDescription('API description') + .setVersion('1.0') + .build(); diff --git a/nestjs-BE/cache-server/src/main.ts b/nestjs-BE/cache-server/src/main.ts index 13cad38c..3d99452a 100644 --- a/nestjs-BE/cache-server/src/main.ts +++ b/nestjs-BE/cache-server/src/main.ts @@ -1,8 +1,14 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; +import { SwaggerModule } from '@nestjs/swagger'; +import { swaggerConfig } from './config/swagger'; +import { PORT } from './config/magic-number'; async function bootstrap() { const app = await NestFactory.create(AppModule); - await app.listen(3000); + const document = SwaggerModule.createDocument(app, swaggerConfig); + SwaggerModule.setup('api-docs', app, document); + + await app.listen(PORT); } bootstrap(); From 9495e11a60d7ec71d226493b17a0ca23df370bdf Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 28 Nov 2023 19:01:30 +0900 Subject: [PATCH 058/170] =?UTF-8?q?remove(#104):=20=EC=8A=A4=ED=82=A4?= =?UTF-8?q?=EB=A7=88=20=EB=B3=80=EA=B2=BD=EC=9C=BC=EB=A1=9C=20=EC=9D=B8?= =?UTF-8?q?=ED=95=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/cache-server/prisma/schema.prisma | 40 --------------------- 1 file changed, 40 deletions(-) delete mode 100644 nestjs-BE/cache-server/prisma/schema.prisma diff --git a/nestjs-BE/cache-server/prisma/schema.prisma b/nestjs-BE/cache-server/prisma/schema.prisma deleted file mode 100644 index 60e97088..00000000 --- a/nestjs-BE/cache-server/prisma/schema.prisma +++ /dev/null @@ -1,40 +0,0 @@ -generator client { - provider = "prisma-client-js" -} - -datasource db { - provider = "mysql" - url = env("DATABASE_URL") -} - -model USER_TB { - uuid String @id @db.VarChar(32) - email String @unique - password String - profiles PROFILE_TB[] -} - -model PROFILE_TB { - uuid String @id @db.VarChar(32) - user_id String @db.VarChar(32) - image String - nickname String - user USER_TB @relation(fields: [user_id], references: [uuid]) - spaces PROFILE_SPACE_TB[] - @@index([user_id]) -} - -model SPACE_TB { - uuid String @id @db.VarChar(32) - name String - icon String - profiles PROFILE_SPACE_TB[] -} - -model PROFILE_SPACE_TB { - space_uuid String @db.VarChar(32) - profile_uuid String @db.VarChar(32) - space SPACE_TB @relation(fields: [space_uuid], references: [uuid]) - profile PROFILE_TB @relation(fields: [profile_uuid], references: [uuid]) - @@id([space_uuid, profile_uuid]) -} \ No newline at end of file From c38463b07dfe771fe56ae443f5734f80fad66f8d Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Wed, 29 Nov 2023 17:11:02 +0900 Subject: [PATCH 059/170] =?UTF-8?q?fix:=20payload=20operation=20json=20?= =?UTF-8?q?=EB=AC=B8=EC=9E=90=EC=97=B4=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/board/board.gateway.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/board/board.gateway.ts b/nestjs-BE/server/src/board/board.gateway.ts index cf3411f7..e68fbc1f 100644 --- a/nestjs-BE/server/src/board/board.gateway.ts +++ b/nestjs-BE/server/src/board/board.gateway.ts @@ -21,6 +21,6 @@ export class BoardGateway { const payloadObject = JSON.parse(payload); client.broadcast .to(payloadObject.boardId) - .emit('operationFromServer', payloadObject.operation); + .emit('operationFromServer', JSON.stringify(payloadObject.operation)); } } From aa5485717daffb05f08a48bc261c4505b7b6b15a Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Tue, 28 Nov 2023 14:56:04 +0900 Subject: [PATCH 060/170] =?UTF-8?q?feat:=20.env=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EB=B6=88=EB=9F=AC=EC=98=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/config/env.ts | 10 ++++++++++ nestjs-BE/server/package-lock.json | 12 ++++++++++++ nestjs-BE/server/package.json | 1 + nestjs-BE/server/src/main.ts | 5 ++--- 4 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 nestjs-BE/server/config/env.ts diff --git a/nestjs-BE/server/config/env.ts b/nestjs-BE/server/config/env.ts new file mode 100644 index 00000000..eba1fb25 --- /dev/null +++ b/nestjs-BE/server/config/env.ts @@ -0,0 +1,10 @@ +import { config } from 'dotenv'; + +interface CustomEnv { + [key: string]: string; +} + +const customEnv: CustomEnv = {}; +config({ processEnv: customEnv }); + +export default customEnv; diff --git a/nestjs-BE/server/package-lock.json b/nestjs-BE/server/package-lock.json index 6b32191a..429c318d 100644 --- a/nestjs-BE/server/package-lock.json +++ b/nestjs-BE/server/package-lock.json @@ -14,6 +14,7 @@ "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.2.8", "@nestjs/websockets": "^10.2.8", + "dotenv": "^16.3.1", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1" }, @@ -3872,6 +3873,17 @@ "node": ">=6.0.0" } }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", diff --git a/nestjs-BE/server/package.json b/nestjs-BE/server/package.json index 4352ced4..945d7725 100644 --- a/nestjs-BE/server/package.json +++ b/nestjs-BE/server/package.json @@ -25,6 +25,7 @@ "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.2.8", "@nestjs/websockets": "^10.2.8", + "dotenv": "^16.3.1", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1" }, diff --git a/nestjs-BE/server/src/main.ts b/nestjs-BE/server/src/main.ts index 6f57e2d4..e45fec4a 100644 --- a/nestjs-BE/server/src/main.ts +++ b/nestjs-BE/server/src/main.ts @@ -1,10 +1,9 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; - -const PORT: number = 3000; +import customEnv from 'config/env'; async function bootstrap() { const app = await NestFactory.create(AppModule); - await app.listen(PORT); + await app.listen(customEnv.SERVER_PORT); } bootstrap(); From 51651ae4adbba4522f8ae4fd01f47f0271ee0396 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Wed, 29 Nov 2023 00:39:00 +0900 Subject: [PATCH 061/170] =?UTF-8?q?feat:=20=EB=8D=94=EB=AF=B8=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=EB=A1=9C=20=EC=9C=A0=EC=A0=80=20=EB=AA=A8?= =?UTF-8?q?=EB=93=88=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/app.module.ts | 3 ++- nestjs-BE/server/src/users/users.module.ts | 8 ++++++ nestjs-BE/server/src/users/users.service.ts | 27 +++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 nestjs-BE/server/src/users/users.module.ts create mode 100644 nestjs-BE/server/src/users/users.service.ts diff --git a/nestjs-BE/server/src/app.module.ts b/nestjs-BE/server/src/app.module.ts index b919faf3..08c391c3 100644 --- a/nestjs-BE/server/src/app.module.ts +++ b/nestjs-BE/server/src/app.module.ts @@ -2,9 +2,10 @@ import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { BoardGateway } from './board/board.gateway'; +import { UsersModule } from './users/users.module'; @Module({ - imports: [], + imports: [UsersModule], controllers: [AppController], providers: [AppService, BoardGateway], }) diff --git a/nestjs-BE/server/src/users/users.module.ts b/nestjs-BE/server/src/users/users.module.ts new file mode 100644 index 00000000..8fa904f1 --- /dev/null +++ b/nestjs-BE/server/src/users/users.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { UsersService } from './users.service'; + +@Module({ + providers: [UsersService], + exports: [UsersService], +}) +export class UsersModule {} diff --git a/nestjs-BE/server/src/users/users.service.ts b/nestjs-BE/server/src/users/users.service.ts new file mode 100644 index 00000000..ffb2a3a7 --- /dev/null +++ b/nestjs-BE/server/src/users/users.service.ts @@ -0,0 +1,27 @@ +import { Injectable } from '@nestjs/common'; + +export type User = { + uuid: string; + email: string; + password: string; +}; + +@Injectable() +export class UsersService { + private readonly users: User[] = [ + { + uuid: '1', + email: 'john', + password: 'changeme', + }, + { + uuid: '2', + email: 'maria', + password: 'guess', + }, + ]; + + async findOne(email: string): Promise { + return this.users.find((user) => user.email === email); + } +} From 1a7d941f94f64b3a791c83aaa9221da9178a04d3 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Wed, 29 Nov 2023 00:39:36 +0900 Subject: [PATCH 062/170] =?UTF-8?q?feat(#73):=20JWT=20=ED=86=A0=ED=81=B0?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=20=EC=84=9C=EB=B9=84=EC=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/auth/auth.service.ts | 19 +++++++++++++++++++ nestjs-BE/server/src/auth/constants.ts | 5 +++++ 2 files changed, 24 insertions(+) create mode 100644 nestjs-BE/server/src/auth/auth.service.ts create mode 100644 nestjs-BE/server/src/auth/constants.ts diff --git a/nestjs-BE/server/src/auth/auth.service.ts b/nestjs-BE/server/src/auth/auth.service.ts new file mode 100644 index 00000000..fd048a69 --- /dev/null +++ b/nestjs-BE/server/src/auth/auth.service.ts @@ -0,0 +1,19 @@ +import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import { UsersService } from 'src/users/users.service'; + +@Injectable() +export class AuthService { + constructor( + private usersService: UsersService, + private jwtService: JwtService, + ) {} + + async signIn(email: string, password: string): Promise { + const user = await this.usersService.findOne(email); + if (user?.password !== password) throw new UnauthorizedException(); + + const payload = { sub: user.uuid, email: user.email }; + return { access_token: await this.jwtService.signAsync(payload) }; + } +} diff --git a/nestjs-BE/server/src/auth/constants.ts b/nestjs-BE/server/src/auth/constants.ts new file mode 100644 index 00000000..969fbc29 --- /dev/null +++ b/nestjs-BE/server/src/auth/constants.ts @@ -0,0 +1,5 @@ +import customEnv from 'config/env'; + +export const jwtConstants = { + secret: customEnv.JWT_SECRET, +}; From 865d409e44d73dd987300edeeece130a8061e429 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Wed, 29 Nov 2023 00:43:01 +0900 Subject: [PATCH 063/170] =?UTF-8?q?feat(#99):=20=EC=9D=B8=EC=A6=9D?= =?UTF-8?q?=EC=9D=B4=20=ED=95=84=EC=9A=94=ED=95=9C=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?Access=20Token=20=ED=99=95=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/app.module.ts | 3 +- nestjs-BE/server/src/auth/auth.controller.ts | 29 +++++++++++++++++ nestjs-BE/server/src/auth/auth.guard.ts | 34 ++++++++++++++++++++ nestjs-BE/server/src/auth/auth.module.ts | 21 ++++++++++++ 4 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 nestjs-BE/server/src/auth/auth.controller.ts create mode 100644 nestjs-BE/server/src/auth/auth.guard.ts create mode 100644 nestjs-BE/server/src/auth/auth.module.ts diff --git a/nestjs-BE/server/src/app.module.ts b/nestjs-BE/server/src/app.module.ts index 08c391c3..2baa726c 100644 --- a/nestjs-BE/server/src/app.module.ts +++ b/nestjs-BE/server/src/app.module.ts @@ -2,10 +2,11 @@ import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { BoardGateway } from './board/board.gateway'; +import { AuthModule } from './auth/auth.module'; import { UsersModule } from './users/users.module'; @Module({ - imports: [UsersModule], + imports: [AuthModule, UsersModule], controllers: [AppController], providers: [AppService, BoardGateway], }) diff --git a/nestjs-BE/server/src/auth/auth.controller.ts b/nestjs-BE/server/src/auth/auth.controller.ts new file mode 100644 index 00000000..87599c1f --- /dev/null +++ b/nestjs-BE/server/src/auth/auth.controller.ts @@ -0,0 +1,29 @@ +import { + Body, + Controller, + HttpCode, + HttpStatus, + Post, + Request, + Get, + UseGuards, +} from '@nestjs/common'; +import { AuthService } from './auth.service'; +import { AuthGuard } from './auth.guard'; + +@Controller('auth') +export class AuthController { + constructor(private authService: AuthService) {} + + @HttpCode(HttpStatus.OK) + @Post('login') + signIn(@Body() signInDto: Record) { + return this.authService.signIn(signInDto.email, signInDto.password); + } + + @UseGuards(AuthGuard) + @Get('profile') + getProfile(@Request() req) { + return req.user; + } +} diff --git a/nestjs-BE/server/src/auth/auth.guard.ts b/nestjs-BE/server/src/auth/auth.guard.ts new file mode 100644 index 00000000..aff8a7f6 --- /dev/null +++ b/nestjs-BE/server/src/auth/auth.guard.ts @@ -0,0 +1,34 @@ +import { + CanActivate, + ExecutionContext, + Injectable, + UnauthorizedException, +} from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import { Request } from 'express'; +import { jwtConstants } from './constants'; + +@Injectable() +export class AuthGuard implements CanActivate { + constructor(private jwtService: JwtService) {} + + async canActivate(context: ExecutionContext): Promise { + const request = context.switchToHttp().getRequest(); + const token = this.extractTokenFromHeader(request); + if (!token) throw new UnauthorizedException(); + try { + const payload = await this.jwtService.verifyAsync(token, { + secret: jwtConstants.secret, + }); + request['user'] = payload; + } catch { + throw new UnauthorizedException(); + } + return true; + } + + private extractTokenFromHeader(request: Request): string | undefined { + const [type, token] = request.headers.authorization?.split(' ') ?? []; + return type === 'Bearer' ? token : undefined; + } +} diff --git a/nestjs-BE/server/src/auth/auth.module.ts b/nestjs-BE/server/src/auth/auth.module.ts new file mode 100644 index 00000000..ec79ac4b --- /dev/null +++ b/nestjs-BE/server/src/auth/auth.module.ts @@ -0,0 +1,21 @@ +import { Module } from '@nestjs/common'; +import { AuthController } from './auth.controller'; +import { AuthService } from './auth.service'; +import { UsersModule } from 'src/users/users.module'; +import { JwtModule } from '@nestjs/jwt'; +import { jwtConstants } from './constants'; + +@Module({ + imports: [ + UsersModule, + JwtModule.register({ + global: true, + secret: jwtConstants.secret, + signOptions: { expiresIn: '60s' }, + }), + ], + controllers: [AuthController], + providers: [AuthService], + exports: [AuthService], +}) +export class AuthModule {} From 58cc40a451191e67a97d644cc7f015ceb1de6d2c Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Wed, 29 Nov 2023 10:43:59 +0900 Subject: [PATCH 064/170] =?UTF-8?q?chore:=20jwt=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/package-lock.json | 114 ++++++++++++++++++++++++++++- nestjs-BE/server/package.json | 1 + 2 files changed, 111 insertions(+), 4 deletions(-) diff --git a/nestjs-BE/server/package-lock.json b/nestjs-BE/server/package-lock.json index 429c318d..f4a45e10 100644 --- a/nestjs-BE/server/package-lock.json +++ b/nestjs-BE/server/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@nestjs/common": "^10.0.0", "@nestjs/core": "^10.0.0", + "@nestjs/jwt": "^10.2.0", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.2.8", "@nestjs/websockets": "^10.2.8", @@ -1648,6 +1649,18 @@ } } }, + "node_modules/@nestjs/jwt": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-10.2.0.tgz", + "integrity": "sha512-x8cG90SURkEiLOehNaN2aRlotxT0KZESUliOPKKnjWiyJOcWurkF3w345WOX0P4MgFzUjGoZ1Sy0aZnxeihT0g==", + "dependencies": { + "@types/jsonwebtoken": "9.0.5", + "jsonwebtoken": "9.0.2" + }, + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0" + } + }, "node_modules/@nestjs/platform-express": { "version": "10.2.8", "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.2.8.tgz", @@ -2070,6 +2083,14 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz", + "integrity": "sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -3061,6 +3082,11 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3890,6 +3916,14 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -6193,6 +6227,46 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -6269,6 +6343,36 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -6281,6 +6385,11 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -7565,7 +7674,6 @@ "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -7580,7 +7688,6 @@ "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" }, @@ -7591,8 +7698,7 @@ "node_modules/semver/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 + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/send": { "version": "0.18.0", diff --git a/nestjs-BE/server/package.json b/nestjs-BE/server/package.json index 945d7725..7a83677b 100644 --- a/nestjs-BE/server/package.json +++ b/nestjs-BE/server/package.json @@ -22,6 +22,7 @@ "dependencies": { "@nestjs/common": "^10.0.0", "@nestjs/core": "^10.0.0", + "@nestjs/jwt": "^10.2.0", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.2.8", "@nestjs/websockets": "^10.2.8", From e8a04aaa3c4a37a29ca86d430154723fe57fe696 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Wed, 29 Nov 2023 14:58:00 +0900 Subject: [PATCH 065/170] =?UTF-8?q?chore:=20.gitignore=EC=97=90=20.env=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/.gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nestjs-BE/server/.gitignore b/nestjs-BE/server/.gitignore index 9751d2d5..2d2fb1cc 100644 --- a/nestjs-BE/server/.gitignore +++ b/nestjs-BE/server/.gitignore @@ -28,4 +28,7 @@ lerna-debug.log* *.sublime-workspace # IDE - VSCode -/.vscode \ No newline at end of file +/.vscode + +# Environment Variable File +.env From acc54ca3b1536f02a6d4ad5b41dd34e20e4fd54d Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Wed, 29 Nov 2023 16:58:41 +0900 Subject: [PATCH 066/170] =?UTF-8?q?feat:=20auth=20guard=20=EC=A0=84?= =?UTF-8?q?=EC=97=AD=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Public 데코레이터를 만들어서 로그인 상태가 아닐 시 접근할 수 있는 엔드포인트 지정 --- nestjs-BE/server/src/app.controller.ts | 2 ++ nestjs-BE/server/src/auth/auth.controller.ts | 5 ++--- nestjs-BE/server/src/auth/auth.guard.ts | 13 ++++++++++++- nestjs-BE/server/src/auth/auth.module.ts | 4 +++- nestjs-BE/server/src/public/public.decorator.ts | 4 ++++ 5 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 nestjs-BE/server/src/public/public.decorator.ts diff --git a/nestjs-BE/server/src/app.controller.ts b/nestjs-BE/server/src/app.controller.ts index cce879ee..45233d0b 100644 --- a/nestjs-BE/server/src/app.controller.ts +++ b/nestjs-BE/server/src/app.controller.ts @@ -1,10 +1,12 @@ import { Controller, Get } from '@nestjs/common'; import { AppService } from './app.service'; +import { Public } from './public/public.decorator'; @Controller() export class AppController { constructor(private readonly appService: AppService) {} + @Public() @Get() getHello(): string { return this.appService.getHello(); diff --git a/nestjs-BE/server/src/auth/auth.controller.ts b/nestjs-BE/server/src/auth/auth.controller.ts index 87599c1f..52385d8b 100644 --- a/nestjs-BE/server/src/auth/auth.controller.ts +++ b/nestjs-BE/server/src/auth/auth.controller.ts @@ -6,22 +6,21 @@ import { Post, Request, Get, - UseGuards, } from '@nestjs/common'; import { AuthService } from './auth.service'; -import { AuthGuard } from './auth.guard'; +import { Public } from 'src/public/public.decorator'; @Controller('auth') export class AuthController { constructor(private authService: AuthService) {} + @Public() @HttpCode(HttpStatus.OK) @Post('login') signIn(@Body() signInDto: Record) { return this.authService.signIn(signInDto.email, signInDto.password); } - @UseGuards(AuthGuard) @Get('profile') getProfile(@Request() req) { return req.user; diff --git a/nestjs-BE/server/src/auth/auth.guard.ts b/nestjs-BE/server/src/auth/auth.guard.ts index aff8a7f6..a8f8739b 100644 --- a/nestjs-BE/server/src/auth/auth.guard.ts +++ b/nestjs-BE/server/src/auth/auth.guard.ts @@ -7,12 +7,23 @@ import { import { JwtService } from '@nestjs/jwt'; import { Request } from 'express'; import { jwtConstants } from './constants'; +import { Reflector } from '@nestjs/core'; +import { IS_PUBLIC_KEY } from 'src/public/public.decorator'; @Injectable() export class AuthGuard implements CanActivate { - constructor(private jwtService: JwtService) {} + constructor( + private jwtService: JwtService, + private reflector: Reflector, + ) {} async canActivate(context: ExecutionContext): Promise { + const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [ + context.getHandler(), + context.getClass(), + ]); + if (isPublic) return true; + const request = context.switchToHttp().getRequest(); const token = this.extractTokenFromHeader(request); if (!token) throw new UnauthorizedException(); diff --git a/nestjs-BE/server/src/auth/auth.module.ts b/nestjs-BE/server/src/auth/auth.module.ts index ec79ac4b..23145aee 100644 --- a/nestjs-BE/server/src/auth/auth.module.ts +++ b/nestjs-BE/server/src/auth/auth.module.ts @@ -4,6 +4,8 @@ import { AuthService } from './auth.service'; import { UsersModule } from 'src/users/users.module'; import { JwtModule } from '@nestjs/jwt'; import { jwtConstants } from './constants'; +import { APP_GUARD } from '@nestjs/core'; +import { AuthGuard } from './auth.guard'; @Module({ imports: [ @@ -15,7 +17,7 @@ import { jwtConstants } from './constants'; }), ], controllers: [AuthController], - providers: [AuthService], + providers: [AuthService, { provide: APP_GUARD, useClass: AuthGuard }], exports: [AuthService], }) export class AuthModule {} diff --git a/nestjs-BE/server/src/public/public.decorator.ts b/nestjs-BE/server/src/public/public.decorator.ts new file mode 100644 index 00000000..b3845e12 --- /dev/null +++ b/nestjs-BE/server/src/public/public.decorator.ts @@ -0,0 +1,4 @@ +import { SetMetadata } from '@nestjs/common'; + +export const IS_PUBLIC_KEY = 'isPublic'; +export const Public = () => SetMetadata(IS_PUBLIC_KEY, true); From 059b13bf81d2b0157519c151bcb72f01af49a7d1 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Wed, 29 Nov 2023 18:23:04 +0900 Subject: [PATCH 067/170] =?UTF-8?q?fix(#118):=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=20end-point=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/cache-server/src/app.controller.ts | 7 +------ nestjs-BE/cache-server/src/app.service.ts | 6 +----- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/nestjs-BE/cache-server/src/app.controller.ts b/nestjs-BE/cache-server/src/app.controller.ts index cce879ee..c73d6d8d 100644 --- a/nestjs-BE/cache-server/src/app.controller.ts +++ b/nestjs-BE/cache-server/src/app.controller.ts @@ -1,12 +1,7 @@ -import { Controller, Get } from '@nestjs/common'; +import { Controller } from '@nestjs/common'; import { AppService } from './app.service'; @Controller() export class AppController { constructor(private readonly appService: AppService) {} - - @Get() - getHello(): string { - return this.appService.getHello(); - } } diff --git a/nestjs-BE/cache-server/src/app.service.ts b/nestjs-BE/cache-server/src/app.service.ts index 927d7cca..7263d33a 100644 --- a/nestjs-BE/cache-server/src/app.service.ts +++ b/nestjs-BE/cache-server/src/app.service.ts @@ -1,8 +1,4 @@ import { Injectable } from '@nestjs/common'; @Injectable() -export class AppService { - getHello(): string { - return 'Hello World!'; - } -} +export class AppService {} From 3d0dd4c15a8c8113144ed316d8a2ff045ad5b8c9 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Wed, 29 Nov 2023 18:24:07 +0900 Subject: [PATCH 068/170] =?UTF-8?q?fix(#118):=20remove=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EB=B9=A0=EC=A7=84=20=EB=B6=80=EB=B6=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/cache-server/src/base/base.service.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/nestjs-BE/cache-server/src/base/base.service.ts b/nestjs-BE/cache-server/src/base/base.service.ts index 8ba5272a..64169999 100644 --- a/nestjs-BE/cache-server/src/base/base.service.ts +++ b/nestjs-BE/cache-server/src/base/base.service.ts @@ -86,12 +86,22 @@ export abstract class BaseService { } async remove(key: string) { + const storeData = this.getDataFromCacheOrDB(key); + if (!storeData) return; this.cache.delete(key); const insertTemporaryData = this.temporaryDatabaseService.get( this.className, key, 'insert', ); + const updateTemporaryData = this.temporaryDatabaseService.get( + this.className, + key, + 'update', + ); + if (updateTemporaryData) { + this.temporaryDatabaseService.delete(this.className, key, 'update'); + } if (insertTemporaryData) { this.temporaryDatabaseService.delete(this.className, key, 'insert'); } else { From 08e5699d3e3e9c44a1b5b169b1ce62827077f4d0 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Wed, 29 Nov 2023 18:56:31 +0900 Subject: [PATCH 069/170] =?UTF-8?q?docs(#118):=20=EC=8A=A4=EC=9B=A8?= =?UTF-8?q?=EA=B1=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/boards/boards.controller.ts | 59 ++++++++++-- .../src/boards/dto/create-board.dto.ts | 9 +- .../src/boards/dto/update-board.dto.ts | 7 ++ nestjs-BE/cache-server/src/config/swagger.ts | 2 +- .../src/profiles/dto/create-profile.dto.ts | 16 ++++ .../src/profiles/dto/profile-space.dto.ts | 8 ++ .../src/profiles/dto/update-profile.dto.ts | 15 ++++ .../src/profiles/profiles.controller.ts | 89 ++++++++++++++++--- .../src/spaces/dto/create-space.dto.ts | 8 ++ .../src/spaces/dto/update-space.dto.ts | 15 ++++ .../src/spaces/spaces.controller.ts | 59 ++++++++++-- .../src/users/dto/create-user.dto.ts | 9 +- .../src/users/dto/update-user.dto.ts | 6 ++ .../src/users/users.controller.ts | 61 +++++++++++++ 14 files changed, 329 insertions(+), 34 deletions(-) diff --git a/nestjs-BE/cache-server/src/boards/boards.controller.ts b/nestjs-BE/cache-server/src/boards/boards.controller.ts index 8a32b04f..f9515b4d 100644 --- a/nestjs-BE/cache-server/src/boards/boards.controller.ts +++ b/nestjs-BE/cache-server/src/boards/boards.controller.ts @@ -10,28 +10,69 @@ import { import { BoardsService } from './boards.service'; import { CreateBoardDto } from './dto/create-board.dto'; import { UpdateBoardDto } from './dto/update-board.dto'; +import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; @Controller('boards') +@ApiTags('boards') export class BoardsController { constructor(private readonly boardsService: BoardsService) {} @Post() + @ApiOperation({ summary: 'Create board' }) + @ApiResponse({ + status: 201, + description: 'The board has been successfully created.', + }) + @ApiResponse({ + status: 400, + description: 'Bad Request. Invalid input data.', + }) create(@Body() createBoardDto: CreateBoardDto) { return this.boardsService.create(createBoardDto); } - @Get(':uuid') - findOne(@Param('uuid') uuid: string) { - return this.boardsService.findOne(uuid); + @Get(':board_uuid') + @ApiOperation({ summary: 'Get board by board_uuid' }) + @ApiResponse({ + status: 200, + description: 'Return the board data.', + }) + @ApiResponse({ + status: 404, + description: 'Board not found.', + }) + findOne(@Param('board_uuid') boardUuid: string) { + return this.boardsService.findOne(boardUuid); } - @Patch(':uuid') - update(@Param('uuid') uuid: string, @Body() updateBoardDto: UpdateBoardDto) { - return this.boardsService.update(uuid, updateBoardDto); + @Patch(':board_uuid') + @ApiOperation({ summary: 'Update board by board_uuid' }) + @ApiResponse({ + status: 200, + description: 'Board has been successfully updated.', + }) + @ApiResponse({ + status: 404, + description: 'Board not found.', + }) + update( + @Param('board_uuid') boardUuid: string, + @Body() updateBoardDto: UpdateBoardDto, + ) { + return this.boardsService.update(boardUuid, updateBoardDto); } - @Delete(':uuid') - remove(@Param('uuid') uuid: string) { - return this.boardsService.remove(uuid); + @Delete(':board_uuid') + @ApiOperation({ summary: 'Remove board by board_uuid' }) + @ApiResponse({ + status: 200, + description: 'Board has been successfully removed.', + }) + @ApiResponse({ + status: 404, + description: 'Board not found.', + }) + remove(@Param('board_uuid') boardUuid: string) { + return this.boardsService.remove(boardUuid); } } diff --git a/nestjs-BE/cache-server/src/boards/dto/create-board.dto.ts b/nestjs-BE/cache-server/src/boards/dto/create-board.dto.ts index 463a2541..1152a04d 100644 --- a/nestjs-BE/cache-server/src/boards/dto/create-board.dto.ts +++ b/nestjs-BE/cache-server/src/boards/dto/create-board.dto.ts @@ -1 +1,8 @@ -export class CreateBoardDto {} +import { ApiProperty } from '@nestjs/swagger'; +export class CreateBoardDto { + @ApiProperty({ + example: { key1: 'value1', key2: 'value2' }, + description: 'JSON data as an object', + }) + data: Record; +} diff --git a/nestjs-BE/cache-server/src/boards/dto/update-board.dto.ts b/nestjs-BE/cache-server/src/boards/dto/update-board.dto.ts index 67fc4bfb..3fee0c33 100644 --- a/nestjs-BE/cache-server/src/boards/dto/update-board.dto.ts +++ b/nestjs-BE/cache-server/src/boards/dto/update-board.dto.ts @@ -1,6 +1,13 @@ import { PartialType } from '@nestjs/swagger'; import { CreateBoardDto } from './create-board.dto'; +import { ApiProperty } from '@nestjs/swagger'; export class UpdateBoardDto extends PartialType(CreateBoardDto) { uuid?: string; + + @ApiProperty({ + example: { key1: 'value1', key2: 'value2' }, + description: 'JSON data as an object for updating the board', + }) + data: Record; } diff --git a/nestjs-BE/cache-server/src/config/swagger.ts b/nestjs-BE/cache-server/src/config/swagger.ts index a8e44ab0..92b38238 100644 --- a/nestjs-BE/cache-server/src/config/swagger.ts +++ b/nestjs-BE/cache-server/src/config/swagger.ts @@ -1,6 +1,6 @@ import { DocumentBuilder } from '@nestjs/swagger'; export const swaggerConfig = new DocumentBuilder() - .setTitle('mind-sync db-api') + .setTitle('mind-sync cache-server-api') .setDescription('API description') .setVersion('1.0') .build(); diff --git a/nestjs-BE/cache-server/src/profiles/dto/create-profile.dto.ts b/nestjs-BE/cache-server/src/profiles/dto/create-profile.dto.ts index a3222cff..a9735b92 100644 --- a/nestjs-BE/cache-server/src/profiles/dto/create-profile.dto.ts +++ b/nestjs-BE/cache-server/src/profiles/dto/create-profile.dto.ts @@ -1,5 +1,21 @@ +import { ApiProperty } from '@nestjs/swagger'; + export class CreateProfileDto { + @ApiProperty({ + example: 'user-uuid-123', + description: 'User UUID for the profile', + }) user_id: string; + + @ApiProperty({ + example: 'profile-image.png', + description: 'Image URL for the profile', + }) image: string; + + @ApiProperty({ + example: 'Sample nickname', + description: 'Nickname for the profile', + }) nickname: string; } diff --git a/nestjs-BE/cache-server/src/profiles/dto/profile-space.dto.ts b/nestjs-BE/cache-server/src/profiles/dto/profile-space.dto.ts index 4c93c418..19fad8d4 100644 --- a/nestjs-BE/cache-server/src/profiles/dto/profile-space.dto.ts +++ b/nestjs-BE/cache-server/src/profiles/dto/profile-space.dto.ts @@ -1,4 +1,12 @@ +import { ApiProperty } from '@nestjs/swagger'; + export class ProfileSpaceDto { + @ApiProperty({ + example: 'profile-uuid-123', + description: 'UUID of the profile', + }) profile_uuid: string; + + @ApiProperty({ example: 'space-uuid-456', description: 'UUID of the space' }) space_uuid: string; } diff --git a/nestjs-BE/cache-server/src/profiles/dto/update-profile.dto.ts b/nestjs-BE/cache-server/src/profiles/dto/update-profile.dto.ts index a715da8d..1511aaba 100644 --- a/nestjs-BE/cache-server/src/profiles/dto/update-profile.dto.ts +++ b/nestjs-BE/cache-server/src/profiles/dto/update-profile.dto.ts @@ -1,6 +1,21 @@ import { PartialType } from '@nestjs/mapped-types'; import { CreateProfileDto } from './create-profile.dto'; +import { ApiProperty } from '@nestjs/swagger'; export class UpdateProfileDto extends PartialType(CreateProfileDto) { + @ApiProperty({ + example: 'new nickname', + description: 'Updated nickname of the profile', + required: false, + }) + nickname?: string; + + @ApiProperty({ + example: 'new image.png', + description: 'Updated image URL for the profile', + required: false, + }) + image?: string; + uuid?: string; } diff --git a/nestjs-BE/cache-server/src/profiles/profiles.controller.ts b/nestjs-BE/cache-server/src/profiles/profiles.controller.ts index c0516f74..5d817524 100644 --- a/nestjs-BE/cache-server/src/profiles/profiles.controller.ts +++ b/nestjs-BE/cache-server/src/profiles/profiles.controller.ts @@ -11,40 +11,96 @@ import { ProfilesService } from './profiles.service'; import { CreateProfileDto } from './dto/create-profile.dto'; import { UpdateProfileDto } from './dto/update-profile.dto'; import { ProfileSpaceDto } from './dto/profile-space.dto'; +import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; @Controller('profiles') +@ApiTags('profiles') export class ProfilesController { constructor(private readonly profilesService: ProfilesService) {} @Post() + @ApiOperation({ summary: 'Create profile' }) + @ApiResponse({ + status: 201, + description: 'The profile has been successfully created.', + }) + @ApiResponse({ + status: 400, + description: 'Bad Request. Invalid input data.', + }) create(@Body() createProfileDto: CreateProfileDto) { return this.profilesService.create(createProfileDto); } - @Get(':uuid') - findOne(@Param('uuid') uuid: string) { - return this.profilesService.findOne(uuid); + @Get(':profile_uuid') + @ApiOperation({ summary: 'Get profile by profile_uuid' }) + @ApiResponse({ + status: 200, + description: 'Return the profile data.', + }) + @ApiResponse({ + status: 404, + description: 'Profile not found.', + }) + findOne(@Param('profile_uuid') profileUuid: string) { + return this.profilesService.findOne(profileUuid); } - @Patch(':uuid') + @Patch(':profile_uuid') + @ApiOperation({ summary: 'Update profile by profile_uuid' }) + @ApiResponse({ + status: 200, + description: 'Profile has been successfully updated.', + }) + @ApiResponse({ + status: 404, + description: 'Profile not found.', + }) update( - @Param('uuid') uuid: string, + @Param('profile_uuid') profileUuid: string, @Body() updateProfileDto: UpdateProfileDto, ) { - return this.profilesService.update(uuid, updateProfileDto); + return this.profilesService.update(profileUuid, updateProfileDto); } - @Delete(':uuid') - remove(@Param('uuid') uuid: string) { - return this.profilesService.remove(uuid); + @Delete(':profile_uuid') + @ApiOperation({ summary: 'Remove profile by profile_uuid' }) + @ApiResponse({ + status: 200, + description: 'Profile has been successfully removed.', + }) + @ApiResponse({ + status: 404, + description: 'Profile not found.', + }) + remove(@Param('profile_uuid') profileUuid: string) { + return this.profilesService.remove(profileUuid); } @Post('/spaces') + @ApiOperation({ summary: 'Join space' }) + @ApiResponse({ + status: 201, + description: 'Joined the space successfully.', + }) + @ApiResponse({ + status: 400, + description: 'Bad Request. Invalid input data.', + }) joinSpace(@Body() profileSpaceDto: ProfileSpaceDto) { return this.profilesService.joinSpace(profileSpaceDto); } @Delete(':profile_uuid/spaces/:space_uuid') + @ApiOperation({ summary: 'Leave space' }) + @ApiResponse({ + status: 200, + description: 'Left the space successfully.', + }) + @ApiResponse({ + status: 404, + description: 'Profile or space not found.', + }) leaveSpace( @Param('profile_uuid') profileUuid: string, @Param('space_uuid') spaceUuid: string, @@ -52,8 +108,17 @@ export class ProfilesController { return this.profilesService.leaveSpace(profileUuid, spaceUuid); } - @Get('users/:uuid') - findUsers(@Param('uuid') uuid: string) { - return this.profilesService.findUsers(uuid); + @Get('users/:space_uuid') + @ApiOperation({ summary: 'Find users in a space' }) + @ApiResponse({ + status: 200, + description: 'Return the list of users in the space.', + }) + @ApiResponse({ + status: 404, + description: 'Space not found.', + }) + findUsers(@Param('space_uuid') spaceUuid: string) { + return this.profilesService.findUsers(spaceUuid); } } diff --git a/nestjs-BE/cache-server/src/spaces/dto/create-space.dto.ts b/nestjs-BE/cache-server/src/spaces/dto/create-space.dto.ts index db6d9a92..209bc3b8 100644 --- a/nestjs-BE/cache-server/src/spaces/dto/create-space.dto.ts +++ b/nestjs-BE/cache-server/src/spaces/dto/create-space.dto.ts @@ -1,4 +1,12 @@ +import { ApiProperty } from '@nestjs/swagger'; + export class CreateSpaceDto { + @ApiProperty({ example: 'Sample Space', description: 'Name of the space' }) name: string; + + @ApiProperty({ + example: 'space-icon.png', + description: 'Profile icon for the space', + }) icon: string; } diff --git a/nestjs-BE/cache-server/src/spaces/dto/update-space.dto.ts b/nestjs-BE/cache-server/src/spaces/dto/update-space.dto.ts index a1e7bb48..017ec463 100644 --- a/nestjs-BE/cache-server/src/spaces/dto/update-space.dto.ts +++ b/nestjs-BE/cache-server/src/spaces/dto/update-space.dto.ts @@ -1,6 +1,21 @@ import { PartialType } from '@nestjs/mapped-types'; import { CreateSpaceDto } from './create-space.dto'; +import { ApiProperty } from '@nestjs/swagger'; export class UpdateSpaceDto extends PartialType(CreateSpaceDto) { + @ApiProperty({ + example: 'new space', + description: 'Updated space name', + required: false, + }) + name?: string; + + @ApiProperty({ + example: 'new image', + description: 'Updated space icon', + required: false, + }) + icon?: string; + uuid?: string; } diff --git a/nestjs-BE/cache-server/src/spaces/spaces.controller.ts b/nestjs-BE/cache-server/src/spaces/spaces.controller.ts index e4440b3a..368809d0 100644 --- a/nestjs-BE/cache-server/src/spaces/spaces.controller.ts +++ b/nestjs-BE/cache-server/src/spaces/spaces.controller.ts @@ -10,28 +10,69 @@ import { import { SpacesService } from './spaces.service'; import { CreateSpaceDto } from './dto/create-space.dto'; import { UpdateSpaceDto } from './dto/update-space.dto'; +import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; @Controller('spaces') +@ApiTags('spaces') export class SpacesController { constructor(private readonly spacesService: SpacesService) {} @Post() + @ApiOperation({ summary: 'Create space' }) + @ApiResponse({ + status: 201, + description: 'The space has been successfully created.', + }) create(@Body() createSpaceDto: CreateSpaceDto) { return this.spacesService.create(createSpaceDto); } - @Get(':uuid') - findOne(@Param('uuid') uuid: string) { - return this.spacesService.findOne(uuid); + @Get(':space_uuid') + @ApiOperation({ summary: 'Get space by space_uuid' }) + @ApiResponse({ + status: 200, + description: 'Return the space data.', + }) + @ApiResponse({ + status: 404, + description: 'Space not found.', + }) + findOne(@Param('space_uuid') spaceUuid: string) { + return this.spacesService.findOne(spaceUuid); } - @Patch(':uuid') - update(@Param('uuid') uuid: string, @Body() updateSpaceDto: UpdateSpaceDto) { - return this.spacesService.update(uuid, updateSpaceDto); + @Patch(':space_uuid') + @ApiOperation({ summary: 'Update space by space_uuid' }) + @ApiResponse({ + status: 200, + description: 'Space has been successfully updated.', + }) + @ApiResponse({ + status: 400, + description: 'Bad Request. Invalid input data.', + }) + @ApiResponse({ + status: 404, + description: 'Space not found.', + }) + update( + @Param('space_uuid') spaceUuid: string, + @Body() updateSpaceDto: UpdateSpaceDto, + ) { + return this.spacesService.update(spaceUuid, updateSpaceDto); } - @Delete(':uuid') - remove(@Param('uuid') uuid: string) { - return this.spacesService.remove(uuid); + @Delete(':space_uuid') + @ApiOperation({ summary: 'Remove space by space_uuid' }) + @ApiResponse({ + status: 200, + description: 'Space has been successfully removed.', + }) + @ApiResponse({ + status: 404, + description: 'Space not found.', + }) + remove(@Param('space_uuid') spaceUuid: string) { + return this.spacesService.remove(spaceUuid); } } diff --git a/nestjs-BE/cache-server/src/users/dto/create-user.dto.ts b/nestjs-BE/cache-server/src/users/dto/create-user.dto.ts index 16baaf2d..f8ef099c 100644 --- a/nestjs-BE/cache-server/src/users/dto/create-user.dto.ts +++ b/nestjs-BE/cache-server/src/users/dto/create-user.dto.ts @@ -1,4 +1,9 @@ +import { ApiProperty } from '@nestjs/swagger'; + export class CreateUserDto { - email: string; - password: string; + @ApiProperty({ example: 'test@gmail.com', description: 'email adress' }) + readonly email: string; + + @ApiProperty({ example: 'qwerasdf@!123', description: 'password' }) + readonly password: string; } diff --git a/nestjs-BE/cache-server/src/users/dto/update-user.dto.ts b/nestjs-BE/cache-server/src/users/dto/update-user.dto.ts index 361e7ba5..fc59078e 100644 --- a/nestjs-BE/cache-server/src/users/dto/update-user.dto.ts +++ b/nestjs-BE/cache-server/src/users/dto/update-user.dto.ts @@ -1,6 +1,12 @@ import { PartialType } from '@nestjs/mapped-types'; import { CreateUserDto } from './create-user.dto'; +import { ApiProperty } from '@nestjs/swagger'; export class UpdateUserDto extends PartialType(CreateUserDto) { + @ApiProperty({ + example: 'newpassword', + description: 'The new password of the user', + }) + password?: string; uuid?: string; } diff --git a/nestjs-BE/cache-server/src/users/users.controller.ts b/nestjs-BE/cache-server/src/users/users.controller.ts index 3080e688..4a188ec0 100644 --- a/nestjs-BE/cache-server/src/users/users.controller.ts +++ b/nestjs-BE/cache-server/src/users/users.controller.ts @@ -10,37 +10,98 @@ import { import { UsersService } from './users.service'; import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; +import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; @Controller('users') +@ApiTags('users') export class UsersController { constructor(private readonly usersService: UsersService) {} @Post() + @ApiOperation({ summary: 'Create user' }) + @ApiResponse({ + status: 201, + description: 'The user has been successfully created.', + }) + @ApiResponse({ + status: 409, + description: 'User with the provided email already exists.', + }) + @ApiResponse({ + status: 400, + description: 'Bad Request. Invalid input data.', + }) create(@Body() createUserDto: CreateUserDto) { return this.usersService.create(createUserDto); } @Get(':email') + @ApiOperation({ summary: 'Get user' }) + @ApiResponse({ + status: 200, + description: 'Return the user data.', + }) + @ApiResponse({ + status: 404, + description: 'User not found.', + }) + @ApiOperation({ summary: 'Get user' }) findOne(@Param('email') email: string) { return this.usersService.findOne(email); } @Patch(':email') + @ApiOperation({ summary: 'Update user' }) + @ApiResponse({ + status: 200, + description: 'User has been successfully updated.', + }) + @ApiResponse({ + status: 404, + description: 'User not found.', + }) update(@Param('email') email: string, @Body() updateUserDto: UpdateUserDto) { return this.usersService.update(email, updateUserDto); } @Delete(':email') + @ApiOperation({ summary: 'Remove user' }) + @ApiResponse({ + status: 200, + description: 'User has been successfully removed.', + }) + @ApiResponse({ + status: 404, + description: 'User not found.', + }) remove(@Param('email') email: string) { return this.usersService.remove(email); } @Get('profiles/:email') + @ApiOperation({ summary: 'Find profiles for a user' }) + @ApiResponse({ + status: 200, + description: 'Return the list of profiles for the user.', + }) + @ApiResponse({ + status: 404, + description: 'User not found.', + }) findProfiles(@Param('email') email: string) { return this.usersService.findProfiles(email); } @Get('rooms/:email') + @ApiOperation({ summary: 'Find rooms for a user' }) + @ApiResponse({ + status: 200, + description: 'Return the list of rooms for the user.', + }) + @ApiResponse({ + status: 404, + description: 'User not found.', + }) findRooms(@Param('email') email: string) { return this.usersService.findRooms(email); } From 661663e17a0dc7dae5715ef547c15400d4714b52 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 30 Nov 2023 13:58:55 +0900 Subject: [PATCH 070/170] =?UTF-8?q?rename(#99):=20public=20=EB=8D=B0?= =?UTF-8?q?=EC=BD=94=EB=A0=88=EC=9D=B4=ED=84=B0=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/app.controller.ts | 2 +- nestjs-BE/server/src/auth/auth.controller.ts | 2 +- nestjs-BE/server/src/{public => auth}/public.decorator.ts | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename nestjs-BE/server/src/{public => auth}/public.decorator.ts (100%) diff --git a/nestjs-BE/server/src/app.controller.ts b/nestjs-BE/server/src/app.controller.ts index 45233d0b..fac17b02 100644 --- a/nestjs-BE/server/src/app.controller.ts +++ b/nestjs-BE/server/src/app.controller.ts @@ -1,6 +1,6 @@ import { Controller, Get } from '@nestjs/common'; import { AppService } from './app.service'; -import { Public } from './public/public.decorator'; +import { Public } from './auth/public.decorator'; @Controller() export class AppController { diff --git a/nestjs-BE/server/src/auth/auth.controller.ts b/nestjs-BE/server/src/auth/auth.controller.ts index 52385d8b..65773d3f 100644 --- a/nestjs-BE/server/src/auth/auth.controller.ts +++ b/nestjs-BE/server/src/auth/auth.controller.ts @@ -8,7 +8,7 @@ import { Get, } from '@nestjs/common'; import { AuthService } from './auth.service'; -import { Public } from 'src/public/public.decorator'; +import { Public } from './public.decorator'; @Controller('auth') export class AuthController { diff --git a/nestjs-BE/server/src/public/public.decorator.ts b/nestjs-BE/server/src/auth/public.decorator.ts similarity index 100% rename from nestjs-BE/server/src/public/public.decorator.ts rename to nestjs-BE/server/src/auth/public.decorator.ts From f253e732ec75e81a734a5c9c74d11629faae3726 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 30 Nov 2023 14:08:50 +0900 Subject: [PATCH 071/170] =?UTF-8?q?feat(#73,=20#99):=20passport=20?= =?UTF-8?q?=ED=8C=A8=ED=82=A4=EC=A7=80=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/package-lock.json | 106 ++++++++++++++++++ nestjs-BE/server/package.json | 6 + nestjs-BE/server/src/auth/auth.controller.ts | 19 ++-- nestjs-BE/server/src/auth/auth.guard.ts | 45 -------- nestjs-BE/server/src/auth/auth.module.ts | 14 ++- nestjs-BE/server/src/auth/auth.service.ts | 9 +- nestjs-BE/server/src/auth/jwt-auth.guard.ts | 28 +++++ nestjs-BE/server/src/auth/jwt.strategy.ts | 19 ++++ nestjs-BE/server/src/auth/local-auth.guard.ts | 5 + nestjs-BE/server/src/auth/local.strategy.ts | 17 +++ 10 files changed, 205 insertions(+), 63 deletions(-) delete mode 100644 nestjs-BE/server/src/auth/auth.guard.ts create mode 100644 nestjs-BE/server/src/auth/jwt-auth.guard.ts create mode 100644 nestjs-BE/server/src/auth/jwt.strategy.ts create mode 100644 nestjs-BE/server/src/auth/local-auth.guard.ts create mode 100644 nestjs-BE/server/src/auth/local.strategy.ts diff --git a/nestjs-BE/server/package-lock.json b/nestjs-BE/server/package-lock.json index f4a45e10..81caf5e0 100644 --- a/nestjs-BE/server/package-lock.json +++ b/nestjs-BE/server/package-lock.json @@ -12,10 +12,14 @@ "@nestjs/common": "^10.0.0", "@nestjs/core": "^10.0.0", "@nestjs/jwt": "^10.2.0", + "@nestjs/passport": "^10.0.2", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.2.8", "@nestjs/websockets": "^10.2.8", "dotenv": "^16.3.1", + "passport": "^0.6.0", + "passport-jwt": "^4.0.1", + "passport-local": "^1.0.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1" }, @@ -26,6 +30,8 @@ "@types/express": "^4.17.17", "@types/jest": "^29.5.2", "@types/node": "^20.3.1", + "@types/passport-jwt": "^3.0.13", + "@types/passport-local": "^1.0.38", "@types/supertest": "^2.0.12", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", @@ -1661,6 +1667,15 @@ "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0" } }, + "node_modules/@nestjs/passport": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-10.0.2.tgz", + "integrity": "sha512-od31vfB2z3y05IDB5dWSbCGE2+pAf2k2WCBinNuTTOxN0O0+wtO1L3kawj/aCW3YR9uxsTOVbTDwtwgpNNsnjQ==", + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "passport": "^0.4.0 || ^0.5.0 || ^0.6.0" + } + }, "node_modules/@nestjs/platform-express": { "version": "10.2.8", "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.2.8.tgz", @@ -2105,6 +2120,47 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/passport": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.16.tgz", + "integrity": "sha512-FD0qD5hbPWQzaM0wHUnJ/T0BBCJBxCeemtnCwc/ThhTg3x9jfrAcRUmj5Dopza+MfFS9acTe3wk7rcVnRIp/0A==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/passport-jwt": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@types/passport-jwt/-/passport-jwt-3.0.13.tgz", + "integrity": "sha512-fjHaC6Bv8EpMMqzTnHP32SXlZGaNfBPC/Po5dmRGYi2Ky7ljXPbGnOy+SxZqa6iZvFgVhoJ1915Re3m93zmcfA==", + "dev": true, + "dependencies": { + "@types/express": "*", + "@types/jsonwebtoken": "*", + "@types/passport-strategy": "*" + } + }, + "node_modules/@types/passport-local": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/passport-local/-/passport-local-1.0.38.tgz", + "integrity": "sha512-nsrW4A963lYE7lNTv9cr5WmiUD1ibYJvWrpE13oxApFsRt77b0RdtZvKbCdNIY4v/QZ6TRQWaDDEwV1kCTmcXg==", + "dev": true, + "dependencies": { + "@types/express": "*", + "@types/passport": "*", + "@types/passport-strategy": "*" + } + }, + "node_modules/@types/passport-strategy": { + "version": "0.2.38", + "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.38.tgz", + "integrity": "sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==", + "dev": true, + "dependencies": { + "@types/express": "*", + "@types/passport": "*" + } + }, "node_modules/@types/qs": { "version": "6.9.10", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", @@ -6943,6 +6999,51 @@ "node": ">= 0.8" } }, + "node_modules/passport": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz", + "integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "dependencies": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", + "integrity": "sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==", + "dependencies": { + "passport-strategy": "1.x.x" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -7015,6 +7116,11 @@ "node": ">=8" } }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", diff --git a/nestjs-BE/server/package.json b/nestjs-BE/server/package.json index 7a83677b..9b2a711c 100644 --- a/nestjs-BE/server/package.json +++ b/nestjs-BE/server/package.json @@ -23,10 +23,14 @@ "@nestjs/common": "^10.0.0", "@nestjs/core": "^10.0.0", "@nestjs/jwt": "^10.2.0", + "@nestjs/passport": "^10.0.2", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.2.8", "@nestjs/websockets": "^10.2.8", "dotenv": "^16.3.1", + "passport": "^0.6.0", + "passport-jwt": "^4.0.1", + "passport-local": "^1.0.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1" }, @@ -37,6 +41,8 @@ "@types/express": "^4.17.17", "@types/jest": "^29.5.2", "@types/node": "^20.3.1", + "@types/passport-jwt": "^3.0.13", + "@types/passport-local": "^1.0.38", "@types/supertest": "^2.0.12", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", diff --git a/nestjs-BE/server/src/auth/auth.controller.ts b/nestjs-BE/server/src/auth/auth.controller.ts index 65773d3f..238b65ef 100644 --- a/nestjs-BE/server/src/auth/auth.controller.ts +++ b/nestjs-BE/server/src/auth/auth.controller.ts @@ -1,13 +1,7 @@ -import { - Body, - Controller, - HttpCode, - HttpStatus, - Post, - Request, - Get, -} from '@nestjs/common'; +import { Controller, Post, Request, UseGuards, Get } from '@nestjs/common'; +import { LocalAuthGuard } from './local-auth.guard'; import { AuthService } from './auth.service'; +import { JwtAuthGuard } from './jwt-auth.guard'; import { Public } from './public.decorator'; @Controller('auth') @@ -15,12 +9,13 @@ export class AuthController { constructor(private authService: AuthService) {} @Public() - @HttpCode(HttpStatus.OK) + @UseGuards(LocalAuthGuard) @Post('login') - signIn(@Body() signInDto: Record) { - return this.authService.signIn(signInDto.email, signInDto.password); + async login(@Request() req) { + return this.authService.login(req.user); } + @UseGuards(JwtAuthGuard) @Get('profile') getProfile(@Request() req) { return req.user; diff --git a/nestjs-BE/server/src/auth/auth.guard.ts b/nestjs-BE/server/src/auth/auth.guard.ts deleted file mode 100644 index a8f8739b..00000000 --- a/nestjs-BE/server/src/auth/auth.guard.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { - CanActivate, - ExecutionContext, - Injectable, - UnauthorizedException, -} from '@nestjs/common'; -import { JwtService } from '@nestjs/jwt'; -import { Request } from 'express'; -import { jwtConstants } from './constants'; -import { Reflector } from '@nestjs/core'; -import { IS_PUBLIC_KEY } from 'src/public/public.decorator'; - -@Injectable() -export class AuthGuard implements CanActivate { - constructor( - private jwtService: JwtService, - private reflector: Reflector, - ) {} - - async canActivate(context: ExecutionContext): Promise { - const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [ - context.getHandler(), - context.getClass(), - ]); - if (isPublic) return true; - - const request = context.switchToHttp().getRequest(); - const token = this.extractTokenFromHeader(request); - if (!token) throw new UnauthorizedException(); - try { - const payload = await this.jwtService.verifyAsync(token, { - secret: jwtConstants.secret, - }); - request['user'] = payload; - } catch { - throw new UnauthorizedException(); - } - return true; - } - - private extractTokenFromHeader(request: Request): string | undefined { - const [type, token] = request.headers.authorization?.split(' ') ?? []; - return type === 'Bearer' ? token : undefined; - } -} diff --git a/nestjs-BE/server/src/auth/auth.module.ts b/nestjs-BE/server/src/auth/auth.module.ts index 23145aee..ed14f3d7 100644 --- a/nestjs-BE/server/src/auth/auth.module.ts +++ b/nestjs-BE/server/src/auth/auth.module.ts @@ -2,22 +2,30 @@ import { Module } from '@nestjs/common'; import { AuthController } from './auth.controller'; import { AuthService } from './auth.service'; import { UsersModule } from 'src/users/users.module'; +import { PassportModule } from '@nestjs/passport'; +import { LocalStrategy } from './local.strategy'; import { JwtModule } from '@nestjs/jwt'; import { jwtConstants } from './constants'; +import { JwtStrategy } from './jwt.strategy'; import { APP_GUARD } from '@nestjs/core'; -import { AuthGuard } from './auth.guard'; +import { JwtAuthGuard } from './jwt-auth.guard'; @Module({ imports: [ UsersModule, + PassportModule, JwtModule.register({ - global: true, secret: jwtConstants.secret, signOptions: { expiresIn: '60s' }, }), ], controllers: [AuthController], - providers: [AuthService, { provide: APP_GUARD, useClass: AuthGuard }], + providers: [ + AuthService, + LocalStrategy, + JwtStrategy, + { provide: APP_GUARD, useClass: JwtAuthGuard }, + ], exports: [AuthService], }) export class AuthModule {} diff --git a/nestjs-BE/server/src/auth/auth.service.ts b/nestjs-BE/server/src/auth/auth.service.ts index fd048a69..9d43ae1d 100644 --- a/nestjs-BE/server/src/auth/auth.service.ts +++ b/nestjs-BE/server/src/auth/auth.service.ts @@ -1,4 +1,4 @@ -import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { UsersService } from 'src/users/users.service'; @@ -9,10 +9,13 @@ export class AuthService { private jwtService: JwtService, ) {} - async signIn(email: string, password: string): Promise { + async validateUser(email: string, password: string): Promise { const user = await this.usersService.findOne(email); - if (user?.password !== password) throw new UnauthorizedException(); + if (user?.password !== password) return null; + return { uuid: user.uuid, email: user.email }; + } + async login(user: any) { const payload = { sub: user.uuid, email: user.email }; return { access_token: await this.jwtService.signAsync(payload) }; } diff --git a/nestjs-BE/server/src/auth/jwt-auth.guard.ts b/nestjs-BE/server/src/auth/jwt-auth.guard.ts new file mode 100644 index 00000000..b94a54e9 --- /dev/null +++ b/nestjs-BE/server/src/auth/jwt-auth.guard.ts @@ -0,0 +1,28 @@ +import { + Injectable, + ExecutionContext, + UnauthorizedException, +} from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; +import { AuthGuard } from '@nestjs/passport'; +import { IS_PUBLIC_KEY } from './public.decorator'; + +@Injectable() +export class JwtAuthGuard extends AuthGuard('jwt') { + constructor(private reflector: Reflector) { + super(); + } + canActivate(context: ExecutionContext) { + const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [ + context.getHandler(), + context.getClass(), + ]); + if (isPublic) return true; + return super.canActivate(context); + } + + handleRequest(err, user) { + if (err || !user) throw err || new UnauthorizedException(); + return user; + } +} diff --git a/nestjs-BE/server/src/auth/jwt.strategy.ts b/nestjs-BE/server/src/auth/jwt.strategy.ts new file mode 100644 index 00000000..a929fb88 --- /dev/null +++ b/nestjs-BE/server/src/auth/jwt.strategy.ts @@ -0,0 +1,19 @@ +import { Injectable } from '@nestjs/common'; +import { ExtractJwt, Strategy } from 'passport-jwt'; +import { PassportStrategy } from '@nestjs/passport'; +import { jwtConstants } from './constants'; + +@Injectable() +export class JwtStrategy extends PassportStrategy(Strategy) { + constructor() { + super({ + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + ignoreExpiration: false, + secretOrKey: jwtConstants.secret, + }); + } + + async validate(payload: any) { + return { uuid: payload.sub, email: payload.email }; + } +} diff --git a/nestjs-BE/server/src/auth/local-auth.guard.ts b/nestjs-BE/server/src/auth/local-auth.guard.ts new file mode 100644 index 00000000..ccf962b6 --- /dev/null +++ b/nestjs-BE/server/src/auth/local-auth.guard.ts @@ -0,0 +1,5 @@ +import { Injectable } from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; + +@Injectable() +export class LocalAuthGuard extends AuthGuard('local') {} diff --git a/nestjs-BE/server/src/auth/local.strategy.ts b/nestjs-BE/server/src/auth/local.strategy.ts new file mode 100644 index 00000000..4f30a6c6 --- /dev/null +++ b/nestjs-BE/server/src/auth/local.strategy.ts @@ -0,0 +1,17 @@ +import { Strategy } from 'passport-local'; +import { PassportStrategy } from '@nestjs/passport'; +import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { AuthService } from './auth.service'; + +@Injectable() +export class LocalStrategy extends PassportStrategy(Strategy) { + 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(); + return user; + } +} From 43c173181e1c663e4b386870d8b5ffc225d14e28 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 30 Nov 2023 19:30:55 +0900 Subject: [PATCH 072/170] =?UTF-8?q?setting(#125):=20=EC=BA=90=EC=8B=9C?= =?UTF-8?q?=EC=84=9C=EB=B2=84=20=EB=B0=B0=ED=8F=AC=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/BE-cache-deploy.yml | 46 +++++++++++++++++++++++++++ nestjs-BE/cache-server/.dockerignore | 8 +++++ nestjs-BE/cache-server/Dockerfile | 19 +++++++++++ 3 files changed, 73 insertions(+) create mode 100644 .github/workflows/BE-cache-deploy.yml create mode 100644 nestjs-BE/cache-server/.dockerignore create mode 100644 nestjs-BE/cache-server/Dockerfile diff --git a/.github/workflows/BE-cache-deploy.yml b/.github/workflows/BE-cache-deploy.yml new file mode 100644 index 00000000..55454c92 --- /dev/null +++ b/.github/workflows/BE-cache-deploy.yml @@ -0,0 +1,46 @@ +name: Cache server build and deploy + +on: + push: + branches: + - "BE-develop" + paths: + - "nestjs-BE/cache-server/*" + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: BE-develop + sparse-checkout: nestjs-BE + - name: Login to github Packages + run: echo ${{ secrets.PACKAGE_ACCESS_TOKEN }} | docker login ghcr.io -u ${{ secrets.PACKAGE_USERNAME }} --password-stdin + - name: Build and push Docker image + run: | + docker build -t ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync-cache-server ./nestjs-BE/cache-server + docker push ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync-cache-server:latest + + deploy: + needs: build + runs-on: ubuntu-latest + steps: + - name: Pull Docker image + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.REMOTE_HOST }} + port: ${{ secrets.REMOTE_PORT }} + username: ${{ secrets.REMOTE_USER }} + key: ${{ secrets.REMOTE_SSH_KEY }} + script: | + eval "$(ssh-agent -s)" + echo "${{ secrets.PRIVATE_SSH_KEY }}" | ssh-add - + ssh -A ${{ secrets.PRIVATE_USER }}@${{ secrets.PRIVATE_HOST }} << ENDSSH + echo "${{ secrets.PACKAGE_ACCESS_TOKEN }}" | docker login ghcr.io -u "${{ secrets.PACKAGE_USERNAME }}" --password-stdin + docker pull ghcr.io/"${{ secrets.PACKAGE_USERNAME }}"/mindsync-cache-server + docker stop mindsync_cache_server || true + docker rm mindsync_cache_server || true + docker run -d --name mindsync_cache_server -p "${{ secrets.SERVER_PORT }}":"${{ secrets.CONTAINER_PORT }}" -e MYSQL_DATABASE_URL="${{ secrets.MYSQL_DATABASE_URL }}" -e MONGODB_DATABASE_URL="${{ secrets.MONGODB_DATABASE_URL }}" ghcr.io/"${{ secrets.PACKAGE_USERNAME }}"/mindsync-cache-server + docker image prune -af + ENDSSH diff --git a/nestjs-BE/cache-server/.dockerignore b/nestjs-BE/cache-server/.dockerignore new file mode 100644 index 00000000..fe33330d --- /dev/null +++ b/nestjs-BE/cache-server/.dockerignore @@ -0,0 +1,8 @@ +README.md +/test +.eslintrc.js +.gitignore +.prettierrc +nest-cli.json + +\*.spec.ts diff --git a/nestjs-BE/cache-server/Dockerfile b/nestjs-BE/cache-server/Dockerfile new file mode 100644 index 00000000..9eb851c7 --- /dev/null +++ b/nestjs-BE/cache-server/Dockerfile @@ -0,0 +1,19 @@ +FROM node:20.4.0-alpine + +WORKDIR /server + +COPY package.json package-lock.json ./ + +RUN npm ci + +COPY ./ ./ + +RUN npx prisma generate --schema=./prisma/mysql.schema.prisma + +RUN npx prisma generate --schema=./prisma/mongodb.schema.prisma + +RUN mkdir operations + +EXPOSE 3000 + +CMD ["npm", "start"] From b5100dd3249a6138e83196159c65387902b0ce13 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Sat, 2 Dec 2023 19:24:49 +0900 Subject: [PATCH 073/170] =?UTF-8?q?fix(#105):=20passport-local=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/package-lock.json | 24 ------------------- nestjs-BE/server/package.json | 2 -- nestjs-BE/server/src/auth/auth.controller.ts | 8 ------- nestjs-BE/server/src/auth/auth.module.ts | 2 -- nestjs-BE/server/src/auth/local-auth.guard.ts | 5 ---- nestjs-BE/server/src/auth/local.strategy.ts | 17 ------------- 6 files changed, 58 deletions(-) delete mode 100644 nestjs-BE/server/src/auth/local-auth.guard.ts delete mode 100644 nestjs-BE/server/src/auth/local.strategy.ts diff --git a/nestjs-BE/server/package-lock.json b/nestjs-BE/server/package-lock.json index 81caf5e0..b92ce154 100644 --- a/nestjs-BE/server/package-lock.json +++ b/nestjs-BE/server/package-lock.json @@ -19,7 +19,6 @@ "dotenv": "^16.3.1", "passport": "^0.6.0", "passport-jwt": "^4.0.1", - "passport-local": "^1.0.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1" }, @@ -31,7 +30,6 @@ "@types/jest": "^29.5.2", "@types/node": "^20.3.1", "@types/passport-jwt": "^3.0.13", - "@types/passport-local": "^1.0.38", "@types/supertest": "^2.0.12", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", @@ -2140,17 +2138,6 @@ "@types/passport-strategy": "*" } }, - "node_modules/@types/passport-local": { - "version": "1.0.38", - "resolved": "https://registry.npmjs.org/@types/passport-local/-/passport-local-1.0.38.tgz", - "integrity": "sha512-nsrW4A963lYE7lNTv9cr5WmiUD1ibYJvWrpE13oxApFsRt77b0RdtZvKbCdNIY4v/QZ6TRQWaDDEwV1kCTmcXg==", - "dev": true, - "dependencies": { - "@types/express": "*", - "@types/passport": "*", - "@types/passport-strategy": "*" - } - }, "node_modules/@types/passport-strategy": { "version": "0.2.38", "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.38.tgz", @@ -7025,17 +7012,6 @@ "passport-strategy": "^1.0.0" } }, - "node_modules/passport-local": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", - "integrity": "sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==", - "dependencies": { - "passport-strategy": "1.x.x" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/passport-strategy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", diff --git a/nestjs-BE/server/package.json b/nestjs-BE/server/package.json index 9b2a711c..3ad1d878 100644 --- a/nestjs-BE/server/package.json +++ b/nestjs-BE/server/package.json @@ -30,7 +30,6 @@ "dotenv": "^16.3.1", "passport": "^0.6.0", "passport-jwt": "^4.0.1", - "passport-local": "^1.0.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1" }, @@ -42,7 +41,6 @@ "@types/jest": "^29.5.2", "@types/node": "^20.3.1", "@types/passport-jwt": "^3.0.13", - "@types/passport-local": "^1.0.38", "@types/supertest": "^2.0.12", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", diff --git a/nestjs-BE/server/src/auth/auth.controller.ts b/nestjs-BE/server/src/auth/auth.controller.ts index 238b65ef..4a2e6a65 100644 --- a/nestjs-BE/server/src/auth/auth.controller.ts +++ b/nestjs-BE/server/src/auth/auth.controller.ts @@ -1,5 +1,4 @@ import { Controller, Post, Request, UseGuards, Get } from '@nestjs/common'; -import { LocalAuthGuard } from './local-auth.guard'; import { AuthService } from './auth.service'; import { JwtAuthGuard } from './jwt-auth.guard'; import { Public } from './public.decorator'; @@ -8,13 +7,6 @@ import { Public } from './public.decorator'; export class AuthController { constructor(private authService: AuthService) {} - @Public() - @UseGuards(LocalAuthGuard) - @Post('login') - async login(@Request() req) { - return this.authService.login(req.user); - } - @UseGuards(JwtAuthGuard) @Get('profile') getProfile(@Request() req) { diff --git a/nestjs-BE/server/src/auth/auth.module.ts b/nestjs-BE/server/src/auth/auth.module.ts index ed14f3d7..b8d0644b 100644 --- a/nestjs-BE/server/src/auth/auth.module.ts +++ b/nestjs-BE/server/src/auth/auth.module.ts @@ -3,7 +3,6 @@ import { AuthController } from './auth.controller'; import { AuthService } from './auth.service'; import { UsersModule } from 'src/users/users.module'; import { PassportModule } from '@nestjs/passport'; -import { LocalStrategy } from './local.strategy'; import { JwtModule } from '@nestjs/jwt'; import { jwtConstants } from './constants'; import { JwtStrategy } from './jwt.strategy'; @@ -22,7 +21,6 @@ import { JwtAuthGuard } from './jwt-auth.guard'; controllers: [AuthController], providers: [ AuthService, - LocalStrategy, JwtStrategy, { provide: APP_GUARD, useClass: JwtAuthGuard }, ], diff --git a/nestjs-BE/server/src/auth/local-auth.guard.ts b/nestjs-BE/server/src/auth/local-auth.guard.ts deleted file mode 100644 index ccf962b6..00000000 --- a/nestjs-BE/server/src/auth/local-auth.guard.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { AuthGuard } from '@nestjs/passport'; - -@Injectable() -export class LocalAuthGuard extends AuthGuard('local') {} diff --git a/nestjs-BE/server/src/auth/local.strategy.ts b/nestjs-BE/server/src/auth/local.strategy.ts deleted file mode 100644 index 4f30a6c6..00000000 --- a/nestjs-BE/server/src/auth/local.strategy.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Strategy } from 'passport-local'; -import { PassportStrategy } from '@nestjs/passport'; -import { Injectable, UnauthorizedException } from '@nestjs/common'; -import { AuthService } from './auth.service'; - -@Injectable() -export class LocalStrategy extends PassportStrategy(Strategy) { - 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(); - return user; - } -} From 9321c6a517c56232cb226b4f821036590e541f02 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Sat, 2 Dec 2023 19:28:29 +0900 Subject: [PATCH 074/170] =?UTF-8?q?feat(#105):=20=EC=B9=B4=EC=B9=B4?= =?UTF-8?q?=EC=98=A4=20OAuth=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/package-lock.json | 50 ++++++++++++++++++- nestjs-BE/server/package.json | 5 +- nestjs-BE/server/src/auth/auth.controller.ts | 34 ++++++++++++- nestjs-BE/server/src/auth/auth.service.ts | 26 ++++++---- nestjs-BE/server/src/auth/constants.ts | 4 ++ .../server/src/auth/dto/kakao-user.dto.ts | 6 +++ nestjs-BE/server/src/users/users.service.ts | 19 +++---- 7 files changed, 118 insertions(+), 26 deletions(-) create mode 100644 nestjs-BE/server/src/auth/dto/kakao-user.dto.ts diff --git a/nestjs-BE/server/package-lock.json b/nestjs-BE/server/package-lock.json index b92ce154..0e96a0d1 100644 --- a/nestjs-BE/server/package-lock.json +++ b/nestjs-BE/server/package-lock.json @@ -16,11 +16,14 @@ "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.2.8", "@nestjs/websockets": "^10.2.8", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", "dotenv": "^16.3.1", "passport": "^0.6.0", "passport-jwt": "^4.0.1", "reflect-metadata": "^0.1.13", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "uuid": "^9.0.1" }, "devDependencies": { "@nestjs/cli": "^10.0.0", @@ -2212,6 +2215,11 @@ "@types/superagent": "*" } }, + "node_modules/@types/validator": { + "version": "13.11.7", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.7.tgz", + "integrity": "sha512-q0JomTsJ2I5Mv7dhHhQLGjMvX0JJm5dyZ1DXQySIUzU1UlwzB8bt+R6+LODUbz0UDIOvEzGc28tk27gBJw2N8Q==" + }, "node_modules/@types/yargs": { "version": "17.0.31", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.31.tgz", @@ -3307,6 +3315,21 @@ "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", "dev": true }, + "node_modules/class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" + }, + "node_modules/class-validator": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.0.tgz", + "integrity": "sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A==", + "dependencies": { + "@types/validator": "^13.7.10", + "libphonenumber-js": "^1.10.14", + "validator": "^13.7.0" + } + }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -6350,6 +6373,11 @@ "node": ">= 0.8.0" } }, + "node_modules/libphonenumber-js": { + "version": "1.10.51", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.51.tgz", + "integrity": "sha512-vY2I+rQwrDQzoPds0JeTEpeWzbUJgqoV0O4v31PauHBb/e+1KCXKylHcDnBMgJZ9fH9mErsEbROJY3Z3JtqEmg==" + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -8807,6 +8835,18 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -8827,6 +8867,14 @@ "node": ">=10.12.0" } }, + "node_modules/validator": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", + "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/nestjs-BE/server/package.json b/nestjs-BE/server/package.json index 3ad1d878..795405d1 100644 --- a/nestjs-BE/server/package.json +++ b/nestjs-BE/server/package.json @@ -27,11 +27,14 @@ "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.2.8", "@nestjs/websockets": "^10.2.8", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", "dotenv": "^16.3.1", "passport": "^0.6.0", "passport-jwt": "^4.0.1", "reflect-metadata": "^0.1.13", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "uuid": "^9.0.1" }, "devDependencies": { "@nestjs/cli": "^10.0.0", diff --git a/nestjs-BE/server/src/auth/auth.controller.ts b/nestjs-BE/server/src/auth/auth.controller.ts index 4a2e6a65..ee23c675 100644 --- a/nestjs-BE/server/src/auth/auth.controller.ts +++ b/nestjs-BE/server/src/auth/auth.controller.ts @@ -1,11 +1,41 @@ -import { Controller, Post, Request, UseGuards, Get } from '@nestjs/common'; +import { + Controller, + Post, + Request, + UseGuards, + Get, + Body, + Query, + NotFoundException, +} from '@nestjs/common'; import { AuthService } from './auth.service'; import { JwtAuthGuard } from './jwt-auth.guard'; import { Public } from './public.decorator'; +import { KakaoUserDto } from './dto/kakao-user.dto'; +import { stringify } from 'qs'; +import { UsersService } from 'src/users/users.service'; @Controller('auth') export class AuthController { - constructor(private authService: AuthService) {} + constructor( + private authService: AuthService, + private usersService: UsersService, + ) {} + + @Public() + @Post('kakao-oauth') + async kakaoLogin(@Body() kakaoUserDto: KakaoUserDto) { + const kakaoUserAccount = await this.authService.getKakaoAccount( + kakaoUserDto.kakaoUserId, + ); + if (!kakaoUserAccount) throw new NotFoundException(); + let user = await this.usersService.findOne(kakaoUserAccount.email); + if (!user) { + this.usersService.createOne(kakaoUserAccount.email); + user = await this.usersService.findOne(kakaoUserAccount.email); + } + return this.authService.login(user); + } @UseGuards(JwtAuthGuard) @Get('profile') diff --git a/nestjs-BE/server/src/auth/auth.service.ts b/nestjs-BE/server/src/auth/auth.service.ts index 9d43ae1d..77259538 100644 --- a/nestjs-BE/server/src/auth/auth.service.ts +++ b/nestjs-BE/server/src/auth/auth.service.ts @@ -1,18 +1,26 @@ import { Injectable } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; -import { UsersService } from 'src/users/users.service'; +import { kakaoOauthConstants } from './constants'; +import { stringify } from 'qs'; @Injectable() export class AuthService { - constructor( - private usersService: UsersService, - private jwtService: JwtService, - ) {} + constructor(private jwtService: JwtService) {} - async validateUser(email: string, password: string): Promise { - const user = await this.usersService.findOne(email); - if (user?.password !== password) return null; - return { uuid: user.uuid, email: user.email }; + async getKakaoAccount(kakaoUserId: number) { + const url = `https://kapi.kakao.com/v2/user/me`; + const queryParams = { target_id_type: 'user_id', target_id: kakaoUserId }; + const response = await fetch(url, { + method: 'POST', + headers: { + Authorization: `KakaoAK ${kakaoOauthConstants.adminKey}`, + 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8', + }, + body: stringify(queryParams), + }); + const responseBody = await response.json(); + if (!response.ok) return null; + return responseBody.kakao_account; } async login(user: any) { diff --git a/nestjs-BE/server/src/auth/constants.ts b/nestjs-BE/server/src/auth/constants.ts index 969fbc29..0a0cd1e1 100644 --- a/nestjs-BE/server/src/auth/constants.ts +++ b/nestjs-BE/server/src/auth/constants.ts @@ -3,3 +3,7 @@ import customEnv from 'config/env'; export const jwtConstants = { secret: customEnv.JWT_SECRET, }; + +export const kakaoOauthConstants = { + adminKey: customEnv.KAKAO_ADMIN_KEY, +}; diff --git a/nestjs-BE/server/src/auth/dto/kakao-user.dto.ts b/nestjs-BE/server/src/auth/dto/kakao-user.dto.ts new file mode 100644 index 00000000..e4173266 --- /dev/null +++ b/nestjs-BE/server/src/auth/dto/kakao-user.dto.ts @@ -0,0 +1,6 @@ +import { IsNumber } from 'class-validator'; + +export class KakaoUserDto { + @IsNumber() + kakaoUserId: number; +} diff --git a/nestjs-BE/server/src/users/users.service.ts b/nestjs-BE/server/src/users/users.service.ts index ffb2a3a7..4d553421 100644 --- a/nestjs-BE/server/src/users/users.service.ts +++ b/nestjs-BE/server/src/users/users.service.ts @@ -1,27 +1,20 @@ import { Injectable } from '@nestjs/common'; +import { v4 } from 'uuid'; export type User = { uuid: string; email: string; - password: string; }; @Injectable() export class UsersService { - private readonly users: User[] = [ - { - uuid: '1', - email: 'john', - password: 'changeme', - }, - { - uuid: '2', - email: 'maria', - password: 'guess', - }, - ]; + private readonly users: User[] = []; async findOne(email: string): Promise { return this.users.find((user) => user.email === email); } + + createOne(email: string) { + this.users.push({ uuid: v4(), email }); + } } From 8cf9cd2b1cea788f92eebbff51792ba1414e8d80 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Sat, 2 Dec 2023 19:32:31 +0900 Subject: [PATCH 075/170] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=84=B1=EA=B3=B5=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=9A=A9=20api?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/app.controller.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nestjs-BE/server/src/app.controller.ts b/nestjs-BE/server/src/app.controller.ts index fac17b02..4a545d13 100644 --- a/nestjs-BE/server/src/app.controller.ts +++ b/nestjs-BE/server/src/app.controller.ts @@ -11,4 +11,9 @@ export class AppController { getHello(): string { return this.appService.getHello(); } + + @Get('login-test') + authTest(): string { + return 'login success'; + } } From a1b0d82ae9091400c6111b644de08d06ef400177 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Sat, 2 Dec 2023 19:53:56 +0900 Subject: [PATCH 076/170] =?UTF-8?q?chore:=20=EC=9E=90=EB=8F=99=20=EB=B0=B0?= =?UTF-8?q?=ED=8F=AC=20yml=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/BE-deploy.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index 056c798b..16f09c5d 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -15,8 +15,15 @@ jobs: run: echo ${{ secrets.PACKAGE_ACCESS_TOKEN }} | docker login ghcr.io -u ${{ secrets.PACKAGE_USERNAME }} --password-stdin - name: Build and push Docker image run: | + echo "SERVER_PORT=$SERVER" >> ./nestjs-BE/server/.env + echo "JWT_SECRET=$JWT_SECRET" >> ./nestjs-BE/server/.env + echo "KAKAO_ADMIN_KEY=$KAKAO_ADMIN_KEY" >> ./nestjs-BE/server/.env docker build -t ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync ./nestjs-BE/server docker push ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync:latest + env: + SERVER_PORT: ${{ secrets.SERVER_PORT }} + JWT_SECRET: ${{ secrets.JWT_SECRET }} + KAKAO_ADMIN_KEY: ${{ secrets.KAKAO_ADMIN_KEY }} deploy: needs: build From a9d08addb46d6a97589e11837227cc5f06ca3cff Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Sun, 3 Dec 2023 14:06:58 +0900 Subject: [PATCH 077/170] =?UTF-8?q?chore:=20=ED=99=98=EA=B2=BD=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/BE-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index 16f09c5d..216f0e6c 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -21,7 +21,7 @@ jobs: docker build -t ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync ./nestjs-BE/server docker push ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync:latest env: - SERVER_PORT: ${{ secrets.SERVER_PORT }} + SERVER_PORT: ${{ secrets.CONTAINER_PORT }} JWT_SECRET: ${{ secrets.JWT_SECRET }} KAKAO_ADMIN_KEY: ${{ secrets.KAKAO_ADMIN_KEY }} From 8340ced2b6a33bda91399cfe2f91b3de8226c80c Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Sun, 3 Dec 2023 14:33:20 +0900 Subject: [PATCH 078/170] =?UTF-8?q?setting:=20=EC=9E=90=EB=8F=99=EB=B0=B0?= =?UTF-8?q?=ED=8F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/BE-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index 216f0e6c..a6e6909a 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -15,7 +15,7 @@ jobs: run: echo ${{ secrets.PACKAGE_ACCESS_TOKEN }} | docker login ghcr.io -u ${{ secrets.PACKAGE_USERNAME }} --password-stdin - name: Build and push Docker image run: | - echo "SERVER_PORT=$SERVER" >> ./nestjs-BE/server/.env + echo "SERVER_PORT=$SERVER_PORT" >> ./nestjs-BE/server/.env echo "JWT_SECRET=$JWT_SECRET" >> ./nestjs-BE/server/.env echo "KAKAO_ADMIN_KEY=$KAKAO_ADMIN_KEY" >> ./nestjs-BE/server/.env docker build -t ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync ./nestjs-BE/server From 70657aa9e8292a4aaa9263f666de659f21e25558 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Sun, 3 Dec 2023 15:56:24 +0900 Subject: [PATCH 079/170] =?UTF-8?q?rename:=20=EC=84=9C=EB=B2=84=EC=99=80?= =?UTF-8?q?=20=EC=BA=90=EC=8B=9C=20=EC=84=9C=EB=B2=84=20=ED=95=A9=EC=B9=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/BE-cache-deploy.yml | 46 - .github/workflows/BE-deploy.yml | 4 + nestjs-BE/cache-server/.dockerignore | 8 - nestjs-BE/cache-server/.eslintrc.js | 29 - nestjs-BE/cache-server/.gitignore | 42 - nestjs-BE/cache-server/.prettierrc | 6 - nestjs-BE/cache-server/Dockerfile | 19 - nestjs-BE/cache-server/README.md | 73 - nestjs-BE/cache-server/nest-cli.json | 8 - nestjs-BE/cache-server/package-lock.json | 9026 ----------------- nestjs-BE/cache-server/package.json | 75 - .../cache-server/src/app.controller.spec.ts | 22 - nestjs-BE/cache-server/src/app.controller.ts | 7 - nestjs-BE/cache-server/src/app.module.ts | 25 - nestjs-BE/cache-server/src/app.service.ts | 4 - nestjs-BE/cache-server/src/main.ts | 14 - .../cache-server/src/users/users.module.ts | 10 - .../cache-server/src/users/users.service.ts | 175 - nestjs-BE/cache-server/test/app.e2e-spec.ts | 24 - nestjs-BE/cache-server/test/jest-e2e.json | 9 - nestjs-BE/cache-server/tsconfig.build.json | 4 - nestjs-BE/cache-server/tsconfig.json | 21 - nestjs-BE/server/.eslintrc.js | 2 +- nestjs-BE/server/.gitignore | 4 + nestjs-BE/server/package-lock.json | 150 +- nestjs-BE/server/package.json | 4 + .../20231203062911_init/migration.sql | 46 + .../prisma/migrations/migration_lock.toml | 3 + .../prisma/mongodb.schema.prisma | 0 .../prisma/mysql.schema.prisma | 0 nestjs-BE/server/src/app.module.ts | 17 +- nestjs-BE/server/src/auth/auth.controller.ts | 6 +- nestjs-BE/server/src/auth/constants.ts | 2 +- .../src/base/base.service.ts | 0 .../src/boards/boards.controller.spec.ts | 0 .../src/boards/boards.controller.ts | 0 .../src/boards/boards.module.ts | 0 .../src/boards/boards.service.spec.ts | 0 .../src/boards/boards.service.ts | 0 .../src/boards/dto/create-board.dto.ts | 0 .../src/boards/dto/update-board.dto.ts | 0 .../src/boards/entities/board.entity.ts | 0 nestjs-BE/server/{ => src}/config/env.ts | 0 .../src/config/magic-number.ts | 0 .../src/config/swagger.ts | 0 nestjs-BE/server/{ => src}/crdt/clock.ts | 3 +- nestjs-BE/server/{ => src}/crdt/crdt-tree.ts | 0 nestjs-BE/server/{ => src}/crdt/node.ts | 0 nestjs-BE/server/{ => src}/crdt/operation.ts | 0 nestjs-BE/server/{ => src}/crdt/tree.ts | 0 nestjs-BE/server/src/main.ts | 7 +- .../src/prisma/prisma.module.ts | 0 .../src/prisma/prisma.service.spec.ts | 0 .../src/prisma/prisma.service.ts | 0 .../src/profiles/dto/create-profile.dto.ts | 0 .../src/profiles/dto/profile-space.dto.ts | 0 .../src/profiles/dto/update-profile.dto.ts | 0 .../src/profiles/entities/profile.entity.ts | 0 .../src/profiles/profiles.controller.spec.ts | 0 .../src/profiles/profiles.controller.ts | 0 .../src/profiles/profiles.module.ts | 0 .../src/profiles/profiles.service.spec.ts | 0 .../src/profiles/profiles.service.ts | 0 .../src/spaces/dto/create-space.dto.ts | 0 .../src/spaces/dto/update-space.dto.ts | 0 .../src/spaces/entities/space.entity.ts | 0 .../src/spaces/spaces.controller.spec.ts | 0 .../src/spaces/spaces.controller.ts | 0 .../src/spaces/spaces.module.ts | 0 .../src/spaces/spaces.service.spec.ts | 0 .../src/spaces/spaces.service.ts | 0 .../temporary-database.module.ts | 0 .../temporary-database.service.spec.ts | 0 .../temporary-database.service.ts | 0 .../src/users/dto/create-user.dto.ts | 0 .../src/users/dto/update-user.dto.ts | 0 .../src/users/entities/user.entity.ts | 0 .../src/users/users.controller.spec.ts | 0 .../src/users/users.controller.ts | 3 + nestjs-BE/server/src/users/users.module.ts | 5 +- .../src/users/users.service.spec.ts | 0 nestjs-BE/server/src/users/users.service.ts | 175 +- .../src/utils/lru-cache.ts | 0 .../src/utils/uuid.ts | 0 84 files changed, 414 insertions(+), 9664 deletions(-) delete mode 100644 .github/workflows/BE-cache-deploy.yml delete mode 100644 nestjs-BE/cache-server/.dockerignore delete mode 100644 nestjs-BE/cache-server/.eslintrc.js delete mode 100644 nestjs-BE/cache-server/.gitignore delete mode 100644 nestjs-BE/cache-server/.prettierrc delete mode 100644 nestjs-BE/cache-server/Dockerfile delete mode 100644 nestjs-BE/cache-server/README.md delete mode 100644 nestjs-BE/cache-server/nest-cli.json delete mode 100644 nestjs-BE/cache-server/package-lock.json delete mode 100644 nestjs-BE/cache-server/package.json delete mode 100644 nestjs-BE/cache-server/src/app.controller.spec.ts delete mode 100644 nestjs-BE/cache-server/src/app.controller.ts delete mode 100644 nestjs-BE/cache-server/src/app.module.ts delete mode 100644 nestjs-BE/cache-server/src/app.service.ts delete mode 100644 nestjs-BE/cache-server/src/main.ts delete mode 100644 nestjs-BE/cache-server/src/users/users.module.ts delete mode 100644 nestjs-BE/cache-server/src/users/users.service.ts delete mode 100644 nestjs-BE/cache-server/test/app.e2e-spec.ts delete mode 100644 nestjs-BE/cache-server/test/jest-e2e.json delete mode 100644 nestjs-BE/cache-server/tsconfig.build.json delete mode 100644 nestjs-BE/cache-server/tsconfig.json create mode 100644 nestjs-BE/server/prisma/migrations/20231203062911_init/migration.sql create mode 100644 nestjs-BE/server/prisma/migrations/migration_lock.toml rename nestjs-BE/{cache-server => server}/prisma/mongodb.schema.prisma (100%) rename nestjs-BE/{cache-server => server}/prisma/mysql.schema.prisma (100%) rename nestjs-BE/{cache-server => server}/src/base/base.service.ts (100%) rename nestjs-BE/{cache-server => server}/src/boards/boards.controller.spec.ts (100%) rename nestjs-BE/{cache-server => server}/src/boards/boards.controller.ts (100%) rename nestjs-BE/{cache-server => server}/src/boards/boards.module.ts (100%) rename nestjs-BE/{cache-server => server}/src/boards/boards.service.spec.ts (100%) rename nestjs-BE/{cache-server => server}/src/boards/boards.service.ts (100%) rename nestjs-BE/{cache-server => server}/src/boards/dto/create-board.dto.ts (100%) rename nestjs-BE/{cache-server => server}/src/boards/dto/update-board.dto.ts (100%) rename nestjs-BE/{cache-server => server}/src/boards/entities/board.entity.ts (100%) rename nestjs-BE/server/{ => src}/config/env.ts (100%) rename nestjs-BE/{cache-server => server}/src/config/magic-number.ts (100%) rename nestjs-BE/{cache-server => server}/src/config/swagger.ts (100%) rename nestjs-BE/server/{ => src}/crdt/clock.ts (97%) rename nestjs-BE/server/{ => src}/crdt/crdt-tree.ts (100%) rename nestjs-BE/server/{ => src}/crdt/node.ts (100%) rename nestjs-BE/server/{ => src}/crdt/operation.ts (100%) rename nestjs-BE/server/{ => src}/crdt/tree.ts (100%) rename nestjs-BE/{cache-server => server}/src/prisma/prisma.module.ts (100%) rename nestjs-BE/{cache-server => server}/src/prisma/prisma.service.spec.ts (100%) rename nestjs-BE/{cache-server => server}/src/prisma/prisma.service.ts (100%) rename nestjs-BE/{cache-server => server}/src/profiles/dto/create-profile.dto.ts (100%) rename nestjs-BE/{cache-server => server}/src/profiles/dto/profile-space.dto.ts (100%) rename nestjs-BE/{cache-server => server}/src/profiles/dto/update-profile.dto.ts (100%) rename nestjs-BE/{cache-server => server}/src/profiles/entities/profile.entity.ts (100%) rename nestjs-BE/{cache-server => server}/src/profiles/profiles.controller.spec.ts (100%) rename nestjs-BE/{cache-server => server}/src/profiles/profiles.controller.ts (100%) rename nestjs-BE/{cache-server => server}/src/profiles/profiles.module.ts (100%) rename nestjs-BE/{cache-server => server}/src/profiles/profiles.service.spec.ts (100%) rename nestjs-BE/{cache-server => server}/src/profiles/profiles.service.ts (100%) rename nestjs-BE/{cache-server => server}/src/spaces/dto/create-space.dto.ts (100%) rename nestjs-BE/{cache-server => server}/src/spaces/dto/update-space.dto.ts (100%) rename nestjs-BE/{cache-server => server}/src/spaces/entities/space.entity.ts (100%) rename nestjs-BE/{cache-server => server}/src/spaces/spaces.controller.spec.ts (100%) rename nestjs-BE/{cache-server => server}/src/spaces/spaces.controller.ts (100%) rename nestjs-BE/{cache-server => server}/src/spaces/spaces.module.ts (100%) rename nestjs-BE/{cache-server => server}/src/spaces/spaces.service.spec.ts (100%) rename nestjs-BE/{cache-server => server}/src/spaces/spaces.service.ts (100%) rename nestjs-BE/{cache-server => server}/src/temporary-database/temporary-database.module.ts (100%) rename nestjs-BE/{cache-server => server}/src/temporary-database/temporary-database.service.spec.ts (100%) rename nestjs-BE/{cache-server => server}/src/temporary-database/temporary-database.service.ts (100%) rename nestjs-BE/{cache-server => server}/src/users/dto/create-user.dto.ts (100%) rename nestjs-BE/{cache-server => server}/src/users/dto/update-user.dto.ts (100%) rename nestjs-BE/{cache-server => server}/src/users/entities/user.entity.ts (100%) rename nestjs-BE/{cache-server => server}/src/users/users.controller.spec.ts (100%) rename nestjs-BE/{cache-server => server}/src/users/users.controller.ts (97%) rename nestjs-BE/{cache-server => server}/src/users/users.service.spec.ts (100%) rename nestjs-BE/{cache-server => server}/src/utils/lru-cache.ts (100%) rename nestjs-BE/{cache-server => server}/src/utils/uuid.ts (100%) diff --git a/.github/workflows/BE-cache-deploy.yml b/.github/workflows/BE-cache-deploy.yml deleted file mode 100644 index 55454c92..00000000 --- a/.github/workflows/BE-cache-deploy.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: Cache server build and deploy - -on: - push: - branches: - - "BE-develop" - paths: - - "nestjs-BE/cache-server/*" - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: BE-develop - sparse-checkout: nestjs-BE - - name: Login to github Packages - run: echo ${{ secrets.PACKAGE_ACCESS_TOKEN }} | docker login ghcr.io -u ${{ secrets.PACKAGE_USERNAME }} --password-stdin - - name: Build and push Docker image - run: | - docker build -t ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync-cache-server ./nestjs-BE/cache-server - docker push ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync-cache-server:latest - - deploy: - needs: build - runs-on: ubuntu-latest - steps: - - name: Pull Docker image - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.REMOTE_HOST }} - port: ${{ secrets.REMOTE_PORT }} - username: ${{ secrets.REMOTE_USER }} - key: ${{ secrets.REMOTE_SSH_KEY }} - script: | - eval "$(ssh-agent -s)" - echo "${{ secrets.PRIVATE_SSH_KEY }}" | ssh-add - - ssh -A ${{ secrets.PRIVATE_USER }}@${{ secrets.PRIVATE_HOST }} << ENDSSH - echo "${{ secrets.PACKAGE_ACCESS_TOKEN }}" | docker login ghcr.io -u "${{ secrets.PACKAGE_USERNAME }}" --password-stdin - docker pull ghcr.io/"${{ secrets.PACKAGE_USERNAME }}"/mindsync-cache-server - docker stop mindsync_cache_server || true - docker rm mindsync_cache_server || true - docker run -d --name mindsync_cache_server -p "${{ secrets.SERVER_PORT }}":"${{ secrets.CONTAINER_PORT }}" -e MYSQL_DATABASE_URL="${{ secrets.MYSQL_DATABASE_URL }}" -e MONGODB_DATABASE_URL="${{ secrets.MONGODB_DATABASE_URL }}" ghcr.io/"${{ secrets.PACKAGE_USERNAME }}"/mindsync-cache-server - docker image prune -af - ENDSSH diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index a6e6909a..4cba2018 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -18,12 +18,16 @@ jobs: echo "SERVER_PORT=$SERVER_PORT" >> ./nestjs-BE/server/.env echo "JWT_SECRET=$JWT_SECRET" >> ./nestjs-BE/server/.env echo "KAKAO_ADMIN_KEY=$KAKAO_ADMIN_KEY" >> ./nestjs-BE/server/.env + echo "MYSQL_DATABASE_URL=$MYSQL_DATABASE_URL" >> ./nestjs-BE/server/.env + echo "MONGODB_DATABASE_URL=$MONGODB_DATABASE_URL" >> ./nestjs-BE/server/.env docker build -t ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync ./nestjs-BE/server docker push ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync:latest env: SERVER_PORT: ${{ secrets.CONTAINER_PORT }} JWT_SECRET: ${{ secrets.JWT_SECRET }} KAKAO_ADMIN_KEY: ${{ secrets.KAKAO_ADMIN_KEY }} + MYSQL_DATABASE_URL: ${{ secrets.MYSQL_DATABASE_URL }} + MONGODB_DATABASE_URL: ${{ secrets.MONGODB_DATABASE_URL }} deploy: needs: build diff --git a/nestjs-BE/cache-server/.dockerignore b/nestjs-BE/cache-server/.dockerignore deleted file mode 100644 index fe33330d..00000000 --- a/nestjs-BE/cache-server/.dockerignore +++ /dev/null @@ -1,8 +0,0 @@ -README.md -/test -.eslintrc.js -.gitignore -.prettierrc -nest-cli.json - -\*.spec.ts diff --git a/nestjs-BE/cache-server/.eslintrc.js b/nestjs-BE/cache-server/.eslintrc.js deleted file mode 100644 index 64cb21cf..00000000 --- a/nestjs-BE/cache-server/.eslintrc.js +++ /dev/null @@ -1,29 +0,0 @@ -module.exports = { - parser: '@typescript-eslint/parser', - parserOptions: { - project: 'tsconfig.json', - tsconfigRootDir: __dirname, - sourceType: 'module', - }, - plugins: ['@typescript-eslint/eslint-plugin'], - extends: [ - 'plugin:@typescript-eslint/recommended', - 'plugin:prettier/recommended', - ], - root: true, - env: { - node: true, - jest: true, - }, - ignorePatterns: ['.eslintrc.js'], - rules: { - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/no-explicit-any': 'off', - 'max-depth': ['error', 3], - 'no-magic-numbers': ['error', { ignore: [-1, 0, 1] }], - curly: ['error', 'multi-line', 'consistent'], - 'max-params': ['error', 3], - }, -}; diff --git a/nestjs-BE/cache-server/.gitignore b/nestjs-BE/cache-server/.gitignore deleted file mode 100644 index fbd14d32..00000000 --- a/nestjs-BE/cache-server/.gitignore +++ /dev/null @@ -1,42 +0,0 @@ -# compiled output -/dist -/node_modules - -# Logs -logs -*.log -npm-debug.log* -pnpm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# OS -.DS_Store - -# Tests -/coverage -/.nyc_output - -# IDEs and editors -/.idea -.project -.classpath -.c9/ -*.launch -.settings/ -*.sublime-workspace - -# IDE - VSCode -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json - -# 환경 변수 -.env - -# csv, prisma -/operations -/prisma/generated \ No newline at end of file diff --git a/nestjs-BE/cache-server/.prettierrc b/nestjs-BE/cache-server/.prettierrc deleted file mode 100644 index cb17f298..00000000 --- a/nestjs-BE/cache-server/.prettierrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "singleQuote": true, - "trailingComma": "all", - "endOfLine": "auto" -} - diff --git a/nestjs-BE/cache-server/Dockerfile b/nestjs-BE/cache-server/Dockerfile deleted file mode 100644 index 9eb851c7..00000000 --- a/nestjs-BE/cache-server/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM node:20.4.0-alpine - -WORKDIR /server - -COPY package.json package-lock.json ./ - -RUN npm ci - -COPY ./ ./ - -RUN npx prisma generate --schema=./prisma/mysql.schema.prisma - -RUN npx prisma generate --schema=./prisma/mongodb.schema.prisma - -RUN mkdir operations - -EXPOSE 3000 - -CMD ["npm", "start"] diff --git a/nestjs-BE/cache-server/README.md b/nestjs-BE/cache-server/README.md deleted file mode 100644 index 00a13b11..00000000 --- a/nestjs-BE/cache-server/README.md +++ /dev/null @@ -1,73 +0,0 @@ -

- Nest Logo -

- -[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 -[circleci-url]: https://circleci.com/gh/nestjs/nest - -

A progressive Node.js framework for building efficient and scalable server-side applications.

-

-NPM Version -Package License -NPM Downloads -CircleCI -Coverage -Discord -Backers on Open Collective -Sponsors on Open Collective - - Support us - -

- - -## Description - -[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. - -## Installation - -```bash -$ npm install -``` - -## Running the app - -```bash -# development -$ npm run start - -# watch mode -$ npm run start:dev - -# production mode -$ npm run start:prod -``` - -## Test - -```bash -# unit tests -$ npm run test - -# e2e tests -$ npm run test:e2e - -# test coverage -$ npm run test:cov -``` - -## Support - -Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). - -## Stay in touch - -- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com) -- Website - [https://nestjs.com](https://nestjs.com/) -- Twitter - [@nestframework](https://twitter.com/nestframework) - -## License - -Nest is [MIT licensed](LICENSE). diff --git a/nestjs-BE/cache-server/nest-cli.json b/nestjs-BE/cache-server/nest-cli.json deleted file mode 100644 index f9aa683b..00000000 --- a/nestjs-BE/cache-server/nest-cli.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/nest-cli", - "collection": "@nestjs/schematics", - "sourceRoot": "src", - "compilerOptions": { - "deleteOutDir": true - } -} diff --git a/nestjs-BE/cache-server/package-lock.json b/nestjs-BE/cache-server/package-lock.json deleted file mode 100644 index 9eb2d308..00000000 --- a/nestjs-BE/cache-server/package-lock.json +++ /dev/null @@ -1,9026 +0,0 @@ -{ - "name": "cache-server", - "version": "0.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "cache-server", - "version": "0.0.1", - "license": "UNLICENSED", - "dependencies": { - "@nestjs/common": "^10.0.0", - "@nestjs/core": "^10.0.0", - "@nestjs/mapped-types": "*", - "@nestjs/platform-express": "^10.0.0", - "@nestjs/schedule": "^4.0.0", - "@nestjs/swagger": "^7.1.16", - "@prisma/client": "^5.6.0", - "reflect-metadata": "^0.1.13", - "rxjs": "^7.8.1", - "uuid": "^9.0.1" - }, - "devDependencies": { - "@nestjs/cli": "^10.0.0", - "@nestjs/schematics": "^10.0.0", - "@nestjs/testing": "^10.0.0", - "@types/express": "^4.17.17", - "@types/jest": "^29.5.2", - "@types/node": "^20.3.1", - "@types/supertest": "^2.0.12", - "@typescript-eslint/eslint-plugin": "^6.0.0", - "@typescript-eslint/parser": "^6.0.0", - "eslint": "^8.42.0", - "eslint-config-prettier": "^9.0.0", - "eslint-plugin-prettier": "^5.0.0", - "jest": "^29.5.0", - "prettier": "^3.0.0", - "prisma": "^5.6.0", - "source-map-support": "^0.5.21", - "supertest": "^6.3.3", - "ts-jest": "^29.1.0", - "ts-loader": "^9.4.3", - "ts-node": "^10.9.1", - "tsconfig-paths": "^4.2.0", - "typescript": "^5.1.3" - } - }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@angular-devkit/core": { - "version": "16.2.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.8.tgz", - "integrity": "sha512-PTGozYvh1Bin5lB15PwcXa26Ayd17bWGLS3H8Rs0s+04mUDvfNofmweaX1LgumWWy3nCUTDuwHxX10M3G0wE2g==", - "dev": true, - "dependencies": { - "ajv": "8.12.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.0", - "picomatch": "2.3.1", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular-devkit/schematics": { - "version": "16.2.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.8.tgz", - "integrity": "sha512-MBiKZOlR9/YMdflALr7/7w/BGAfo/BGTrlkqsIB6rDWV1dYiCgxI+033HsiNssLS6RQyCFx/e7JA2aBBzu9zEg==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "16.2.8", - "jsonc-parser": "3.2.0", - "magic-string": "0.30.1", - "ora": "5.4.1", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-devkit/schematics-cli": { - "version": "16.2.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-16.2.8.tgz", - "integrity": "sha512-EXURJCzWTVYCipiTT4vxQQOrF63asOUDbeOy3OtiSh7EwIUvxm3BPG6hquJqngEnI/N6bA75NJ1fBhU6Hrh7eA==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "16.2.8", - "@angular-devkit/schematics": "16.2.8", - "ansi-colors": "4.1.3", - "inquirer": "8.2.4", - "symbol-observable": "4.0.0", - "yargs-parser": "21.1.1" - }, - "bin": { - "schematics": "bin/schematics.js" - }, - "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-devkit/schematics-cli/node_modules/inquirer": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", - "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/@angular-devkit/schematics-cli/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.4.tgz", - "integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", - "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz", - "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.3", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.2", - "@babel/parser": "^7.23.3", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.3", - "@babel/types": "^7.23.3", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.4.tgz", - "integrity": "sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.23.4", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.4.tgz", - "integrity": "sha512-HfcMizYz10cr3h29VqyfGL6ZWIjTwWfvYBMsBVGwpcbhNGe3wQ1ZXZRPzZoAHhd9OqHadHqjQ89iVKINXnbzuw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.4", - "@babel/types": "^7.23.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.4.tgz", - "integrity": "sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", - "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", - "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.4.tgz", - "integrity": "sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.23.4", - "@babel/generator": "^7.23.4", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.4", - "@babel/types": "^7.23.4", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.4.tgz", - "integrity": "sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.1.90" - } - }, - "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", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", - "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/@eslint/js": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz", - "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", - "dev": true - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.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/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/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/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/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/@istanbuljs/load-nyc-config/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/@istanbuljs/load-nyc-config/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/@istanbuljs/load-nyc-config/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/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", - "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", - "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", - "dev": true, - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/reporters": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.7.0", - "jest-config": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-resolve-dependencies": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "jest-watcher": "^29.7.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/environment": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", - "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", - "dev": true, - "dependencies": { - "expect": "^29.7.0", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", - "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.6.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", - "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", - "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/types": "^29.6.3", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", - "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/reporters/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", - "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", - "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", - "dev": true, - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", - "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", - "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@lukeed/csprng": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", - "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@nestjs/cli": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-10.2.1.tgz", - "integrity": "sha512-CAJAQwmxFZfB3RTvqz/eaXXWpyU+mZ4QSqfBYzjneTsPgF+uyOAW3yQpaLNn9Dfcv39R9UxSuAhayv6yuFd+Jg==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "16.2.8", - "@angular-devkit/schematics": "16.2.8", - "@angular-devkit/schematics-cli": "16.2.8", - "@nestjs/schematics": "^10.0.1", - "chalk": "4.1.2", - "chokidar": "3.5.3", - "cli-table3": "0.6.3", - "commander": "4.1.1", - "fork-ts-checker-webpack-plugin": "9.0.2", - "glob": "10.3.10", - "inquirer": "8.2.6", - "node-emoji": "1.11.0", - "ora": "5.4.1", - "os-name": "4.0.1", - "rimraf": "4.4.1", - "shelljs": "0.8.5", - "source-map-support": "0.5.21", - "tree-kill": "1.2.2", - "tsconfig-paths": "4.2.0", - "tsconfig-paths-webpack-plugin": "4.1.0", - "typescript": "5.2.2", - "webpack": "5.89.0", - "webpack-node-externals": "3.0.0" - }, - "bin": { - "nest": "bin/nest.js" - }, - "engines": { - "node": ">= 16.14" - }, - "peerDependencies": { - "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.62" - }, - "peerDependenciesMeta": { - "@swc/cli": { - "optional": true - }, - "@swc/core": { - "optional": true - } - } - }, - "node_modules/@nestjs/cli/node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/@nestjs/common": { - "version": "10.2.10", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.2.10.tgz", - "integrity": "sha512-fwAk931rjW8CNH2Mgwawq/7HWHH1dxkOLdcgs7U52ddLk8CtHXjejm1cbNahewlSbNhvlOl7y1STLHutE6sUqw==", - "dependencies": { - "iterare": "1.2.1", - "tslib": "2.6.2", - "uid": "2.0.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nest" - }, - "peerDependencies": { - "class-transformer": "*", - "class-validator": "*", - "reflect-metadata": "^0.1.12", - "rxjs": "^7.1.0" - }, - "peerDependenciesMeta": { - "class-transformer": { - "optional": true - }, - "class-validator": { - "optional": true - } - } - }, - "node_modules/@nestjs/core": { - "version": "10.2.10", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.2.10.tgz", - "integrity": "sha512-+ckOI6BPi2ZMHikT9MCG4ctHDc4OnjhoIytrn7f2AYMMXI4bnutJhqyQKc30VDka5x3Wq6QAD57pgSP7y+JjJg==", - "hasInstallScript": true, - "dependencies": { - "@nuxtjs/opencollective": "0.3.2", - "fast-safe-stringify": "2.1.1", - "iterare": "1.2.1", - "path-to-regexp": "3.2.0", - "tslib": "2.6.2", - "uid": "2.0.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nest" - }, - "peerDependencies": { - "@nestjs/common": "^10.0.0", - "@nestjs/microservices": "^10.0.0", - "@nestjs/platform-express": "^10.0.0", - "@nestjs/websockets": "^10.0.0", - "reflect-metadata": "^0.1.12", - "rxjs": "^7.1.0" - }, - "peerDependenciesMeta": { - "@nestjs/microservices": { - "optional": true - }, - "@nestjs/platform-express": { - "optional": true - }, - "@nestjs/websockets": { - "optional": true - } - } - }, - "node_modules/@nestjs/mapped-types": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.0.4.tgz", - "integrity": "sha512-xl+gUSp0B+ln1VSNoUftlglk8dfpUes3DHGxKZ5knuBxS5g2H/8p9/DSBOYWUfO5f4u9s6ffBPZ71WO+tbe5SA==", - "peerDependencies": { - "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", - "class-transformer": "^0.4.0 || ^0.5.0", - "class-validator": "^0.13.0 || ^0.14.0", - "reflect-metadata": "^0.1.12" - }, - "peerDependenciesMeta": { - "class-transformer": { - "optional": true - }, - "class-validator": { - "optional": true - } - } - }, - "node_modules/@nestjs/platform-express": { - "version": "10.2.10", - "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.2.10.tgz", - "integrity": "sha512-U4KDgtMjH8TqEvt0RzC/POP8ABvL9bYoCScvlGtFSKgVGaMLBKkZ4+jHtbQx6qItYSlBBRUuz/dveMZCObfrkQ==", - "dependencies": { - "body-parser": "1.20.2", - "cors": "2.8.5", - "express": "4.18.2", - "multer": "1.4.4-lts.1", - "tslib": "2.6.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nest" - }, - "peerDependencies": { - "@nestjs/common": "^10.0.0", - "@nestjs/core": "^10.0.0" - } - }, - "node_modules/@nestjs/schedule": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@nestjs/schedule/-/schedule-4.0.0.tgz", - "integrity": "sha512-zz4h54m/F/1qyQKvMJCRphmuwGqJltDAkFxUXCVqJBXEs5kbPt93Pza3heCQOcMH22MZNhGlc9DmDMLXVHmgVQ==", - "dependencies": { - "cron": "3.1.3", - "uuid": "9.0.1" - }, - "peerDependencies": { - "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", - "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0", - "reflect-metadata": "^0.1.12" - } - }, - "node_modules/@nestjs/schematics": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-10.0.3.tgz", - "integrity": "sha512-2BRujK0GqGQ7j1Zpz+obVfskDnnOeVKt5aXoSaVngKo8Oczy8uYCY+R547TQB+Kf35epdfFER2pVnQrX3/It5A==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "16.2.8", - "@angular-devkit/schematics": "16.2.8", - "comment-json": "4.2.3", - "jsonc-parser": "3.2.0", - "pluralize": "8.0.0" - }, - "peerDependencies": { - "typescript": ">=4.8.2" - } - }, - "node_modules/@nestjs/swagger": { - "version": "7.1.16", - "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-7.1.16.tgz", - "integrity": "sha512-f9KBk/BX9MUKPTj7tQNYJ124wV/jP5W2lwWHLGwe/4qQXixuDOo39zP55HIJ44LE7S04B7BOeUOo9GBJD/vRcw==", - "dependencies": { - "@nestjs/mapped-types": "2.0.3", - "js-yaml": "4.1.0", - "lodash": "4.17.21", - "path-to-regexp": "3.2.0", - "swagger-ui-dist": "5.9.1" - }, - "peerDependencies": { - "@fastify/static": "^6.0.0", - "@nestjs/common": "^9.0.0 || ^10.0.0", - "@nestjs/core": "^9.0.0 || ^10.0.0", - "class-transformer": "*", - "class-validator": "*", - "reflect-metadata": "^0.1.12" - }, - "peerDependenciesMeta": { - "@fastify/static": { - "optional": true - }, - "class-transformer": { - "optional": true - }, - "class-validator": { - "optional": true - } - } - }, - "node_modules/@nestjs/swagger/node_modules/@nestjs/mapped-types": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.0.3.tgz", - "integrity": "sha512-40Zdqg98lqoF0+7ThWIZFStxgzisK6GG22+1ABO4kZiGF/Tu2FE+DYLw+Q9D94vcFWizJ+MSjNN4ns9r6hIGxw==", - "peerDependencies": { - "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", - "class-transformer": "^0.4.0 || ^0.5.0", - "class-validator": "^0.13.0 || ^0.14.0", - "reflect-metadata": "^0.1.12" - }, - "peerDependenciesMeta": { - "class-transformer": { - "optional": true - }, - "class-validator": { - "optional": true - } - } - }, - "node_modules/@nestjs/testing": { - "version": "10.2.10", - "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.2.10.tgz", - "integrity": "sha512-IVLUnPz/+fkBtPATYfqTIP+phN9yjkXejmj+JyhmcfPJZpxBmD1i9VSMqa4u54l37j0xkGPscQ0IXpbhqMYUKw==", - "dev": true, - "dependencies": { - "tslib": "2.6.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nest" - }, - "peerDependencies": { - "@nestjs/common": "^10.0.0", - "@nestjs/core": "^10.0.0", - "@nestjs/microservices": "^10.0.0", - "@nestjs/platform-express": "^10.0.0" - }, - "peerDependenciesMeta": { - "@nestjs/microservices": { - "optional": true - }, - "@nestjs/platform-express": { - "optional": true - } - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nuxtjs/opencollective": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz", - "integrity": "sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==", - "dependencies": { - "chalk": "^4.1.0", - "consola": "^2.15.0", - "node-fetch": "^2.6.1" - }, - "bin": { - "opencollective": "bin/opencollective.js" - }, - "engines": { - "node": ">=8.0.0", - "npm": ">=5.0.0" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@pkgr/utils": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", - "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "fast-glob": "^3.3.0", - "is-glob": "^4.0.3", - "open": "^9.1.0", - "picocolors": "^1.0.0", - "tslib": "^2.6.0" - }, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/@prisma/client": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.6.0.tgz", - "integrity": "sha512-mUDefQFa1wWqk4+JhKPYq8BdVoFk9NFMBXUI8jAkBfQTtgx8WPx02U2HB/XbAz3GSUJpeJOKJQtNvaAIDs6sug==", - "hasInstallScript": true, - "dependencies": { - "@prisma/engines-version": "5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee" - }, - "engines": { - "node": ">=16.13" - }, - "peerDependencies": { - "prisma": "*" - }, - "peerDependenciesMeta": { - "prisma": { - "optional": true - } - } - }, - "node_modules/@prisma/engines": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.6.0.tgz", - "integrity": "sha512-Mt2q+GNJpU2vFn6kif24oRSBQv1KOkYaterQsi0k2/lA+dLvhRX6Lm26gon6PYHwUM8/h8KRgXIUMU0PCLB6bw==", - "devOptional": true, - "hasInstallScript": true - }, - "node_modules/@prisma/engines-version": { - "version": "5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee.tgz", - "integrity": "sha512-UoFgbV1awGL/3wXuUK3GDaX2SolqczeeJ5b4FVec9tzeGbSWJboPSbT0psSrmgYAKiKnkOPFSLlH6+b+IyOwAw==" - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", - "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.7", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", - "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.4", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", - "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/cookiejar": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", - "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", - "dev": true - }, - "node_modules/@types/eslint": { - "version": "8.44.7", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.7.tgz", - "integrity": "sha512-f5ORu2hcBbKei97U73mf+l9t4zTGl74IqZ0GQk4oVea/VS8tQZYkUveSYojk+frraAVYId0V2WC9O4PTNru2FQ==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true - }, - "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", - "dev": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.41", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz", - "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.5.9", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.9.tgz", - "integrity": "sha512-zJeWhqBwVoPm83sP8h1/SVntwWTu5lZbKQGCvBjxQOyEWnKnsaomt2y7SlV4KfwlrHAHHAn00Sh4IAWaIsGOgQ==", - "dev": true, - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/luxon": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.5.tgz", - "integrity": "sha512-1cyf6Ge/94zlaWIZA2ei1pE6SZ8xpad2hXaYa5JEFiaUH0YS494CZwyi4MXNpXD9oEuv6ZH0Bmh0e7F9sPhmZA==" - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true - }, - "node_modules/@types/node": { - "version": "20.9.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.3.tgz", - "integrity": "sha512-nk5wXLAXGBKfrhLB0cyHGbSqopS+nz0BUgZkUQqSHSSgdee0kssp1IAqlQOu333bW+gMNs2QREx7iynm19Abxw==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/qs": { - "version": "6.9.10", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", - "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==", - "dev": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true - }, - "node_modules/@types/semver": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", - "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", - "dev": true - }, - "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", - "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", - "dev": true, - "dependencies": { - "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true - }, - "node_modules/@types/superagent": { - "version": "4.1.22", - "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.22.tgz", - "integrity": "sha512-GMaOrnnUsjChvH8zlzdDPARRXky8bU3E8xsU/fOclgqsINekbwDu1+wzJzJaGzZP91SGpOutf5Te5pm5M/qCWg==", - "dev": true, - "dependencies": { - "@types/cookiejar": "*", - "@types/node": "*" - } - }, - "node_modules/@types/supertest": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.16.tgz", - "integrity": "sha512-6c2ogktZ06tr2ENoZivgm7YnprnhYE4ZoXGMY+oA7IuAf17M8FWvujXZGmxLv8y0PTyts4x5A+erSwVUFA8XSg==", - "dev": true, - "dependencies": { - "@types/superagent": "*" - } - }, - "node_modules/@types/yargs": { - "version": "17.0.32", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", - "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.12.0.tgz", - "integrity": "sha512-XOpZ3IyJUIV1b15M7HVOpgQxPPF7lGXgsfcEIu3yDxFPaf/xZKt7s9QO/pbk7vpWQyVulpJbu4E5LwpZiQo4kA==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.12.0", - "@typescript-eslint/type-utils": "6.12.0", - "@typescript-eslint/utils": "6.12.0", - "@typescript-eslint/visitor-keys": "6.12.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.12.0.tgz", - "integrity": "sha512-s8/jNFPKPNRmXEnNXfuo1gemBdVmpQsK1pcu+QIvuNJuhFzGrpD7WjOcvDc/+uEdfzSYpNu7U/+MmbScjoQ6vg==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "6.12.0", - "@typescript-eslint/types": "6.12.0", - "@typescript-eslint/typescript-estree": "6.12.0", - "@typescript-eslint/visitor-keys": "6.12.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.12.0.tgz", - "integrity": "sha512-5gUvjg+XdSj8pcetdL9eXJzQNTl3RD7LgUiYTl8Aabdi8hFkaGSYnaS6BLc0BGNaDH+tVzVwmKtWvu0jLgWVbw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.12.0", - "@typescript-eslint/visitor-keys": "6.12.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.12.0.tgz", - "integrity": "sha512-WWmRXxhm1X8Wlquj+MhsAG4dU/Blvf1xDgGaYCzfvStP2NwPQh6KBvCDbiOEvaE0filhranjIlK/2fSTVwtBng==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "6.12.0", - "@typescript-eslint/utils": "6.12.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.12.0.tgz", - "integrity": "sha512-MA16p/+WxM5JG/F3RTpRIcuOghWO30//VEOvzubM8zuOOBYXsP+IfjoCXXiIfy2Ta8FRh9+IO9QLlaFQUU+10Q==", - "dev": true, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.12.0.tgz", - "integrity": "sha512-vw9E2P9+3UUWzhgjyyVczLWxZ3GuQNT7QpnIY3o5OMeLO/c8oHljGc8ZpryBMIyympiAAaKgw9e5Hl9dCWFOYw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.12.0", - "@typescript-eslint/visitor-keys": "6.12.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.12.0.tgz", - "integrity": "sha512-LywPm8h3tGEbgfyjYnu3dauZ0U7R60m+miXgKcZS8c7QALO9uWJdvNoP+duKTk2XMWc7/Q3d/QiCuLN9X6SWyQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.12.0", - "@typescript-eslint/types": "6.12.0", - "@typescript-eslint/typescript-estree": "6.12.0", - "semver": "^7.5.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.12.0.tgz", - "integrity": "sha512-rg3BizTZHF1k3ipn8gfrzDXXSFKyOEB5zxYXInQ6z0hUvmQlhaZQzK+YmHmNViMA9HzW5Q9+bPPt90bU6GQwyw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.12.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", - "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", - "dev": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", - "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", - "dev": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", - "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", - "dev": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", - "dev": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", - "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-opt": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6", - "@webassemblyjs/wast-printer": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", - "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", - "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", - "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", - "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-assertions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "dev": true, - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", - "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/append-field": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "node_modules/array-timsort": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", - "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/babel-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", - "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", - "dev": true, - "dependencies": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", - "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", - "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/bplist-parser": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", - "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", - "dev": true, - "dependencies": { - "big-integer": "^1.6.44" - }, - "engines": { - "node": ">= 5.10.0" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", - "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001541", - "electron-to-chromium": "^1.4.535", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.13" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "node_modules/bundle-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", - "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", - "dev": true, - "dependencies": { - "run-applescript": "^5.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dependencies": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001563", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001563.tgz", - "integrity": "sha512-na2WUmOxnwIZtwnFI2CZ/3er0wdNzU7hN+cPYz/z2ajHThnkWjNBOpEPP4n+4r2WPM847JaMotaJE3bnfzjyKw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", - "dev": true - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.1.tgz", - "integrity": "sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-table3": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", - "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" - } - }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", - "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "dev": true - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/comment-json": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.3.tgz", - "integrity": "sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw==", - "dev": true, - "dependencies": { - "array-timsort": "^1.0.3", - "core-util-is": "^1.0.3", - "esprima": "^4.0.1", - "has-own-prop": "^2.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/component-emitter": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", - "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/consola": { - "version": "2.15.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", - "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "node_modules/cookiejar": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", - "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", - "dev": true - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, - "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/create-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", - "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "prompts": "^2.0.1" - }, - "bin": { - "create-jest": "bin/create-jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cron": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/cron/-/cron-3.1.3.tgz", - "integrity": "sha512-KVxeKTKYj2eNzN4ElnT6nRSbjbfhyxR92O/Jdp6SH3pc05CDJws59jBrZWEMQlxevCiE6QUTrXy+Im3vC3oD3A==", - "dependencies": { - "@types/luxon": "~3.3.0", - "luxon": "~3.4.0" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/dedent": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", - "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", - "dev": true, - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" - }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-browser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", - "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", - "dev": true, - "dependencies": { - "bundle-name": "^3.0.0", - "default-browser-id": "^3.0.0", - "execa": "^7.1.1", - "titleize": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser-id": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", - "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", - "dev": true, - "dependencies": { - "bplist-parser": "^0.2.0", - "untildify": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/execa": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", - "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": "^14.18.0 || ^16.14.0 || >=18.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/default-browser/node_modules/human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", - "dev": true, - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/default-browser/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/default-browser/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/default-browser/node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "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/default-browser/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/default-browser/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/default-browser/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/default-browser/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/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", - "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/dezalgo": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", - "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", - "dev": true, - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "node_modules/electron-to-chromium": { - "version": "1.4.589", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.589.tgz", - "integrity": "sha512-zF6y5v/YfoFIgwf2dDfAqVlPPsyQeWNpEWXbAlDUS8Ax4Z2VoiiZpAPC0Jm9hXEkJm2vIZpwB6rc4KnLTQffbQ==", - "dev": true - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-module-lexer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", - "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz", - "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.3", - "@eslint/js": "8.54.0", - "@humanwhocodes/config-array": "^0.11.13", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", - "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz", - "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.5" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "engines": { - "node": ">=0.8.x" - } - }, - "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/execa/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/express/node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, - "node_modules/express/node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/figures/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flat-cache/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true - }, - "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/fork-ts-checker-webpack-plugin": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.0.2.tgz", - "integrity": "sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "chalk": "^4.1.2", - "chokidar": "^3.5.3", - "cosmiconfig": "^8.2.0", - "deepmerge": "^4.2.2", - "fs-extra": "^10.0.0", - "memfs": "^3.4.1", - "minimatch": "^3.0.4", - "node-abort-controller": "^3.0.1", - "schema-utils": "^3.1.1", - "semver": "^7.3.5", - "tapable": "^2.2.1" - }, - "engines": { - "node": ">=12.13.0", - "yarn": ">=1.0.0" - }, - "peerDependencies": { - "typescript": ">3.6.0", - "webpack": "^5.11.0" - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/formidable": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", - "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", - "dev": true, - "dependencies": { - "dezalgo": "^1.0.4", - "hexoid": "^1.0.0", - "once": "^1.4.0", - "qs": "^6.11.0" - }, - "funding": { - "url": "https://ko-fi.com/tunnckoCore/commissions" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/fs-monkey": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", - "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dependencies": { - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "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/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-own-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz", - "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", - "dependencies": { - "get-intrinsic": "^1.2.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hexoid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", - "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/inquirer": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", - "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^6.0.1" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dev": true, - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/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/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-wsl/node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz", - "integrity": "sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/iterare": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", - "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "dev": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", - "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", - "dev": true, - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/types": "^29.6.3", - "import-local": "^3.0.2", - "jest-cli": "^29.7.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", - "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", - "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^1.0.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.7.0", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.7.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", - "dev": true, - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", - "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-jest": "^29.7.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-config/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", - "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", - "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "jest-util": "^29.7.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", - "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", - "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", - "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", - "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", - "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.6.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", - "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", - "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", - "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", - "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", - "dev": true, - "dependencies": { - "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", - "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/environment": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-leak-detector": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-resolve": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-util": "^29.7.0", - "jest-watcher": "^29.7.0", - "jest-worker": "^29.7.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-runner/node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", - "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/globals": "^29.7.0", - "@jest/source-map": "^29.6.3", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/jest-snapshot": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", - "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.7.0", - "semver": "^7.5.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", - "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.7.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/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/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/luxon": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", - "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/macos-release": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.5.1.tgz", - "integrity": "sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/magic-string": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz", - "integrity": "sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", - "dev": true, - "dependencies": { - "fs-monkey": "^1.0.4" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/multer": { - "version": "1.4.4-lts.1", - "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz", - "integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==", - "dependencies": { - "append-field": "^1.0.0", - "busboy": "^1.0.0", - "concat-stream": "^1.5.2", - "mkdirp": "^0.5.4", - "object-assign": "^4.1.1", - "type-is": "^1.6.4", - "xtend": "^4.0.0" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/node-abort-controller": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", - "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", - "dev": true - }, - "node_modules/node-emoji": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", - "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", - "dev": true, - "dependencies": { - "lodash": "^4.17.21" - } - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", - "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", - "dev": true, - "dependencies": { - "default-browser": "^4.0.0", - "define-lazy-prop": "^3.0.0", - "is-inside-container": "^1.0.0", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/os-name": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/os-name/-/os-name-4.0.1.tgz", - "integrity": "sha512-xl9MAoU97MH1Xt5K9ERft2YfCAoaO6msy1OBA0ozxEC0x0TmIoE6K3QvgJMMZA9yKGLmHXNY/YZoDbiGDj4zYw==", - "dev": true, - "dependencies": { - "macos-release": "^2.5.0", - "windows-release": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-scurry": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", - "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", - "dev": true, - "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.3.tgz", - "integrity": "sha512-B7gr+F6MkqB3uzINHXNctGieGsRTMwIBgxkp0yq/5BwcuDzD4A8wQpHQW6vDAm1uKSLQghmRdD9sKqf2vJ1cEg==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/path-to-regexp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.2.0.tgz", - "integrity": "sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==" - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/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/pkg-dir/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/pkg-dir/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/pkg-dir/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/pluralize": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", - "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prisma": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.6.0.tgz", - "integrity": "sha512-EEaccku4ZGshdr2cthYHhf7iyvCcXqwJDvnoQRAJg5ge2Tzpv0e2BaMCp+CbbDUwoVTzwgOap9Zp+d4jFa2O9A==", - "devOptional": true, - "hasInstallScript": true, - "dependencies": { - "@prisma/engines": "5.6.0" - }, - "bin": { - "prisma": "build/index.js" - }, - "engines": { - "node": ">=16.13" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pure-rand": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", - "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ] - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dev": true, - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/reflect-metadata": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/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/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/restore-cursor/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", - "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", - "dev": true, - "dependencies": { - "glob": "^9.2.0" - }, - "bin": { - "rimraf": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "9.3.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", - "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "minimatch": "^8.0.2", - "minipass": "^4.2.4", - "path-scurry": "^1.6.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", - "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minipass": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", - "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/run-applescript": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", - "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", - "dev": true, - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/schema-utils/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/schema-utils/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/schema-utils/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/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/semver/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/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-function-length": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", - "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", - "dependencies": { - "define-data-property": "^1.1.1", - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dev": true, - "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/shelljs/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/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/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/superagent": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", - "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==", - "dev": true, - "dependencies": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.4", - "debug": "^4.3.4", - "fast-safe-stringify": "^2.1.1", - "form-data": "^4.0.0", - "formidable": "^2.1.2", - "methods": "^1.1.2", - "mime": "2.6.0", - "qs": "^6.11.0", - "semver": "^7.3.8" - }, - "engines": { - "node": ">=6.4.0 <13 || >=14" - } - }, - "node_modules/superagent/node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/supertest": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.3.tgz", - "integrity": "sha512-EMCG6G8gDu5qEqRQ3JjjPs6+FYT1a7Hv5ApHvtSghmOFJYtsU5S+pSb6Y2EUeCEY3CmEL3mmQ8YWlPOzQomabA==", - "dev": true, - "dependencies": { - "methods": "^1.1.2", - "superagent": "^8.0.5" - }, - "engines": { - "node": ">=6.4.0" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/swagger-ui-dist": { - "version": "5.9.1", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.9.1.tgz", - "integrity": "sha512-5zAx+hUwJb9T3EAntc7TqYkV716CMqG6sZpNlAAMOMWkNXRYxGkN8ADIvD55dQZ10LxN90ZM/TQmN7y1gpICnw==" - }, - "node_modules/symbol-observable": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", - "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/synckit": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", - "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", - "dev": true, - "dependencies": { - "@pkgr/utils": "^2.3.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/terser": { - "version": "5.24.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz", - "integrity": "sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==", - "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.9", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", - "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.16.8" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser-webpack-plugin/node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/terser-webpack-plugin/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "node_modules/titleize": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", - "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", - "dev": true, - "engines": { - "node": ">=16.13.0" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/ts-jest": { - "version": "29.1.1", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", - "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", - "dev": true, - "dependencies": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^29.0.0", - "json5": "^2.2.3", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "^7.5.3", - "yargs-parser": "^21.0.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3 <6" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/ts-loader": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", - "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.0.0", - "micromatch": "^4.0.0", - "semver": "^7.3.4", - "source-map": "^0.7.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "typescript": "*", - "webpack": "^5.0.0" - } - }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "dev": true, - "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tsconfig-paths-webpack-plugin": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.1.0.tgz", - "integrity": "sha512-xWFISjviPydmtmgeUAuXp4N1fky+VCtfhOkDUFIv5ea7p4wuTomI4QTrXvFBX2S4jZsmyTSrStQl+E+4w+RzxA==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.7.0", - "tsconfig-paths": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" - }, - "node_modules/typescript": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", - "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/uid": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", - "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", - "dependencies": { - "@lukeed/csprng": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/v8-to-istanbul": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", - "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dev": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/webpack": { - "version": "5.89.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", - "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", - "dev": true, - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "^1.11.5", - "@webassemblyjs/wasm-edit": "^1.11.5", - "@webassemblyjs/wasm-parser": "^1.11.5", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.15.0", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-node-externals": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz", - "integrity": "sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/webpack/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/windows-release": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-4.0.0.tgz", - "integrity": "sha512-OxmV4wzDKB1x7AZaZgXMVsdJ1qER1ed83ZrTYd5Bwq2HfJVg3DJS8nqlAG4sMoJ7mu8cuRmLEYyU13BKwctRAg==", - "dev": true, - "dependencies": { - "execa": "^4.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/windows-release/node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/windows-release/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/windows-release/node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true, - "engines": { - "node": ">=8.12.0" - } - }, - "node_modules/windows-release/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/write-file-atomic/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/nestjs-BE/cache-server/package.json b/nestjs-BE/cache-server/package.json deleted file mode 100644 index 2b297eff..00000000 --- a/nestjs-BE/cache-server/package.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "name": "cache-server", - "version": "0.0.1", - "description": "", - "author": "", - "private": true, - "license": "UNLICENSED", - "scripts": { - "build": "nest build", - "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", - "start": "nest start", - "start:dev": "nest start --watch", - "start:debug": "nest start --debug --watch", - "start:prod": "node dist/main", - "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", - "test": "jest", - "test:watch": "jest --watch", - "test:cov": "jest --coverage", - "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", - "test:e2e": "jest --config ./test/jest-e2e.json" - }, - "dependencies": { - "@nestjs/common": "^10.0.0", - "@nestjs/core": "^10.0.0", - "@nestjs/mapped-types": "*", - "@nestjs/platform-express": "^10.0.0", - "@nestjs/schedule": "^4.0.0", - "@nestjs/swagger": "^7.1.16", - "@prisma/client": "^5.6.0", - "reflect-metadata": "^0.1.13", - "rxjs": "^7.8.1", - "uuid": "^9.0.1" - }, - "devDependencies": { - "@nestjs/cli": "^10.0.0", - "@nestjs/schematics": "^10.0.0", - "@nestjs/testing": "^10.0.0", - "@types/express": "^4.17.17", - "@types/jest": "^29.5.2", - "@types/node": "^20.3.1", - "@types/supertest": "^2.0.12", - "@typescript-eslint/eslint-plugin": "^6.0.0", - "@typescript-eslint/parser": "^6.0.0", - "eslint": "^8.42.0", - "eslint-config-prettier": "^9.0.0", - "eslint-plugin-prettier": "^5.0.0", - "jest": "^29.5.0", - "prettier": "^3.0.0", - "prisma": "^5.6.0", - "source-map-support": "^0.5.21", - "supertest": "^6.3.3", - "ts-jest": "^29.1.0", - "ts-loader": "^9.4.3", - "ts-node": "^10.9.1", - "tsconfig-paths": "^4.2.0", - "typescript": "^5.1.3" - }, - "jest": { - "moduleFileExtensions": [ - "js", - "json", - "ts" - ], - "rootDir": "src", - "testRegex": ".*\\.spec\\.ts$", - "transform": { - "^.+\\.(t|j)s$": "ts-jest" - }, - "collectCoverageFrom": [ - "**/*.(t|j)s" - ], - "coverageDirectory": "../coverage", - "testEnvironment": "node" - } -} diff --git a/nestjs-BE/cache-server/src/app.controller.spec.ts b/nestjs-BE/cache-server/src/app.controller.spec.ts deleted file mode 100644 index d22f3890..00000000 --- a/nestjs-BE/cache-server/src/app.controller.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { AppController } from './app.controller'; -import { AppService } from './app.service'; - -describe('AppController', () => { - let appController: AppController; - - beforeEach(async () => { - const app: TestingModule = await Test.createTestingModule({ - controllers: [AppController], - providers: [AppService], - }).compile(); - - appController = app.get(AppController); - }); - - describe('root', () => { - it('should return "Hello World!"', () => { - expect(appController.getHello()).toBe('Hello World!'); - }); - }); -}); diff --git a/nestjs-BE/cache-server/src/app.controller.ts b/nestjs-BE/cache-server/src/app.controller.ts deleted file mode 100644 index c73d6d8d..00000000 --- a/nestjs-BE/cache-server/src/app.controller.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Controller } from '@nestjs/common'; -import { AppService } from './app.service'; - -@Controller() -export class AppController { - constructor(private readonly appService: AppService) {} -} diff --git a/nestjs-BE/cache-server/src/app.module.ts b/nestjs-BE/cache-server/src/app.module.ts deleted file mode 100644 index 70b5f4ab..00000000 --- a/nestjs-BE/cache-server/src/app.module.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Module } from '@nestjs/common'; -import { AppController } from './app.controller'; -import { AppService } from './app.service'; -import { UsersModule } from './users/users.module'; -import { PrismaModule } from './prisma/prisma.module'; -import { TemporaryDatabaseModule } from './temporary-database/temporary-database.module'; -import { ScheduleModule } from '@nestjs/schedule'; -import { ProfilesModule } from './profiles/profiles.module'; -import { SpacesModule } from './spaces/spaces.module'; -import { BoardsModule } from './boards/boards.module'; - -@Module({ - imports: [ - UsersModule, - PrismaModule, - TemporaryDatabaseModule, - ScheduleModule.forRoot(), - ProfilesModule, - SpacesModule, - BoardsModule, - ], - controllers: [AppController], - providers: [AppService], -}) -export class AppModule {} diff --git a/nestjs-BE/cache-server/src/app.service.ts b/nestjs-BE/cache-server/src/app.service.ts deleted file mode 100644 index 7263d33a..00000000 --- a/nestjs-BE/cache-server/src/app.service.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -@Injectable() -export class AppService {} diff --git a/nestjs-BE/cache-server/src/main.ts b/nestjs-BE/cache-server/src/main.ts deleted file mode 100644 index 3d99452a..00000000 --- a/nestjs-BE/cache-server/src/main.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { NestFactory } from '@nestjs/core'; -import { AppModule } from './app.module'; -import { SwaggerModule } from '@nestjs/swagger'; -import { swaggerConfig } from './config/swagger'; -import { PORT } from './config/magic-number'; - -async function bootstrap() { - const app = await NestFactory.create(AppModule); - const document = SwaggerModule.createDocument(app, swaggerConfig); - SwaggerModule.setup('api-docs', app, document); - - await app.listen(PORT); -} -bootstrap(); diff --git a/nestjs-BE/cache-server/src/users/users.module.ts b/nestjs-BE/cache-server/src/users/users.module.ts deleted file mode 100644 index d2a63d80..00000000 --- a/nestjs-BE/cache-server/src/users/users.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Module } from '@nestjs/common'; -import { UsersService } from './users.service'; -import { UsersController } from './users.controller'; -import { SpacesService } from 'src/spaces/spaces.service'; - -@Module({ - controllers: [UsersController], - providers: [UsersService, SpacesService], -}) -export class UsersModule {} diff --git a/nestjs-BE/cache-server/src/users/users.service.ts b/nestjs-BE/cache-server/src/users/users.service.ts deleted file mode 100644 index 7bb4ae4e..00000000 --- a/nestjs-BE/cache-server/src/users/users.service.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { PrismaServiceMySQL } from '../prisma/prisma.service'; -import { TemporaryDatabaseService } from '../temporary-database/temporary-database.service'; -import { BaseService } from '../base/base.service'; -import { USER_CACHE_SIZE } from '../config/magic-number'; -import { UpdateUserDto } from './dto/update-user.dto'; -import { ProfileSpaceDto } from 'src/profiles/dto/profile-space.dto'; -import { SpacesService } from 'src/spaces/spaces.service'; - -interface Profile { - spaces: ProfileSpaceDto[]; -} - -type IncludeObject = { - profiles: - | boolean - | { - include?: { - spaces: - | boolean - | { - include?: { - space: boolean; - }; - }; - }; - }; -}; - -interface Item extends ProfileSpaceDto { - uuid?: string; -} - -@Injectable() -export class UsersService extends BaseService { - profileTable = 'PROFILE_TB'; - profileSpaceTable = 'PROFILE_SPACE_TB'; - constructor( - protected prisma: PrismaServiceMySQL, - protected temporaryDatabaseService: TemporaryDatabaseService, - protected spacesService: SpacesService, - ) { - super({ - prisma, - temporaryDatabaseService, - cacheSize: USER_CACHE_SIZE, - className: 'USER_TB', - field: 'email', - }); - } - - generateKey(data: UpdateUserDto): string { - return data.email; - } - - async findProfiles(email: string, includeSpaces = false) { - const user = await this.getUser(email, includeSpaces); - if (!user) return; - - const profiles = user.profiles || []; - const temporaryProfiles = this.getTemporaryProfiles(user); - const combinedProfiles = [...profiles, ...temporaryProfiles]; - const mergedData = this.mergeProfileData(combinedProfiles); - - return mergedData; - } - - async getUser(email: string, includeSpaces = false) { - const includeObject: IncludeObject = { profiles: true }; - - if (includeSpaces) { - includeObject.profiles = { - include: { - spaces: { - include: { - space: true, - }, - }, - }, - }; - } - let user = await this.prisma[this.className].findUnique({ - where: { email }, - include: includeObject, - }); - if (!user) user = await super.getDataFromCacheOrDB(email); - if (user && user.profiles) { - user.profiles = this.filterNotDeleted(this.profileTable, user.profiles); - - if (includeSpaces) { - user.profiles.forEach((profile: Profile) => { - if (profile.spaces) { - profile.spaces = this.filterNotDeleted( - this.profileSpaceTable, - profile.spaces, - ); - } - }); - } - } - return user; - } - - filterNotDeleted(tableName: string, items: Item[]) { - return items.filter((item) => { - let key = item.uuid; - if (item.profile_uuid && item.space_uuid) { - key = `${item.profile_uuid}_${item.space_uuid}`; - } - - const deleteOperation = this.temporaryDatabaseService.get( - tableName, - key, - 'delete', - ); - return !deleteOperation; - }); - } - - getTemporaryProfiles(user: UpdateUserDto) { - const temporaryProfilesUuids = this.temporaryDatabaseService.getEntries( - user.uuid, - ); - const temporaryProfiles = temporaryProfilesUuids.map((uuid) => - this.temporaryDatabaseService.get(this.profileTable, uuid, 'insert'), - ); - return temporaryProfiles; - } - - mergeProfileData(combinedProfiles: UpdateUserDto[]) { - const mergedData = combinedProfiles.map((data) => { - const updateOperation = this.temporaryDatabaseService.get( - this.profileTable, - data.uuid, - 'update', - ); - if (updateOperation) return { ...data, ...updateOperation.value }; - return data; - }); - return mergedData; - } - - async findRooms(email: string) { - const profiles = await this.findProfiles(email, true); - if (!profiles) return; - const spaceList = await profiles.reduce(async (listPromise, profile) => { - const list = await listPromise; - const spaceUuidsFromTempDB = this.temporaryDatabaseService.getEntries( - profile.uuid, - ); - profile.spaces = profile.spaces.filter((profileSpace) => { - const deleteTempData = this.temporaryDatabaseService.get( - this.profileSpaceTable, - `${profileSpace.profile_uuid}_${profileSpace.space_uuid}`, - 'delete', - ); - return !deleteTempData; - }); - const updatedSpaces = await Promise.all( - spaceUuidsFromTempDB.map(async (spaceUuid) => { - const space = - await this.spacesService.getDataFromCacheOrDB(spaceUuid); - return { space_uuid: spaceUuid, profile_uuid: profile.uuid, space }; - }), - ); - profile.spaces = [...profile.spaces, ...updatedSpaces]; - const spaces = profile.spaces - .filter((profileSpace) => profileSpace.space) - .map((profileSpace) => profileSpace.space); - - return list.concat(spaces); - }, Promise.resolve([])); - return spaceList; - } -} diff --git a/nestjs-BE/cache-server/test/app.e2e-spec.ts b/nestjs-BE/cache-server/test/app.e2e-spec.ts deleted file mode 100644 index 50cda623..00000000 --- a/nestjs-BE/cache-server/test/app.e2e-spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { INestApplication } from '@nestjs/common'; -import * as request from 'supertest'; -import { AppModule } from './../src/app.module'; - -describe('AppController (e2e)', () => { - let app: INestApplication; - - beforeEach(async () => { - const moduleFixture: TestingModule = await Test.createTestingModule({ - imports: [AppModule], - }).compile(); - - app = moduleFixture.createNestApplication(); - await app.init(); - }); - - it('/ (GET)', () => { - return request(app.getHttpServer()) - .get('/') - .expect(200) - .expect('Hello World!'); - }); -}); diff --git a/nestjs-BE/cache-server/test/jest-e2e.json b/nestjs-BE/cache-server/test/jest-e2e.json deleted file mode 100644 index e9d912f3..00000000 --- a/nestjs-BE/cache-server/test/jest-e2e.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "moduleFileExtensions": ["js", "json", "ts"], - "rootDir": ".", - "testEnvironment": "node", - "testRegex": ".e2e-spec.ts$", - "transform": { - "^.+\\.(t|j)s$": "ts-jest" - } -} diff --git a/nestjs-BE/cache-server/tsconfig.build.json b/nestjs-BE/cache-server/tsconfig.build.json deleted file mode 100644 index 64f86c6b..00000000 --- a/nestjs-BE/cache-server/tsconfig.build.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "./tsconfig.json", - "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] -} diff --git a/nestjs-BE/cache-server/tsconfig.json b/nestjs-BE/cache-server/tsconfig.json deleted file mode 100644 index 95f5641c..00000000 --- a/nestjs-BE/cache-server/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "declaration": true, - "removeComments": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "allowSyntheticDefaultImports": true, - "target": "ES2021", - "sourceMap": true, - "outDir": "./dist", - "baseUrl": "./", - "incremental": true, - "skipLibCheck": true, - "strictNullChecks": false, - "noImplicitAny": false, - "strictBindCallApply": false, - "forceConsistentCasingInFileNames": false, - "noFallthroughCasesInSwitch": false - } -} diff --git a/nestjs-BE/server/.eslintrc.js b/nestjs-BE/server/.eslintrc.js index 563a12ca..5d07f54b 100644 --- a/nestjs-BE/server/.eslintrc.js +++ b/nestjs-BE/server/.eslintrc.js @@ -23,7 +23,7 @@ module.exports = { '@typescript-eslint/no-explicit-any': 'off', 'max-depth': ['error', 3], 'no-magic-numbers': ['error', { ignore: [-1, 0, 1] }], - 'curly': ['error', 'multi', 'consistent'], + 'curly': ['error', 'multi-line', 'consistent'], 'max-params': ['error', 3], }, }; diff --git a/nestjs-BE/server/.gitignore b/nestjs-BE/server/.gitignore index 2d2fb1cc..4af1e623 100644 --- a/nestjs-BE/server/.gitignore +++ b/nestjs-BE/server/.gitignore @@ -32,3 +32,7 @@ lerna-debug.log* # Environment Variable File .env + +# csv, prisma +/operations +/prisma/generated diff --git a/nestjs-BE/server/package-lock.json b/nestjs-BE/server/package-lock.json index 0e96a0d1..ab43fc57 100644 --- a/nestjs-BE/server/package-lock.json +++ b/nestjs-BE/server/package-lock.json @@ -15,7 +15,10 @@ "@nestjs/passport": "^10.0.2", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.2.8", + "@nestjs/schedule": "^4.0.0", + "@nestjs/swagger": "^7.1.16", "@nestjs/websockets": "^10.2.8", + "@prisma/client": "^5.6.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "dotenv": "^16.3.1", @@ -41,6 +44,7 @@ "eslint-plugin-prettier": "^5.0.0", "jest": "^29.5.0", "prettier": "^3.0.0", + "prisma": "^5.6.0", "source-map-support": "^0.5.21", "supertest": "^6.3.3", "ts-jest": "^29.1.0", @@ -1668,6 +1672,25 @@ "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0" } }, + "node_modules/@nestjs/mapped-types": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.0.3.tgz", + "integrity": "sha512-40Zdqg98lqoF0+7ThWIZFStxgzisK6GG22+1ABO4kZiGF/Tu2FE+DYLw+Q9D94vcFWizJ+MSjNN4ns9r6hIGxw==", + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "class-transformer": "^0.4.0 || ^0.5.0", + "class-validator": "^0.13.0 || ^0.14.0", + "reflect-metadata": "^0.1.12" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, "node_modules/@nestjs/passport": { "version": "10.0.2", "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-10.0.2.tgz", @@ -1715,6 +1738,20 @@ "rxjs": "^7.1.0" } }, + "node_modules/@nestjs/schedule": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@nestjs/schedule/-/schedule-4.0.0.tgz", + "integrity": "sha512-zz4h54m/F/1qyQKvMJCRphmuwGqJltDAkFxUXCVqJBXEs5kbPt93Pza3heCQOcMH22MZNhGlc9DmDMLXVHmgVQ==", + "dependencies": { + "cron": "3.1.3", + "uuid": "9.0.1" + }, + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0", + "reflect-metadata": "^0.1.12" + } + }, "node_modules/@nestjs/schematics": { "version": "10.0.3", "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-10.0.3.tgz", @@ -1731,6 +1768,37 @@ "typescript": ">=4.8.2" } }, + "node_modules/@nestjs/swagger": { + "version": "7.1.16", + "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-7.1.16.tgz", + "integrity": "sha512-f9KBk/BX9MUKPTj7tQNYJ124wV/jP5W2lwWHLGwe/4qQXixuDOo39zP55HIJ44LE7S04B7BOeUOo9GBJD/vRcw==", + "dependencies": { + "@nestjs/mapped-types": "2.0.3", + "js-yaml": "4.1.0", + "lodash": "4.17.21", + "path-to-regexp": "3.2.0", + "swagger-ui-dist": "5.9.1" + }, + "peerDependencies": { + "@fastify/static": "^6.0.0", + "@nestjs/common": "^9.0.0 || ^10.0.0", + "@nestjs/core": "^9.0.0 || ^10.0.0", + "class-transformer": "*", + "class-validator": "*", + "reflect-metadata": "^0.1.12" + }, + "peerDependenciesMeta": { + "@fastify/static": { + "optional": true + }, + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, "node_modules/@nestjs/testing": { "version": "10.2.8", "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.2.8.tgz", @@ -1862,6 +1930,38 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@prisma/client": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.6.0.tgz", + "integrity": "sha512-mUDefQFa1wWqk4+JhKPYq8BdVoFk9NFMBXUI8jAkBfQTtgx8WPx02U2HB/XbAz3GSUJpeJOKJQtNvaAIDs6sug==", + "hasInstallScript": true, + "dependencies": { + "@prisma/engines-version": "5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee" + }, + "engines": { + "node": ">=16.13" + }, + "peerDependencies": { + "prisma": "*" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + } + } + }, + "node_modules/@prisma/engines": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.6.0.tgz", + "integrity": "sha512-Mt2q+GNJpU2vFn6kif24oRSBQv1KOkYaterQsi0k2/lA+dLvhRX6Lm26gon6PYHwUM8/h8KRgXIUMU0PCLB6bw==", + "devOptional": true, + "hasInstallScript": true + }, + "node_modules/@prisma/engines-version": { + "version": "5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee.tgz", + "integrity": "sha512-UoFgbV1awGL/3wXuUK3GDaX2SolqczeeJ5b4FVec9tzeGbSWJboPSbT0psSrmgYAKiKnkOPFSLlH6+b+IyOwAw==" + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -2107,6 +2207,11 @@ "@types/node": "*" } }, + "node_modules/@types/luxon": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.6.tgz", + "integrity": "sha512-LblarKeI26YsMLxHDIQ0295wPSLjkl98eNwDcVhz3zbo1H+kfnkzR01H5Ai5LBzSeddX0ZJSpGwKEZihGb5diw==" + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -2758,8 +2863,7 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/array-flatten": { "version": "1.1.1", @@ -3632,6 +3736,15 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "node_modules/cron": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/cron/-/cron-3.1.3.tgz", + "integrity": "sha512-KVxeKTKYj2eNzN4ElnT6nRSbjbfhyxR92O/Jdp6SH3pc05CDJws59jBrZWEMQlxevCiE6QUTrXy+Im3vC3oD3A==", + "dependencies": { + "@types/luxon": "~3.3.0", + "luxon": "~3.4.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -6219,7 +6332,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -6411,8 +6523,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.includes": { "version": "4.3.0", @@ -6486,6 +6597,14 @@ "yallist": "^3.0.2" } }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "engines": { + "node": ">=12" + } + }, "node_modules/macos-release": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.5.1.tgz", @@ -7287,6 +7406,22 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/prisma": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.6.0.tgz", + "integrity": "sha512-EEaccku4ZGshdr2cthYHhf7iyvCcXqwJDvnoQRAJg5ge2Tzpv0e2BaMCp+CbbDUwoVTzwgOap9Zp+d4jFa2O9A==", + "devOptional": true, + "hasInstallScript": true, + "dependencies": { + "@prisma/engines": "5.6.0" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=16.13" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -8278,6 +8413,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swagger-ui-dist": { + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.9.1.tgz", + "integrity": "sha512-5zAx+hUwJb9T3EAntc7TqYkV716CMqG6sZpNlAAMOMWkNXRYxGkN8ADIvD55dQZ10LxN90ZM/TQmN7y1gpICnw==" + }, "node_modules/symbol-observable": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", diff --git a/nestjs-BE/server/package.json b/nestjs-BE/server/package.json index 795405d1..c125a649 100644 --- a/nestjs-BE/server/package.json +++ b/nestjs-BE/server/package.json @@ -26,7 +26,10 @@ "@nestjs/passport": "^10.0.2", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.2.8", + "@nestjs/schedule": "^4.0.0", + "@nestjs/swagger": "^7.1.16", "@nestjs/websockets": "^10.2.8", + "@prisma/client": "^5.6.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "dotenv": "^16.3.1", @@ -52,6 +55,7 @@ "eslint-plugin-prettier": "^5.0.0", "jest": "^29.5.0", "prettier": "^3.0.0", + "prisma": "^5.6.0", "source-map-support": "^0.5.21", "supertest": "^6.3.3", "ts-jest": "^29.1.0", diff --git a/nestjs-BE/server/prisma/migrations/20231203062911_init/migration.sql b/nestjs-BE/server/prisma/migrations/20231203062911_init/migration.sql new file mode 100644 index 00000000..c7113828 --- /dev/null +++ b/nestjs-BE/server/prisma/migrations/20231203062911_init/migration.sql @@ -0,0 +1,46 @@ +-- CreateTable +CREATE TABLE `USER_TB` ( + `uuid` VARCHAR(32) NOT NULL, + `email` VARCHAR(191) NOT NULL, + `password` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `USER_TB_email_key`(`email`), + PRIMARY KEY (`uuid`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `PROFILE_TB` ( + `uuid` VARCHAR(32) NOT NULL, + `user_id` VARCHAR(32) NOT NULL, + `image` VARCHAR(191) NOT NULL, + `nickname` VARCHAR(191) NOT NULL, + + INDEX `PROFILE_TB_user_id_idx`(`user_id`), + PRIMARY KEY (`uuid`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `SPACE_TB` ( + `uuid` VARCHAR(32) NOT NULL, + `name` VARCHAR(191) NOT NULL, + `icon` VARCHAR(191) NOT NULL, + + PRIMARY KEY (`uuid`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `PROFILE_SPACE_TB` ( + `space_uuid` VARCHAR(32) NOT NULL, + `profile_uuid` VARCHAR(32) NOT NULL, + + PRIMARY KEY (`space_uuid`, `profile_uuid`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- AddForeignKey +ALTER TABLE `PROFILE_TB` ADD CONSTRAINT `PROFILE_TB_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `USER_TB`(`uuid`) ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `PROFILE_SPACE_TB` ADD CONSTRAINT `PROFILE_SPACE_TB_space_uuid_fkey` FOREIGN KEY (`space_uuid`) REFERENCES `SPACE_TB`(`uuid`) ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `PROFILE_SPACE_TB` ADD CONSTRAINT `PROFILE_SPACE_TB_profile_uuid_fkey` FOREIGN KEY (`profile_uuid`) REFERENCES `PROFILE_TB`(`uuid`) ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/nestjs-BE/server/prisma/migrations/migration_lock.toml b/nestjs-BE/server/prisma/migrations/migration_lock.toml new file mode 100644 index 00000000..e5a788a7 --- /dev/null +++ b/nestjs-BE/server/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "mysql" \ No newline at end of file diff --git a/nestjs-BE/cache-server/prisma/mongodb.schema.prisma b/nestjs-BE/server/prisma/mongodb.schema.prisma similarity index 100% rename from nestjs-BE/cache-server/prisma/mongodb.schema.prisma rename to nestjs-BE/server/prisma/mongodb.schema.prisma diff --git a/nestjs-BE/cache-server/prisma/mysql.schema.prisma b/nestjs-BE/server/prisma/mysql.schema.prisma similarity index 100% rename from nestjs-BE/cache-server/prisma/mysql.schema.prisma rename to nestjs-BE/server/prisma/mysql.schema.prisma diff --git a/nestjs-BE/server/src/app.module.ts b/nestjs-BE/server/src/app.module.ts index 2baa726c..d270f20b 100644 --- a/nestjs-BE/server/src/app.module.ts +++ b/nestjs-BE/server/src/app.module.ts @@ -4,9 +4,24 @@ import { AppService } from './app.service'; import { BoardGateway } from './board/board.gateway'; import { AuthModule } from './auth/auth.module'; import { UsersModule } from './users/users.module'; +import { PrismaModule } from './prisma/prisma.module'; +import { TemporaryDatabaseModule } from './temporary-database/temporary-database.module'; +import { ProfilesModule } from './profiles/profiles.module'; +import { SpacesModule } from './spaces/spaces.module'; +import { BoardsModule } from './boards/boards.module'; +import { ScheduleModule } from '@nestjs/schedule'; @Module({ - imports: [AuthModule, UsersModule], + imports: [ + AuthModule, + UsersModule, + PrismaModule, + TemporaryDatabaseModule, + ScheduleModule.forRoot(), + ProfilesModule, + SpacesModule, + BoardsModule, + ], controllers: [AppController], providers: [AppService, BoardGateway], }) diff --git a/nestjs-BE/server/src/auth/auth.controller.ts b/nestjs-BE/server/src/auth/auth.controller.ts index ee23c675..18032889 100644 --- a/nestjs-BE/server/src/auth/auth.controller.ts +++ b/nestjs-BE/server/src/auth/auth.controller.ts @@ -5,14 +5,12 @@ import { UseGuards, Get, Body, - Query, NotFoundException, } from '@nestjs/common'; import { AuthService } from './auth.service'; import { JwtAuthGuard } from './jwt-auth.guard'; import { Public } from './public.decorator'; import { KakaoUserDto } from './dto/kakao-user.dto'; -import { stringify } from 'qs'; import { UsersService } from 'src/users/users.service'; @Controller('auth') @@ -29,10 +27,10 @@ export class AuthController { kakaoUserDto.kakaoUserId, ); if (!kakaoUserAccount) throw new NotFoundException(); - let user = await this.usersService.findOne(kakaoUserAccount.email); + let user = await this.usersService.findOneByEmail(kakaoUserAccount.email); if (!user) { this.usersService.createOne(kakaoUserAccount.email); - user = await this.usersService.findOne(kakaoUserAccount.email); + user = await this.usersService.findOneByEmail(kakaoUserAccount.email); } return this.authService.login(user); } diff --git a/nestjs-BE/server/src/auth/constants.ts b/nestjs-BE/server/src/auth/constants.ts index 0a0cd1e1..a5d9e521 100644 --- a/nestjs-BE/server/src/auth/constants.ts +++ b/nestjs-BE/server/src/auth/constants.ts @@ -1,4 +1,4 @@ -import customEnv from 'config/env'; +import customEnv from 'src/config/env'; export const jwtConstants = { secret: customEnv.JWT_SECRET, diff --git a/nestjs-BE/cache-server/src/base/base.service.ts b/nestjs-BE/server/src/base/base.service.ts similarity index 100% rename from nestjs-BE/cache-server/src/base/base.service.ts rename to nestjs-BE/server/src/base/base.service.ts diff --git a/nestjs-BE/cache-server/src/boards/boards.controller.spec.ts b/nestjs-BE/server/src/boards/boards.controller.spec.ts similarity index 100% rename from nestjs-BE/cache-server/src/boards/boards.controller.spec.ts rename to nestjs-BE/server/src/boards/boards.controller.spec.ts diff --git a/nestjs-BE/cache-server/src/boards/boards.controller.ts b/nestjs-BE/server/src/boards/boards.controller.ts similarity index 100% rename from nestjs-BE/cache-server/src/boards/boards.controller.ts rename to nestjs-BE/server/src/boards/boards.controller.ts diff --git a/nestjs-BE/cache-server/src/boards/boards.module.ts b/nestjs-BE/server/src/boards/boards.module.ts similarity index 100% rename from nestjs-BE/cache-server/src/boards/boards.module.ts rename to nestjs-BE/server/src/boards/boards.module.ts diff --git a/nestjs-BE/cache-server/src/boards/boards.service.spec.ts b/nestjs-BE/server/src/boards/boards.service.spec.ts similarity index 100% rename from nestjs-BE/cache-server/src/boards/boards.service.spec.ts rename to nestjs-BE/server/src/boards/boards.service.spec.ts diff --git a/nestjs-BE/cache-server/src/boards/boards.service.ts b/nestjs-BE/server/src/boards/boards.service.ts similarity index 100% rename from nestjs-BE/cache-server/src/boards/boards.service.ts rename to nestjs-BE/server/src/boards/boards.service.ts diff --git a/nestjs-BE/cache-server/src/boards/dto/create-board.dto.ts b/nestjs-BE/server/src/boards/dto/create-board.dto.ts similarity index 100% rename from nestjs-BE/cache-server/src/boards/dto/create-board.dto.ts rename to nestjs-BE/server/src/boards/dto/create-board.dto.ts diff --git a/nestjs-BE/cache-server/src/boards/dto/update-board.dto.ts b/nestjs-BE/server/src/boards/dto/update-board.dto.ts similarity index 100% rename from nestjs-BE/cache-server/src/boards/dto/update-board.dto.ts rename to nestjs-BE/server/src/boards/dto/update-board.dto.ts diff --git a/nestjs-BE/cache-server/src/boards/entities/board.entity.ts b/nestjs-BE/server/src/boards/entities/board.entity.ts similarity index 100% rename from nestjs-BE/cache-server/src/boards/entities/board.entity.ts rename to nestjs-BE/server/src/boards/entities/board.entity.ts diff --git a/nestjs-BE/server/config/env.ts b/nestjs-BE/server/src/config/env.ts similarity index 100% rename from nestjs-BE/server/config/env.ts rename to nestjs-BE/server/src/config/env.ts diff --git a/nestjs-BE/cache-server/src/config/magic-number.ts b/nestjs-BE/server/src/config/magic-number.ts similarity index 100% rename from nestjs-BE/cache-server/src/config/magic-number.ts rename to nestjs-BE/server/src/config/magic-number.ts diff --git a/nestjs-BE/cache-server/src/config/swagger.ts b/nestjs-BE/server/src/config/swagger.ts similarity index 100% rename from nestjs-BE/cache-server/src/config/swagger.ts rename to nestjs-BE/server/src/config/swagger.ts diff --git a/nestjs-BE/server/crdt/clock.ts b/nestjs-BE/server/src/crdt/clock.ts similarity index 97% rename from nestjs-BE/server/crdt/clock.ts rename to nestjs-BE/server/src/crdt/clock.ts index 4a78508d..975a329f 100644 --- a/nestjs-BE/server/crdt/clock.ts +++ b/nestjs-BE/server/src/crdt/clock.ts @@ -26,8 +26,9 @@ export class Clock { compare(remoteClock: Clock): COMPARE { if (this.counter > remoteClock.counter) return COMPARE.GREATER; - if (this.counter === remoteClock.counter && this.id > remoteClock.id) + if (this.counter === remoteClock.counter && this.id > remoteClock.id) { return COMPARE.GREATER; + } return COMPARE.LESS; } } diff --git a/nestjs-BE/server/crdt/crdt-tree.ts b/nestjs-BE/server/src/crdt/crdt-tree.ts similarity index 100% rename from nestjs-BE/server/crdt/crdt-tree.ts rename to nestjs-BE/server/src/crdt/crdt-tree.ts diff --git a/nestjs-BE/server/crdt/node.ts b/nestjs-BE/server/src/crdt/node.ts similarity index 100% rename from nestjs-BE/server/crdt/node.ts rename to nestjs-BE/server/src/crdt/node.ts diff --git a/nestjs-BE/server/crdt/operation.ts b/nestjs-BE/server/src/crdt/operation.ts similarity index 100% rename from nestjs-BE/server/crdt/operation.ts rename to nestjs-BE/server/src/crdt/operation.ts diff --git a/nestjs-BE/server/crdt/tree.ts b/nestjs-BE/server/src/crdt/tree.ts similarity index 100% rename from nestjs-BE/server/crdt/tree.ts rename to nestjs-BE/server/src/crdt/tree.ts diff --git a/nestjs-BE/server/src/main.ts b/nestjs-BE/server/src/main.ts index e45fec4a..af82ed33 100644 --- a/nestjs-BE/server/src/main.ts +++ b/nestjs-BE/server/src/main.ts @@ -1,9 +1,14 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; -import customEnv from 'config/env'; +import { SwaggerModule } from '@nestjs/swagger'; +import { swaggerConfig } from './config/swagger'; +import customEnv from 'src/config/env'; async function bootstrap() { const app = await NestFactory.create(AppModule); + const document = SwaggerModule.createDocument(app, swaggerConfig); + SwaggerModule.setup('api-docs', app, document); + await app.listen(customEnv.SERVER_PORT); } bootstrap(); diff --git a/nestjs-BE/cache-server/src/prisma/prisma.module.ts b/nestjs-BE/server/src/prisma/prisma.module.ts similarity index 100% rename from nestjs-BE/cache-server/src/prisma/prisma.module.ts rename to nestjs-BE/server/src/prisma/prisma.module.ts diff --git a/nestjs-BE/cache-server/src/prisma/prisma.service.spec.ts b/nestjs-BE/server/src/prisma/prisma.service.spec.ts similarity index 100% rename from nestjs-BE/cache-server/src/prisma/prisma.service.spec.ts rename to nestjs-BE/server/src/prisma/prisma.service.spec.ts diff --git a/nestjs-BE/cache-server/src/prisma/prisma.service.ts b/nestjs-BE/server/src/prisma/prisma.service.ts similarity index 100% rename from nestjs-BE/cache-server/src/prisma/prisma.service.ts rename to nestjs-BE/server/src/prisma/prisma.service.ts diff --git a/nestjs-BE/cache-server/src/profiles/dto/create-profile.dto.ts b/nestjs-BE/server/src/profiles/dto/create-profile.dto.ts similarity index 100% rename from nestjs-BE/cache-server/src/profiles/dto/create-profile.dto.ts rename to nestjs-BE/server/src/profiles/dto/create-profile.dto.ts diff --git a/nestjs-BE/cache-server/src/profiles/dto/profile-space.dto.ts b/nestjs-BE/server/src/profiles/dto/profile-space.dto.ts similarity index 100% rename from nestjs-BE/cache-server/src/profiles/dto/profile-space.dto.ts rename to nestjs-BE/server/src/profiles/dto/profile-space.dto.ts diff --git a/nestjs-BE/cache-server/src/profiles/dto/update-profile.dto.ts b/nestjs-BE/server/src/profiles/dto/update-profile.dto.ts similarity index 100% rename from nestjs-BE/cache-server/src/profiles/dto/update-profile.dto.ts rename to nestjs-BE/server/src/profiles/dto/update-profile.dto.ts diff --git a/nestjs-BE/cache-server/src/profiles/entities/profile.entity.ts b/nestjs-BE/server/src/profiles/entities/profile.entity.ts similarity index 100% rename from nestjs-BE/cache-server/src/profiles/entities/profile.entity.ts rename to nestjs-BE/server/src/profiles/entities/profile.entity.ts diff --git a/nestjs-BE/cache-server/src/profiles/profiles.controller.spec.ts b/nestjs-BE/server/src/profiles/profiles.controller.spec.ts similarity index 100% rename from nestjs-BE/cache-server/src/profiles/profiles.controller.spec.ts rename to nestjs-BE/server/src/profiles/profiles.controller.spec.ts diff --git a/nestjs-BE/cache-server/src/profiles/profiles.controller.ts b/nestjs-BE/server/src/profiles/profiles.controller.ts similarity index 100% rename from nestjs-BE/cache-server/src/profiles/profiles.controller.ts rename to nestjs-BE/server/src/profiles/profiles.controller.ts diff --git a/nestjs-BE/cache-server/src/profiles/profiles.module.ts b/nestjs-BE/server/src/profiles/profiles.module.ts similarity index 100% rename from nestjs-BE/cache-server/src/profiles/profiles.module.ts rename to nestjs-BE/server/src/profiles/profiles.module.ts diff --git a/nestjs-BE/cache-server/src/profiles/profiles.service.spec.ts b/nestjs-BE/server/src/profiles/profiles.service.spec.ts similarity index 100% rename from nestjs-BE/cache-server/src/profiles/profiles.service.spec.ts rename to nestjs-BE/server/src/profiles/profiles.service.spec.ts diff --git a/nestjs-BE/cache-server/src/profiles/profiles.service.ts b/nestjs-BE/server/src/profiles/profiles.service.ts similarity index 100% rename from nestjs-BE/cache-server/src/profiles/profiles.service.ts rename to nestjs-BE/server/src/profiles/profiles.service.ts diff --git a/nestjs-BE/cache-server/src/spaces/dto/create-space.dto.ts b/nestjs-BE/server/src/spaces/dto/create-space.dto.ts similarity index 100% rename from nestjs-BE/cache-server/src/spaces/dto/create-space.dto.ts rename to nestjs-BE/server/src/spaces/dto/create-space.dto.ts diff --git a/nestjs-BE/cache-server/src/spaces/dto/update-space.dto.ts b/nestjs-BE/server/src/spaces/dto/update-space.dto.ts similarity index 100% rename from nestjs-BE/cache-server/src/spaces/dto/update-space.dto.ts rename to nestjs-BE/server/src/spaces/dto/update-space.dto.ts diff --git a/nestjs-BE/cache-server/src/spaces/entities/space.entity.ts b/nestjs-BE/server/src/spaces/entities/space.entity.ts similarity index 100% rename from nestjs-BE/cache-server/src/spaces/entities/space.entity.ts rename to nestjs-BE/server/src/spaces/entities/space.entity.ts diff --git a/nestjs-BE/cache-server/src/spaces/spaces.controller.spec.ts b/nestjs-BE/server/src/spaces/spaces.controller.spec.ts similarity index 100% rename from nestjs-BE/cache-server/src/spaces/spaces.controller.spec.ts rename to nestjs-BE/server/src/spaces/spaces.controller.spec.ts diff --git a/nestjs-BE/cache-server/src/spaces/spaces.controller.ts b/nestjs-BE/server/src/spaces/spaces.controller.ts similarity index 100% rename from nestjs-BE/cache-server/src/spaces/spaces.controller.ts rename to nestjs-BE/server/src/spaces/spaces.controller.ts diff --git a/nestjs-BE/cache-server/src/spaces/spaces.module.ts b/nestjs-BE/server/src/spaces/spaces.module.ts similarity index 100% rename from nestjs-BE/cache-server/src/spaces/spaces.module.ts rename to nestjs-BE/server/src/spaces/spaces.module.ts diff --git a/nestjs-BE/cache-server/src/spaces/spaces.service.spec.ts b/nestjs-BE/server/src/spaces/spaces.service.spec.ts similarity index 100% rename from nestjs-BE/cache-server/src/spaces/spaces.service.spec.ts rename to nestjs-BE/server/src/spaces/spaces.service.spec.ts diff --git a/nestjs-BE/cache-server/src/spaces/spaces.service.ts b/nestjs-BE/server/src/spaces/spaces.service.ts similarity index 100% rename from nestjs-BE/cache-server/src/spaces/spaces.service.ts rename to nestjs-BE/server/src/spaces/spaces.service.ts diff --git a/nestjs-BE/cache-server/src/temporary-database/temporary-database.module.ts b/nestjs-BE/server/src/temporary-database/temporary-database.module.ts similarity index 100% rename from nestjs-BE/cache-server/src/temporary-database/temporary-database.module.ts rename to nestjs-BE/server/src/temporary-database/temporary-database.module.ts diff --git a/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.spec.ts b/nestjs-BE/server/src/temporary-database/temporary-database.service.spec.ts similarity index 100% rename from nestjs-BE/cache-server/src/temporary-database/temporary-database.service.spec.ts rename to nestjs-BE/server/src/temporary-database/temporary-database.service.spec.ts diff --git a/nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts b/nestjs-BE/server/src/temporary-database/temporary-database.service.ts similarity index 100% rename from nestjs-BE/cache-server/src/temporary-database/temporary-database.service.ts rename to nestjs-BE/server/src/temporary-database/temporary-database.service.ts diff --git a/nestjs-BE/cache-server/src/users/dto/create-user.dto.ts b/nestjs-BE/server/src/users/dto/create-user.dto.ts similarity index 100% rename from nestjs-BE/cache-server/src/users/dto/create-user.dto.ts rename to nestjs-BE/server/src/users/dto/create-user.dto.ts diff --git a/nestjs-BE/cache-server/src/users/dto/update-user.dto.ts b/nestjs-BE/server/src/users/dto/update-user.dto.ts similarity index 100% rename from nestjs-BE/cache-server/src/users/dto/update-user.dto.ts rename to nestjs-BE/server/src/users/dto/update-user.dto.ts diff --git a/nestjs-BE/cache-server/src/users/entities/user.entity.ts b/nestjs-BE/server/src/users/entities/user.entity.ts similarity index 100% rename from nestjs-BE/cache-server/src/users/entities/user.entity.ts rename to nestjs-BE/server/src/users/entities/user.entity.ts diff --git a/nestjs-BE/cache-server/src/users/users.controller.spec.ts b/nestjs-BE/server/src/users/users.controller.spec.ts similarity index 100% rename from nestjs-BE/cache-server/src/users/users.controller.spec.ts rename to nestjs-BE/server/src/users/users.controller.spec.ts diff --git a/nestjs-BE/cache-server/src/users/users.controller.ts b/nestjs-BE/server/src/users/users.controller.ts similarity index 97% rename from nestjs-BE/cache-server/src/users/users.controller.ts rename to nestjs-BE/server/src/users/users.controller.ts index 4a188ec0..99ad92cc 100644 --- a/nestjs-BE/cache-server/src/users/users.controller.ts +++ b/nestjs-BE/server/src/users/users.controller.ts @@ -11,12 +11,14 @@ import { UsersService } from './users.service'; import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; +import { Public } from 'src/auth/public.decorator'; @Controller('users') @ApiTags('users') export class UsersController { constructor(private readonly usersService: UsersService) {} + @Public() @Post() @ApiOperation({ summary: 'Create user' }) @ApiResponse({ @@ -35,6 +37,7 @@ export class UsersController { return this.usersService.create(createUserDto); } + @Public() @Get(':email') @ApiOperation({ summary: 'Get user' }) @ApiResponse({ diff --git a/nestjs-BE/server/src/users/users.module.ts b/nestjs-BE/server/src/users/users.module.ts index 8fa904f1..89102492 100644 --- a/nestjs-BE/server/src/users/users.module.ts +++ b/nestjs-BE/server/src/users/users.module.ts @@ -1,8 +1,11 @@ import { Module } from '@nestjs/common'; import { UsersService } from './users.service'; +import { UsersController } from './users.controller'; +import { SpacesService } from 'src/spaces/spaces.service'; @Module({ - providers: [UsersService], + controllers: [UsersController], + providers: [UsersService, SpacesService], exports: [UsersService], }) export class UsersModule {} diff --git a/nestjs-BE/cache-server/src/users/users.service.spec.ts b/nestjs-BE/server/src/users/users.service.spec.ts similarity index 100% rename from nestjs-BE/cache-server/src/users/users.service.spec.ts rename to nestjs-BE/server/src/users/users.service.spec.ts diff --git a/nestjs-BE/server/src/users/users.service.ts b/nestjs-BE/server/src/users/users.service.ts index 4d553421..943ba54c 100644 --- a/nestjs-BE/server/src/users/users.service.ts +++ b/nestjs-BE/server/src/users/users.service.ts @@ -1,20 +1,191 @@ import { Injectable } from '@nestjs/common'; +import { PrismaServiceMySQL } from '../prisma/prisma.service'; +import { TemporaryDatabaseService } from '../temporary-database/temporary-database.service'; +import { BaseService } from '../base/base.service'; +import { USER_CACHE_SIZE } from '../config/magic-number'; +import { UpdateUserDto } from './dto/update-user.dto'; +import { ProfileSpaceDto } from 'src/profiles/dto/profile-space.dto'; +import { SpacesService } from 'src/spaces/spaces.service'; import { v4 } from 'uuid'; +interface Profile { + spaces: ProfileSpaceDto[]; +} + +type IncludeObject = { + profiles: + | boolean + | { + include?: { + spaces: + | boolean + | { + include?: { + space: boolean; + }; + }; + }; + }; +}; + +interface Item extends ProfileSpaceDto { + uuid?: string; +} + export type User = { uuid: string; email: string; }; @Injectable() -export class UsersService { +export class UsersService extends BaseService { + profileTable = 'PROFILE_TB'; + profileSpaceTable = 'PROFILE_SPACE_TB'; + constructor( + protected prisma: PrismaServiceMySQL, + protected temporaryDatabaseService: TemporaryDatabaseService, + protected spacesService: SpacesService, + ) { + super({ + prisma, + temporaryDatabaseService, + cacheSize: USER_CACHE_SIZE, + className: 'USER_TB', + field: 'email', + }); + } + private readonly users: User[] = []; - async findOne(email: string): Promise { + async findOneByEmail(email: string): Promise { return this.users.find((user) => user.email === email); } createOne(email: string) { this.users.push({ uuid: v4(), email }); } + + generateKey(data: UpdateUserDto): string { + return data.email; + } + + async findProfiles(email: string, includeSpaces = false) { + const user = await this.getUser(email, includeSpaces); + if (!user) return; + + const profiles = user.profiles || []; + const temporaryProfiles = this.getTemporaryProfiles(user); + const combinedProfiles = [...profiles, ...temporaryProfiles]; + const mergedData = this.mergeProfileData(combinedProfiles); + + return mergedData; + } + + async getUser(email: string, includeSpaces = false) { + const includeObject: IncludeObject = { profiles: true }; + + if (includeSpaces) { + includeObject.profiles = { + include: { + spaces: { + include: { + space: true, + }, + }, + }, + }; + } + let user = await this.prisma[this.className].findUnique({ + where: { email }, + include: includeObject, + }); + if (!user) user = await super.getDataFromCacheOrDB(email); + if (user && user.profiles) { + user.profiles = this.filterNotDeleted(this.profileTable, user.profiles); + + if (includeSpaces) { + user.profiles.forEach((profile: Profile) => { + if (profile.spaces) { + profile.spaces = this.filterNotDeleted( + this.profileSpaceTable, + profile.spaces, + ); + } + }); + } + } + return user; + } + + filterNotDeleted(tableName: string, items: Item[]) { + return items.filter((item) => { + let key = item.uuid; + if (item.profile_uuid && item.space_uuid) { + key = `${item.profile_uuid}_${item.space_uuid}`; + } + + const deleteOperation = this.temporaryDatabaseService.get( + tableName, + key, + 'delete', + ); + return !deleteOperation; + }); + } + + getTemporaryProfiles(user: UpdateUserDto) { + const temporaryProfilesUuids = this.temporaryDatabaseService.getEntries( + user.uuid, + ); + const temporaryProfiles = temporaryProfilesUuids.map((uuid) => + this.temporaryDatabaseService.get(this.profileTable, uuid, 'insert'), + ); + return temporaryProfiles; + } + + mergeProfileData(combinedProfiles: UpdateUserDto[]) { + const mergedData = combinedProfiles.map((data) => { + const updateOperation = this.temporaryDatabaseService.get( + this.profileTable, + data.uuid, + 'update', + ); + if (updateOperation) return { ...data, ...updateOperation.value }; + return data; + }); + return mergedData; + } + + async findRooms(email: string) { + const profiles = await this.findProfiles(email, true); + if (!profiles) return; + const spaceList = await profiles.reduce(async (listPromise, profile) => { + const list = await listPromise; + const spaceUuidsFromTempDB = this.temporaryDatabaseService.getEntries( + profile.uuid, + ); + profile.spaces = profile.spaces.filter((profileSpace) => { + const deleteTempData = this.temporaryDatabaseService.get( + this.profileSpaceTable, + `${profileSpace.profile_uuid}_${profileSpace.space_uuid}`, + 'delete', + ); + return !deleteTempData; + }); + const updatedSpaces = await Promise.all( + spaceUuidsFromTempDB.map(async (spaceUuid) => { + const space = + await this.spacesService.getDataFromCacheOrDB(spaceUuid); + return { space_uuid: spaceUuid, profile_uuid: profile.uuid, space }; + }), + ); + profile.spaces = [...profile.spaces, ...updatedSpaces]; + const spaces = profile.spaces + .filter((profileSpace) => profileSpace.space) + .map((profileSpace) => profileSpace.space); + + return list.concat(spaces); + }, Promise.resolve([])); + return spaceList; + } } diff --git a/nestjs-BE/cache-server/src/utils/lru-cache.ts b/nestjs-BE/server/src/utils/lru-cache.ts similarity index 100% rename from nestjs-BE/cache-server/src/utils/lru-cache.ts rename to nestjs-BE/server/src/utils/lru-cache.ts diff --git a/nestjs-BE/cache-server/src/utils/uuid.ts b/nestjs-BE/server/src/utils/uuid.ts similarity index 100% rename from nestjs-BE/cache-server/src/utils/uuid.ts rename to nestjs-BE/server/src/utils/uuid.ts From 63517e6e6732c0f0de5dbd1b70452c810e30558d Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Sun, 3 Dec 2023 16:06:12 +0900 Subject: [PATCH 080/170] =?UTF-8?q?setting:=20=EB=8F=84=EC=BB=A4=20?= =?UTF-8?q?=EB=B9=8C=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/.dockerignore | 1 - nestjs-BE/server/Dockerfile | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/nestjs-BE/server/.dockerignore b/nestjs-BE/server/.dockerignore index 56296465..9b915193 100644 --- a/nestjs-BE/server/.dockerignore +++ b/nestjs-BE/server/.dockerignore @@ -1,5 +1,4 @@ README.md -/node_modules /test .eslintrc.js diff --git a/nestjs-BE/server/Dockerfile b/nestjs-BE/server/Dockerfile index 9b939a5c..9eb851c7 100644 --- a/nestjs-BE/server/Dockerfile +++ b/nestjs-BE/server/Dockerfile @@ -8,6 +8,12 @@ RUN npm ci COPY ./ ./ +RUN npx prisma generate --schema=./prisma/mysql.schema.prisma + +RUN npx prisma generate --schema=./prisma/mongodb.schema.prisma + +RUN mkdir operations + EXPOSE 3000 CMD ["npm", "start"] From 2ff74bcf557cd4ca511108ef21f645c35e3b2f6c Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Mon, 4 Dec 2023 10:51:12 +0900 Subject: [PATCH 081/170] =?UTF-8?q?feat:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EB=A5=BC=20=EC=9C=84=ED=95=9C=20=EC=A0=9C=ED=95=9C=20=EB=82=AE?= =?UTF-8?q?=EC=B6=94=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/auth/auth.module.ts | 2 +- nestjs-BE/server/src/boards/boards.controller.ts | 5 +++++ nestjs-BE/server/src/profiles/profiles.controller.ts | 8 ++++++++ nestjs-BE/server/src/spaces/spaces.controller.ts | 5 +++++ nestjs-BE/server/src/users/users.controller.ts | 4 ++++ 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/auth/auth.module.ts b/nestjs-BE/server/src/auth/auth.module.ts index b8d0644b..e4fac2f1 100644 --- a/nestjs-BE/server/src/auth/auth.module.ts +++ b/nestjs-BE/server/src/auth/auth.module.ts @@ -15,7 +15,7 @@ import { JwtAuthGuard } from './jwt-auth.guard'; PassportModule, JwtModule.register({ secret: jwtConstants.secret, - signOptions: { expiresIn: '60s' }, + signOptions: { expiresIn: '5m' }, }), ], controllers: [AuthController], diff --git a/nestjs-BE/server/src/boards/boards.controller.ts b/nestjs-BE/server/src/boards/boards.controller.ts index f9515b4d..f1a2d64b 100644 --- a/nestjs-BE/server/src/boards/boards.controller.ts +++ b/nestjs-BE/server/src/boards/boards.controller.ts @@ -11,12 +11,14 @@ import { BoardsService } from './boards.service'; import { CreateBoardDto } from './dto/create-board.dto'; import { UpdateBoardDto } from './dto/update-board.dto'; import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; +import { Public } from 'src/auth/public.decorator'; @Controller('boards') @ApiTags('boards') export class BoardsController { constructor(private readonly boardsService: BoardsService) {} + @Public() @Post() @ApiOperation({ summary: 'Create board' }) @ApiResponse({ @@ -31,6 +33,7 @@ export class BoardsController { return this.boardsService.create(createBoardDto); } + @Public() @Get(':board_uuid') @ApiOperation({ summary: 'Get board by board_uuid' }) @ApiResponse({ @@ -45,6 +48,7 @@ export class BoardsController { return this.boardsService.findOne(boardUuid); } + @Public() @Patch(':board_uuid') @ApiOperation({ summary: 'Update board by board_uuid' }) @ApiResponse({ @@ -62,6 +66,7 @@ export class BoardsController { return this.boardsService.update(boardUuid, updateBoardDto); } + @Public() @Delete(':board_uuid') @ApiOperation({ summary: 'Remove board by board_uuid' }) @ApiResponse({ diff --git a/nestjs-BE/server/src/profiles/profiles.controller.ts b/nestjs-BE/server/src/profiles/profiles.controller.ts index 5d817524..ebe9a10f 100644 --- a/nestjs-BE/server/src/profiles/profiles.controller.ts +++ b/nestjs-BE/server/src/profiles/profiles.controller.ts @@ -12,12 +12,14 @@ import { CreateProfileDto } from './dto/create-profile.dto'; import { UpdateProfileDto } from './dto/update-profile.dto'; import { ProfileSpaceDto } from './dto/profile-space.dto'; import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; +import { Public } from 'src/auth/public.decorator'; @Controller('profiles') @ApiTags('profiles') export class ProfilesController { constructor(private readonly profilesService: ProfilesService) {} + @Public() @Post() @ApiOperation({ summary: 'Create profile' }) @ApiResponse({ @@ -32,6 +34,7 @@ export class ProfilesController { return this.profilesService.create(createProfileDto); } + @Public() @Get(':profile_uuid') @ApiOperation({ summary: 'Get profile by profile_uuid' }) @ApiResponse({ @@ -46,6 +49,7 @@ export class ProfilesController { return this.profilesService.findOne(profileUuid); } + @Public() @Patch(':profile_uuid') @ApiOperation({ summary: 'Update profile by profile_uuid' }) @ApiResponse({ @@ -63,6 +67,7 @@ export class ProfilesController { return this.profilesService.update(profileUuid, updateProfileDto); } + @Public() @Delete(':profile_uuid') @ApiOperation({ summary: 'Remove profile by profile_uuid' }) @ApiResponse({ @@ -77,6 +82,7 @@ export class ProfilesController { return this.profilesService.remove(profileUuid); } + @Public() @Post('/spaces') @ApiOperation({ summary: 'Join space' }) @ApiResponse({ @@ -91,6 +97,7 @@ export class ProfilesController { return this.profilesService.joinSpace(profileSpaceDto); } + @Public() @Delete(':profile_uuid/spaces/:space_uuid') @ApiOperation({ summary: 'Leave space' }) @ApiResponse({ @@ -108,6 +115,7 @@ export class ProfilesController { return this.profilesService.leaveSpace(profileUuid, spaceUuid); } + @Public() @Get('users/:space_uuid') @ApiOperation({ summary: 'Find users in a space' }) @ApiResponse({ diff --git a/nestjs-BE/server/src/spaces/spaces.controller.ts b/nestjs-BE/server/src/spaces/spaces.controller.ts index 368809d0..640a5af6 100644 --- a/nestjs-BE/server/src/spaces/spaces.controller.ts +++ b/nestjs-BE/server/src/spaces/spaces.controller.ts @@ -11,12 +11,14 @@ import { SpacesService } from './spaces.service'; import { CreateSpaceDto } from './dto/create-space.dto'; import { UpdateSpaceDto } from './dto/update-space.dto'; import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; +import { Public } from 'src/auth/public.decorator'; @Controller('spaces') @ApiTags('spaces') export class SpacesController { constructor(private readonly spacesService: SpacesService) {} + @Public() @Post() @ApiOperation({ summary: 'Create space' }) @ApiResponse({ @@ -27,6 +29,7 @@ export class SpacesController { return this.spacesService.create(createSpaceDto); } + @Public() @Get(':space_uuid') @ApiOperation({ summary: 'Get space by space_uuid' }) @ApiResponse({ @@ -41,6 +44,7 @@ export class SpacesController { return this.spacesService.findOne(spaceUuid); } + @Public() @Patch(':space_uuid') @ApiOperation({ summary: 'Update space by space_uuid' }) @ApiResponse({ @@ -62,6 +66,7 @@ export class SpacesController { return this.spacesService.update(spaceUuid, updateSpaceDto); } + @Public() @Delete(':space_uuid') @ApiOperation({ summary: 'Remove space by space_uuid' }) @ApiResponse({ diff --git a/nestjs-BE/server/src/users/users.controller.ts b/nestjs-BE/server/src/users/users.controller.ts index 99ad92cc..e76fe3b5 100644 --- a/nestjs-BE/server/src/users/users.controller.ts +++ b/nestjs-BE/server/src/users/users.controller.ts @@ -53,6 +53,7 @@ export class UsersController { return this.usersService.findOne(email); } + @Public() @Patch(':email') @ApiOperation({ summary: 'Update user' }) @ApiResponse({ @@ -67,6 +68,7 @@ export class UsersController { return this.usersService.update(email, updateUserDto); } + @Public() @Delete(':email') @ApiOperation({ summary: 'Remove user' }) @ApiResponse({ @@ -81,6 +83,7 @@ export class UsersController { return this.usersService.remove(email); } + @Public() @Get('profiles/:email') @ApiOperation({ summary: 'Find profiles for a user' }) @ApiResponse({ @@ -95,6 +98,7 @@ export class UsersController { return this.usersService.findProfiles(email); } + @Public() @Get('rooms/:email') @ApiOperation({ summary: 'Find rooms for a user' }) @ApiResponse({ From 066a514b2dd1d3e4290187806dda9931ad8cb2ab Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 4 Dec 2023 17:19:01 +0900 Subject: [PATCH 082/170] =?UTF-8?q?fix(#58):=20=EC=84=9C=EB=B2=84=20?= =?UTF-8?q?=EC=8B=A4=ED=96=89=20=EC=8B=9C=20csv=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/temporary-database/temporary-database.service.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/temporary-database/temporary-database.service.ts b/nestjs-BE/server/src/temporary-database/temporary-database.service.ts index 52ef7906..ea034d8a 100644 --- a/nestjs-BE/server/src/temporary-database/temporary-database.service.ts +++ b/nestjs-BE/server/src/temporary-database/temporary-database.service.ts @@ -26,6 +26,7 @@ export class TemporaryDatabaseService { ) { this.initializeDatabase(); this.readDataFromFiles(); + this.executeBulkOperations(); } private initializeDatabase() { @@ -109,7 +110,7 @@ export class TemporaryDatabaseService { }); } - @Cron('* */10 * * * *') + @Cron('0 */10 * * * *') async executeBulkOperations() { for (const service of this.database.keys()) { const serviceMap = this.database.get(service); From c508bfa97d79d8d4593491e4606a45ff6d862139 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Mon, 4 Dec 2023 17:54:06 +0900 Subject: [PATCH 083/170] =?UTF-8?q?feat(#59):=20=EB=B3=B4=EB=93=9C=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=ED=95=98=EA=B8=B0=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/BE-deploy.yml | 2 + nestjs-BE/server/package-lock.json | 201 +++++++++++++++++- nestjs-BE/server/package.json | 2 + nestjs-BE/server/src/app.module.ts | 3 + .../server/src/boards/boards.controller.ts | 77 +------ nestjs-BE/server/src/boards/boards.module.ts | 5 + nestjs-BE/server/src/boards/boards.service.ts | 40 ++-- .../server/src/boards/dto/create-board.dto.ts | 19 +- .../server/src/boards/dto/update-board.dto.ts | 13 -- .../src/boards/entities/board.entity.ts | 1 - .../server/src/boards/schemas/board.schema.ts | 24 +++ 11 files changed, 276 insertions(+), 111 deletions(-) delete mode 100644 nestjs-BE/server/src/boards/dto/update-board.dto.ts delete mode 100644 nestjs-BE/server/src/boards/entities/board.entity.ts create mode 100644 nestjs-BE/server/src/boards/schemas/board.schema.ts diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index 4cba2018..c295ddab 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -20,6 +20,7 @@ jobs: echo "KAKAO_ADMIN_KEY=$KAKAO_ADMIN_KEY" >> ./nestjs-BE/server/.env echo "MYSQL_DATABASE_URL=$MYSQL_DATABASE_URL" >> ./nestjs-BE/server/.env echo "MONGODB_DATABASE_URL=$MONGODB_DATABASE_URL" >> ./nestjs-BE/server/.env + echo "MONGODB_DATABASE_URI=$MONGODB_DATABASE_URI" >> ./nestjs-BE/server/.env docker build -t ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync ./nestjs-BE/server docker push ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync:latest env: @@ -28,6 +29,7 @@ jobs: KAKAO_ADMIN_KEY: ${{ secrets.KAKAO_ADMIN_KEY }} MYSQL_DATABASE_URL: ${{ secrets.MYSQL_DATABASE_URL }} MONGODB_DATABASE_URL: ${{ secrets.MONGODB_DATABASE_URL }} + MONGODB_DATABASE_URI: ${{ secrets.MONGODB_DATABASE_URI }} deploy: needs: build diff --git a/nestjs-BE/server/package-lock.json b/nestjs-BE/server/package-lock.json index ab43fc57..be6a145b 100644 --- a/nestjs-BE/server/package-lock.json +++ b/nestjs-BE/server/package-lock.json @@ -12,6 +12,7 @@ "@nestjs/common": "^10.0.0", "@nestjs/core": "^10.0.0", "@nestjs/jwt": "^10.2.0", + "@nestjs/mongoose": "^10.0.2", "@nestjs/passport": "^10.0.2", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.2.8", @@ -22,6 +23,7 @@ "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "dotenv": "^16.3.1", + "mongoose": "^8.0.2", "passport": "^0.6.0", "passport-jwt": "^4.0.1", "reflect-metadata": "^0.1.13", @@ -1546,6 +1548,14 @@ "node": ">=8" } }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.1.tgz", + "integrity": "sha512-t7c5K033joZZMspnHg/gWPE4kandgc2OxE74aYOtGKfgB9VPuVJPix0H6fhmm2erj5PBJ21mqcx34lpIGtUCsQ==", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, "node_modules/@nestjs/cli": { "version": "10.2.1", "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-10.2.1.tgz", @@ -1691,6 +1701,18 @@ } } }, + "node_modules/@nestjs/mongoose": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@nestjs/mongoose/-/mongoose-10.0.2.tgz", + "integrity": "sha512-ITHh075DynjPIaKeJh6WkarS21WXYslu4nrLkNPbWaCP6JfxVAOftaA2X5tPSiiE/gNJWgs+QFWsfCFZUUenow==", + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0", + "mongoose": "^6.0.2 || ^7.0.0 || ^8.0.0", + "reflect-metadata": "^0.1.12", + "rxjs": "^7.0.0" + } + }, "node_modules/@nestjs/passport": { "version": "10.0.2", "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-10.0.2.tgz", @@ -2325,6 +2347,20 @@ "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.7.tgz", "integrity": "sha512-q0JomTsJ2I5Mv7dhHhQLGjMvX0JJm5dyZ1DXQySIUzU1UlwzB8bt+R6+LODUbz0UDIOvEzGc28tk27gBJw2N8Q==" }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + }, + "node_modules/@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, "node_modules/@types/yargs": { "version": "17.0.31", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.31.tgz", @@ -3213,6 +3249,14 @@ "node-int64": "^0.4.0" } }, + "node_modules/bson": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.2.0.tgz", + "integrity": "sha512-ID1cI+7bazPDyL9wYy9GaQ8gEEohWvcUl/Yf0dIdutJxnmInEEyCsb4awy/OiBfall7zBA179Pahi3vCdFze3Q==", + "engines": { + "node": ">=16.20.1" + } + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -6445,6 +6489,14 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/kareem": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz", + "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -6679,6 +6731,11 @@ "node": ">= 4.0.0" } }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -6799,6 +6856,136 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mongodb": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.2.0.tgz", + "integrity": "sha512-d7OSuGjGWDZ5usZPqfvb36laQ9CPhnWkAGHT61x5P95p/8nMVeH8asloMwW6GcYFeB0Vj4CB/1wOTDG2RA9BFA==", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.0", + "bson": "^6.2.0", + "mongodb-connection-string-url": "^2.6.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "dependencies": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mongoose": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.0.2.tgz", + "integrity": "sha512-Vsi9GzTXjdBVzheT1HZOZ2jHNzzR9Xwb5OyLz/FvDEAhlwrRnXnuqJf0QHINUOQSm7aoyvnPks0q85HJkd6yDw==", + "dependencies": { + "bson": "^6.2.0", + "kareem": "2.5.1", + "mongodb": "6.2.0", + "mpath": "0.9.0", + "mquery": "5.0.0", + "ms": "2.1.3", + "sift": "16.0.1" + }, + "engines": { + "node": ">=16.20.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/mongoose/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", + "dependencies": { + "debug": "4.x" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -7466,7 +7653,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, "engines": { "node": ">=6" } @@ -8099,6 +8285,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sift": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", + "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" + }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -8191,6 +8382,14 @@ "node": ">=0.10.0" } }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", diff --git a/nestjs-BE/server/package.json b/nestjs-BE/server/package.json index c125a649..14c53e7b 100644 --- a/nestjs-BE/server/package.json +++ b/nestjs-BE/server/package.json @@ -23,6 +23,7 @@ "@nestjs/common": "^10.0.0", "@nestjs/core": "^10.0.0", "@nestjs/jwt": "^10.2.0", + "@nestjs/mongoose": "^10.0.2", "@nestjs/passport": "^10.0.2", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.2.8", @@ -33,6 +34,7 @@ "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "dotenv": "^16.3.1", + "mongoose": "^8.0.2", "passport": "^0.6.0", "passport-jwt": "^4.0.1", "reflect-metadata": "^0.1.13", diff --git a/nestjs-BE/server/src/app.module.ts b/nestjs-BE/server/src/app.module.ts index d270f20b..f973eb42 100644 --- a/nestjs-BE/server/src/app.module.ts +++ b/nestjs-BE/server/src/app.module.ts @@ -10,6 +10,8 @@ import { ProfilesModule } from './profiles/profiles.module'; import { SpacesModule } from './spaces/spaces.module'; import { BoardsModule } from './boards/boards.module'; import { ScheduleModule } from '@nestjs/schedule'; +import { MongooseModule } from '@nestjs/mongoose'; +import customEnv from './config/env'; @Module({ imports: [ @@ -21,6 +23,7 @@ import { ScheduleModule } from '@nestjs/schedule'; ProfilesModule, SpacesModule, BoardsModule, + MongooseModule.forRoot(customEnv.MONGODB_DATABASE_URI), ], controllers: [AppController], providers: [AppService, BoardGateway], diff --git a/nestjs-BE/server/src/boards/boards.controller.ts b/nestjs-BE/server/src/boards/boards.controller.ts index f1a2d64b..1bac4033 100644 --- a/nestjs-BE/server/src/boards/boards.controller.ts +++ b/nestjs-BE/server/src/boards/boards.controller.ts @@ -1,16 +1,7 @@ -import { - Controller, - Get, - Post, - Body, - Patch, - Param, - Delete, -} from '@nestjs/common'; +import { Controller, Post, Body, HttpCode, HttpStatus } from '@nestjs/common'; import { BoardsService } from './boards.service'; import { CreateBoardDto } from './dto/create-board.dto'; -import { UpdateBoardDto } from './dto/update-board.dto'; -import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; +import { ApiTags } from '@nestjs/swagger'; import { Public } from 'src/auth/public.decorator'; @Controller('boards') @@ -20,64 +11,10 @@ export class BoardsController { @Public() @Post() - @ApiOperation({ summary: 'Create board' }) - @ApiResponse({ - status: 201, - description: 'The board has been successfully created.', - }) - @ApiResponse({ - status: 400, - description: 'Bad Request. Invalid input data.', - }) - create(@Body() createBoardDto: CreateBoardDto) { - return this.boardsService.create(createBoardDto); - } - - @Public() - @Get(':board_uuid') - @ApiOperation({ summary: 'Get board by board_uuid' }) - @ApiResponse({ - status: 200, - description: 'Return the board data.', - }) - @ApiResponse({ - status: 404, - description: 'Board not found.', - }) - findOne(@Param('board_uuid') boardUuid: string) { - return this.boardsService.findOne(boardUuid); - } - - @Public() - @Patch(':board_uuid') - @ApiOperation({ summary: 'Update board by board_uuid' }) - @ApiResponse({ - status: 200, - description: 'Board has been successfully updated.', - }) - @ApiResponse({ - status: 404, - description: 'Board not found.', - }) - update( - @Param('board_uuid') boardUuid: string, - @Body() updateBoardDto: UpdateBoardDto, - ) { - return this.boardsService.update(boardUuid, updateBoardDto); - } - - @Public() - @Delete(':board_uuid') - @ApiOperation({ summary: 'Remove board by board_uuid' }) - @ApiResponse({ - status: 200, - description: 'Board has been successfully removed.', - }) - @ApiResponse({ - status: 404, - description: 'Board not found.', - }) - remove(@Param('board_uuid') boardUuid: string) { - return this.boardsService.remove(boardUuid); + @HttpCode(HttpStatus.CREATED) + async createBoard(@Body() createBoardDto: CreateBoardDto) { + const document = await this.boardsService.create(createBoardDto); + const responseData = { boardId: document.uuid, date: document.date }; + return responseData; } } diff --git a/nestjs-BE/server/src/boards/boards.module.ts b/nestjs-BE/server/src/boards/boards.module.ts index 16204c29..08a5729a 100644 --- a/nestjs-BE/server/src/boards/boards.module.ts +++ b/nestjs-BE/server/src/boards/boards.module.ts @@ -1,8 +1,13 @@ import { Module } from '@nestjs/common'; import { BoardsService } from './boards.service'; import { BoardsController } from './boards.controller'; +import { MongooseModule } from '@nestjs/mongoose'; +import { Board, BoardSchema } from './schemas/board.schema'; @Module({ + imports: [ + MongooseModule.forFeature([{ name: Board.name, schema: BoardSchema }]), + ], controllers: [BoardsController], providers: [BoardsService], }) diff --git a/nestjs-BE/server/src/boards/boards.service.ts b/nestjs-BE/server/src/boards/boards.service.ts index d9c63142..90b8cd33 100644 --- a/nestjs-BE/server/src/boards/boards.service.ts +++ b/nestjs-BE/server/src/boards/boards.service.ts @@ -1,25 +1,25 @@ import { Injectable } from '@nestjs/common'; -import { UpdateBoardDto } from './dto/update-board.dto'; -import { PrismaServiceMongoDB } from 'src/prisma/prisma.service'; -import { BOARD_CACHE_SIZE } from 'src/config/magic-number'; -import { BaseService } from 'src/base/base.service'; -import { TemporaryDatabaseService } from 'src/temporary-database/temporary-database.service'; +import { InjectModel } from '@nestjs/mongoose'; +import { Board } from './schemas/board.schema'; +import { Model } from 'mongoose'; +import { CreateBoardDto } from './dto/create-board.dto'; +import { v4 } from 'uuid'; + @Injectable() -export class BoardsService extends BaseService { - constructor( - protected prisma: PrismaServiceMongoDB, - protected temporaryDatabaseService: TemporaryDatabaseService, - ) { - super({ - prisma, - temporaryDatabaseService, - cacheSize: BOARD_CACHE_SIZE, - className: 'BoardCollection', - field: 'uuid', - }); - } +export class BoardsService { + constructor(@InjectModel(Board.name) private boardModel: Model) {} - generateKey(data: UpdateBoardDto): string { - return data.uuid; + async create(createBoardDto: CreateBoardDto): Promise { + const { boardName, spaceId, imageUrl } = createBoardDto; + const uuid = v4(); + const date = new Date(); + const createdBoard = new this.boardModel({ + boardName, + imageUrl, + spaceId, + uuid, + date, + }); + return createdBoard.save(); } } diff --git a/nestjs-BE/server/src/boards/dto/create-board.dto.ts b/nestjs-BE/server/src/boards/dto/create-board.dto.ts index 1152a04d..9f8b32b0 100644 --- a/nestjs-BE/server/src/boards/dto/create-board.dto.ts +++ b/nestjs-BE/server/src/boards/dto/create-board.dto.ts @@ -1,8 +1,15 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { IsNotEmpty, IsString, IsUrl } from 'class-validator'; + export class CreateBoardDto { - @ApiProperty({ - example: { key1: 'value1', key2: 'value2' }, - description: 'JSON data as an object', - }) - data: Record; + @IsString() + @IsNotEmpty() + boardName: string; + + @IsString() + @IsNotEmpty() + spaceId: string; + + @IsUrl() + @IsNotEmpty() + imageUrl: string; } diff --git a/nestjs-BE/server/src/boards/dto/update-board.dto.ts b/nestjs-BE/server/src/boards/dto/update-board.dto.ts deleted file mode 100644 index 3fee0c33..00000000 --- a/nestjs-BE/server/src/boards/dto/update-board.dto.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { PartialType } from '@nestjs/swagger'; -import { CreateBoardDto } from './create-board.dto'; -import { ApiProperty } from '@nestjs/swagger'; - -export class UpdateBoardDto extends PartialType(CreateBoardDto) { - uuid?: string; - - @ApiProperty({ - example: { key1: 'value1', key2: 'value2' }, - description: 'JSON data as an object for updating the board', - }) - data: Record; -} diff --git a/nestjs-BE/server/src/boards/entities/board.entity.ts b/nestjs-BE/server/src/boards/entities/board.entity.ts deleted file mode 100644 index 555916ba..00000000 --- a/nestjs-BE/server/src/boards/entities/board.entity.ts +++ /dev/null @@ -1 +0,0 @@ -export class Board {} diff --git a/nestjs-BE/server/src/boards/schemas/board.schema.ts b/nestjs-BE/server/src/boards/schemas/board.schema.ts new file mode 100644 index 00000000..65eb86d4 --- /dev/null +++ b/nestjs-BE/server/src/boards/schemas/board.schema.ts @@ -0,0 +1,24 @@ +import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; +import { HydratedDocument } from 'mongoose'; + +export type BoardDocument = HydratedDocument; + +@Schema() +export class Board { + @Prop() + uuid: string; + + @Prop() + boardName: string; + + @Prop() + spaceId: string; + + @Prop() + date: Date; + + @Prop() + imageUrl: string; +} + +export const BoardSchema = SchemaFactory.createForClass(Board); From 00610635171cef21055b8e790944f983eb35af9e Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Mon, 4 Dec 2023 17:54:28 +0900 Subject: [PATCH 084/170] =?UTF-8?q?feat(#55):=20=EB=B3=B4=EB=93=9C=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EB=B6=88=EB=9F=AC=EC=98=A4=EA=B8=B0=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/src/boards/boards.controller.ts | 25 ++++++++++++++++++- nestjs-BE/server/src/boards/boards.service.ts | 4 +++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/boards/boards.controller.ts b/nestjs-BE/server/src/boards/boards.controller.ts index 1bac4033..0e53f643 100644 --- a/nestjs-BE/server/src/boards/boards.controller.ts +++ b/nestjs-BE/server/src/boards/boards.controller.ts @@ -1,4 +1,12 @@ -import { Controller, Post, Body, HttpCode, HttpStatus } from '@nestjs/common'; +import { + Controller, + Get, + Post, + Body, + HttpCode, + HttpStatus, + Query, +} from '@nestjs/common'; import { BoardsService } from './boards.service'; import { CreateBoardDto } from './dto/create-board.dto'; import { ApiTags } from '@nestjs/swagger'; @@ -17,4 +25,19 @@ export class BoardsController { const responseData = { boardId: document.uuid, date: document.date }; return responseData; } + + @Public() + @Get() + async findBySpaceId(@Query('spaceId') spaceId: string) { + const boardList = await this.boardsService.findBySpaceId(spaceId); + const responseData = boardList.map((board) => { + return { + boardId: board.uuid, + boardName: board.boardName, + date: board.date, + imageUrl: board.imageUrl, + }; + }); + return responseData; + } } diff --git a/nestjs-BE/server/src/boards/boards.service.ts b/nestjs-BE/server/src/boards/boards.service.ts index 90b8cd33..5e3ab278 100644 --- a/nestjs-BE/server/src/boards/boards.service.ts +++ b/nestjs-BE/server/src/boards/boards.service.ts @@ -22,4 +22,8 @@ export class BoardsService { }); return createdBoard.save(); } + + async findBySpaceId(spaceId: string): Promise { + return this.boardModel.find({ spaceId }).exec(); + } } From 9f3ebd38f6ae2c07ffe00e200905a80a4c2c0f01 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Mon, 4 Dec 2023 18:10:15 +0900 Subject: [PATCH 085/170] =?UTF-8?q?fix(#59):=20=EC=A0=84=EC=97=AD=20valida?= =?UTF-8?q?tion=20pipe=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/main.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nestjs-BE/server/src/main.ts b/nestjs-BE/server/src/main.ts index af82ed33..2f997991 100644 --- a/nestjs-BE/server/src/main.ts +++ b/nestjs-BE/server/src/main.ts @@ -2,12 +2,14 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { SwaggerModule } from '@nestjs/swagger'; import { swaggerConfig } from './config/swagger'; +import { ValidationPipe } from '@nestjs/common'; import customEnv from 'src/config/env'; async function bootstrap() { const app = await NestFactory.create(AppModule); const document = SwaggerModule.createDocument(app, swaggerConfig); SwaggerModule.setup('api-docs', app, document); + app.useGlobalPipes(new ValidationPipe()); await app.listen(customEnv.SERVER_PORT); } From 37012849e39770096e2ad50c7393927d0d11b7f7 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Mon, 4 Dec 2023 18:42:07 +0900 Subject: [PATCH 086/170] =?UTF-8?q?fix(#59):=20=EB=B3=B4=EB=93=9C=20?= =?UTF-8?q?=EC=A4=91=EB=B3=B5=20=EC=8B=9C=20409=20Conflict=20=EB=B0=98?= =?UTF-8?q?=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/boards/boards.service.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/boards/boards.service.ts b/nestjs-BE/server/src/boards/boards.service.ts index 5e3ab278..3d87418c 100644 --- a/nestjs-BE/server/src/boards/boards.service.ts +++ b/nestjs-BE/server/src/boards/boards.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, ConflictException } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Board } from './schemas/board.schema'; import { Model } from 'mongoose'; @@ -11,6 +11,12 @@ export class BoardsService { async create(createBoardDto: CreateBoardDto): Promise { const { boardName, spaceId, imageUrl } = createBoardDto; + + const existingBoard = await this.boardModel + .findOne({ boardName, spaceId }) + .exec(); + if (existingBoard) throw new ConflictException(); + const uuid = v4(); const date = new Date(); const createdBoard = new this.boardModel({ From 825c5269a21736fedbf57e6e796c96718fadf9a2 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 4 Dec 2023 20:39:57 +0900 Subject: [PATCH 087/170] =?UTF-8?q?chore(#135):=20image=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EA=B4=80=EB=A6=AC=EB=A5=BC=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?=ED=8C=A8=ED=82=A4=EC=A7=80=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/package-lock.json | 236 ++++++++++++++++++++++++++++- nestjs-BE/server/package.json | 2 + 2 files changed, 237 insertions(+), 1 deletion(-) diff --git a/nestjs-BE/server/package-lock.json b/nestjs-BE/server/package-lock.json index ab43fc57..67da773a 100644 --- a/nestjs-BE/server/package-lock.json +++ b/nestjs-BE/server/package-lock.json @@ -19,6 +19,7 @@ "@nestjs/swagger": "^7.1.16", "@nestjs/websockets": "^10.2.8", "@prisma/client": "^5.6.0", + "aws-sdk": "^2.1510.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "dotenv": "^16.3.1", @@ -34,6 +35,7 @@ "@nestjs/testing": "^10.0.0", "@types/express": "^4.17.17", "@types/jest": "^29.5.2", + "@types/multer": "^1.4.11", "@types/node": "^20.3.1", "@types/passport-jwt": "^3.0.13", "@types/supertest": "^2.0.12", @@ -2218,6 +2220,15 @@ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", "dev": true }, + "node_modules/@types/multer": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.11.tgz", + "integrity": "sha512-svK240gr6LVWvv3YGyhLlA+6LRRWA4mnGIU7RcNmgjBYFl6665wcXrRfxGp5tEPVHUNm5FMcmq7too9bxCwX/w==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, "node_modules/@types/node": { "version": "20.9.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", @@ -2897,6 +2908,68 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sdk": { + "version": "2.1510.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1510.0.tgz", + "integrity": "sha512-XQj3QINBNseA5G9Vaa/iihNz3HCrzeyhxrOUjuH0AVxYqa5Q4cxaQhrWiAiUndtO2F70nfukEYe4cCUoTalUoQ==", + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-sdk/node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/aws-sdk/node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/aws-sdk/node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "node_modules/aws-sdk/node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -3023,7 +3096,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -4862,6 +4934,14 @@ "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/foreground-child": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", @@ -5224,6 +5304,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", @@ -5416,6 +5510,21 @@ "node": ">= 0.10" } }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -5434,6 +5543,17 @@ "node": ">=8" } }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-core-module": { "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", @@ -5488,6 +5608,20 @@ "node": ">=6" } }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -5557,6 +5691,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -6322,6 +6470,14 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -7501,6 +7657,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -7866,6 +8031,11 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" + }, "node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -8962,6 +9132,32 @@ "punycode": "^2.1.0" } }, + "node_modules/url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -9170,6 +9366,24 @@ "node": ">= 8" } }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/windows-release": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-4.0.0.tgz", @@ -9315,6 +9529,26 @@ } } }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/nestjs-BE/server/package.json b/nestjs-BE/server/package.json index c125a649..7afe223e 100644 --- a/nestjs-BE/server/package.json +++ b/nestjs-BE/server/package.json @@ -30,6 +30,7 @@ "@nestjs/swagger": "^7.1.16", "@nestjs/websockets": "^10.2.8", "@prisma/client": "^5.6.0", + "aws-sdk": "^2.1510.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "dotenv": "^16.3.1", @@ -45,6 +46,7 @@ "@nestjs/testing": "^10.0.0", "@types/express": "^4.17.17", "@types/jest": "^29.5.2", + "@types/multer": "^1.4.11", "@types/node": "^20.3.1", "@types/passport-jwt": "^3.0.13", "@types/supertest": "^2.0.12", From a2163f12e515bcd05a9387a2711c13793823a5e1 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 4 Dec 2023 20:41:50 +0900 Subject: [PATCH 088/170] =?UTF-8?q?feat(#135):=20image=20upload=20?= =?UTF-8?q?=EB=AA=A8=EB=93=88=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/upload/upload.module.ts | 7 ++++ .../server/src/upload/upload.service.spec.ts | 18 +++++++++ nestjs-BE/server/src/upload/upload.service.ts | 38 +++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 nestjs-BE/server/src/upload/upload.module.ts create mode 100644 nestjs-BE/server/src/upload/upload.service.spec.ts create mode 100644 nestjs-BE/server/src/upload/upload.service.ts diff --git a/nestjs-BE/server/src/upload/upload.module.ts b/nestjs-BE/server/src/upload/upload.module.ts new file mode 100644 index 00000000..a6258a8e --- /dev/null +++ b/nestjs-BE/server/src/upload/upload.module.ts @@ -0,0 +1,7 @@ +import { Module } from '@nestjs/common'; +import { UploadService } from './upload.service'; + +@Module({ + providers: [UploadService], +}) +export class UploadModule {} diff --git a/nestjs-BE/server/src/upload/upload.service.spec.ts b/nestjs-BE/server/src/upload/upload.service.spec.ts new file mode 100644 index 00000000..7b83db6a --- /dev/null +++ b/nestjs-BE/server/src/upload/upload.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { UploadService } from './upload.service'; + +describe('UploadService', () => { + let service: UploadService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [UploadService], + }).compile(); + + service = module.get(UploadService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/nestjs-BE/server/src/upload/upload.service.ts b/nestjs-BE/server/src/upload/upload.service.ts new file mode 100644 index 00000000..12a0fb28 --- /dev/null +++ b/nestjs-BE/server/src/upload/upload.service.ts @@ -0,0 +1,38 @@ +import { Injectable } from '@nestjs/common'; +import customEnv from 'src/config/env'; +import { S3, Endpoint } from 'aws-sdk'; +import uuid from '../utils/uuid'; +const { + NCLOUD_ACCESS_KEY, + NCLOUD_SECRET_KEY, + NCLOUD_REGION, + STORAGE_URL, + BUCKET_NAME, +} = customEnv; +const endpoint = new Endpoint(STORAGE_URL); + +@Injectable() +export class UploadService { + private s3: S3; + constructor() { + this.s3 = new S3({ + endpoint: endpoint, + region: NCLOUD_REGION, + credentials: { + accessKeyId: NCLOUD_ACCESS_KEY, + secretAccessKey: NCLOUD_SECRET_KEY, + }, + }); + } + + async uploadFile(image: Express.Multer.File) { + const params = { + Bucket: BUCKET_NAME, + Key: `${uuid()}-${image.originalname}`, + Body: image.buffer, + ACL: 'public-read', + }; + const uploadResult = await this.s3.upload(params).promise(); + return uploadResult.Location; + } +} From cbc2eb31be68b1142f4992b197a71387fa26525d Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Mon, 4 Dec 2023 21:12:30 +0900 Subject: [PATCH 089/170] =?UTF-8?q?fix:=20api=20=EC=A3=BC=EC=86=8C=20?= =?UTF-8?q?=EB=AA=85=ED=99=95=ED=95=98=EA=B2=8C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/boards/boards.controller.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nestjs-BE/server/src/boards/boards.controller.ts b/nestjs-BE/server/src/boards/boards.controller.ts index 0e53f643..33c6268a 100644 --- a/nestjs-BE/server/src/boards/boards.controller.ts +++ b/nestjs-BE/server/src/boards/boards.controller.ts @@ -18,7 +18,7 @@ export class BoardsController { constructor(private readonly boardsService: BoardsService) {} @Public() - @Post() + @Post('create') @HttpCode(HttpStatus.CREATED) async createBoard(@Body() createBoardDto: CreateBoardDto) { const document = await this.boardsService.create(createBoardDto); @@ -27,7 +27,7 @@ export class BoardsController { } @Public() - @Get() + @Get('list') async findBySpaceId(@Query('spaceId') spaceId: string) { const boardList = await this.boardsService.findBySpaceId(spaceId); const responseData = boardList.map((board) => { From f9af557bdd6c0a88688b8bb97350683892dccd26 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Mon, 4 Dec 2023 23:01:21 +0900 Subject: [PATCH 090/170] =?UTF-8?q?feat(#137):=20=EB=B3=B4=EB=93=9C=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/src/boards/boards.controller.ts | 52 ++++++++++++++++--- nestjs-BE/server/src/boards/boards.service.ts | 19 ++++++- .../server/src/boards/dto/delete-board.dto.ts | 7 +++ .../src/boards/dto/restore-board.dto.ts | 7 +++ .../server/src/boards/schemas/board.schema.ts | 8 ++- 5 files changed, 84 insertions(+), 9 deletions(-) create mode 100644 nestjs-BE/server/src/boards/dto/delete-board.dto.ts create mode 100644 nestjs-BE/server/src/boards/dto/restore-board.dto.ts diff --git a/nestjs-BE/server/src/boards/boards.controller.ts b/nestjs-BE/server/src/boards/boards.controller.ts index 33c6268a..18669400 100644 --- a/nestjs-BE/server/src/boards/boards.controller.ts +++ b/nestjs-BE/server/src/boards/boards.controller.ts @@ -6,11 +6,17 @@ import { HttpCode, HttpStatus, Query, + Patch, + NotFoundException, } from '@nestjs/common'; import { BoardsService } from './boards.service'; import { CreateBoardDto } from './dto/create-board.dto'; import { ApiTags } from '@nestjs/swagger'; import { Public } from 'src/auth/public.decorator'; +import { DeleteBoardDto } from './dto/delete-board.dto'; +import { RestoreBoardDto } from './dto/restore-board.dto'; + +const BOARD_EXPIRE_DAY = 7; @Controller('boards') @ApiTags('boards') @@ -22,7 +28,7 @@ export class BoardsController { @HttpCode(HttpStatus.CREATED) async createBoard(@Body() createBoardDto: CreateBoardDto) { const document = await this.boardsService.create(createBoardDto); - const responseData = { boardId: document.uuid, date: document.date }; + const responseData = { boardId: document.uuid, date: document.createdAt }; return responseData; } @@ -30,14 +36,48 @@ export class BoardsController { @Get('list') async findBySpaceId(@Query('spaceId') spaceId: string) { const boardList = await this.boardsService.findBySpaceId(spaceId); - const responseData = boardList.map((board) => { - return { + const responseData = boardList.reduce((list, board) => { + let isDeleted = false; + + if (board.deletedAt && board.deletedAt > board.restoredAt) { + const expireDate = new Date(board.deletedAt); + expireDate.setDate(board.deletedAt.getDate() + BOARD_EXPIRE_DAY); + if (new Date() > expireDate) { + this.boardsService.deleteExpiredBoard(board.uuid); + return list; + } + isDeleted = true; + } + + list.push({ boardId: board.uuid, boardName: board.boardName, - date: board.date, + createdAt: board.createdAt, imageUrl: board.imageUrl, - }; - }); + isDeleted, + }); + return list; + }, []); return responseData; } + + @Public() + @Patch('delete') + async deleteBoard(@Body() deleteBoardDto: DeleteBoardDto) { + const updateResult = await this.boardsService.deleteBoard( + deleteBoardDto.boardId, + ); + if (!updateResult.matchedCount) throw new NotFoundException(); + return 'board deleted.'; + } + + @Public() + @Patch('restore') + async restoreBoard(@Body() resotreBoardDto: RestoreBoardDto) { + const updateResult = await this.boardsService.restoreBoard( + resotreBoardDto.boardId, + ); + if (!updateResult.matchedCount) throw new NotFoundException(); + return 'board restored.'; + } } diff --git a/nestjs-BE/server/src/boards/boards.service.ts b/nestjs-BE/server/src/boards/boards.service.ts index 3d87418c..f307c421 100644 --- a/nestjs-BE/server/src/boards/boards.service.ts +++ b/nestjs-BE/server/src/boards/boards.service.ts @@ -18,13 +18,14 @@ export class BoardsService { if (existingBoard) throw new ConflictException(); const uuid = v4(); - const date = new Date(); + const now = new Date(); const createdBoard = new this.boardModel({ boardName, imageUrl, spaceId, uuid, - date, + createdAt: now, + restoredAt: now, }); return createdBoard.save(); } @@ -32,4 +33,18 @@ export class BoardsService { async findBySpaceId(spaceId: string): Promise { return this.boardModel.find({ spaceId }).exec(); } + + async deleteBoard(boardId: string) { + const now = new Date(); + return this.boardModel.updateOne({ uuid: boardId }, { deletedAt: now }); + } + + async deleteExpiredBoard(boardId: string) { + return this.boardModel.deleteOne({ uuid: boardId }); + } + + async restoreBoard(boardId: string) { + const now = new Date(); + return this.boardModel.updateOne({ uuid: boardId }, { restoredAt: now }); + } } diff --git a/nestjs-BE/server/src/boards/dto/delete-board.dto.ts b/nestjs-BE/server/src/boards/dto/delete-board.dto.ts new file mode 100644 index 00000000..f661e22b --- /dev/null +++ b/nestjs-BE/server/src/boards/dto/delete-board.dto.ts @@ -0,0 +1,7 @@ +import { IsNotEmpty, IsString } from 'class-validator'; + +export class DeleteBoardDto { + @IsString() + @IsNotEmpty() + boardId: string; +} diff --git a/nestjs-BE/server/src/boards/dto/restore-board.dto.ts b/nestjs-BE/server/src/boards/dto/restore-board.dto.ts new file mode 100644 index 00000000..70745417 --- /dev/null +++ b/nestjs-BE/server/src/boards/dto/restore-board.dto.ts @@ -0,0 +1,7 @@ +import { IsNotEmpty, IsString } from 'class-validator'; + +export class RestoreBoardDto { + @IsString() + @IsNotEmpty() + boardId: string; +} diff --git a/nestjs-BE/server/src/boards/schemas/board.schema.ts b/nestjs-BE/server/src/boards/schemas/board.schema.ts index 65eb86d4..e5045504 100644 --- a/nestjs-BE/server/src/boards/schemas/board.schema.ts +++ b/nestjs-BE/server/src/boards/schemas/board.schema.ts @@ -15,7 +15,13 @@ export class Board { spaceId: string; @Prop() - date: Date; + createdAt: Date; + + @Prop() + restoredAt: Date; + + @Prop() + deletedAt: Date; @Prop() imageUrl: string; From 6a70f6ee1ec885f5af5315dbb46554b307033426 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Mon, 4 Dec 2023 23:47:58 +0900 Subject: [PATCH 091/170] =?UTF-8?q?feat:=20=EB=B3=B4=EB=93=9C=20API=20swag?= =?UTF-8?q?ger=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/src/boards/boards.controller.ts | 50 ++++++++++++++++++- .../server/src/boards/dto/create-board.dto.ts | 4 ++ .../server/src/boards/dto/delete-board.dto.ts | 2 + .../src/boards/dto/restore-board.dto.ts | 2 + .../server/src/boards/swagger/boards.type.ts | 26 ++++++++++ 5 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 nestjs-BE/server/src/boards/swagger/boards.type.ts diff --git a/nestjs-BE/server/src/boards/boards.controller.ts b/nestjs-BE/server/src/boards/boards.controller.ts index 18669400..fabbcb8e 100644 --- a/nestjs-BE/server/src/boards/boards.controller.ts +++ b/nestjs-BE/server/src/boards/boards.controller.ts @@ -11,10 +11,20 @@ import { } from '@nestjs/common'; import { BoardsService } from './boards.service'; import { CreateBoardDto } from './dto/create-board.dto'; -import { ApiTags } from '@nestjs/swagger'; +import { + ApiBody, + ApiConflictResponse, + ApiCreatedResponse, + ApiNotFoundResponse, + ApiOkResponse, + ApiOperation, + ApiQuery, + ApiTags, +} from '@nestjs/swagger'; import { Public } from 'src/auth/public.decorator'; import { DeleteBoardDto } from './dto/delete-board.dto'; import { RestoreBoardDto } from './dto/restore-board.dto'; +import { BoardInSpace, CreateBoardSuccess } from './swagger/boards.type'; const BOARD_EXPIRE_DAY = 7; @@ -23,6 +33,16 @@ const BOARD_EXPIRE_DAY = 7; export class BoardsController { constructor(private readonly boardsService: BoardsService) {} + @ApiOperation({ + summary: '보드 생성', + description: '보드 이름, 스페이스 id, 이미지 url을 받아서 보드를 생성한다.', + }) + @ApiBody({ type: CreateBoardDto }) + @ApiCreatedResponse({ + type: CreateBoardSuccess, + description: '보드 생성 완료', + }) + @ApiConflictResponse({ description: '보드가 이미 존재함' }) @Public() @Post('create') @HttpCode(HttpStatus.CREATED) @@ -32,6 +52,20 @@ export class BoardsController { return responseData; } + @ApiOperation({ + summary: '보드 목록 불러오기', + description: '스페이스 id를 받아서 보드 목록을 불러온다.', + }) + @ApiQuery({ + name: 'spaceId', + required: true, + description: '보드 목록을 불러올 스페이스 id', + }) + @ApiOkResponse({ + type: BoardInSpace, + isArray: true, + description: '보드 목록 불러오기 완료', + }) @Public() @Get('list') async findBySpaceId(@Query('spaceId') spaceId: string) { @@ -61,6 +95,13 @@ export class BoardsController { return responseData; } + @ApiOperation({ + summary: '보드 삭제', + description: '삭제할 보드 id를 받아서 보드를 삭제한다.', + }) + @ApiBody({ type: DeleteBoardDto }) + @ApiOkResponse({ description: '보드 삭제 완료' }) + @ApiNotFoundResponse({ description: '보드가 존재하지 않음' }) @Public() @Patch('delete') async deleteBoard(@Body() deleteBoardDto: DeleteBoardDto) { @@ -71,6 +112,13 @@ export class BoardsController { return 'board deleted.'; } + @ApiOperation({ + summary: '보드 복구', + description: '복구할 보드 id를 받아서 보드를 복구한다.', + }) + @ApiBody({ type: RestoreBoardDto }) + @ApiOkResponse({ description: '보드 복구 완료' }) + @ApiNotFoundResponse({ description: '보드가 존재하지 않음' }) @Public() @Patch('restore') async restoreBoard(@Body() resotreBoardDto: RestoreBoardDto) { diff --git a/nestjs-BE/server/src/boards/dto/create-board.dto.ts b/nestjs-BE/server/src/boards/dto/create-board.dto.ts index 9f8b32b0..18ffdf3a 100644 --- a/nestjs-BE/server/src/boards/dto/create-board.dto.ts +++ b/nestjs-BE/server/src/boards/dto/create-board.dto.ts @@ -1,14 +1,18 @@ +import { ApiProperty } from '@nestjs/swagger'; import { IsNotEmpty, IsString, IsUrl } from 'class-validator'; export class CreateBoardDto { + @ApiProperty({ description: '보드 이름' }) @IsString() @IsNotEmpty() boardName: string; + @ApiProperty({ description: '스페이스 id' }) @IsString() @IsNotEmpty() spaceId: string; + @ApiProperty({ description: '이미지 url' }) @IsUrl() @IsNotEmpty() imageUrl: string; diff --git a/nestjs-BE/server/src/boards/dto/delete-board.dto.ts b/nestjs-BE/server/src/boards/dto/delete-board.dto.ts index f661e22b..03bbeb18 100644 --- a/nestjs-BE/server/src/boards/dto/delete-board.dto.ts +++ b/nestjs-BE/server/src/boards/dto/delete-board.dto.ts @@ -1,6 +1,8 @@ +import { ApiProperty } from '@nestjs/swagger'; import { IsNotEmpty, IsString } from 'class-validator'; export class DeleteBoardDto { + @ApiProperty({ description: '삭제할 보드 id' }) @IsString() @IsNotEmpty() boardId: string; diff --git a/nestjs-BE/server/src/boards/dto/restore-board.dto.ts b/nestjs-BE/server/src/boards/dto/restore-board.dto.ts index 70745417..e5829261 100644 --- a/nestjs-BE/server/src/boards/dto/restore-board.dto.ts +++ b/nestjs-BE/server/src/boards/dto/restore-board.dto.ts @@ -1,6 +1,8 @@ +import { ApiProperty } from '@nestjs/swagger'; import { IsNotEmpty, IsString } from 'class-validator'; export class RestoreBoardDto { + @ApiProperty({ description: '복구할 보드 id' }) @IsString() @IsNotEmpty() boardId: string; diff --git a/nestjs-BE/server/src/boards/swagger/boards.type.ts b/nestjs-BE/server/src/boards/swagger/boards.type.ts new file mode 100644 index 00000000..0e79fd4b --- /dev/null +++ b/nestjs-BE/server/src/boards/swagger/boards.type.ts @@ -0,0 +1,26 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class CreateBoardSuccess { + @ApiProperty({ description: '생성한 보드 id' }) + boardId: string; + + @ApiProperty({ description: '보드를 생성한 UTC 시각' }) + date: Date; +} + +export class BoardInSpace { + @ApiProperty({ description: '보드 id' }) + boardId: string; + + @ApiProperty({ description: '보드 이름' }) + boardName: string; + + @ApiProperty({ description: '보드를 생성한 UTC 시각' }) + createdAt: Date; + + @ApiProperty({ description: '보드 이미지 url' }) + imageUrl: string; + + @ApiProperty({ description: '삭제 여부' }) + isDeleted: boolean; +} From c87fe122f5e86c460826c7fb1729ff8f46b7e790 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 5 Dec 2023 10:36:45 +0900 Subject: [PATCH 092/170] =?UTF-8?q?feat(#135):=20=EC=8A=A4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4,=20=ED=94=84=EB=A1=9C=ED=95=84=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EC=97=85=EB=A1=9C=EB=93=9C=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/app.module.ts | 2 + nestjs-BE/server/src/config/magic-number.ts | 1 - .../src/profiles/dto/create-profile.dto.ts | 6 +-- .../src/profiles/dto/update-profile.dto.ts | 2 +- .../src/profiles/profiles.controller.ts | 37 +++++++++++++++++-- .../server/src/profiles/profiles.module.ts | 3 +- .../server/src/spaces/spaces.controller.ts | 23 ++++++++++-- nestjs-BE/server/src/spaces/spaces.module.ts | 3 +- 8 files changed, 62 insertions(+), 15 deletions(-) diff --git a/nestjs-BE/server/src/app.module.ts b/nestjs-BE/server/src/app.module.ts index d270f20b..19f83129 100644 --- a/nestjs-BE/server/src/app.module.ts +++ b/nestjs-BE/server/src/app.module.ts @@ -10,6 +10,7 @@ import { ProfilesModule } from './profiles/profiles.module'; import { SpacesModule } from './spaces/spaces.module'; import { BoardsModule } from './boards/boards.module'; import { ScheduleModule } from '@nestjs/schedule'; +import { UploadModule } from './upload/upload.module'; @Module({ imports: [ @@ -21,6 +22,7 @@ import { ScheduleModule } from '@nestjs/schedule'; ProfilesModule, SpacesModule, BoardsModule, + UploadModule, ], controllers: [AppController], providers: [AppService, BoardGateway], diff --git a/nestjs-BE/server/src/config/magic-number.ts b/nestjs-BE/server/src/config/magic-number.ts index 825d7d4e..47e8df75 100644 --- a/nestjs-BE/server/src/config/magic-number.ts +++ b/nestjs-BE/server/src/config/magic-number.ts @@ -2,4 +2,3 @@ export const USER_CACHE_SIZE = 1000; export const PROFILE_CACHE_SIZE = 5000; export const SPACE_CACHE_SIZE = 10000; export const BOARD_CACHE_SIZE = 10000; -export const PORT = 3000; diff --git a/nestjs-BE/server/src/profiles/dto/create-profile.dto.ts b/nestjs-BE/server/src/profiles/dto/create-profile.dto.ts index a9735b92..905a78e3 100644 --- a/nestjs-BE/server/src/profiles/dto/create-profile.dto.ts +++ b/nestjs-BE/server/src/profiles/dto/create-profile.dto.ts @@ -1,15 +1,11 @@ import { ApiProperty } from '@nestjs/swagger'; export class CreateProfileDto { - @ApiProperty({ - example: 'user-uuid-123', - description: 'User UUID for the profile', - }) user_id: string; @ApiProperty({ example: 'profile-image.png', - description: 'Image URL for the profile', + description: 'Profile image file', }) image: string; diff --git a/nestjs-BE/server/src/profiles/dto/update-profile.dto.ts b/nestjs-BE/server/src/profiles/dto/update-profile.dto.ts index 1511aaba..c6e4c50e 100644 --- a/nestjs-BE/server/src/profiles/dto/update-profile.dto.ts +++ b/nestjs-BE/server/src/profiles/dto/update-profile.dto.ts @@ -12,7 +12,7 @@ export class UpdateProfileDto extends PartialType(CreateProfileDto) { @ApiProperty({ example: 'new image.png', - description: 'Updated image URL for the profile', + description: 'Updated Profile image file', required: false, }) image?: string; diff --git a/nestjs-BE/server/src/profiles/profiles.controller.ts b/nestjs-BE/server/src/profiles/profiles.controller.ts index 5d817524..8d97a3d8 100644 --- a/nestjs-BE/server/src/profiles/profiles.controller.ts +++ b/nestjs-BE/server/src/profiles/profiles.controller.ts @@ -6,19 +6,37 @@ import { Patch, Param, Delete, + UseInterceptors, + UploadedFile, + Request as Req, } from '@nestjs/common'; +import { FileInterceptor } from '@nestjs/platform-express'; import { ProfilesService } from './profiles.service'; import { CreateProfileDto } from './dto/create-profile.dto'; import { UpdateProfileDto } from './dto/update-profile.dto'; import { ProfileSpaceDto } from './dto/profile-space.dto'; import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; +import { UploadService } from 'src/upload/upload.service'; +import customEnv from 'src/config/env'; +import { Request } from 'express'; +const { BASE_IMAGE_URL } = customEnv; + +interface RequestWithUser extends Request { + user: { + uuid: string; + }; +} @Controller('profiles') @ApiTags('profiles') export class ProfilesController { - constructor(private readonly profilesService: ProfilesService) {} + constructor( + private readonly profilesService: ProfilesService, + private readonly uploadService: UploadService, + ) {} @Post() + @UseInterceptors(FileInterceptor('image')) @ApiOperation({ summary: 'Create profile' }) @ApiResponse({ status: 201, @@ -28,7 +46,16 @@ export class ProfilesController { status: 400, description: 'Bad Request. Invalid input data.', }) - create(@Body() createProfileDto: CreateProfileDto) { + async create( + @UploadedFile() image: Express.Multer.File, + @Body() createProfileDto: CreateProfileDto, + @Req() req: RequestWithUser, + ) { + const imageUrl = image + ? await this.uploadService.uploadFile(image) + : BASE_IMAGE_URL; + createProfileDto.image = imageUrl; + createProfileDto.user_id = req.user.uuid; return this.profilesService.create(createProfileDto); } @@ -56,10 +83,14 @@ export class ProfilesController { status: 404, description: 'Profile not found.', }) - update( + async update( + @UploadedFile() image: Express.Multer.File, @Param('profile_uuid') profileUuid: string, @Body() updateProfileDto: UpdateProfileDto, ) { + if (image) { + updateProfileDto.image = await this.uploadService.uploadFile(image); + } return this.profilesService.update(profileUuid, updateProfileDto); } diff --git a/nestjs-BE/server/src/profiles/profiles.module.ts b/nestjs-BE/server/src/profiles/profiles.module.ts index 65a9fe50..fb2e5537 100644 --- a/nestjs-BE/server/src/profiles/profiles.module.ts +++ b/nestjs-BE/server/src/profiles/profiles.module.ts @@ -2,8 +2,9 @@ import { Module } from '@nestjs/common'; import { ProfilesService } from './profiles.service'; import { ProfilesController } from './profiles.controller'; import { SpacesService } from '../spaces/spaces.service'; +import { UploadService } from 'src/upload/upload.service'; @Module({ controllers: [ProfilesController], - providers: [ProfilesService, SpacesService], + providers: [ProfilesService, SpacesService, UploadService], }) export class ProfilesModule {} diff --git a/nestjs-BE/server/src/spaces/spaces.controller.ts b/nestjs-BE/server/src/spaces/spaces.controller.ts index 368809d0..2d0a32c4 100644 --- a/nestjs-BE/server/src/spaces/spaces.controller.ts +++ b/nestjs-BE/server/src/spaces/spaces.controller.ts @@ -6,24 +6,37 @@ import { Patch, Param, Delete, + UseInterceptors, + UploadedFile, } from '@nestjs/common'; +import { FileInterceptor } from '@nestjs/platform-express'; import { SpacesService } from './spaces.service'; import { CreateSpaceDto } from './dto/create-space.dto'; import { UpdateSpaceDto } from './dto/update-space.dto'; import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; +import { UploadService } from 'src/upload/upload.service'; @Controller('spaces') @ApiTags('spaces') export class SpacesController { - constructor(private readonly spacesService: SpacesService) {} + constructor( + private readonly spacesService: SpacesService, + private readonly uploadService: UploadService, + ) {} @Post() + @UseInterceptors(FileInterceptor('icon')) @ApiOperation({ summary: 'Create space' }) @ApiResponse({ status: 201, description: 'The space has been successfully created.', }) - create(@Body() createSpaceDto: CreateSpaceDto) { + async create( + @UploadedFile() icon: Express.Multer.File, + @Body() createSpaceDto: CreateSpaceDto, + ) { + const iconUrl = await this.uploadService.uploadFile(icon); + createSpaceDto.icon = iconUrl; return this.spacesService.create(createSpaceDto); } @@ -42,6 +55,7 @@ export class SpacesController { } @Patch(':space_uuid') + @UseInterceptors(FileInterceptor('icon')) @ApiOperation({ summary: 'Update space by space_uuid' }) @ApiResponse({ status: 200, @@ -55,10 +69,13 @@ export class SpacesController { status: 404, description: 'Space not found.', }) - update( + async update( + @UploadedFile() icon: Express.Multer.File, @Param('space_uuid') spaceUuid: string, @Body() updateSpaceDto: UpdateSpaceDto, ) { + const iconUrl = await this.uploadService.uploadFile(icon); + updateSpaceDto.icon = iconUrl; return this.spacesService.update(spaceUuid, updateSpaceDto); } diff --git a/nestjs-BE/server/src/spaces/spaces.module.ts b/nestjs-BE/server/src/spaces/spaces.module.ts index 5a9b68c9..ef744633 100644 --- a/nestjs-BE/server/src/spaces/spaces.module.ts +++ b/nestjs-BE/server/src/spaces/spaces.module.ts @@ -1,9 +1,10 @@ import { Module } from '@nestjs/common'; import { SpacesService } from './spaces.service'; import { SpacesController } from './spaces.controller'; +import { UploadService } from 'src/upload/upload.service'; @Module({ controllers: [SpacesController], - providers: [SpacesService], + providers: [SpacesService, UploadService], }) export class SpacesModule {} From b25d9663e1ca139c5245dad7a22a39ff1ce75fd7 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 5 Dec 2023 10:43:56 +0900 Subject: [PATCH 093/170] =?UTF-8?q?fix(#135):=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=97=86=EC=9D=84=20=EA=B2=BD=EC=9A=B0=20=EA=B3=A0?= =?UTF-8?q?=EB=A0=A4=ED=95=B4=EC=84=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/spaces/spaces.controller.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/nestjs-BE/server/src/spaces/spaces.controller.ts b/nestjs-BE/server/src/spaces/spaces.controller.ts index 2d0a32c4..e89f4f46 100644 --- a/nestjs-BE/server/src/spaces/spaces.controller.ts +++ b/nestjs-BE/server/src/spaces/spaces.controller.ts @@ -15,7 +15,8 @@ import { CreateSpaceDto } from './dto/create-space.dto'; import { UpdateSpaceDto } from './dto/update-space.dto'; import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; import { UploadService } from 'src/upload/upload.service'; - +import customEnv from 'src/config/env'; +const { BASE_IMAGE_URL } = customEnv; @Controller('spaces') @ApiTags('spaces') export class SpacesController { @@ -35,7 +36,9 @@ export class SpacesController { @UploadedFile() icon: Express.Multer.File, @Body() createSpaceDto: CreateSpaceDto, ) { - const iconUrl = await this.uploadService.uploadFile(icon); + const iconUrl = icon + ? await this.uploadService.uploadFile(icon) + : BASE_IMAGE_URL; createSpaceDto.icon = iconUrl; return this.spacesService.create(createSpaceDto); } @@ -74,8 +77,9 @@ export class SpacesController { @Param('space_uuid') spaceUuid: string, @Body() updateSpaceDto: UpdateSpaceDto, ) { - const iconUrl = await this.uploadService.uploadFile(icon); - updateSpaceDto.icon = iconUrl; + if (icon) { + updateSpaceDto.icon = await this.uploadService.uploadFile(icon); + } return this.spacesService.update(spaceUuid, updateSpaceDto); } From f1aeb5356a862c4007aa0748c837a4e96e476793 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 5 Dec 2023 11:31:23 +0900 Subject: [PATCH 094/170] =?UTF-8?q?chore(#135):=20env=20=EB=B3=80=EC=88=98?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/BE-deploy.yml | 82 ++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 36 deletions(-) diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index c295ddab..d5bd4f61 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -7,44 +7,54 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - with: - ref: BE-develop - sparse-checkout: nestjs-BE - - name: Login to github Packages - run: echo ${{ secrets.PACKAGE_ACCESS_TOKEN }} | docker login ghcr.io -u ${{ secrets.PACKAGE_USERNAME }} --password-stdin - - name: Build and push Docker image - run: | - echo "SERVER_PORT=$SERVER_PORT" >> ./nestjs-BE/server/.env - echo "JWT_SECRET=$JWT_SECRET" >> ./nestjs-BE/server/.env - echo "KAKAO_ADMIN_KEY=$KAKAO_ADMIN_KEY" >> ./nestjs-BE/server/.env - echo "MYSQL_DATABASE_URL=$MYSQL_DATABASE_URL" >> ./nestjs-BE/server/.env - echo "MONGODB_DATABASE_URL=$MONGODB_DATABASE_URL" >> ./nestjs-BE/server/.env - echo "MONGODB_DATABASE_URI=$MONGODB_DATABASE_URI" >> ./nestjs-BE/server/.env - docker build -t ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync ./nestjs-BE/server - docker push ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync:latest - env: - SERVER_PORT: ${{ secrets.CONTAINER_PORT }} - JWT_SECRET: ${{ secrets.JWT_SECRET }} - KAKAO_ADMIN_KEY: ${{ secrets.KAKAO_ADMIN_KEY }} - MYSQL_DATABASE_URL: ${{ secrets.MYSQL_DATABASE_URL }} - MONGODB_DATABASE_URL: ${{ secrets.MONGODB_DATABASE_URL }} - MONGODB_DATABASE_URI: ${{ secrets.MONGODB_DATABASE_URI }} + - uses: actions/checkout@v4 + with: + ref: BE-develop + sparse-checkout: nestjs-BE + - name: Login to github Packages + run: echo ${{ secrets.PACKAGE_ACCESS_TOKEN }} | docker login ghcr.io -u ${{ secrets.PACKAGE_USERNAME }} --password-stdin + - name: Build and push Docker image + run: | + echo "SERVER_PORT=$SERVER_PORT" >> ./nestjs-BE/server/.env + echo "JWT_SECRET=$JWT_SECRET" >> ./nestjs-BE/server/.env + echo "KAKAO_ADMIN_KEY=$KAKAO_ADMIN_KEY" >> ./nestjs-BE/server/.env + echo "MYSQL_DATABASE_URL=$MYSQL_DATABASE_URL" >> ./nestjs-BE/server/.env + echo "MONGODB_DATABASE_URL=$MONGODB_DATABASE_URL" >> ./nestjs-BE/server/.env + echo "NCLOUD_ACCESS_KEY=$NCLOUD_ACCESS_KEY" >> ./nestjs-BE/server/.env + echo "NCLOUD_SECRET_KEY=$NCLOUD_SECRET_KEY" >> ./nestjs-BE/server/.env + echo "NCLOUD_REGION=$NCLOUD_REGION" >> ./nestjs-BE/server/.env + echo "STORAGE_URL=$STORAGE_URL" >> ./nestjs-BE/server/.env + echo "BASE_IMAGE_URL=$BASE_IMAGE_URL" >> ./nestjs-BE/server/.env + echo "BUCKET_NAME=$BUCKET_NAME" >> ./nestjs-BE/server/.env + docker build -t ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync ./nestjs-BE/server + docker push ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync:latest + env: + SERVER_PORT: ${{ secrets.CONTAINER_PORT }} + JWT_SECRET: ${{ secrets.JWT_SECRET }} + KAKAO_ADMIN_KEY: ${{ secrets.KAKAO_ADMIN_KEY }} + MYSQL_DATABASE_URL: ${{ secrets.MYSQL_DATABASE_URL }} + MONGODB_DATABASE_URL: ${{ secrets.MONGODB_DATABASE_URL }} + NCLOUD_ACCESS_KEY: ${{ secrets.NCLOUD_ACCESS_KEY }} + NCLOUD_SECRET_KEY: ${{ secrets.NCLOUD_SECRET_KEY }} + NCLOUD_REGION: ${{ secrets.NCLOUD_REGION }} + STORAGE_URL: ${{ secrets.STORAGE_URL }} + BASE_IMAGE_URL: ${{ secrets.BASE_IMAGE_URL }} + BUCKET_NAME: ${{ secrets.BUCKET_NAME }} deploy: needs: build runs-on: ubuntu-latest steps: - - name: Pull Docker image - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.REMOTE_HOST }} - port: ${{ secrets.REMOTE_PORT }} - username: ${{ secrets.REMOTE_USER }} - key: ${{ secrets.REMOTE_SSH_KEY }} - script: | - echo ${{ secrets.PACKAGE_ACCESS_TOKEN }} | docker login ghcr.io -u ${{ secrets.PACKAGE_USERNAME }} --password-stdin - docker pull ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync - docker stop mindsync_server || true - docker rm mindsync_server || true - docker run -d --name mindsync_server -p ${{ secrets.SERVER_PORT }}:${{ secrets.CONTAINER_PORT }} ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync \ No newline at end of file + - name: Pull Docker image + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.REMOTE_HOST }} + port: ${{ secrets.REMOTE_PORT }} + username: ${{ secrets.REMOTE_USER }} + key: ${{ secrets.REMOTE_SSH_KEY }} + script: | + echo ${{ secrets.PACKAGE_ACCESS_TOKEN }} | docker login ghcr.io -u ${{ secrets.PACKAGE_USERNAME }} --password-stdin + docker pull ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync + docker stop mindsync_server || true + docker rm mindsync_server || true + docker run -d --name mindsync_server -p ${{ secrets.SERVER_PORT }}:${{ secrets.CONTAINER_PORT }} ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync From 6440c1c94f56ec23aea6396793ad05f01f4aa637 Mon Sep 17 00:00:00 2001 From: Yong <108651414+tnpfldyd@users.noreply.github.com> Date: Tue, 5 Dec 2023 11:35:56 +0900 Subject: [PATCH 095/170] =?UTF-8?q?fix:=20=EC=8B=A4=EC=88=98=EB=A1=9C=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=ED=95=9C=20=EB=B6=80=EB=B6=84=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/BE-deploy.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index d5bd4f61..97e0e8d4 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -20,6 +20,7 @@ jobs: echo "KAKAO_ADMIN_KEY=$KAKAO_ADMIN_KEY" >> ./nestjs-BE/server/.env echo "MYSQL_DATABASE_URL=$MYSQL_DATABASE_URL" >> ./nestjs-BE/server/.env echo "MONGODB_DATABASE_URL=$MONGODB_DATABASE_URL" >> ./nestjs-BE/server/.env + echo "MONGODB_DATABASE_URI=$MONGODB_DATABASE_URI" >> ./nestjs-BE/server/.env echo "NCLOUD_ACCESS_KEY=$NCLOUD_ACCESS_KEY" >> ./nestjs-BE/server/.env echo "NCLOUD_SECRET_KEY=$NCLOUD_SECRET_KEY" >> ./nestjs-BE/server/.env echo "NCLOUD_REGION=$NCLOUD_REGION" >> ./nestjs-BE/server/.env @@ -34,6 +35,7 @@ jobs: KAKAO_ADMIN_KEY: ${{ secrets.KAKAO_ADMIN_KEY }} MYSQL_DATABASE_URL: ${{ secrets.MYSQL_DATABASE_URL }} MONGODB_DATABASE_URL: ${{ secrets.MONGODB_DATABASE_URL }} + MONGODB_DATABASE_URI: ${{ secrets.MONGODB_DATABASE_URI }} NCLOUD_ACCESS_KEY: ${{ secrets.NCLOUD_ACCESS_KEY }} NCLOUD_SECRET_KEY: ${{ secrets.NCLOUD_SECRET_KEY }} NCLOUD_REGION: ${{ secrets.NCLOUD_REGION }} From 809303b436fc01941a90c28bb18640e17058c18b Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Tue, 5 Dec 2023 12:09:01 +0900 Subject: [PATCH 096/170] =?UTF-8?q?fix:=20mongodb=20=EB=B3=80=EC=88=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/BE-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index 97e0e8d4..edf93c28 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -35,7 +35,7 @@ jobs: KAKAO_ADMIN_KEY: ${{ secrets.KAKAO_ADMIN_KEY }} MYSQL_DATABASE_URL: ${{ secrets.MYSQL_DATABASE_URL }} MONGODB_DATABASE_URL: ${{ secrets.MONGODB_DATABASE_URL }} - MONGODB_DATABASE_URI: ${{ secrets.MONGODB_DATABASE_URI }} + MONGODB_DATABASE_URI: ${{ secrets.MONGODB_DATABASE_URL }} NCLOUD_ACCESS_KEY: ${{ secrets.NCLOUD_ACCESS_KEY }} NCLOUD_SECRET_KEY: ${{ secrets.NCLOUD_SECRET_KEY }} NCLOUD_REGION: ${{ secrets.NCLOUD_REGION }} From 945aa1ecc7dccac61b3af0cd82bb209d6f8177eb Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Tue, 5 Dec 2023 12:20:19 +0900 Subject: [PATCH 097/170] =?UTF-8?q?fix:=20mongodb=20=EB=B3=80=EC=88=98=20?= =?UTF-8?q?=EC=9B=90=EB=9E=98=EB=8C=80=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/BE-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index edf93c28..97e0e8d4 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -35,7 +35,7 @@ jobs: KAKAO_ADMIN_KEY: ${{ secrets.KAKAO_ADMIN_KEY }} MYSQL_DATABASE_URL: ${{ secrets.MYSQL_DATABASE_URL }} MONGODB_DATABASE_URL: ${{ secrets.MONGODB_DATABASE_URL }} - MONGODB_DATABASE_URI: ${{ secrets.MONGODB_DATABASE_URL }} + MONGODB_DATABASE_URI: ${{ secrets.MONGODB_DATABASE_URI }} NCLOUD_ACCESS_KEY: ${{ secrets.NCLOUD_ACCESS_KEY }} NCLOUD_SECRET_KEY: ${{ secrets.NCLOUD_SECRET_KEY }} NCLOUD_REGION: ${{ secrets.NCLOUD_REGION }} From 63db52c737a7694b83d35ff91f64776905cc6597 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 5 Dec 2023 18:44:10 +0900 Subject: [PATCH 098/170] =?UTF-8?q?fix(#135):=20=EC=9C=A0=EC=A0=80=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20=EB=AA=BB=ED=95=98=EB=8A=94=20=EB=B2=84?= =?UTF-8?q?=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/profiles/profiles.controller.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/nestjs-BE/server/src/profiles/profiles.controller.ts b/nestjs-BE/server/src/profiles/profiles.controller.ts index 077c979e..ed192323 100644 --- a/nestjs-BE/server/src/profiles/profiles.controller.ts +++ b/nestjs-BE/server/src/profiles/profiles.controller.ts @@ -36,7 +36,6 @@ export class ProfilesController { private readonly uploadService: UploadService, ) {} - @Public() @Post() @UseInterceptors(FileInterceptor('image')) @ApiOperation({ summary: 'Create profile' }) From 7aa86d62bb8482cd1e77483cc13fc3ee99fe85b2 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Tue, 5 Dec 2023 20:28:56 +0900 Subject: [PATCH 099/170] =?UTF-8?q?feat(#134):=20=EB=A7=88=EC=9D=B8?= =?UTF-8?q?=EB=93=9C=EB=A7=B5=20=EC=A7=81=EB=A0=AC=ED=99=94,=20=EC=97=AD?= =?UTF-8?q?=EC=A7=81=EB=A0=AC=ED=99=94=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/crdt/clock.ts | 6 +++++ nestjs-BE/server/src/crdt/crdt-tree.ts | 36 ++++++++++++++++++++++---- nestjs-BE/server/src/crdt/node.ts | 11 ++++++++ nestjs-BE/server/src/crdt/tree.ts | 15 +++++++++++ 4 files changed, 63 insertions(+), 5 deletions(-) diff --git a/nestjs-BE/server/src/crdt/clock.ts b/nestjs-BE/server/src/crdt/clock.ts index 975a329f..9b807e89 100644 --- a/nestjs-BE/server/src/crdt/clock.ts +++ b/nestjs-BE/server/src/crdt/clock.ts @@ -31,4 +31,10 @@ export class Clock { } return COMPARE.LESS; } + + static parse(json: string) { + const parsedJson = JSON.parse(json); + const clock = new Clock(parsedJson.id, parsedJson.counter); + return clock; + } } diff --git a/nestjs-BE/server/src/crdt/crdt-tree.ts b/nestjs-BE/server/src/crdt/crdt-tree.ts index ce6b18ae..afd78abd 100644 --- a/nestjs-BE/server/src/crdt/crdt-tree.ts +++ b/nestjs-BE/server/src/crdt/crdt-tree.ts @@ -13,7 +13,7 @@ import { Tree } from './tree'; import { Node } from './node'; export class CrdtTree { - operationLog: OperationLog[] = []; + operationLogs: OperationLog[] = []; clock: Clock; tree = new Tree(); @@ -26,7 +26,7 @@ export class CrdtTree { } addLog(log: OperationLog) { - this.operationLog.push(log); + this.operationLogs.push(log); } generateOperationAdd( @@ -183,16 +183,16 @@ export class CrdtTree { applyOperation(operation: Operation) { this.clock = this.clock.merge(operation.clock); - if (this.operationLog.length === 0) { + if (this.operationLogs.length === 0) { const log = operation.doOperation(this.tree); this.addLog(log); return; } const lastOperation = - this.operationLog[this.operationLog.length - 1].operation; + this.operationLogs[this.operationLogs.length - 1].operation; if (operation.clock.compare(lastOperation.clock) === COMPARE.LESS) { - const prevLog = this.operationLog.pop(); + const prevLog = this.operationLogs.pop(); prevLog.operation.undoOperation(this.tree, prevLog); this.applyOperation(operation); const redoLog = prevLog.operation.redoOperation(this.tree, prevLog); @@ -206,4 +206,30 @@ export class CrdtTree { applyOperations(operations: Operation[]) { for (const operation of operations) this.applyOperation(operation); } + + static parse(json: string) { + const parsedJson = JSON.parse(json); + const crdtTree = new CrdtTree('0'); + crdtTree.clock = Clock.parse(JSON.stringify(parsedJson.clock)); + crdtTree.tree = Tree.parse(JSON.stringify(parsedJson.tree)); + + const operationTypeMap = { + add: crdtTree.deserializeOperationAdd, + delete: crdtTree.deserializeOperationDelete, + move: crdtTree.deserializeOperationMove, + update: crdtTree.deserializeOperationUpdate, + }; + + const parsedOperationLogs = parsedJson.operationLogs.map( + (operationLog: OperationLog) => { + const operationType = operationLog.operation.operationType; + operationLog.operation = operationTypeMap[operationType]( + operationLog.operation, + ); + return operationLog; + }, + ); + crdtTree.operationLogs = parsedOperationLogs; + return crdtTree; + } } diff --git a/nestjs-BE/server/src/crdt/node.ts b/nestjs-BE/server/src/crdt/node.ts index 7a334ce8..78d825f3 100644 --- a/nestjs-BE/server/src/crdt/node.ts +++ b/nestjs-BE/server/src/crdt/node.ts @@ -13,4 +13,15 @@ export class Node { this.parentId = parentId; this.description = description; } + + static parse(json: string) { + const parsedJson = JSON.parse(json); + const node = new Node( + parsedJson.targetId, + parsedJson.parentId, + parsedJson.description, + ); + node.children = parsedJson.children; + return node; + } } diff --git a/nestjs-BE/server/src/crdt/tree.ts b/nestjs-BE/server/src/crdt/tree.ts index a183ceb4..e285a210 100644 --- a/nestjs-BE/server/src/crdt/tree.ts +++ b/nestjs-BE/server/src/crdt/tree.ts @@ -51,4 +51,19 @@ export class Tree { targetNode.description = description; } + + toJSON() { + return { nodes: Array.from(this.nodes) }; + } + + static parse(json: string) { + const { nodes } = JSON.parse(json); + const tree = new Tree(); + tree.nodes = new Map>(); + nodes.forEach(([nodeId, nodeJson]) => { + const node = Node.parse(JSON.stringify(nodeJson)); + tree.nodes.set(nodeId, node); + }); + return tree; + } } From 1d8b320d8a9d862f10dc89aa470b7ceeabcd023b Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Tue, 5 Dec 2023 23:15:05 +0900 Subject: [PATCH 100/170] =?UTF-8?q?refactor:=20operation=20=EC=A7=81?= =?UTF-8?q?=EB=A0=AC=ED=99=94,=20=EC=97=AD=EC=A7=81=EB=A0=AC=ED=99=94=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/crdt/crdt-tree.ts | 109 +------------------------ nestjs-BE/server/src/crdt/operation.ts | 56 +++++++++++++ 2 files changed, 60 insertions(+), 105 deletions(-) diff --git a/nestjs-BE/server/src/crdt/crdt-tree.ts b/nestjs-BE/server/src/crdt/crdt-tree.ts index afd78abd..4462748e 100644 --- a/nestjs-BE/server/src/crdt/crdt-tree.ts +++ b/nestjs-BE/server/src/crdt/crdt-tree.ts @@ -7,7 +7,6 @@ import { OperationLog, OperationMove, OperationUpdate, - SerializedOperation, } from './operation'; import { Tree } from './tree'; import { Node } from './node'; @@ -80,106 +79,6 @@ export class CrdtTree { return new OperationUpdate(input); } - serializeOperationAdd(operation: OperationAdd): SerializedOperation { - const serializedOperation: SerializedOperation = { - operationType: 'add', - id: operation.id, - clock: { id: operation.clock.id, counter: operation.clock.counter }, - description: operation.description, - parentId: operation.parentId, - }; - return serializedOperation; - } - - serializeOperationDelete( - operation: OperationDelete, - ): SerializedOperation { - const serializedOperation: SerializedOperation = { - operationType: 'delete', - id: operation.id, - clock: { id: operation.clock.id, counter: operation.clock.counter }, - }; - return serializedOperation; - } - - serializeOperationMove(operation: OperationMove): SerializedOperation { - const serializedOperation: SerializedOperation = { - operationType: 'move', - id: operation.id, - clock: { id: operation.clock.id, counter: operation.clock.counter }, - parentId: operation.parentId, - }; - return serializedOperation; - } - - serializeOperationUpdate( - operation: OperationUpdate, - ): SerializedOperation { - const serializedOperation: SerializedOperation = { - operationType: 'update', - id: operation.id, - clock: { id: operation.clock.id, counter: operation.clock.counter }, - description: operation.description, - }; - return serializedOperation; - } - - deserializeOperationAdd( - serializedOperation: SerializedOperation, - ): OperationAdd { - const input: OperationInput = { - id: serializedOperation.id, - parentId: serializedOperation.parentId, - description: serializedOperation.description, - clock: new Clock( - serializedOperation.clock.id, - serializedOperation.clock.counter, - ), - }; - return new OperationAdd(input); - } - - deserializeOperationDelete( - serializedOperation: SerializedOperation, - ): OperationDelete { - const input: OperationInput = { - id: serializedOperation.id, - clock: new Clock( - serializedOperation.clock.id, - serializedOperation.clock.counter, - ), - }; - return new OperationDelete(input); - } - - deserializeOperationMove( - serializedOperation: SerializedOperation, - ): OperationMove { - const input: OperationInput = { - id: serializedOperation.id, - parentId: serializedOperation.parentId, - clock: new Clock( - serializedOperation.clock.id, - serializedOperation.clock.counter, - ), - }; - return new OperationMove(input); - } - - deserializeOperationUpdate( - serializedOperation: SerializedOperation, - ): OperationUpdate { - const input: OperationInput = { - id: serializedOperation.id, - description: serializedOperation.description, - clock: new Clock( - serializedOperation.clock.id, - serializedOperation.clock.counter, - ), - }; - return new OperationUpdate(input); - } - applyOperation(operation: Operation) { this.clock = this.clock.merge(operation.clock); @@ -214,10 +113,10 @@ export class CrdtTree { crdtTree.tree = Tree.parse(JSON.stringify(parsedJson.tree)); const operationTypeMap = { - add: crdtTree.deserializeOperationAdd, - delete: crdtTree.deserializeOperationDelete, - move: crdtTree.deserializeOperationMove, - update: crdtTree.deserializeOperationUpdate, + add: OperationAdd.parse, + delete: OperationDelete.parse, + move: OperationMove.parse, + update: OperationUpdate.parse, }; const parsedOperationLogs = parsedJson.operationLogs.map( diff --git a/nestjs-BE/server/src/crdt/operation.ts b/nestjs-BE/server/src/crdt/operation.ts index 006a94d0..f3e28175 100644 --- a/nestjs-BE/server/src/crdt/operation.ts +++ b/nestjs-BE/server/src/crdt/operation.ts @@ -66,6 +66,21 @@ export class OperationAdd extends Operation { tree.attachNode(log.operation.id, this.parentId); return { operation: this }; } + + static parse( + serializedOperation: SerializedOperation, + ): OperationAdd { + const input: OperationInput = { + id: serializedOperation.id, + parentId: serializedOperation.parentId, + description: serializedOperation.description, + clock: new Clock( + serializedOperation.clock.id, + serializedOperation.clock.counter, + ), + }; + return new OperationAdd(input); + } } export class OperationDelete extends Operation { @@ -88,6 +103,19 @@ export class OperationDelete extends Operation { const redoLog = log.operation.doOperation(tree); return redoLog; } + + static parse( + serializedOperation: SerializedOperation, + ): OperationDelete { + const input: OperationInput = { + id: serializedOperation.id, + clock: new Clock( + serializedOperation.clock.id, + serializedOperation.clock.counter, + ), + }; + return new OperationDelete(input); + } } export class OperationMove extends Operation { @@ -116,6 +144,20 @@ export class OperationMove extends Operation { const redoLog = log.operation.doOperation(tree); return redoLog; } + + static parse( + serializedOperation: SerializedOperation, + ): OperationMove { + const input: OperationInput = { + id: serializedOperation.id, + parentId: serializedOperation.parentId, + clock: new Clock( + serializedOperation.clock.id, + serializedOperation.clock.counter, + ), + }; + return new OperationMove(input); + } } export class OperationUpdate extends Operation { @@ -141,4 +183,18 @@ export class OperationUpdate extends Operation { const redoLog = log.operation.doOperation(tree); return redoLog; } + + static parse( + serializedOperation: SerializedOperation, + ): OperationUpdate { + const input: OperationInput = { + id: serializedOperation.id, + description: serializedOperation.description, + clock: new Clock( + serializedOperation.clock.id, + serializedOperation.clock.counter, + ), + }; + return new OperationUpdate(input); + } } From c0efe28d97de16e7f9e33d89acb51927b003288b Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 5 Dec 2023 23:20:03 +0900 Subject: [PATCH 101/170] =?UTF-8?q?fix(#133):=20refresh=20token=EC=9D=84?= =?UTF-8?q?=20=EA=B4=80=EB=A6=AC=ED=95=98=EA=B8=B0=20=EC=9C=84=ED=95=B4=20?= =?UTF-8?q?schema=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migration.sql | 18 ++++++++++++++++-- nestjs-BE/server/prisma/mysql.schema.prisma | 19 +++++++++++++++---- 2 files changed, 31 insertions(+), 6 deletions(-) rename nestjs-BE/server/prisma/migrations/{20231203062911_init => 20231205080004_init}/migration.sql (71%) diff --git a/nestjs-BE/server/prisma/migrations/20231203062911_init/migration.sql b/nestjs-BE/server/prisma/migrations/20231205080004_init/migration.sql similarity index 71% rename from nestjs-BE/server/prisma/migrations/20231203062911_init/migration.sql rename to nestjs-BE/server/prisma/migrations/20231205080004_init/migration.sql index c7113828..ef07d16b 100644 --- a/nestjs-BE/server/prisma/migrations/20231203062911_init/migration.sql +++ b/nestjs-BE/server/prisma/migrations/20231205080004_init/migration.sql @@ -2,9 +2,20 @@ CREATE TABLE `USER_TB` ( `uuid` VARCHAR(32) NOT NULL, `email` VARCHAR(191) NOT NULL, - `password` VARCHAR(191) NOT NULL, + `provider` VARCHAR(191) NOT NULL, - UNIQUE INDEX `USER_TB_email_key`(`email`), + UNIQUE INDEX `USER_TB_email_provider_key`(`email`, `provider`), + PRIMARY KEY (`uuid`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `REFRESH_TOKEN_TB` ( + `uuid` VARCHAR(32) NOT NULL, + `token` VARCHAR(191) NOT NULL, + `expiry_date` DATETIME(3) NOT NULL, + `user_id` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `REFRESH_TOKEN_TB_token_key`(`token`), PRIMARY KEY (`uuid`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; @@ -36,6 +47,9 @@ CREATE TABLE `PROFILE_SPACE_TB` ( PRIMARY KEY (`space_uuid`, `profile_uuid`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +-- AddForeignKey +ALTER TABLE `REFRESH_TOKEN_TB` ADD CONSTRAINT `REFRESH_TOKEN_TB_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `USER_TB`(`uuid`) ON DELETE RESTRICT ON UPDATE CASCADE; + -- AddForeignKey ALTER TABLE `PROFILE_TB` ADD CONSTRAINT `PROFILE_TB_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `USER_TB`(`uuid`) ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/nestjs-BE/server/prisma/mysql.schema.prisma b/nestjs-BE/server/prisma/mysql.schema.prisma index d01cfb9d..1666ccef 100644 --- a/nestjs-BE/server/prisma/mysql.schema.prisma +++ b/nestjs-BE/server/prisma/mysql.schema.prisma @@ -10,9 +10,19 @@ datasource db { model USER_TB { uuid String @id @db.VarChar(32) - email String @unique - password String - profiles PROFILE_TB[] + email String + provider String + profiles PROFILE_TB[] + refresh_tokens REFRESH_TOKEN_TB[] + @@unique([email, provider]) +} + +model REFRESH_TOKEN_TB { + uuid String @id @db.VarChar(32) + token String @unique + expiry_date DateTime + user_id String + user USER_TB @relation(fields: [user_id], references: [uuid]) } model PROFILE_TB { @@ -38,4 +48,5 @@ model PROFILE_SPACE_TB { space SPACE_TB @relation(fields: [space_uuid], references: [uuid]) profile PROFILE_TB @relation(fields: [profile_uuid], references: [uuid]) @@id([space_uuid, profile_uuid]) -} \ No newline at end of file +} + From 0d9719f68e510f75ebca5f0befcd598e73e362f1 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 5 Dec 2023 23:21:11 +0900 Subject: [PATCH 102/170] =?UTF-8?q?fix(#133):=20=ED=85=8C=EC=9D=B4?= =?UTF-8?q?=EB=B8=94=EC=9D=B4=20=EB=B3=80=EA=B2=BD=EB=90=A8=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=9D=BC=20=EB=B3=B5=ED=95=A9=ED=82=A4=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=EB=A5=BC=20=EC=9C=84=ED=95=B4=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/base/base.service.ts | 18 ++++++++++++++++-- .../server/src/users/dto/create-user.dto.ts | 4 ++-- nestjs-BE/server/src/users/users.service.ts | 6 +++--- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/nestjs-BE/server/src/base/base.service.ts b/nestjs-BE/server/src/base/base.service.ts index 64169999..fbf5bf8d 100644 --- a/nestjs-BE/server/src/base/base.service.ts +++ b/nestjs-BE/server/src/base/base.service.ts @@ -86,7 +86,7 @@ export abstract class BaseService { } async remove(key: string) { - const storeData = this.getDataFromCacheOrDB(key); + const storeData = await this.getDataFromCacheOrDB(key); if (!storeData) return; this.cache.delete(key); const insertTemporaryData = this.temporaryDatabaseService.get( @@ -122,11 +122,25 @@ export abstract class BaseService { ); if (temporaryDatabaseData) return temporaryDatabaseData; const databaseData = await this.prisma[this.className].findUnique({ - where: { [this.field]: key }, + where: { + [this.field]: key.includes('+') ? this.stringToObject(key) : key, + }, }); return databaseData; } + stringToObject(key: string) { + const obj = {}; + const keyValuePairs = key.split('+'); + + keyValuePairs.forEach((keyValue) => { + const [key, value] = keyValue.split(':'); + obj[key] = value; + }); + + return obj; + } + private mergeWithUpdateCommand(data: T, key: string): T { const updateCommand = this.temporaryDatabaseService.get( this.className, diff --git a/nestjs-BE/server/src/users/dto/create-user.dto.ts b/nestjs-BE/server/src/users/dto/create-user.dto.ts index f8ef099c..db2d100b 100644 --- a/nestjs-BE/server/src/users/dto/create-user.dto.ts +++ b/nestjs-BE/server/src/users/dto/create-user.dto.ts @@ -4,6 +4,6 @@ export class CreateUserDto { @ApiProperty({ example: 'test@gmail.com', description: 'email adress' }) readonly email: string; - @ApiProperty({ example: 'qwerasdf@!123', description: 'password' }) - readonly password: string; + @ApiProperty({ example: 'kakao', description: 'social site name' }) + readonly provider: string; } diff --git a/nestjs-BE/server/src/users/users.service.ts b/nestjs-BE/server/src/users/users.service.ts index 943ba54c..bf7d05df 100644 --- a/nestjs-BE/server/src/users/users.service.ts +++ b/nestjs-BE/server/src/users/users.service.ts @@ -51,7 +51,7 @@ export class UsersService extends BaseService { temporaryDatabaseService, cacheSize: USER_CACHE_SIZE, className: 'USER_TB', - field: 'email', + field: 'email_provider', }); } @@ -65,8 +65,8 @@ export class UsersService extends BaseService { this.users.push({ uuid: v4(), email }); } - generateKey(data: UpdateUserDto): string { - return data.email; + generateKey(data: UpdateUserDto) { + return `email:${data.email}+provider:${data.provider}`; } async findProfiles(email: string, includeSpaces = false) { From a338e2dfe2dd118985c0c7badd9fd99c4ed493e1 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 5 Dec 2023 23:23:01 +0900 Subject: [PATCH 103/170] =?UTF-8?q?fix(#133):=20access=20token=20payload?= =?UTF-8?q?=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20=EC=82=AD=EC=A0=9C=EB=90=A8?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/auth/jwt.strategy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/auth/jwt.strategy.ts b/nestjs-BE/server/src/auth/jwt.strategy.ts index a929fb88..9f457c54 100644 --- a/nestjs-BE/server/src/auth/jwt.strategy.ts +++ b/nestjs-BE/server/src/auth/jwt.strategy.ts @@ -14,6 +14,6 @@ export class JwtStrategy extends PassportStrategy(Strategy) { } async validate(payload: any) { - return { uuid: payload.sub, email: payload.email }; + return { uuid: payload.sub }; } } From b538d325e4156a1228bca40caf99ce0a2ce84a70 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Tue, 5 Dec 2023 23:24:06 +0900 Subject: [PATCH 104/170] =?UTF-8?q?feat(#133):=20refresh=20token=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EB=B0=8F=20=EC=83=9D=EC=84=B1=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/auth/auth.controller.ts | 11 +++ nestjs-BE/server/src/auth/auth.service.ts | 96 +++++++++++++++++-- nestjs-BE/server/src/config/magic-number.ts | 2 + .../temporary-database.service.ts | 1 + 4 files changed, 104 insertions(+), 6 deletions(-) diff --git a/nestjs-BE/server/src/auth/auth.controller.ts b/nestjs-BE/server/src/auth/auth.controller.ts index 18032889..057fdee9 100644 --- a/nestjs-BE/server/src/auth/auth.controller.ts +++ b/nestjs-BE/server/src/auth/auth.controller.ts @@ -35,6 +35,17 @@ export class AuthController { return this.authService.login(user); } + @Post('token') + @Public() + renewAccessToken(@Body('refresh_token') refreshToken) { + return this.authService.renewAccessToken(refreshToken); + } + + @Post('logout') + logout(@Body('refresh_token') refreshToken) { + return this.authService.remove(refreshToken); + } + @UseGuards(JwtAuthGuard) @Get('profile') getProfile(@Request() req) { diff --git a/nestjs-BE/server/src/auth/auth.service.ts b/nestjs-BE/server/src/auth/auth.service.ts index 77259538..27fc2de8 100644 --- a/nestjs-BE/server/src/auth/auth.service.ts +++ b/nestjs-BE/server/src/auth/auth.service.ts @@ -1,11 +1,42 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, UnauthorizedException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; -import { kakaoOauthConstants } from './constants'; +import { jwtConstants, kakaoOauthConstants } from './constants'; import { stringify } from 'qs'; +import { PrismaServiceMySQL } from 'src/prisma/prisma.service'; +import { TemporaryDatabaseService } from 'src/temporary-database/temporary-database.service'; +import { BaseService } from 'src/base/base.service'; +import { + REFRESH_TOKEN_CACHE_SIZE, + REFRESH_TOKEN_EXPIRY_DAYS, +} from 'src/config/magic-number'; +import generateUuid from 'src/utils/uuid'; + +interface TokenData { + uuid?: string; + token: string; + expiry_date: Date; + user_id: string; +} @Injectable() -export class AuthService { - constructor(private jwtService: JwtService) {} +export class AuthService extends BaseService { + constructor( + private jwtService: JwtService, + protected prisma: PrismaServiceMySQL, + protected temporaryDatabaseService: TemporaryDatabaseService, + ) { + super({ + prisma, + temporaryDatabaseService, + cacheSize: REFRESH_TOKEN_CACHE_SIZE, + className: 'REFRESH_TOKEN_TB', + field: 'token', + }); + } + + generateKey(data: TokenData): string { + return data.token; + } async getKakaoAccount(kakaoUserId: number) { const url = `https://kapi.kakao.com/v2/user/me`; @@ -23,8 +54,61 @@ export class AuthService { return responseBody.kakao_account; } + async createAccessToken(userUuid: string): Promise { + const payload = { sub: userUuid }; + const accessToken = await this.jwtService.signAsync(payload); + return accessToken; + } + + async createRefreshToken(): Promise { + const refreshTokenPayload = { uuid: generateUuid() }; + const refreshToken = await this.jwtService.signAsync(refreshTokenPayload, { + secret: jwtConstants.secret, + expiresIn: '14d', + }); + return refreshToken; + } + + createRefreshTokenData(refreshToken: string, userUuid: string) { + const currentDate = new Date(); + const expiryDate = new Date(currentDate); + expiryDate.setDate(currentDate.getDate() + REFRESH_TOKEN_EXPIRY_DAYS); + const refreshTokenData: TokenData = { + token: refreshToken, + expiry_date: expiryDate, + user_id: userUuid, + }; + return refreshTokenData; + } + async login(user: any) { - const payload = { sub: user.uuid, email: user.email }; - return { access_token: await this.jwtService.signAsync(payload) }; + const refreshToken = await this.createRefreshToken(); + const accessToken = await this.createAccessToken(user.uuid); + const refreshTokenData = this.createRefreshTokenData( + refreshToken, + user.uuid, + ); + super.create(refreshTokenData); + return { + access_token: accessToken, + refresh_token: refreshToken, + }; + } + + async renewAccessToken(refreshToken: string) { + try { + this.jwtService.verify(refreshToken, { + secret: jwtConstants.secret, + }); + const tokenData = await this.getDataFromCacheOrDB(refreshToken); + if (!tokenData) throw new Error('No token data found'); + const accessToken = await this.createAccessToken(tokenData.user_id); + return accessToken; + } catch (error) { + super.remove(refreshToken); + throw new UnauthorizedException( + 'Refresh token expired. Please log in again.', + ); + } } } diff --git a/nestjs-BE/server/src/config/magic-number.ts b/nestjs-BE/server/src/config/magic-number.ts index 47e8df75..3c271ccf 100644 --- a/nestjs-BE/server/src/config/magic-number.ts +++ b/nestjs-BE/server/src/config/magic-number.ts @@ -2,3 +2,5 @@ export const USER_CACHE_SIZE = 1000; export const PROFILE_CACHE_SIZE = 5000; export const SPACE_CACHE_SIZE = 10000; export const BOARD_CACHE_SIZE = 10000; +export const REFRESH_TOKEN_CACHE_SIZE = 1000; +export const REFRESH_TOKEN_EXPIRY_DAYS = 14; diff --git a/nestjs-BE/server/src/temporary-database/temporary-database.service.ts b/nestjs-BE/server/src/temporary-database/temporary-database.service.ts index ea034d8a..e0102d2e 100644 --- a/nestjs-BE/server/src/temporary-database/temporary-database.service.ts +++ b/nestjs-BE/server/src/temporary-database/temporary-database.service.ts @@ -36,6 +36,7 @@ export class TemporaryDatabaseService { 'SPACE_TB', 'BoardCollection', 'PROFILE_SPACE_TB', + 'REFRESH_TOKEN_TB', ]; const operations = ['insert', 'update', 'delete']; From 8b6109929d82c28246a82475ca2304d28e4fb7dc Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Wed, 6 Dec 2023 00:01:47 +0900 Subject: [PATCH 105/170] =?UTF-8?q?refactor:=20operationInput=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EB=AA=85=ED=99=95?= =?UTF-8?q?=ED=95=98=EA=B2=8C=20=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/crdt/crdt-tree.ts | 11 +++++---- nestjs-BE/server/src/crdt/operation.ts | 33 +++++++++++++++++--------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/nestjs-BE/server/src/crdt/crdt-tree.ts b/nestjs-BE/server/src/crdt/crdt-tree.ts index 4462748e..88542065 100644 --- a/nestjs-BE/server/src/crdt/crdt-tree.ts +++ b/nestjs-BE/server/src/crdt/crdt-tree.ts @@ -2,11 +2,14 @@ import { Clock, COMPARE } from './clock'; import { Operation, OperationAdd, + OperationAddInput, OperationDelete, OperationInput, OperationLog, OperationMove, + OperationMoveInput, OperationUpdate, + OperationUpdateInput, } from './operation'; import { Tree } from './tree'; import { Node } from './node'; @@ -35,7 +38,7 @@ export class CrdtTree { ): OperationAdd { this.clock.increment(); const clock = this.clock.copy(); - const input: OperationInput = { + const input: OperationAddInput = { id: targetId, parentId, description, @@ -47,7 +50,7 @@ export class CrdtTree { generateOperationDelete(targetId: string): OperationDelete { this.clock.increment(); const clock = this.clock.copy(); - const input: OperationInput = { + const input: OperationInput = { id: targetId, clock, }; @@ -57,7 +60,7 @@ export class CrdtTree { generateOperationMove(targetId: string, parentId: string): OperationMove { this.clock.increment(); const clock = this.clock.copy(); - const input: OperationInput = { + const input: OperationMoveInput = { id: targetId, parentId, clock, @@ -71,7 +74,7 @@ export class CrdtTree { ): OperationUpdate { this.clock.increment(); const clock = this.clock.copy(); - const input: OperationInput = { + const input: OperationUpdateInput = { id: targetId, description, clock, diff --git a/nestjs-BE/server/src/crdt/operation.ts b/nestjs-BE/server/src/crdt/operation.ts index f3e28175..ef2704c7 100644 --- a/nestjs-BE/server/src/crdt/operation.ts +++ b/nestjs-BE/server/src/crdt/operation.ts @@ -7,11 +7,22 @@ export interface OperationLog { oldDescription?: T; } -export interface OperationInput { +export interface OperationInput { id: string; clock: Clock; - description?: T; - parentId?: string; +} + +export interface OperationAddInput extends OperationInput { + description: T; + parentId: string; +} + +export interface OperationMoveInput extends OperationInput { + parentId: string; +} + +export interface OperationUpdateInput extends OperationInput { + description: T; } interface ClockInterface { @@ -47,7 +58,7 @@ export class OperationAdd extends Operation { description: T; parentId: string; - constructor(input: OperationInput) { + constructor(input: OperationAddInput) { super('add', input.id, input.clock); this.description = input.description; this.parentId = input.parentId; @@ -70,7 +81,7 @@ export class OperationAdd extends Operation { static parse( serializedOperation: SerializedOperation, ): OperationAdd { - const input: OperationInput = { + const input: OperationAddInput = { id: serializedOperation.id, parentId: serializedOperation.parentId, description: serializedOperation.description, @@ -84,7 +95,7 @@ export class OperationAdd extends Operation { } export class OperationDelete extends Operation { - constructor(input: OperationInput) { + constructor(input: OperationInput) { super('delete', input.id, input.clock); } @@ -107,7 +118,7 @@ export class OperationDelete extends Operation { static parse( serializedOperation: SerializedOperation, ): OperationDelete { - const input: OperationInput = { + const input: OperationInput = { id: serializedOperation.id, clock: new Clock( serializedOperation.clock.id, @@ -121,7 +132,7 @@ export class OperationDelete extends Operation { export class OperationMove extends Operation { parentId: string; - constructor(input: OperationInput) { + constructor(input: OperationMoveInput) { super('move', input.id, input.clock); this.parentId = input.parentId; } @@ -148,7 +159,7 @@ export class OperationMove extends Operation { static parse( serializedOperation: SerializedOperation, ): OperationMove { - const input: OperationInput = { + const input: OperationMoveInput = { id: serializedOperation.id, parentId: serializedOperation.parentId, clock: new Clock( @@ -163,7 +174,7 @@ export class OperationMove extends Operation { export class OperationUpdate extends Operation { description: T; - constructor(input: OperationInput) { + constructor(input: OperationUpdateInput) { super('update', input.id, input.clock); this.description = input.description; } @@ -187,7 +198,7 @@ export class OperationUpdate extends Operation { static parse( serializedOperation: SerializedOperation, ): OperationUpdate { - const input: OperationInput = { + const input: OperationUpdateInput = { id: serializedOperation.id, description: serializedOperation.description, clock: new Clock( From 00cd43548916f6f6b1e889b81ac8838841039fc8 Mon Sep 17 00:00:00 2001 From: Yong <108651414+tnpfldyd@users.noreply.github.com> Date: Wed, 6 Dec 2023 11:08:29 +0900 Subject: [PATCH 106/170] =?UTF-8?q?fix:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EB=A5=BC=20=EC=9C=84=ED=95=B4=20=EC=8B=9C=EA=B0=84=20=EC=A4=84?= =?UTF-8?q?=EC=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/auth/auth.module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/auth/auth.module.ts b/nestjs-BE/server/src/auth/auth.module.ts index e4fac2f1..a16f4f87 100644 --- a/nestjs-BE/server/src/auth/auth.module.ts +++ b/nestjs-BE/server/src/auth/auth.module.ts @@ -15,7 +15,7 @@ import { JwtAuthGuard } from './jwt-auth.guard'; PassportModule, JwtModule.register({ secret: jwtConstants.secret, - signOptions: { expiresIn: '5m' }, + signOptions: { expiresIn: '1s' }, }), ], controllers: [AuthController], From 828adc6b56eee1b61faf37c2fc8bfdad67250aac Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Wed, 6 Dec 2023 11:36:40 +0900 Subject: [PATCH 107/170] =?UTF-8?q?rename:=20board=20gateway=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84,=20=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/app.module.ts | 4 ++-- .../board.gateway.ts => board-trees/board-trees.gateway.ts} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename nestjs-BE/server/src/{board/board.gateway.ts => board-trees/board-trees.gateway.ts} (95%) diff --git a/nestjs-BE/server/src/app.module.ts b/nestjs-BE/server/src/app.module.ts index 5a7349ac..2f0d0f98 100644 --- a/nestjs-BE/server/src/app.module.ts +++ b/nestjs-BE/server/src/app.module.ts @@ -1,7 +1,7 @@ import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; -import { BoardGateway } from './board/board.gateway'; +import { BoardTreesGateway } from './board-trees/board-trees.gateway'; import { AuthModule } from './auth/auth.module'; import { UsersModule } from './users/users.module'; import { PrismaModule } from './prisma/prisma.module'; @@ -28,6 +28,6 @@ import customEnv from './config/env'; MongooseModule.forRoot(customEnv.MONGODB_DATABASE_URI), ], controllers: [AppController], - providers: [AppService, BoardGateway], + providers: [AppService, BoardTreesGateway], }) export class AppModule {} diff --git a/nestjs-BE/server/src/board/board.gateway.ts b/nestjs-BE/server/src/board-trees/board-trees.gateway.ts similarity index 95% rename from nestjs-BE/server/src/board/board.gateway.ts rename to nestjs-BE/server/src/board-trees/board-trees.gateway.ts index e68fbc1f..6b9f129c 100644 --- a/nestjs-BE/server/src/board/board.gateway.ts +++ b/nestjs-BE/server/src/board-trees/board-trees.gateway.ts @@ -6,7 +6,7 @@ import { import { Server, Socket } from 'socket.io'; @WebSocketGateway({ namespace: 'board' }) -export class BoardGateway { +export class BoardTreesGateway { @WebSocketServer() server: Server; From 404a325ab4e6608ad9f8ea00dc6196ddd3953adc Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Wed, 6 Dec 2023 11:41:11 +0900 Subject: [PATCH 108/170] =?UTF-8?q?feat:=20board=20trees=20=EB=AA=A8?= =?UTF-8?q?=EB=93=88=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/app.module.ts | 2 ++ nestjs-BE/server/src/board-trees/board-trees.module.ts | 7 +++++++ nestjs-BE/server/src/board-trees/board-trees.service.ts | 4 ++++ 3 files changed, 13 insertions(+) create mode 100644 nestjs-BE/server/src/board-trees/board-trees.module.ts create mode 100644 nestjs-BE/server/src/board-trees/board-trees.service.ts diff --git a/nestjs-BE/server/src/app.module.ts b/nestjs-BE/server/src/app.module.ts index 2f0d0f98..2ec82ee5 100644 --- a/nestjs-BE/server/src/app.module.ts +++ b/nestjs-BE/server/src/app.module.ts @@ -12,6 +12,7 @@ import { BoardsModule } from './boards/boards.module'; import { ScheduleModule } from '@nestjs/schedule'; import { UploadModule } from './upload/upload.module'; import { MongooseModule } from '@nestjs/mongoose'; +import { BoardTreesModule } from './board-trees/board-trees.module'; import customEnv from './config/env'; @Module({ @@ -26,6 +27,7 @@ import customEnv from './config/env'; BoardsModule, UploadModule, MongooseModule.forRoot(customEnv.MONGODB_DATABASE_URI), + BoardTreesModule, ], controllers: [AppController], providers: [AppService, BoardTreesGateway], diff --git a/nestjs-BE/server/src/board-trees/board-trees.module.ts b/nestjs-BE/server/src/board-trees/board-trees.module.ts new file mode 100644 index 00000000..6393f8d3 --- /dev/null +++ b/nestjs-BE/server/src/board-trees/board-trees.module.ts @@ -0,0 +1,7 @@ +import { Module } from '@nestjs/common'; +import { BoardTreesService } from './board-trees.service'; + +@Module({ + providers: [BoardTreesService], +}) +export class BoardTreesModule {} diff --git a/nestjs-BE/server/src/board-trees/board-trees.service.ts b/nestjs-BE/server/src/board-trees/board-trees.service.ts new file mode 100644 index 00000000..abd0ecc3 --- /dev/null +++ b/nestjs-BE/server/src/board-trees/board-trees.service.ts @@ -0,0 +1,4 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BoardTreesService {} From 543299d9735f591051c4cb4fa399b46b795792aa Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Wed, 6 Dec 2023 11:42:07 +0900 Subject: [PATCH 109/170] =?UTF-8?q?fix:=20boards=20gateway=EB=A5=BC=20boar?= =?UTF-8?q?d=20trees=20=EB=AA=A8=EB=93=88=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/app.module.ts | 3 +-- nestjs-BE/server/src/board-trees/board-trees.module.ts | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nestjs-BE/server/src/app.module.ts b/nestjs-BE/server/src/app.module.ts index 2ec82ee5..5a44c8a3 100644 --- a/nestjs-BE/server/src/app.module.ts +++ b/nestjs-BE/server/src/app.module.ts @@ -1,7 +1,6 @@ import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; -import { BoardTreesGateway } from './board-trees/board-trees.gateway'; import { AuthModule } from './auth/auth.module'; import { UsersModule } from './users/users.module'; import { PrismaModule } from './prisma/prisma.module'; @@ -30,6 +29,6 @@ import customEnv from './config/env'; BoardTreesModule, ], controllers: [AppController], - providers: [AppService, BoardTreesGateway], + providers: [AppService], }) export class AppModule {} diff --git a/nestjs-BE/server/src/board-trees/board-trees.module.ts b/nestjs-BE/server/src/board-trees/board-trees.module.ts index 6393f8d3..828ec0ca 100644 --- a/nestjs-BE/server/src/board-trees/board-trees.module.ts +++ b/nestjs-BE/server/src/board-trees/board-trees.module.ts @@ -1,7 +1,8 @@ import { Module } from '@nestjs/common'; import { BoardTreesService } from './board-trees.service'; +import { BoardTreesGateway } from './board-trees.gateway'; @Module({ - providers: [BoardTreesService], + providers: [BoardTreesService, BoardTreesGateway], }) export class BoardTreesModule {} From 329ae22338f88c75e00b5b2958aa18e347074b7d Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Wed, 6 Dec 2023 16:08:14 +0900 Subject: [PATCH 110/170] =?UTF-8?q?fix:=20CrdtTree=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EC=8B=9C=20=EC=A0=9C=EB=84=A4=EB=A6=AD=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EC=A7=80=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/crdt/crdt-tree.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/crdt/crdt-tree.ts b/nestjs-BE/server/src/crdt/crdt-tree.ts index 88542065..d8791b93 100644 --- a/nestjs-BE/server/src/crdt/crdt-tree.ts +++ b/nestjs-BE/server/src/crdt/crdt-tree.ts @@ -111,7 +111,7 @@ export class CrdtTree { static parse(json: string) { const parsedJson = JSON.parse(json); - const crdtTree = new CrdtTree('0'); + const crdtTree = new CrdtTree('0'); crdtTree.clock = Clock.parse(JSON.stringify(parsedJson.clock)); crdtTree.tree = Tree.parse(JSON.stringify(parsedJson.tree)); From 2cd571e69ec1e02ec8280430d86355b507ea78ec Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Wed, 6 Dec 2023 18:11:04 +0900 Subject: [PATCH 111/170] =?UTF-8?q?fix(#136):=20=EC=B4=88=EB=8C=80=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EA=B5=AC=ED=98=84=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20=ED=85=8C=EC=9D=B4=EB=B8=94=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migration.sql | 22 ++++++++++++++---- nestjs-BE/server/prisma/mysql.schema.prisma | 23 +++++++++++++------ 2 files changed, 34 insertions(+), 11 deletions(-) rename nestjs-BE/server/prisma/migrations/{20231205080004_init => 20231206083732_init}/migration.sql (73%) diff --git a/nestjs-BE/server/prisma/migrations/20231205080004_init/migration.sql b/nestjs-BE/server/prisma/migrations/20231206083732_init/migration.sql similarity index 73% rename from nestjs-BE/server/prisma/migrations/20231205080004_init/migration.sql rename to nestjs-BE/server/prisma/migrations/20231206083732_init/migration.sql index ef07d16b..c48b097a 100644 --- a/nestjs-BE/server/prisma/migrations/20231205080004_init/migration.sql +++ b/nestjs-BE/server/prisma/migrations/20231206083732_init/migration.sql @@ -47,14 +47,28 @@ CREATE TABLE `PROFILE_SPACE_TB` ( PRIMARY KEY (`space_uuid`, `profile_uuid`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +-- CreateTable +CREATE TABLE `INVITE_CODE_TB` ( + `uuid` VARCHAR(32) NOT NULL, + `invite_code` VARCHAR(10) NOT NULL, + `space_uuid` VARCHAR(32) NOT NULL, + `expiry_date` DATETIME(3) NOT NULL, + + UNIQUE INDEX `INVITE_CODE_TB_invite_code_key`(`invite_code`), + PRIMARY KEY (`uuid`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- AddForeignKey +ALTER TABLE `REFRESH_TOKEN_TB` ADD CONSTRAINT `REFRESH_TOKEN_TB_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `USER_TB`(`uuid`) ON DELETE CASCADE ON UPDATE CASCADE; + -- AddForeignKey -ALTER TABLE `REFRESH_TOKEN_TB` ADD CONSTRAINT `REFRESH_TOKEN_TB_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `USER_TB`(`uuid`) ON DELETE RESTRICT ON UPDATE CASCADE; +ALTER TABLE `PROFILE_TB` ADD CONSTRAINT `PROFILE_TB_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `USER_TB`(`uuid`) ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey -ALTER TABLE `PROFILE_TB` ADD CONSTRAINT `PROFILE_TB_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `USER_TB`(`uuid`) ON DELETE RESTRICT ON UPDATE CASCADE; +ALTER TABLE `PROFILE_SPACE_TB` ADD CONSTRAINT `PROFILE_SPACE_TB_space_uuid_fkey` FOREIGN KEY (`space_uuid`) REFERENCES `SPACE_TB`(`uuid`) ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey -ALTER TABLE `PROFILE_SPACE_TB` ADD CONSTRAINT `PROFILE_SPACE_TB_space_uuid_fkey` FOREIGN KEY (`space_uuid`) REFERENCES `SPACE_TB`(`uuid`) ON DELETE RESTRICT ON UPDATE CASCADE; +ALTER TABLE `PROFILE_SPACE_TB` ADD CONSTRAINT `PROFILE_SPACE_TB_profile_uuid_fkey` FOREIGN KEY (`profile_uuid`) REFERENCES `PROFILE_TB`(`uuid`) ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey -ALTER TABLE `PROFILE_SPACE_TB` ADD CONSTRAINT `PROFILE_SPACE_TB_profile_uuid_fkey` FOREIGN KEY (`profile_uuid`) REFERENCES `PROFILE_TB`(`uuid`) ON DELETE RESTRICT ON UPDATE CASCADE; +ALTER TABLE `INVITE_CODE_TB` ADD CONSTRAINT `INVITE_CODE_TB_space_uuid_fkey` FOREIGN KEY (`space_uuid`) REFERENCES `SPACE_TB`(`uuid`) ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/nestjs-BE/server/prisma/mysql.schema.prisma b/nestjs-BE/server/prisma/mysql.schema.prisma index 1666ccef..0db50592 100644 --- a/nestjs-BE/server/prisma/mysql.schema.prisma +++ b/nestjs-BE/server/prisma/mysql.schema.prisma @@ -18,11 +18,11 @@ model USER_TB { } model REFRESH_TOKEN_TB { - uuid String @id @db.VarChar(32) - token String @unique + uuid String @id @db.VarChar(32) + token String @unique expiry_date DateTime - user_id String - user USER_TB @relation(fields: [user_id], references: [uuid]) + user_id String + user USER_TB @relation(fields: [user_id], references: [uuid], onDelete: Cascade) } model PROFILE_TB { @@ -30,7 +30,7 @@ model PROFILE_TB { user_id String @db.VarChar(32) image String nickname String - user USER_TB @relation(fields: [user_id], references: [uuid]) + user USER_TB @relation(fields: [user_id], references: [uuid], onDelete: Cascade) spaces PROFILE_SPACE_TB[] @@index([user_id]) } @@ -40,13 +40,22 @@ model SPACE_TB { name String icon String profiles PROFILE_SPACE_TB[] + invite_codes INVITE_CODE_TB[] } model PROFILE_SPACE_TB { space_uuid String @db.VarChar(32) profile_uuid String @db.VarChar(32) - space SPACE_TB @relation(fields: [space_uuid], references: [uuid]) - profile PROFILE_TB @relation(fields: [profile_uuid], references: [uuid]) + space SPACE_TB @relation(fields: [space_uuid], references: [uuid], onDelete: Cascade) + profile PROFILE_TB @relation(fields: [profile_uuid], references: [uuid], onDelete: Cascade) @@id([space_uuid, profile_uuid]) } +model INVITE_CODE_TB { + uuid String @id @db.VarChar(32) + invite_code String @unique @db.VarChar(10) + space_uuid String @db.VarChar(32) + expiry_date DateTime + space SPACE_TB @relation(fields: [space_uuid], references: [uuid], onDelete: Cascade) +} + From f81336795c130af96dc490b7d4030116f7dd417d Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Wed, 6 Dec 2023 18:11:54 +0900 Subject: [PATCH 112/170] =?UTF-8?q?chore(#136):=20JWT=20secret=20access?= =?UTF-8?q?=EC=99=80=20refresh=EB=A1=9C=20=EB=82=98=EB=88=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/BE-deploy.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index 97e0e8d4..8cdca3cf 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -16,7 +16,8 @@ jobs: - name: Build and push Docker image run: | echo "SERVER_PORT=$SERVER_PORT" >> ./nestjs-BE/server/.env - echo "JWT_SECRET=$JWT_SECRET" >> ./nestjs-BE/server/.env + echo "JWT_ACCESS_SECRET=$JWT_ACCESS_SECRET" >> ./nestjs-BE/server/.env + echo "JWT_REFRESH_SECRET=$JWT_REFRESH_SECRET" >> ./nestjs-BE/server/.env echo "KAKAO_ADMIN_KEY=$KAKAO_ADMIN_KEY" >> ./nestjs-BE/server/.env echo "MYSQL_DATABASE_URL=$MYSQL_DATABASE_URL" >> ./nestjs-BE/server/.env echo "MONGODB_DATABASE_URL=$MONGODB_DATABASE_URL" >> ./nestjs-BE/server/.env @@ -31,7 +32,8 @@ jobs: docker push ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync:latest env: SERVER_PORT: ${{ secrets.CONTAINER_PORT }} - JWT_SECRET: ${{ secrets.JWT_SECRET }} + JWT_ACCESS_SECRET: ${{ secrets.JWT_ACCESS_SECRET }} + JWT_REFRESH_SECRET: ${{ secrets.JWT_REFRESH_SECRET }} KAKAO_ADMIN_KEY: ${{ secrets.KAKAO_ADMIN_KEY }} MYSQL_DATABASE_URL: ${{ secrets.MYSQL_DATABASE_URL }} MONGODB_DATABASE_URL: ${{ secrets.MONGODB_DATABASE_URL }} From 253c05f3d21cdaf8fd3c3b94fc2c9f0b0a14d47c Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Wed, 6 Dec 2023 18:15:19 +0900 Subject: [PATCH 113/170] =?UTF-8?q?fix(#133):=20=EC=8B=9C=ED=81=AC?= =?UTF-8?q?=EB=A6=BF=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20=EC=8B=9C=EA=B0=84?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/auth/auth.controller.ts | 8 ++++++-- nestjs-BE/server/src/auth/auth.module.ts | 10 +--------- nestjs-BE/server/src/auth/auth.service.ts | 9 ++++++--- nestjs-BE/server/src/auth/constants.ts | 3 ++- nestjs-BE/server/src/auth/dto/refresh-token.dto.ts | 7 +++++++ nestjs-BE/server/src/auth/jwt.strategy.ts | 2 +- 6 files changed, 23 insertions(+), 16 deletions(-) create mode 100644 nestjs-BE/server/src/auth/dto/refresh-token.dto.ts diff --git a/nestjs-BE/server/src/auth/auth.controller.ts b/nestjs-BE/server/src/auth/auth.controller.ts index 057fdee9..b18b92a9 100644 --- a/nestjs-BE/server/src/auth/auth.controller.ts +++ b/nestjs-BE/server/src/auth/auth.controller.ts @@ -12,6 +12,7 @@ import { JwtAuthGuard } from './jwt-auth.guard'; import { Public } from './public.decorator'; import { KakaoUserDto } from './dto/kakao-user.dto'; import { UsersService } from 'src/users/users.service'; +import { RefreshTokenDto } from './dto/refresh-token.dto'; @Controller('auth') export class AuthController { @@ -37,12 +38,15 @@ export class AuthController { @Post('token') @Public() - renewAccessToken(@Body('refresh_token') refreshToken) { + renewAccessToken(@Body() refreshTokenDto: RefreshTokenDto) { + const refreshToken = refreshTokenDto.refresh_token; return this.authService.renewAccessToken(refreshToken); } @Post('logout') - logout(@Body('refresh_token') refreshToken) { + @Public() + logout(@Body() refreshTokenDto: RefreshTokenDto) { + const refreshToken = refreshTokenDto.refresh_token; return this.authService.remove(refreshToken); } diff --git a/nestjs-BE/server/src/auth/auth.module.ts b/nestjs-BE/server/src/auth/auth.module.ts index a16f4f87..e6de0e89 100644 --- a/nestjs-BE/server/src/auth/auth.module.ts +++ b/nestjs-BE/server/src/auth/auth.module.ts @@ -4,20 +4,12 @@ import { AuthService } from './auth.service'; import { UsersModule } from 'src/users/users.module'; import { PassportModule } from '@nestjs/passport'; import { JwtModule } from '@nestjs/jwt'; -import { jwtConstants } from './constants'; import { JwtStrategy } from './jwt.strategy'; import { APP_GUARD } from '@nestjs/core'; import { JwtAuthGuard } from './jwt-auth.guard'; @Module({ - imports: [ - UsersModule, - PassportModule, - JwtModule.register({ - secret: jwtConstants.secret, - signOptions: { expiresIn: '1s' }, - }), - ], + imports: [UsersModule, PassportModule, JwtModule], controllers: [AuthController], providers: [ AuthService, diff --git a/nestjs-BE/server/src/auth/auth.service.ts b/nestjs-BE/server/src/auth/auth.service.ts index 27fc2de8..d5ca4691 100644 --- a/nestjs-BE/server/src/auth/auth.service.ts +++ b/nestjs-BE/server/src/auth/auth.service.ts @@ -56,14 +56,17 @@ export class AuthService extends BaseService { async createAccessToken(userUuid: string): Promise { const payload = { sub: userUuid }; - const accessToken = await this.jwtService.signAsync(payload); + const accessToken = await this.jwtService.signAsync(payload, { + secret: jwtConstants.accessSecret, + expiresIn: '5m', + }); return accessToken; } async createRefreshToken(): Promise { const refreshTokenPayload = { uuid: generateUuid() }; const refreshToken = await this.jwtService.signAsync(refreshTokenPayload, { - secret: jwtConstants.secret, + secret: jwtConstants.refreshSecret, expiresIn: '14d', }); return refreshToken; @@ -98,7 +101,7 @@ export class AuthService extends BaseService { async renewAccessToken(refreshToken: string) { try { this.jwtService.verify(refreshToken, { - secret: jwtConstants.secret, + secret: jwtConstants.refreshSecret, }); const tokenData = await this.getDataFromCacheOrDB(refreshToken); if (!tokenData) throw new Error('No token data found'); diff --git a/nestjs-BE/server/src/auth/constants.ts b/nestjs-BE/server/src/auth/constants.ts index a5d9e521..bdb08300 100644 --- a/nestjs-BE/server/src/auth/constants.ts +++ b/nestjs-BE/server/src/auth/constants.ts @@ -1,7 +1,8 @@ import customEnv from 'src/config/env'; export const jwtConstants = { - secret: customEnv.JWT_SECRET, + accessSecret: customEnv.JWT_ACCESS_SECRET, + refreshSecret: customEnv.JWT_REFRESH_SECRET, }; export const kakaoOauthConstants = { diff --git a/nestjs-BE/server/src/auth/dto/refresh-token.dto.ts b/nestjs-BE/server/src/auth/dto/refresh-token.dto.ts new file mode 100644 index 00000000..ea39ed4a --- /dev/null +++ b/nestjs-BE/server/src/auth/dto/refresh-token.dto.ts @@ -0,0 +1,7 @@ +import { IsNotEmpty, IsString } from 'class-validator'; + +export class RefreshTokenDto { + @IsString() + @IsNotEmpty() + refresh_token: string; +} diff --git a/nestjs-BE/server/src/auth/jwt.strategy.ts b/nestjs-BE/server/src/auth/jwt.strategy.ts index 9f457c54..8a171c6c 100644 --- a/nestjs-BE/server/src/auth/jwt.strategy.ts +++ b/nestjs-BE/server/src/auth/jwt.strategy.ts @@ -9,7 +9,7 @@ export class JwtStrategy extends PassportStrategy(Strategy) { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, - secretOrKey: jwtConstants.secret, + secretOrKey: jwtConstants.accessSecret, }); } From 7bb3265384793d62cebb212c5d3baaf9290fb42e Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Wed, 6 Dec 2023 18:17:25 +0900 Subject: [PATCH 114/170] =?UTF-8?q?feat(#136):=20=EC=8A=A4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EC=B4=88=EB=8C=80=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/config/magic-number.ts | 3 + .../dto/create-invite-code.dto.ts | 3 + .../invite-codes/invite-codes.controller.ts | 21 ++++ .../src/invite-codes/invite-codes.module.ts | 10 ++ .../src/invite-codes/invite-codes.service.ts | 103 ++++++++++++++++++ .../temporary-database.service.ts | 3 +- 6 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 nestjs-BE/server/src/invite-codes/dto/create-invite-code.dto.ts create mode 100644 nestjs-BE/server/src/invite-codes/invite-codes.controller.ts create mode 100644 nestjs-BE/server/src/invite-codes/invite-codes.module.ts create mode 100644 nestjs-BE/server/src/invite-codes/invite-codes.service.ts diff --git a/nestjs-BE/server/src/config/magic-number.ts b/nestjs-BE/server/src/config/magic-number.ts index 3c271ccf..9776ea9f 100644 --- a/nestjs-BE/server/src/config/magic-number.ts +++ b/nestjs-BE/server/src/config/magic-number.ts @@ -4,3 +4,6 @@ export const SPACE_CACHE_SIZE = 10000; export const BOARD_CACHE_SIZE = 10000; export const REFRESH_TOKEN_CACHE_SIZE = 1000; export const REFRESH_TOKEN_EXPIRY_DAYS = 14; +export const INVITE_CODE_CACHE_SIZE = 5000; +export const INVITE_CODE_LENGTH = 10; +export const INVITE_CODE_EXPIRY_HOURS = 6; diff --git a/nestjs-BE/server/src/invite-codes/dto/create-invite-code.dto.ts b/nestjs-BE/server/src/invite-codes/dto/create-invite-code.dto.ts new file mode 100644 index 00000000..820f5c63 --- /dev/null +++ b/nestjs-BE/server/src/invite-codes/dto/create-invite-code.dto.ts @@ -0,0 +1,3 @@ +export class CreateInviteCodeDto { + space_uuid: string; +} diff --git a/nestjs-BE/server/src/invite-codes/invite-codes.controller.ts b/nestjs-BE/server/src/invite-codes/invite-codes.controller.ts new file mode 100644 index 00000000..d0be951a --- /dev/null +++ b/nestjs-BE/server/src/invite-codes/invite-codes.controller.ts @@ -0,0 +1,21 @@ +import { Controller, Get, Post, Body, Param } from '@nestjs/common'; +import { InviteCodesService } from './invite-codes.service'; +import { CreateInviteCodeDto } from './dto/create-invite-code.dto'; +import { Public } from 'src/auth/public.decorator'; + +@Controller('inviteCodes') +export class InviteCodesController { + constructor(private readonly inviteCodesService: InviteCodesService) {} + + @Post() + @Public() + create(@Body() createInviteCodeDto: CreateInviteCodeDto) { + return this.inviteCodesService.createCode(createInviteCodeDto); + } + + @Get(':inviteCode') + @Public() + findSpace(@Param('inviteCode') inviteCode: string) { + return this.inviteCodesService.findSpace(inviteCode); + } +} diff --git a/nestjs-BE/server/src/invite-codes/invite-codes.module.ts b/nestjs-BE/server/src/invite-codes/invite-codes.module.ts new file mode 100644 index 00000000..ba6ec305 --- /dev/null +++ b/nestjs-BE/server/src/invite-codes/invite-codes.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { InviteCodesService } from './invite-codes.service'; +import { InviteCodesController } from './invite-codes.controller'; +import { SpacesService } from 'src/spaces/spaces.service'; + +@Module({ + controllers: [InviteCodesController], + providers: [InviteCodesService, SpacesService], +}) +export class InviteCodesModule {} diff --git a/nestjs-BE/server/src/invite-codes/invite-codes.service.ts b/nestjs-BE/server/src/invite-codes/invite-codes.service.ts new file mode 100644 index 00000000..af7d208f --- /dev/null +++ b/nestjs-BE/server/src/invite-codes/invite-codes.service.ts @@ -0,0 +1,103 @@ +import { Injectable, HttpException, HttpStatus } from '@nestjs/common'; +import { CreateInviteCodeDto } from './dto/create-invite-code.dto'; +import { BaseService } from 'src/base/base.service'; +import { PrismaServiceMySQL } from 'src/prisma/prisma.service'; +import { TemporaryDatabaseService } from 'src/temporary-database/temporary-database.service'; +import { + INVITE_CODE_CACHE_SIZE, + INVITE_CODE_EXPIRY_HOURS, + INVITE_CODE_LENGTH, +} from 'src/config/magic-number'; +import { SpacesService } from 'src/spaces/spaces.service'; + +export interface InviteCodeData extends CreateInviteCodeDto { + uuid?: string; + invite_code: string; + expiry_date: Date; +} + +@Injectable() +export class InviteCodesService extends BaseService { + constructor( + protected prisma: PrismaServiceMySQL, + protected temporaryDatabaseService: TemporaryDatabaseService, + protected spacesService: SpacesService, + ) { + super({ + prisma, + temporaryDatabaseService, + cacheSize: INVITE_CODE_CACHE_SIZE, + className: 'INVITE_CODE_TB', + field: 'invite_code', + }); + } + + generateKey(data: InviteCodeData): string { + return data.invite_code; + } + + async createCode(createInviteCodeDto: CreateInviteCodeDto) { + const inviteCode = await this.generateUniqueInviteCode(INVITE_CODE_LENGTH); + const currentDate = new Date(); + const expiryDate = new Date(currentDate); + expiryDate.setHours(currentDate.getHours() + INVITE_CODE_EXPIRY_HOURS); + const data: InviteCodeData = { + ...createInviteCodeDto, + invite_code: inviteCode, + expiry_date: expiryDate, + }; + super.create(data); + return { + statusCode: HttpStatus.CREATED, + message: 'Created', + data: { invite_code: inviteCode }, + }; + } + + async findSpace(inviteCode: string) { + const inviteCodeData = await super.getDataFromCacheOrDB(inviteCode); + if (!inviteCodeData) { + throw new HttpException('Invalid invite code.', HttpStatus.BAD_REQUEST); + } + const currentTimestamp = new Date().getTime(); + const expiryTimestamp = new Date(inviteCodeData.expiry_date).getTime(); + if (expiryTimestamp < currentTimestamp) { + super.remove(inviteCode); + throw new HttpException( + 'Invite code has expired.', + HttpStatus.BAD_REQUEST, + ); + } + const spaceUuid = inviteCodeData.space_uuid; + const spaceData = await this.spacesService.getDataFromCacheOrDB(spaceUuid); + return { + statusCode: HttpStatus.OK, + message: 'Success', + data: spaceData, + }; + } + + generateShortInviteCode(length: number) { + const characters = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + let inviteCode = ''; + for (let i = 0; i < length; i++) { + inviteCode += characters.charAt( + Math.floor(Math.random() * characters.length), + ); + } + return inviteCode; + } + + async generateUniqueInviteCode(length: number): Promise { + let inviteCode: string; + let inviteCodeData: InviteCodeData; + + do { + inviteCode = this.generateShortInviteCode(length); + inviteCodeData = await super.getDataFromCacheOrDB(inviteCode); + } while (inviteCodeData !== null); + + return inviteCode; + } +} diff --git a/nestjs-BE/server/src/temporary-database/temporary-database.service.ts b/nestjs-BE/server/src/temporary-database/temporary-database.service.ts index e0102d2e..6e9ec3b8 100644 --- a/nestjs-BE/server/src/temporary-database/temporary-database.service.ts +++ b/nestjs-BE/server/src/temporary-database/temporary-database.service.ts @@ -37,6 +37,7 @@ export class TemporaryDatabaseService { 'BoardCollection', 'PROFILE_SPACE_TB', 'REFRESH_TOKEN_TB', + 'INVITE_CODE_TB', ]; const operations = ['insert', 'update', 'delete']; @@ -111,7 +112,7 @@ export class TemporaryDatabaseService { }); } - @Cron('0 */10 * * * *') + @Cron('* * * * * *') async executeBulkOperations() { for (const service of this.database.keys()) { const serviceMap = this.database.get(service); From 31ce5c8e3d71d97c79d8636e8cafb2a75444359a Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Wed, 6 Dec 2023 18:19:39 +0900 Subject: [PATCH 115/170] =?UTF-8?q?fix(#136):=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=ED=98=95=EC=8B=9D=20=EB=B3=80=ED=99=98=20=EB=B0=8F?= =?UTF-8?q?=20=EB=AA=A8=EB=93=88=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/app.module.ts | 2 ++ nestjs-BE/server/src/base/base.service.ts | 14 ++++++++++---- nestjs-BE/server/src/profiles/profiles.service.ts | 7 +++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/nestjs-BE/server/src/app.module.ts b/nestjs-BE/server/src/app.module.ts index 5a7349ac..9112c682 100644 --- a/nestjs-BE/server/src/app.module.ts +++ b/nestjs-BE/server/src/app.module.ts @@ -12,6 +12,7 @@ import { BoardsModule } from './boards/boards.module'; import { ScheduleModule } from '@nestjs/schedule'; import { UploadModule } from './upload/upload.module'; import { MongooseModule } from '@nestjs/mongoose'; +import { InviteCodesModule } from './invite-codes/invite-codes.module'; import customEnv from './config/env'; @Module({ @@ -26,6 +27,7 @@ import customEnv from './config/env'; BoardsModule, UploadModule, MongooseModule.forRoot(customEnv.MONGODB_DATABASE_URI), + InviteCodesModule, ], controllers: [AppController], providers: [AppService, BoardGateway], diff --git a/nestjs-BE/server/src/base/base.service.ts b/nestjs-BE/server/src/base/base.service.ts index fbf5bf8d..9133d5f4 100644 --- a/nestjs-BE/server/src/base/base.service.ts +++ b/nestjs-BE/server/src/base/base.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, HttpException, HttpStatus } from '@nestjs/common'; import { PrismaServiceMySQL, PrismaServiceMongoDB, @@ -37,15 +37,21 @@ export abstract class BaseService { abstract generateKey(data: T): string; - async create(data: T): Promise { + async create(data: T) { data.uuid = generateUuid(); const key = this.generateKey(data); const storeData = await this.getDataFromCacheOrDB(key); - if (storeData) return 'Data already exists.'; + if (storeData) { + throw new HttpException('Data already exists.', HttpStatus.CONFLICT); + } this.temporaryDatabaseService.create(this.className, key, data); this.cache.put(key, data); - return data; + return { + statusCode: HttpStatus.CREATED, + message: 'Created', + data, + }; } async findOne(key: string): Promise { diff --git a/nestjs-BE/server/src/profiles/profiles.service.ts b/nestjs-BE/server/src/profiles/profiles.service.ts index 21ac9194..a0174387 100644 --- a/nestjs-BE/server/src/profiles/profiles.service.ts +++ b/nestjs-BE/server/src/profiles/profiles.service.ts @@ -29,11 +29,10 @@ export class ProfilesService extends BaseService { return data.uuid; } - async create(data: CreateProfileDto): Promise { + async create(data: CreateProfileDto) { const createdProfile = await super.create(data); - if (typeof createdProfile !== 'string') { - this.temporaryDatabaseService.addEntry(data.user_id, createdProfile.uuid); - } + const profileData = createdProfile.data; + this.temporaryDatabaseService.addEntry(data.user_id, profileData.uuid); return createdProfile; } From 6d914dd86fa35056ca6bd728820e1478ecf995e4 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Wed, 6 Dec 2023 18:51:14 +0900 Subject: [PATCH 116/170] =?UTF-8?q?fix(#188):=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=95=84=20=ED=85=8C=EC=9D=B4=EB=B8=94=20=EB=8B=A8=EC=9D=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{20231206083732_init => 20231206093559_init}/migration.sql | 2 +- nestjs-BE/server/prisma/mysql.schema.prisma | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) rename nestjs-BE/server/prisma/migrations/{20231206083732_init => 20231206093559_init}/migration.sql (98%) diff --git a/nestjs-BE/server/prisma/migrations/20231206083732_init/migration.sql b/nestjs-BE/server/prisma/migrations/20231206093559_init/migration.sql similarity index 98% rename from nestjs-BE/server/prisma/migrations/20231206083732_init/migration.sql rename to nestjs-BE/server/prisma/migrations/20231206093559_init/migration.sql index c48b097a..72079c55 100644 --- a/nestjs-BE/server/prisma/migrations/20231206083732_init/migration.sql +++ b/nestjs-BE/server/prisma/migrations/20231206093559_init/migration.sql @@ -26,7 +26,7 @@ CREATE TABLE `PROFILE_TB` ( `image` VARCHAR(191) NOT NULL, `nickname` VARCHAR(191) NOT NULL, - INDEX `PROFILE_TB_user_id_idx`(`user_id`), + UNIQUE INDEX `PROFILE_TB_user_id_key`(`user_id`), PRIMARY KEY (`uuid`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; diff --git a/nestjs-BE/server/prisma/mysql.schema.prisma b/nestjs-BE/server/prisma/mysql.schema.prisma index 0db50592..3afd38ac 100644 --- a/nestjs-BE/server/prisma/mysql.schema.prisma +++ b/nestjs-BE/server/prisma/mysql.schema.prisma @@ -27,12 +27,11 @@ model REFRESH_TOKEN_TB { model PROFILE_TB { uuid String @id @db.VarChar(32) - user_id String @db.VarChar(32) + user_id String @unique @db.VarChar(32) image String nickname String user USER_TB @relation(fields: [user_id], references: [uuid], onDelete: Cascade) spaces PROFILE_SPACE_TB[] - @@index([user_id]) } model SPACE_TB { From e422f281e524bbb80d0eaaeda400fbb19f187724 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Wed, 6 Dec 2023 19:04:42 +0900 Subject: [PATCH 117/170] =?UTF-8?q?fix(#136):=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EA=B2=80=EC=A6=9D=20=EB=B0=8F=20public=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/src/invite-codes/dto/create-invite-code.dto.ts | 4 ++++ nestjs-BE/server/src/invite-codes/invite-codes.controller.ts | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/nestjs-BE/server/src/invite-codes/dto/create-invite-code.dto.ts b/nestjs-BE/server/src/invite-codes/dto/create-invite-code.dto.ts index 820f5c63..191a05d4 100644 --- a/nestjs-BE/server/src/invite-codes/dto/create-invite-code.dto.ts +++ b/nestjs-BE/server/src/invite-codes/dto/create-invite-code.dto.ts @@ -1,3 +1,7 @@ +import { IsNotEmpty, IsString } from 'class-validator'; + export class CreateInviteCodeDto { + @IsNotEmpty() + @IsString() space_uuid: string; } diff --git a/nestjs-BE/server/src/invite-codes/invite-codes.controller.ts b/nestjs-BE/server/src/invite-codes/invite-codes.controller.ts index d0be951a..8dac1e35 100644 --- a/nestjs-BE/server/src/invite-codes/invite-codes.controller.ts +++ b/nestjs-BE/server/src/invite-codes/invite-codes.controller.ts @@ -1,20 +1,17 @@ import { Controller, Get, Post, Body, Param } from '@nestjs/common'; import { InviteCodesService } from './invite-codes.service'; import { CreateInviteCodeDto } from './dto/create-invite-code.dto'; -import { Public } from 'src/auth/public.decorator'; @Controller('inviteCodes') export class InviteCodesController { constructor(private readonly inviteCodesService: InviteCodesService) {} @Post() - @Public() create(@Body() createInviteCodeDto: CreateInviteCodeDto) { return this.inviteCodesService.createCode(createInviteCodeDto); } @Get(':inviteCode') - @Public() findSpace(@Param('inviteCode') inviteCode: string) { return this.inviteCodesService.findSpace(inviteCode); } From afca6efb7c7bbb25b7d654c32ad4fbfdb6b573d9 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Wed, 6 Dec 2023 19:08:32 +0900 Subject: [PATCH 118/170] =?UTF-8?q?feat(#19,=20#106):=20=EB=B3=B4=EB=93=9C?= =?UTF-8?q?=20=EC=9E=85=EC=9E=A5=20=EC=8B=9C=20=EB=A7=88=EC=9D=B8=EB=93=9C?= =?UTF-8?q?=EB=A7=B5=20=ED=8A=B8=EB=A6=AC=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EB=B3=B4=EB=82=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/board-trees/board-trees.gateway.ts | 12 ++++- .../src/board-trees/board-trees.module.ts | 7 +++ .../src/board-trees/board-trees.service.ts | 44 ++++++++++++++++++- .../board-trees/schemas/board-tree.schema.ts | 15 +++++++ 4 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 nestjs-BE/server/src/board-trees/schemas/board-tree.schema.ts diff --git a/nestjs-BE/server/src/board-trees/board-trees.gateway.ts b/nestjs-BE/server/src/board-trees/board-trees.gateway.ts index 6b9f129c..c1ca1a9e 100644 --- a/nestjs-BE/server/src/board-trees/board-trees.gateway.ts +++ b/nestjs-BE/server/src/board-trees/board-trees.gateway.ts @@ -4,16 +4,26 @@ import { WebSocketServer, } from '@nestjs/websockets'; import { Server, Socket } from 'socket.io'; +import { BoardTreesService } from './board-trees.service'; @WebSocketGateway({ namespace: 'board' }) export class BoardTreesGateway { + constructor(private boardTreesService: BoardTreesService) {} + @WebSocketServer() server: Server; @SubscribeMessage('joinBoard') - handleJoinBoard(client: Socket, payload: string): void { + async handleJoinBoard(client: Socket, payload: string) { const payloadObject = JSON.parse(payload); + if (!this.boardTreesService.hasTree(payloadObject.boardId)) { + await this.boardTreesService.initBoardTree(payloadObject.boardId); + } client.join(payloadObject.boardId); + client.emit( + 'initTree', + this.boardTreesService.getTreeData(payloadObject.boardId), + ); } @SubscribeMessage('updateMindmap') diff --git a/nestjs-BE/server/src/board-trees/board-trees.module.ts b/nestjs-BE/server/src/board-trees/board-trees.module.ts index 828ec0ca..aada1901 100644 --- a/nestjs-BE/server/src/board-trees/board-trees.module.ts +++ b/nestjs-BE/server/src/board-trees/board-trees.module.ts @@ -1,8 +1,15 @@ import { Module } from '@nestjs/common'; import { BoardTreesService } from './board-trees.service'; import { BoardTreesGateway } from './board-trees.gateway'; +import { MongooseModule } from '@nestjs/mongoose'; +import { BoardTree, BoardTreeSchema } from './schemas/board-tree.schema'; @Module({ + imports: [ + MongooseModule.forFeature([ + { name: BoardTree.name, schema: BoardTreeSchema }, + ]), + ], providers: [BoardTreesService, BoardTreesGateway], }) export class BoardTreesModule {} diff --git a/nestjs-BE/server/src/board-trees/board-trees.service.ts b/nestjs-BE/server/src/board-trees/board-trees.service.ts index abd0ecc3..1115b8f9 100644 --- a/nestjs-BE/server/src/board-trees/board-trees.service.ts +++ b/nestjs-BE/server/src/board-trees/board-trees.service.ts @@ -1,4 +1,46 @@ import { Injectable } from '@nestjs/common'; +import { InjectModel } from '@nestjs/mongoose'; +import { BoardTree } from './schemas/board-tree.schema'; +import { Model } from 'mongoose'; +import { CrdtTree } from 'src/crdt/crdt-tree'; @Injectable() -export class BoardTreesService {} +export class BoardTreesService { + constructor( + @InjectModel(BoardTree.name) private boardTreeModel: Model, + ) {} + + private boardTrees = new Map>(); + + async create(boardId: string, tree: string) { + const createdTree = new this.boardTreeModel({ + boardId, + tree, + }); + return createdTree.save(); + } + + async findByBoardId(boardId: string) { + return this.boardTreeModel.findOne({ boardId }).exec(); + } + + getTreeData(boardId: string) { + const boardTree = this.boardTrees.get(boardId); + return JSON.stringify(boardTree); + } + + async initBoardTree(boardId: string) { + const existingTree = await this.findByBoardId(boardId); + if (existingTree) { + this.boardTrees.set(boardId, CrdtTree.parse(existingTree.tree)); + } else { + const newTree = new CrdtTree(boardId); + this.create(boardId, JSON.stringify(newTree)); + this.boardTrees.set(boardId, newTree); + } + } + + hasTree(boardId: string) { + return this.boardTrees.has(boardId); + } +} diff --git a/nestjs-BE/server/src/board-trees/schemas/board-tree.schema.ts b/nestjs-BE/server/src/board-trees/schemas/board-tree.schema.ts new file mode 100644 index 00000000..949cd13c --- /dev/null +++ b/nestjs-BE/server/src/board-trees/schemas/board-tree.schema.ts @@ -0,0 +1,15 @@ +import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; +import { HydratedDocument } from 'mongoose'; + +export type BoardTreeDocument = HydratedDocument; + +@Schema() +export class BoardTree { + @Prop() + boardId: string; + + @Prop() + tree: string; +} + +export const BoardTreeSchema = SchemaFactory.createForClass(BoardTree); From e0d78fb5d3b91131424f4e3b4ba4439fe3e4c5a0 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Wed, 6 Dec 2023 21:48:15 +0900 Subject: [PATCH 119/170] =?UTF-8?q?feat:=20updateMindmap=20=EC=9D=B4?= =?UTF-8?q?=EB=B2=A4=ED=8A=B8=EB=A1=9C=20operation=EC=9D=B4=20=EB=93=A4?= =?UTF-8?q?=EC=96=B4=EC=98=A4=EB=A9=B4=20=ED=8A=B8=EB=A6=AC=EC=97=90=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/board-trees/board-trees.gateway.ts | 24 +++++++++++++++++-- .../src/board-trees/board-trees.service.ts | 6 +++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/nestjs-BE/server/src/board-trees/board-trees.gateway.ts b/nestjs-BE/server/src/board-trees/board-trees.gateway.ts index c1ca1a9e..338fbfc7 100644 --- a/nestjs-BE/server/src/board-trees/board-trees.gateway.ts +++ b/nestjs-BE/server/src/board-trees/board-trees.gateway.ts @@ -5,6 +5,12 @@ import { } from '@nestjs/websockets'; import { Server, Socket } from 'socket.io'; import { BoardTreesService } from './board-trees.service'; +import { + OperationAdd, + OperationDelete, + OperationMove, + OperationUpdate, +} from 'src/crdt/operation'; @WebSocketGateway({ namespace: 'board' }) export class BoardTreesGateway { @@ -29,8 +35,22 @@ export class BoardTreesGateway { @SubscribeMessage('updateMindmap') handleUpdateMindmap(client: Socket, payload: string) { const payloadObject = JSON.parse(payload); + const { boardId, operation: serializedOperation } = payloadObject; + + const operationObject = JSON.parse(serializedOperation); + const operationTypeMap = { + add: OperationAdd.parse, + delete: OperationDelete.parse, + move: OperationMove.parse, + update: OperationUpdate.parse, + }; + + const operation = + operationTypeMap[operationObject.operationType](operationObject); + this.boardTreesService.applyOperation(boardId, operation); + client.broadcast - .to(payloadObject.boardId) - .emit('operationFromServer', JSON.stringify(payloadObject.operation)); + .to(boardId) + .emit('operationFromServer', serializedOperation); } } diff --git a/nestjs-BE/server/src/board-trees/board-trees.service.ts b/nestjs-BE/server/src/board-trees/board-trees.service.ts index 1115b8f9..0fc77236 100644 --- a/nestjs-BE/server/src/board-trees/board-trees.service.ts +++ b/nestjs-BE/server/src/board-trees/board-trees.service.ts @@ -3,6 +3,7 @@ import { InjectModel } from '@nestjs/mongoose'; import { BoardTree } from './schemas/board-tree.schema'; import { Model } from 'mongoose'; import { CrdtTree } from 'src/crdt/crdt-tree'; +import { Operation } from 'src/crdt/operation'; @Injectable() export class BoardTreesService { @@ -40,6 +41,11 @@ export class BoardTreesService { } } + applyOperation(boardId: string, operation: Operation) { + const boardTree = this.boardTrees.get(boardId); + boardTree.applyOperation(operation); + } + hasTree(boardId: string) { return this.boardTrees.has(boardId); } From 5260f55f51437d2f7653e23d2ac535c7f929aef1 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Wed, 6 Dec 2023 22:23:11 +0900 Subject: [PATCH 120/170] =?UTF-8?q?fix(#133):=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EC=B6=9C=EB=A0=A5=20=EB=B0=A9=EC=8B=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/auth/auth.service.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/nestjs-BE/server/src/auth/auth.service.ts b/nestjs-BE/server/src/auth/auth.service.ts index d5ca4691..692180d5 100644 --- a/nestjs-BE/server/src/auth/auth.service.ts +++ b/nestjs-BE/server/src/auth/auth.service.ts @@ -1,4 +1,4 @@ -import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { Injectable, UnauthorizedException, HttpStatus } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { jwtConstants, kakaoOauthConstants } from './constants'; import { stringify } from 'qs'; @@ -93,8 +93,12 @@ export class AuthService extends BaseService { ); super.create(refreshTokenData); return { - access_token: accessToken, - refresh_token: refreshToken, + statusCode: HttpStatus.OK, + message: 'Success', + data: { + access_token: accessToken, + refresh_token: refreshToken, + }, }; } @@ -106,7 +110,11 @@ export class AuthService extends BaseService { const tokenData = await this.getDataFromCacheOrDB(refreshToken); if (!tokenData) throw new Error('No token data found'); const accessToken = await this.createAccessToken(tokenData.user_id); - return accessToken; + return { + statusCode: HttpStatus.OK, + message: 'Success', + data: { acecss_token: accessToken }, + }; } catch (error) { super.remove(refreshToken); throw new UnauthorizedException( From 86839c58dfd14896d0702f883ddcc859f98aeb1e Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 01:11:25 +0900 Subject: [PATCH 121/170] =?UTF-8?q?fix(#188):=20=ED=9A=8C=EC=9B=90=20?= =?UTF-8?q?=EA=B0=80=EC=9E=85=EC=8B=9C=20profile=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=83=9D=EC=84=B1=EB=90=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/auth/auth.controller.ts | 43 ++++++++++++++++--- nestjs-BE/server/src/auth/auth.module.ts | 3 +- nestjs-BE/server/src/auth/auth.service.ts | 33 ++++++++++++-- .../server/src/auth/dto/refresh-token.dto.ts | 5 +++ 4 files changed, 74 insertions(+), 10 deletions(-) diff --git a/nestjs-BE/server/src/auth/auth.controller.ts b/nestjs-BE/server/src/auth/auth.controller.ts index b18b92a9..d16f6de4 100644 --- a/nestjs-BE/server/src/auth/auth.controller.ts +++ b/nestjs-BE/server/src/auth/auth.controller.ts @@ -13,31 +13,62 @@ import { Public } from './public.decorator'; import { KakaoUserDto } from './dto/kakao-user.dto'; import { UsersService } from 'src/users/users.service'; import { RefreshTokenDto } from './dto/refresh-token.dto'; +import { ProfilesService } from 'src/profiles/profiles.service'; +import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; @Controller('auth') +@ApiTags('auth') export class AuthController { constructor( private authService: AuthService, private usersService: UsersService, + private profilesService: ProfilesService, ) {} - @Public() @Post('kakao-oauth') + @Public() + @ApiOperation({ summary: 'kakao login' }) + @ApiResponse({ + status: 200, + description: 'Return the token data.', + }) + @ApiResponse({ + status: 404, + description: 'Not Found.', + }) async kakaoLogin(@Body() kakaoUserDto: KakaoUserDto) { const kakaoUserAccount = await this.authService.getKakaoAccount( kakaoUserDto.kakaoUserId, ); if (!kakaoUserAccount) throw new NotFoundException(); - let user = await this.usersService.findOneByEmail(kakaoUserAccount.email); - if (!user) { - this.usersService.createOne(kakaoUserAccount.email); - user = await this.usersService.findOneByEmail(kakaoUserAccount.email); + const email = kakaoUserAccount.email; + let userUuid = await this.authService.findUser( + this.usersService, + email, + 'kakao', + ); + if (!userUuid) { + const data = { email, provider: 'kakao' }; + userUuid = await this.authService.createUser( + data, + this.usersService, + this.profilesService, + ); } - return this.authService.login(user); + return this.authService.login(userUuid); } @Post('token') @Public() + @ApiOperation({ summary: 'Renew Access Token' }) + @ApiResponse({ + status: 200, + description: 'Return the access token data.', + }) + @ApiResponse({ + status: 401, + description: 'Refresh token expired. Please log in again.', + }) renewAccessToken(@Body() refreshTokenDto: RefreshTokenDto) { const refreshToken = refreshTokenDto.refresh_token; return this.authService.renewAccessToken(refreshToken); diff --git a/nestjs-BE/server/src/auth/auth.module.ts b/nestjs-BE/server/src/auth/auth.module.ts index e6de0e89..14b7cccd 100644 --- a/nestjs-BE/server/src/auth/auth.module.ts +++ b/nestjs-BE/server/src/auth/auth.module.ts @@ -7,9 +7,10 @@ import { JwtModule } from '@nestjs/jwt'; import { JwtStrategy } from './jwt.strategy'; import { APP_GUARD } from '@nestjs/core'; import { JwtAuthGuard } from './jwt-auth.guard'; +import { ProfilesModule } from 'src/profiles/profiles.module'; @Module({ - imports: [UsersModule, PassportModule, JwtModule], + imports: [UsersModule, PassportModule, JwtModule, ProfilesModule], controllers: [AuthController], providers: [ AuthService, diff --git a/nestjs-BE/server/src/auth/auth.service.ts b/nestjs-BE/server/src/auth/auth.service.ts index 692180d5..513d7d5f 100644 --- a/nestjs-BE/server/src/auth/auth.service.ts +++ b/nestjs-BE/server/src/auth/auth.service.ts @@ -10,6 +10,11 @@ import { REFRESH_TOKEN_EXPIRY_DAYS, } from 'src/config/magic-number'; import generateUuid from 'src/utils/uuid'; +import { UsersService } from 'src/users/users.service'; +import { ProfilesService } from 'src/profiles/profiles.service'; +import { CreateUserDto } from 'src/users/dto/create-user.dto'; +import customEnv from 'src/config/env'; +const { BASE_IMAGE_URL } = customEnv; interface TokenData { uuid?: string; @@ -84,12 +89,12 @@ export class AuthService extends BaseService { return refreshTokenData; } - async login(user: any) { + async login(userUuid: string) { const refreshToken = await this.createRefreshToken(); - const accessToken = await this.createAccessToken(user.uuid); + const accessToken = await this.createAccessToken(userUuid); const refreshTokenData = this.createRefreshTokenData( refreshToken, - user.uuid, + userUuid, ); super.create(refreshTokenData); return { @@ -122,4 +127,26 @@ export class AuthService extends BaseService { ); } } + + async findUser(usersService: UsersService, email: string, provider: string) { + const key = `email:${email}+provider:${provider}`; + const findUserData = await usersService.findOne(key); + return findUserData.data?.uuid; + } + + async createUser( + data: CreateUserDto, + usersService: UsersService, + profilesService: ProfilesService, + ) { + const createdData = await usersService.create(data); + const userUuid = createdData.data.uuid; + const profileData = { + user_id: userUuid, + image: BASE_IMAGE_URL, + nickname: '익명의 사용자', + }; + profilesService.create(profileData); + return userUuid; + } } diff --git a/nestjs-BE/server/src/auth/dto/refresh-token.dto.ts b/nestjs-BE/server/src/auth/dto/refresh-token.dto.ts index ea39ed4a..9978f844 100644 --- a/nestjs-BE/server/src/auth/dto/refresh-token.dto.ts +++ b/nestjs-BE/server/src/auth/dto/refresh-token.dto.ts @@ -1,7 +1,12 @@ import { IsNotEmpty, IsString } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; export class RefreshTokenDto { @IsString() @IsNotEmpty() + @ApiProperty({ + example: 'refresh token', + description: 'refresh token', + }) refresh_token: string; } From c8a6778000b13619fcedb111a48d1cf0a5223f2c Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 01:13:24 +0900 Subject: [PATCH 122/170] =?UTF-8?q?fix(#188):=20=EC=97=AD=ED=95=A0=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=EB=A5=BC=20=EC=9C=84=ED=95=B4=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=82=AD=EC=A0=9C=20=EB=B0=8F=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/profiles/profiles.controller.ts | 123 ++------------ .../server/src/profiles/profiles.module.ts | 1 + .../server/src/profiles/profiles.service.ts | 152 +----------------- 3 files changed, 17 insertions(+), 259 deletions(-) diff --git a/nestjs-BE/server/src/profiles/profiles.controller.ts b/nestjs-BE/server/src/profiles/profiles.controller.ts index ed192323..f3a4ba8d 100644 --- a/nestjs-BE/server/src/profiles/profiles.controller.ts +++ b/nestjs-BE/server/src/profiles/profiles.controller.ts @@ -1,26 +1,19 @@ import { Controller, Get, - Post, Body, Patch, - Param, - Delete, UseInterceptors, UploadedFile, Request as Req, } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; import { ProfilesService } from './profiles.service'; -import { CreateProfileDto } from './dto/create-profile.dto'; import { UpdateProfileDto } from './dto/update-profile.dto'; -import { ProfileSpaceDto } from './dto/profile-space.dto'; + import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; import { UploadService } from 'src/upload/upload.service'; -import customEnv from 'src/config/env'; import { Request } from 'express'; -import { Public } from 'src/auth/public.decorator'; -const { BASE_IMAGE_URL } = customEnv; interface RequestWithUser extends Request { user: { @@ -36,127 +29,39 @@ export class ProfilesController { private readonly uploadService: UploadService, ) {} - @Post() - @UseInterceptors(FileInterceptor('image')) - @ApiOperation({ summary: 'Create profile' }) - @ApiResponse({ - status: 201, - description: 'The profile has been successfully created.', - }) - @ApiResponse({ - status: 400, - description: 'Bad Request. Invalid input data.', - }) - async create( - @UploadedFile() image: Express.Multer.File, - @Body() createProfileDto: CreateProfileDto, - @Req() req: RequestWithUser, - ) { - const imageUrl = image - ? await this.uploadService.uploadFile(image) - : BASE_IMAGE_URL; - createProfileDto.image = imageUrl; - createProfileDto.user_id = req.user.uuid; - return this.profilesService.create(createProfileDto); - } - - @Public() - @Get(':profile_uuid') - @ApiOperation({ summary: 'Get profile by profile_uuid' }) + @Get() + @ApiOperation({ summary: 'Get profile' }) @ApiResponse({ status: 200, description: 'Return the profile data.', }) @ApiResponse({ - status: 404, - description: 'Profile not found.', + status: 401, + description: 'Unauthorized.', }) - findOne(@Param('profile_uuid') profileUuid: string) { - return this.profilesService.findOne(profileUuid); + findOne(@Req() req: RequestWithUser) { + return this.profilesService.findOne(req.user.uuid); } - @Public() - @Patch(':profile_uuid') - @ApiOperation({ summary: 'Update profile by profile_uuid' }) + @Patch() + @UseInterceptors(FileInterceptor('image')) + @ApiOperation({ summary: 'Update profile' }) @ApiResponse({ status: 200, description: 'Profile has been successfully updated.', }) @ApiResponse({ - status: 404, - description: 'Profile not found.', + status: 401, + description: 'Unauthorized.', }) async update( @UploadedFile() image: Express.Multer.File, - @Param('profile_uuid') profileUuid: string, + @Req() req: RequestWithUser, @Body() updateProfileDto: UpdateProfileDto, ) { if (image) { updateProfileDto.image = await this.uploadService.uploadFile(image); } - return this.profilesService.update(profileUuid, updateProfileDto); - } - - @Public() - @Delete(':profile_uuid') - @ApiOperation({ summary: 'Remove profile by profile_uuid' }) - @ApiResponse({ - status: 200, - description: 'Profile has been successfully removed.', - }) - @ApiResponse({ - status: 404, - description: 'Profile not found.', - }) - remove(@Param('profile_uuid') profileUuid: string) { - return this.profilesService.remove(profileUuid); - } - - @Public() - @Post('/spaces') - @ApiOperation({ summary: 'Join space' }) - @ApiResponse({ - status: 201, - description: 'Joined the space successfully.', - }) - @ApiResponse({ - status: 400, - description: 'Bad Request. Invalid input data.', - }) - joinSpace(@Body() profileSpaceDto: ProfileSpaceDto) { - return this.profilesService.joinSpace(profileSpaceDto); - } - - @Public() - @Delete(':profile_uuid/spaces/:space_uuid') - @ApiOperation({ summary: 'Leave space' }) - @ApiResponse({ - status: 200, - description: 'Left the space successfully.', - }) - @ApiResponse({ - status: 404, - description: 'Profile or space not found.', - }) - leaveSpace( - @Param('profile_uuid') profileUuid: string, - @Param('space_uuid') spaceUuid: string, - ) { - return this.profilesService.leaveSpace(profileUuid, spaceUuid); - } - - @Public() - @Get('users/:space_uuid') - @ApiOperation({ summary: 'Find users in a space' }) - @ApiResponse({ - status: 200, - description: 'Return the list of users in the space.', - }) - @ApiResponse({ - status: 404, - description: 'Space not found.', - }) - findUsers(@Param('space_uuid') spaceUuid: string) { - return this.profilesService.findUsers(spaceUuid); + return this.profilesService.update(req.user.uuid, updateProfileDto); } } diff --git a/nestjs-BE/server/src/profiles/profiles.module.ts b/nestjs-BE/server/src/profiles/profiles.module.ts index fb2e5537..525bfbfb 100644 --- a/nestjs-BE/server/src/profiles/profiles.module.ts +++ b/nestjs-BE/server/src/profiles/profiles.module.ts @@ -6,5 +6,6 @@ import { UploadService } from 'src/upload/upload.service'; @Module({ controllers: [ProfilesController], providers: [ProfilesService, SpacesService, UploadService], + exports: [ProfilesService], }) export class ProfilesModule {} diff --git a/nestjs-BE/server/src/profiles/profiles.service.ts b/nestjs-BE/server/src/profiles/profiles.service.ts index a0174387..9870259e 100644 --- a/nestjs-BE/server/src/profiles/profiles.service.ts +++ b/nestjs-BE/server/src/profiles/profiles.service.ts @@ -4,9 +4,7 @@ import { TemporaryDatabaseService } from '../temporary-database/temporary-databa import { BaseService } from '../base/base.service'; import { PROFILE_CACHE_SIZE } from 'src/config/magic-number'; import { UpdateProfileDto } from './dto/update-profile.dto'; -import { CreateProfileDto } from './dto/create-profile.dto'; import { SpacesService } from '../spaces/spaces.service'; -import { ProfileSpaceDto } from './dto/profile-space.dto'; @Injectable() export class ProfilesService extends BaseService { @@ -21,157 +19,11 @@ export class ProfilesService extends BaseService { temporaryDatabaseService, cacheSize: PROFILE_CACHE_SIZE, className: 'PROFILE_TB', - field: 'uuid', + field: 'user_id', }); } generateKey(data: UpdateProfileDto): string { - return data.uuid; - } - - async create(data: CreateProfileDto) { - const createdProfile = await super.create(data); - const profileData = createdProfile.data; - this.temporaryDatabaseService.addEntry(data.user_id, profileData.uuid); - return createdProfile; - } - - async remove(key: string) { - const profile = await super.getDataFromCacheOrDB(key); - if (profile) { - this.temporaryDatabaseService.removeEntry(profile.user_id, key); - } - await super.remove(key); - } - - async joinSpace(data: ProfileSpaceDto) { - const { profile_uuid: profileUuid, space_uuid: spaceUuid } = data; - const result = await this.getProfileAndSpace(profileUuid, spaceUuid); - if (typeof result === 'string') return result; - const key = `${profileUuid}_${spaceUuid}`; - const isExists = await this.isDataExists(key, spaceUuid, profileUuid); - if (typeof isExists === 'string') return isExists; - - this.temporaryDatabaseService.create(this.profileSpaceTable, key, data); - this.temporaryDatabaseService.addEntry(profileUuid, spaceUuid); - this.temporaryDatabaseService.addEntry(spaceUuid, profileUuid); - } - - async leaveSpace(profileUuid: string, spaceUuid: string) { - const result = await this.getProfileAndSpace(profileUuid, spaceUuid); - if (typeof result === 'string') return result; - const key = `${profileUuid}_${spaceUuid}`; - const insertTemporaryData = this.temporaryDatabaseService.get( - this.profileSpaceTable, - key, - 'insert', - ); - if (insertTemporaryData) { - this.temporaryDatabaseService.delete( - this.profileSpaceTable, - key, - 'insert', - ); - this.temporaryDatabaseService.removeEntry(profileUuid, spaceUuid); - this.temporaryDatabaseService.removeEntry(spaceUuid, profileUuid); - } else { - const data = { - field: 'space_uuid_profile_uuid', - value: { - space_uuid: spaceUuid, - profile_uuid: profileUuid, - }, - }; - this.temporaryDatabaseService.remove(this.profileSpaceTable, key, data); - } - } - - private async getProfileAndSpace(profileUuid: string, spaceUuid: string) { - const profile = await super.getDataFromCacheOrDB(profileUuid); - if (!profile) return `Profile not found: ${profileUuid}`; - const space = await this.spacesService.getDataFromCacheOrDB(spaceUuid); - if (!space) return `Space not found: ${spaceUuid}`; - return { profile, space }; - } - - async isDataExists(key: string, space_uuid: string, profile_uuid: string) { - const existingEntry = await this.prisma[this.profileSpaceTable].findUnique({ - where: { - space_uuid_profile_uuid: { - space_uuid, - profile_uuid, - }, - }, - }); - - const existingTempEntry = this.temporaryDatabaseService.get( - this.profileSpaceTable, - key, - 'insert', - ); - - const deleteTemporaryData = this.temporaryDatabaseService.get( - this.profileSpaceTable, - key, - 'delete', - ); - if (deleteTemporaryData) { - this.temporaryDatabaseService.delete( - this.profileSpaceTable, - key, - 'delete', - ); - return 'Removed the data scheduled for deletion and re-joined the room.'; - } - if (existingEntry || existingTempEntry) { - return 'Data already exists.'; - } - return; - } - - async findUsers(uuid: string) { - const space = await this.prisma['SPACE_TB'].findUnique({ - where: { - uuid, - }, - include: { - profiles: { include: { profile: true } }, - }, - }); - - space.profiles = space.profiles.filter((profileSpace) => { - const deleteTempData = this.temporaryDatabaseService.get( - 'PROFILE_SPACE_TB', - `${profileSpace.profile_uuid}_${profileSpace.space_uuid}`, - 'delete', - ); - return !deleteTempData; - }); - - const spaceUuidsFromTempDB = this.temporaryDatabaseService.getEntries(uuid); - const addedProfiles = await Promise.all( - spaceUuidsFromTempDB.map(async (spaceUuid) => { - const insertTempData = this.temporaryDatabaseService.get( - 'PROFILE_SPACE_TB', - `${spaceUuid}_${uuid}`, - 'insert', - ); - if (insertTempData) { - const userProfile = await super.getDataFromCacheOrDB(spaceUuid); - if (userProfile) { - return { - profile_uuid: spaceUuid, - profile: userProfile, - }; - } - } - return null; - }), - ); - space.profiles = [ - ...space.profiles, - ...addedProfiles.filter((profile) => profile), - ]; - return space.profiles.map((profileSpace) => profileSpace.profile); + return data.user_id; } } From 87718e511f2c511b4ccb5a8c831b8d51ef32d7f3 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 01:13:43 +0900 Subject: [PATCH 123/170] =?UTF-8?q?fix(#188):=20=EB=A6=AC=ED=84=B4=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=AA=85=ED=99=95=ED=95=98?= =?UTF-8?q?=EA=B2=8C=20=EB=AA=85=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/base/base.service.ts | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/nestjs-BE/server/src/base/base.service.ts b/nestjs-BE/server/src/base/base.service.ts index 9133d5f4..b7abe3ce 100644 --- a/nestjs-BE/server/src/base/base.service.ts +++ b/nestjs-BE/server/src/base/base.service.ts @@ -54,7 +54,7 @@ export abstract class BaseService { }; } - async findOne(key: string): Promise { + async findOne(key: string) { const data = await this.getDataFromCacheOrDB(key); const deleteCommand = this.temporaryDatabaseService.get( this.className, @@ -65,10 +65,17 @@ export abstract class BaseService { if (data) { const mergedData = this.mergeWithUpdateCommand(data, key); this.cache.put(key, mergedData); - return mergedData; + return { + statusCode: HttpStatus.OK, + message: 'Success', + data: mergedData, + }; } - return data; + return { + statusCode: HttpStatus.NOT_FOUND, + message: 'Not Found', + }; } async update(key: string, updateData: T) { @@ -88,7 +95,16 @@ export abstract class BaseService { this.temporaryDatabaseService.update(this.className, key, updatedData); } this.cache.put(key, updatedData.value); + return { + statusCode: HttpStatus.OK, + message: 'Success', + data: updatedData.value, + }; } + return { + statusCode: HttpStatus.NOT_FOUND, + message: 'Not Found', + }; } async remove(key: string) { From 5557488a21e2de4ca1f4ec6bac629546002a0b86 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 01:18:20 +0900 Subject: [PATCH 124/170] =?UTF-8?q?fix(#188):=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=EB=A5=BC=20=EC=9C=84=ED=95=B4=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/src/users/entities/user.entity.ts | 1 - .../server/src/users/users.controller.spec.ts | 20 --- .../server/src/users/users.controller.ts | 115 ------------ nestjs-BE/server/src/users/users.module.ts | 2 - nestjs-BE/server/src/users/users.service.ts | 165 ------------------ 5 files changed, 303 deletions(-) delete mode 100644 nestjs-BE/server/src/users/entities/user.entity.ts delete mode 100644 nestjs-BE/server/src/users/users.controller.spec.ts delete mode 100644 nestjs-BE/server/src/users/users.controller.ts diff --git a/nestjs-BE/server/src/users/entities/user.entity.ts b/nestjs-BE/server/src/users/entities/user.entity.ts deleted file mode 100644 index 4f82c145..00000000 --- a/nestjs-BE/server/src/users/entities/user.entity.ts +++ /dev/null @@ -1 +0,0 @@ -export class User {} diff --git a/nestjs-BE/server/src/users/users.controller.spec.ts b/nestjs-BE/server/src/users/users.controller.spec.ts deleted file mode 100644 index a76d3103..00000000 --- a/nestjs-BE/server/src/users/users.controller.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { UsersController } from './users.controller'; -import { UsersService } from './users.service'; - -describe('UsersController', () => { - let controller: UsersController; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [UsersController], - providers: [UsersService], - }).compile(); - - controller = module.get(UsersController); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); -}); diff --git a/nestjs-BE/server/src/users/users.controller.ts b/nestjs-BE/server/src/users/users.controller.ts deleted file mode 100644 index e76fe3b5..00000000 --- a/nestjs-BE/server/src/users/users.controller.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { - Controller, - Get, - Post, - Body, - Patch, - Param, - Delete, -} from '@nestjs/common'; -import { UsersService } from './users.service'; -import { CreateUserDto } from './dto/create-user.dto'; -import { UpdateUserDto } from './dto/update-user.dto'; -import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; -import { Public } from 'src/auth/public.decorator'; - -@Controller('users') -@ApiTags('users') -export class UsersController { - constructor(private readonly usersService: UsersService) {} - - @Public() - @Post() - @ApiOperation({ summary: 'Create user' }) - @ApiResponse({ - status: 201, - description: 'The user has been successfully created.', - }) - @ApiResponse({ - status: 409, - description: 'User with the provided email already exists.', - }) - @ApiResponse({ - status: 400, - description: 'Bad Request. Invalid input data.', - }) - create(@Body() createUserDto: CreateUserDto) { - return this.usersService.create(createUserDto); - } - - @Public() - @Get(':email') - @ApiOperation({ summary: 'Get user' }) - @ApiResponse({ - status: 200, - description: 'Return the user data.', - }) - @ApiResponse({ - status: 404, - description: 'User not found.', - }) - @ApiOperation({ summary: 'Get user' }) - findOne(@Param('email') email: string) { - return this.usersService.findOne(email); - } - - @Public() - @Patch(':email') - @ApiOperation({ summary: 'Update user' }) - @ApiResponse({ - status: 200, - description: 'User has been successfully updated.', - }) - @ApiResponse({ - status: 404, - description: 'User not found.', - }) - update(@Param('email') email: string, @Body() updateUserDto: UpdateUserDto) { - return this.usersService.update(email, updateUserDto); - } - - @Public() - @Delete(':email') - @ApiOperation({ summary: 'Remove user' }) - @ApiResponse({ - status: 200, - description: 'User has been successfully removed.', - }) - @ApiResponse({ - status: 404, - description: 'User not found.', - }) - remove(@Param('email') email: string) { - return this.usersService.remove(email); - } - - @Public() - @Get('profiles/:email') - @ApiOperation({ summary: 'Find profiles for a user' }) - @ApiResponse({ - status: 200, - description: 'Return the list of profiles for the user.', - }) - @ApiResponse({ - status: 404, - description: 'User not found.', - }) - findProfiles(@Param('email') email: string) { - return this.usersService.findProfiles(email); - } - - @Public() - @Get('rooms/:email') - @ApiOperation({ summary: 'Find rooms for a user' }) - @ApiResponse({ - status: 200, - description: 'Return the list of rooms for the user.', - }) - @ApiResponse({ - status: 404, - description: 'User not found.', - }) - findRooms(@Param('email') email: string) { - return this.usersService.findRooms(email); - } -} diff --git a/nestjs-BE/server/src/users/users.module.ts b/nestjs-BE/server/src/users/users.module.ts index 89102492..153ff941 100644 --- a/nestjs-BE/server/src/users/users.module.ts +++ b/nestjs-BE/server/src/users/users.module.ts @@ -1,10 +1,8 @@ import { Module } from '@nestjs/common'; import { UsersService } from './users.service'; -import { UsersController } from './users.controller'; import { SpacesService } from 'src/spaces/spaces.service'; @Module({ - controllers: [UsersController], providers: [UsersService, SpacesService], exports: [UsersService], }) diff --git a/nestjs-BE/server/src/users/users.service.ts b/nestjs-BE/server/src/users/users.service.ts index bf7d05df..be26c750 100644 --- a/nestjs-BE/server/src/users/users.service.ts +++ b/nestjs-BE/server/src/users/users.service.ts @@ -4,47 +4,12 @@ import { TemporaryDatabaseService } from '../temporary-database/temporary-databa import { BaseService } from '../base/base.service'; import { USER_CACHE_SIZE } from '../config/magic-number'; import { UpdateUserDto } from './dto/update-user.dto'; -import { ProfileSpaceDto } from 'src/profiles/dto/profile-space.dto'; -import { SpacesService } from 'src/spaces/spaces.service'; -import { v4 } from 'uuid'; - -interface Profile { - spaces: ProfileSpaceDto[]; -} - -type IncludeObject = { - profiles: - | boolean - | { - include?: { - spaces: - | boolean - | { - include?: { - space: boolean; - }; - }; - }; - }; -}; - -interface Item extends ProfileSpaceDto { - uuid?: string; -} - -export type User = { - uuid: string; - email: string; -}; @Injectable() export class UsersService extends BaseService { - profileTable = 'PROFILE_TB'; - profileSpaceTable = 'PROFILE_SPACE_TB'; constructor( protected prisma: PrismaServiceMySQL, protected temporaryDatabaseService: TemporaryDatabaseService, - protected spacesService: SpacesService, ) { super({ prisma, @@ -55,137 +20,7 @@ export class UsersService extends BaseService { }); } - private readonly users: User[] = []; - - async findOneByEmail(email: string): Promise { - return this.users.find((user) => user.email === email); - } - - createOne(email: string) { - this.users.push({ uuid: v4(), email }); - } - generateKey(data: UpdateUserDto) { return `email:${data.email}+provider:${data.provider}`; } - - async findProfiles(email: string, includeSpaces = false) { - const user = await this.getUser(email, includeSpaces); - if (!user) return; - - const profiles = user.profiles || []; - const temporaryProfiles = this.getTemporaryProfiles(user); - const combinedProfiles = [...profiles, ...temporaryProfiles]; - const mergedData = this.mergeProfileData(combinedProfiles); - - return mergedData; - } - - async getUser(email: string, includeSpaces = false) { - const includeObject: IncludeObject = { profiles: true }; - - if (includeSpaces) { - includeObject.profiles = { - include: { - spaces: { - include: { - space: true, - }, - }, - }, - }; - } - let user = await this.prisma[this.className].findUnique({ - where: { email }, - include: includeObject, - }); - if (!user) user = await super.getDataFromCacheOrDB(email); - if (user && user.profiles) { - user.profiles = this.filterNotDeleted(this.profileTable, user.profiles); - - if (includeSpaces) { - user.profiles.forEach((profile: Profile) => { - if (profile.spaces) { - profile.spaces = this.filterNotDeleted( - this.profileSpaceTable, - profile.spaces, - ); - } - }); - } - } - return user; - } - - filterNotDeleted(tableName: string, items: Item[]) { - return items.filter((item) => { - let key = item.uuid; - if (item.profile_uuid && item.space_uuid) { - key = `${item.profile_uuid}_${item.space_uuid}`; - } - - const deleteOperation = this.temporaryDatabaseService.get( - tableName, - key, - 'delete', - ); - return !deleteOperation; - }); - } - - getTemporaryProfiles(user: UpdateUserDto) { - const temporaryProfilesUuids = this.temporaryDatabaseService.getEntries( - user.uuid, - ); - const temporaryProfiles = temporaryProfilesUuids.map((uuid) => - this.temporaryDatabaseService.get(this.profileTable, uuid, 'insert'), - ); - return temporaryProfiles; - } - - mergeProfileData(combinedProfiles: UpdateUserDto[]) { - const mergedData = combinedProfiles.map((data) => { - const updateOperation = this.temporaryDatabaseService.get( - this.profileTable, - data.uuid, - 'update', - ); - if (updateOperation) return { ...data, ...updateOperation.value }; - return data; - }); - return mergedData; - } - - async findRooms(email: string) { - const profiles = await this.findProfiles(email, true); - if (!profiles) return; - const spaceList = await profiles.reduce(async (listPromise, profile) => { - const list = await listPromise; - const spaceUuidsFromTempDB = this.temporaryDatabaseService.getEntries( - profile.uuid, - ); - profile.spaces = profile.spaces.filter((profileSpace) => { - const deleteTempData = this.temporaryDatabaseService.get( - this.profileSpaceTable, - `${profileSpace.profile_uuid}_${profileSpace.space_uuid}`, - 'delete', - ); - return !deleteTempData; - }); - const updatedSpaces = await Promise.all( - spaceUuidsFromTempDB.map(async (spaceUuid) => { - const space = - await this.spacesService.getDataFromCacheOrDB(spaceUuid); - return { space_uuid: spaceUuid, profile_uuid: profile.uuid, space }; - }), - ); - profile.spaces = [...profile.spaces, ...updatedSpaces]; - const spaces = profile.spaces - .filter((profileSpace) => profileSpace.space) - .map((profileSpace) => profileSpace.space); - - return list.concat(spaces); - }, Promise.resolve([])); - return spaceList; - } } From d66b918114f2d1188edb627eef0c86ed998b4c89 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 01:34:08 +0900 Subject: [PATCH 125/170] =?UTF-8?q?fix(#188):=20=ED=8D=BC=EB=B8=94?= =?UTF-8?q?=EB=A6=AD=20=EB=8D=B0=EC=BD=94=EB=A0=88=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/spaces/spaces.controller.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/nestjs-BE/server/src/spaces/spaces.controller.ts b/nestjs-BE/server/src/spaces/spaces.controller.ts index 7f70e486..1ee595e6 100644 --- a/nestjs-BE/server/src/spaces/spaces.controller.ts +++ b/nestjs-BE/server/src/spaces/spaces.controller.ts @@ -15,7 +15,6 @@ import { CreateSpaceDto } from './dto/create-space.dto'; import { UpdateSpaceDto } from './dto/update-space.dto'; import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; import { UploadService } from 'src/upload/upload.service'; -import { Public } from 'src/auth/public.decorator'; import customEnv from 'src/config/env'; const { BASE_IMAGE_URL } = customEnv; @@ -27,7 +26,6 @@ export class SpacesController { private readonly uploadService: UploadService, ) {} - @Public() @Post() @UseInterceptors(FileInterceptor('icon')) @ApiOperation({ summary: 'Create space' }) @@ -46,7 +44,6 @@ export class SpacesController { return this.spacesService.create(createSpaceDto); } - @Public() @Get(':space_uuid') @ApiOperation({ summary: 'Get space by space_uuid' }) @ApiResponse({ @@ -61,7 +58,6 @@ export class SpacesController { return this.spacesService.findOne(spaceUuid); } - @Public() @Patch(':space_uuid') @UseInterceptors(FileInterceptor('icon')) @ApiOperation({ summary: 'Update space by space_uuid' }) @@ -88,7 +84,6 @@ export class SpacesController { return this.spacesService.update(spaceUuid, updateSpaceDto); } - @Public() @Delete(':space_uuid') @ApiOperation({ summary: 'Remove space by space_uuid' }) @ApiResponse({ From c0879e51c449eddc2c9fc0eaa8ff601177256e29 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 01:37:51 +0900 Subject: [PATCH 126/170] =?UTF-8?q?fix(#188):=20=EB=8B=A4=EC=96=91?= =?UTF-8?q?=ED=95=9C=20=EA=B3=B3=EC=97=90=EC=84=9C=20=EC=93=B0=EA=B8=B0=20?= =?UTF-8?q?=EC=9C=84=ED=95=98=EC=97=AC=20utils=20=ED=8F=B4=EB=8D=94?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/profiles/profiles.controller.ts | 8 +------- nestjs-BE/server/src/utils/interface.ts | 6 ++++++ 2 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 nestjs-BE/server/src/utils/interface.ts diff --git a/nestjs-BE/server/src/profiles/profiles.controller.ts b/nestjs-BE/server/src/profiles/profiles.controller.ts index f3a4ba8d..88c177dd 100644 --- a/nestjs-BE/server/src/profiles/profiles.controller.ts +++ b/nestjs-BE/server/src/profiles/profiles.controller.ts @@ -13,13 +13,7 @@ import { UpdateProfileDto } from './dto/update-profile.dto'; import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; import { UploadService } from 'src/upload/upload.service'; -import { Request } from 'express'; - -interface RequestWithUser extends Request { - user: { - uuid: string; - }; -} +import { RequestWithUser } from 'src/utils/interface'; @Controller('profiles') @ApiTags('profiles') diff --git a/nestjs-BE/server/src/utils/interface.ts b/nestjs-BE/server/src/utils/interface.ts new file mode 100644 index 00000000..05104ac2 --- /dev/null +++ b/nestjs-BE/server/src/utils/interface.ts @@ -0,0 +1,6 @@ +import { Request } from 'express'; +export interface RequestWithUser extends Request { + user: { + uuid: string; + }; +} From 2e89d47be7bfa693c2fcc8ed0a2210d8a5129f4a Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 7 Dec 2023 02:04:48 +0900 Subject: [PATCH 127/170] =?UTF-8?q?fix:=20=ED=8A=B8=EB=A6=AC=20toJSON=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/crdt/tree.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/crdt/tree.ts b/nestjs-BE/server/src/crdt/tree.ts index e285a210..8f94c6bd 100644 --- a/nestjs-BE/server/src/crdt/tree.ts +++ b/nestjs-BE/server/src/crdt/tree.ts @@ -53,7 +53,7 @@ export class Tree { } toJSON() { - return { nodes: Array.from(this.nodes) }; + return { nodes: Array.from(this.nodes.values()) }; } static parse(json: string) { From 0f8490cca31c4e1f22b60091c2848389e06cf2f9 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 7 Dec 2023 02:13:51 +0900 Subject: [PATCH 128/170] =?UTF-8?q?fix:=20tree=20parse=EB=8F=84=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/crdt/tree.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nestjs-BE/server/src/crdt/tree.ts b/nestjs-BE/server/src/crdt/tree.ts index 8f94c6bd..f0ea9066 100644 --- a/nestjs-BE/server/src/crdt/tree.ts +++ b/nestjs-BE/server/src/crdt/tree.ts @@ -60,9 +60,9 @@ export class Tree { const { nodes } = JSON.parse(json); const tree = new Tree(); tree.nodes = new Map>(); - nodes.forEach(([nodeId, nodeJson]) => { + nodes.forEach((nodeJson) => { const node = Node.parse(JSON.stringify(nodeJson)); - tree.nodes.set(nodeId, node); + tree.nodes.set(node.targetId, node); }); return tree; } From 944e6f1358f70095048eacd3b0404a681d37691a Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 06:04:44 +0900 Subject: [PATCH 129/170] =?UTF-8?q?fix(#188):=20=EB=AA=85=ED=99=95?= =?UTF-8?q?=ED=95=98=EA=B2=8C=20=ED=95=98=EA=B8=B0=20=EC=9C=84=ED=95=98?= =?UTF-8?q?=EC=97=AC=20id=20>=20unique=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/prisma/mysql.schema.prisma | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nestjs-BE/server/prisma/mysql.schema.prisma b/nestjs-BE/server/prisma/mysql.schema.prisma index 3afd38ac..30b53a6e 100644 --- a/nestjs-BE/server/prisma/mysql.schema.prisma +++ b/nestjs-BE/server/prisma/mysql.schema.prisma @@ -47,7 +47,7 @@ model PROFILE_SPACE_TB { profile_uuid String @db.VarChar(32) space SPACE_TB @relation(fields: [space_uuid], references: [uuid], onDelete: Cascade) profile PROFILE_TB @relation(fields: [profile_uuid], references: [uuid], onDelete: Cascade) - @@id([space_uuid, profile_uuid]) + @@unique([space_uuid, profile_uuid]) } model INVITE_CODE_TB { From b62df110c85c0319bda1616d60fed853538e4ef0 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 06:06:36 +0900 Subject: [PATCH 130/170] =?UTF-8?q?fix(#188):=20=EC=8A=A4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EB=A7=8C=EB=93=A0=20=EC=82=AC=EB=9E=8C?= =?UTF-8?q?=EC=9D=80=20=EC=9E=90=EB=8F=99=EC=9C=BC=EB=A1=9C=20=EC=B0=B8?= =?UTF-8?q?=EC=97=AC=EB=90=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/spaces/spaces.controller.ts | 16 +++++++++++++++- nestjs-BE/server/src/spaces/spaces.module.ts | 5 ++++- nestjs-BE/server/src/spaces/spaces.service.ts | 8 ++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/nestjs-BE/server/src/spaces/spaces.controller.ts b/nestjs-BE/server/src/spaces/spaces.controller.ts index 1ee595e6..e411ea7b 100644 --- a/nestjs-BE/server/src/spaces/spaces.controller.ts +++ b/nestjs-BE/server/src/spaces/spaces.controller.ts @@ -8,6 +8,7 @@ import { Delete, UseInterceptors, UploadedFile, + Request as Req, } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; import { SpacesService } from './spaces.service'; @@ -15,6 +16,8 @@ import { CreateSpaceDto } from './dto/create-space.dto'; import { UpdateSpaceDto } from './dto/update-space.dto'; import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; import { UploadService } from 'src/upload/upload.service'; +import { ProfileSpaceService } from 'src/profile-space/profile-space.service'; +import { RequestWithUser } from 'src/utils/interface'; import customEnv from 'src/config/env'; const { BASE_IMAGE_URL } = customEnv; @@ -24,6 +27,7 @@ export class SpacesController { constructor( private readonly spacesService: SpacesService, private readonly uploadService: UploadService, + private readonly profileSpaceService: ProfileSpaceService, ) {} @Post() @@ -36,12 +40,22 @@ export class SpacesController { async create( @UploadedFile() icon: Express.Multer.File, @Body() createSpaceDto: CreateSpaceDto, + @Req() req: RequestWithUser, ) { const iconUrl = icon ? await this.uploadService.uploadFile(icon) : BASE_IMAGE_URL; createSpaceDto.icon = iconUrl; - return this.spacesService.create(createSpaceDto); + const response = await this.spacesService.create(createSpaceDto); + const { uuid: spaceUuid } = response.data; + const userUuid = req.user.uuid; + const { joinData, profileData } = + await this.profileSpaceService.processData(userUuid, spaceUuid); + this.profileSpaceService.create(joinData); + const spaceData = response.data; + const data = { profileData, spaceData }; + this.profileSpaceService.put(userUuid, spaceUuid, data); + return response; } @Get(':space_uuid') diff --git a/nestjs-BE/server/src/spaces/spaces.module.ts b/nestjs-BE/server/src/spaces/spaces.module.ts index ef744633..2964682c 100644 --- a/nestjs-BE/server/src/spaces/spaces.module.ts +++ b/nestjs-BE/server/src/spaces/spaces.module.ts @@ -1,10 +1,13 @@ -import { Module } from '@nestjs/common'; +import { forwardRef, Module } from '@nestjs/common'; import { SpacesService } from './spaces.service'; import { SpacesController } from './spaces.controller'; import { UploadService } from 'src/upload/upload.service'; +import { ProfileSpaceModule } from 'src/profile-space/profile-space.module'; @Module({ + imports: [forwardRef(() => ProfileSpaceModule)], controllers: [SpacesController], providers: [SpacesService, UploadService], + exports: [SpacesService], }) export class SpacesModule {} diff --git a/nestjs-BE/server/src/spaces/spaces.service.ts b/nestjs-BE/server/src/spaces/spaces.service.ts index eff278c6..4eba8ff0 100644 --- a/nestjs-BE/server/src/spaces/spaces.service.ts +++ b/nestjs-BE/server/src/spaces/spaces.service.ts @@ -4,6 +4,7 @@ import { TemporaryDatabaseService } from '../temporary-database/temporary-databa import { BaseService } from '../base/base.service'; import { SPACE_CACHE_SIZE } from 'src/config/magic-number'; import { UpdateSpaceDto } from './dto/update-space.dto'; +import { UpdateProfileDto } from 'src/profiles/dto/update-profile.dto'; @Injectable() export class SpacesService extends BaseService { @@ -23,4 +24,11 @@ export class SpacesService extends BaseService { generateKey(data: UpdateSpaceDto): string { return data.uuid; } + + async processData(spaceUuid: string, profileData: UpdateProfileDto) { + const spaceResponseData = await super.findOne(spaceUuid); + const spaceData = spaceResponseData.data; + const data = { profileData, spaceData }; + return data; + } } From 0507489bac432ecb6eb8bcb5a70b5027eed6f8bd Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 06:07:14 +0900 Subject: [PATCH 131/170] =?UTF-8?q?feat(#188):=20=EC=A1=B0=EC=9D=B8=20?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EB=B8=94=20=EA=B4=80=EB=A6=AC=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=AA=A8=EB=93=88=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/app.module.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nestjs-BE/server/src/app.module.ts b/nestjs-BE/server/src/app.module.ts index 9112c682..d43ea38f 100644 --- a/nestjs-BE/server/src/app.module.ts +++ b/nestjs-BE/server/src/app.module.ts @@ -13,6 +13,7 @@ import { ScheduleModule } from '@nestjs/schedule'; import { UploadModule } from './upload/upload.module'; import { MongooseModule } from '@nestjs/mongoose'; import { InviteCodesModule } from './invite-codes/invite-codes.module'; +import { ProfileSpaceModule } from './profile-space/profile-space.module'; import customEnv from './config/env'; @Module({ @@ -28,6 +29,7 @@ import customEnv from './config/env'; UploadModule, MongooseModule.forRoot(customEnv.MONGODB_DATABASE_URI), InviteCodesModule, + ProfileSpaceModule, ], controllers: [AppController], providers: [AppService, BoardGateway], From a53fef5c8cc27dbbee1e1e3339b76e4110d6edc1 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 06:07:36 +0900 Subject: [PATCH 132/170] =?UTF-8?q?fix(#188):=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/profiles/profiles.controller.ts | 1 - nestjs-BE/server/src/profiles/profiles.module.ts | 4 ++-- nestjs-BE/server/src/profiles/profiles.service.ts | 3 --- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/nestjs-BE/server/src/profiles/profiles.controller.ts b/nestjs-BE/server/src/profiles/profiles.controller.ts index 88c177dd..c59bff3b 100644 --- a/nestjs-BE/server/src/profiles/profiles.controller.ts +++ b/nestjs-BE/server/src/profiles/profiles.controller.ts @@ -10,7 +10,6 @@ import { import { FileInterceptor } from '@nestjs/platform-express'; import { ProfilesService } from './profiles.service'; import { UpdateProfileDto } from './dto/update-profile.dto'; - import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; import { UploadService } from 'src/upload/upload.service'; import { RequestWithUser } from 'src/utils/interface'; diff --git a/nestjs-BE/server/src/profiles/profiles.module.ts b/nestjs-BE/server/src/profiles/profiles.module.ts index 525bfbfb..97674fa9 100644 --- a/nestjs-BE/server/src/profiles/profiles.module.ts +++ b/nestjs-BE/server/src/profiles/profiles.module.ts @@ -1,11 +1,11 @@ import { Module } from '@nestjs/common'; import { ProfilesService } from './profiles.service'; import { ProfilesController } from './profiles.controller'; -import { SpacesService } from '../spaces/spaces.service'; import { UploadService } from 'src/upload/upload.service'; + @Module({ controllers: [ProfilesController], - providers: [ProfilesService, SpacesService, UploadService], + providers: [ProfilesService, UploadService], exports: [ProfilesService], }) export class ProfilesModule {} diff --git a/nestjs-BE/server/src/profiles/profiles.service.ts b/nestjs-BE/server/src/profiles/profiles.service.ts index 9870259e..0a1027fb 100644 --- a/nestjs-BE/server/src/profiles/profiles.service.ts +++ b/nestjs-BE/server/src/profiles/profiles.service.ts @@ -4,15 +4,12 @@ import { TemporaryDatabaseService } from '../temporary-database/temporary-databa import { BaseService } from '../base/base.service'; import { PROFILE_CACHE_SIZE } from 'src/config/magic-number'; import { UpdateProfileDto } from './dto/update-profile.dto'; -import { SpacesService } from '../spaces/spaces.service'; @Injectable() export class ProfilesService extends BaseService { - profileSpaceTable = 'PROFILE_SPACE_TB'; constructor( protected prisma: PrismaServiceMySQL, protected temporaryDatabaseService: TemporaryDatabaseService, - protected spacesService: SpacesService, ) { super({ prisma, From e27ec5a8e991c71b3b09a90c8e847563b1c7259d Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 06:09:29 +0900 Subject: [PATCH 133/170] =?UTF-8?q?fix(#188):=20join=20table=EC=9D=80=20uu?= =?UTF-8?q?id=EA=B0=80=20=ED=95=84=EC=9A=94=20=EC=97=86=EA=B8=B0=20?= =?UTF-8?q?=EB=95=8C=EB=AC=B8=EC=97=90=20flag=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/base/base.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nestjs-BE/server/src/base/base.service.ts b/nestjs-BE/server/src/base/base.service.ts index b7abe3ce..060f8ca1 100644 --- a/nestjs-BE/server/src/base/base.service.ts +++ b/nestjs-BE/server/src/base/base.service.ts @@ -37,8 +37,8 @@ export abstract class BaseService { abstract generateKey(data: T): string; - async create(data: T) { - data.uuid = generateUuid(); + async create(data: T, generateUuidFlag: boolean = true) { + if (generateUuidFlag) data.uuid = generateUuid(); const key = this.generateKey(data); const storeData = await this.getDataFromCacheOrDB(key); if (storeData) { From f9c1862e672fcbd13832311bf34c2041c596b12f Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 06:10:45 +0900 Subject: [PATCH 134/170] =?UTF-8?q?fix(#188):=20=EC=8A=A4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EC=B0=B8=EA=B0=80=20=EB=B0=8F=20=EB=82=98?= =?UTF-8?q?=EA=B0=80=EA=B8=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/config/magic-number.ts | 3 + .../dto/create-profile-space.dto.ts | 14 ++++ .../dto/update-profile-space.dto.ts | 6 ++ .../profile-space/profile-space.controller.ts | 49 +++++++++++++ .../src/profile-space/profile-space.module.ts | 13 ++++ .../profile-space/profile-space.service.ts | 70 +++++++++++++++++++ 6 files changed, 155 insertions(+) create mode 100644 nestjs-BE/server/src/profile-space/dto/create-profile-space.dto.ts create mode 100644 nestjs-BE/server/src/profile-space/dto/update-profile-space.dto.ts create mode 100644 nestjs-BE/server/src/profile-space/profile-space.controller.ts create mode 100644 nestjs-BE/server/src/profile-space/profile-space.module.ts create mode 100644 nestjs-BE/server/src/profile-space/profile-space.service.ts diff --git a/nestjs-BE/server/src/config/magic-number.ts b/nestjs-BE/server/src/config/magic-number.ts index 9776ea9f..75e72de4 100644 --- a/nestjs-BE/server/src/config/magic-number.ts +++ b/nestjs-BE/server/src/config/magic-number.ts @@ -3,6 +3,9 @@ export const PROFILE_CACHE_SIZE = 5000; export const SPACE_CACHE_SIZE = 10000; export const BOARD_CACHE_SIZE = 10000; export const REFRESH_TOKEN_CACHE_SIZE = 1000; +export const PROFILE_SPACE_CACHE_SIZE = 1; +export const USER_SPACE_CACHE_SIZE = 1000; +export const SPACE_USER_CACHE_SIZE = 1000; export const REFRESH_TOKEN_EXPIRY_DAYS = 14; export const INVITE_CODE_CACHE_SIZE = 5000; export const INVITE_CODE_LENGTH = 10; diff --git a/nestjs-BE/server/src/profile-space/dto/create-profile-space.dto.ts b/nestjs-BE/server/src/profile-space/dto/create-profile-space.dto.ts new file mode 100644 index 00000000..fb85e2d6 --- /dev/null +++ b/nestjs-BE/server/src/profile-space/dto/create-profile-space.dto.ts @@ -0,0 +1,14 @@ +import { IsNotEmpty, IsString } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; + +export class CreateProfileSpaceDto { + @ApiProperty({ + example: 'space uuid', + description: 'Space UUID', + }) + @IsString() + @IsNotEmpty() + space_uuid: string; + + profile_uuid: string; +} diff --git a/nestjs-BE/server/src/profile-space/dto/update-profile-space.dto.ts b/nestjs-BE/server/src/profile-space/dto/update-profile-space.dto.ts new file mode 100644 index 00000000..9bef8027 --- /dev/null +++ b/nestjs-BE/server/src/profile-space/dto/update-profile-space.dto.ts @@ -0,0 +1,6 @@ +import { PartialType } from '@nestjs/swagger'; +import { CreateProfileSpaceDto } from './create-profile-space.dto'; + +export class UpdateProfileSpaceDto extends PartialType(CreateProfileSpaceDto) { + uuid?: string; +} diff --git a/nestjs-BE/server/src/profile-space/profile-space.controller.ts b/nestjs-BE/server/src/profile-space/profile-space.controller.ts new file mode 100644 index 00000000..525e1a36 --- /dev/null +++ b/nestjs-BE/server/src/profile-space/profile-space.controller.ts @@ -0,0 +1,49 @@ +import { + Controller, + Post, + Body, + Delete, + Param, + Request as Req, +} from '@nestjs/common'; +import { ProfileSpaceService } from './profile-space.service'; +import { CreateProfileSpaceDto } from './dto/create-profile-space.dto'; +import { RequestWithUser } from 'src/utils/interface'; +import { SpacesService } from 'src/spaces/spaces.service'; + +@Controller('profileSpace') +export class ProfileSpaceController { + constructor( + private readonly profileSpaceService: ProfileSpaceService, + private readonly spacesService: SpacesService, + ) {} + + @Post() + async create( + @Body() createProfileSpaceDto: CreateProfileSpaceDto, + @Req() req: RequestWithUser, + ) { + const userUuid = req.user.uuid; + const { space_uuid } = createProfileSpaceDto; + const { joinData, profileData } = + await this.profileSpaceService.processData(userUuid, space_uuid); + const responseData = await this.profileSpaceService.create(joinData); + const data = await this.spacesService.processData(space_uuid, profileData); + this.profileSpaceService.put(userUuid, space_uuid, data); + return responseData; + } + + @Delete(':space_uuid') + async delete( + @Param('space_uuid') spaceUuid: string, + @Req() req: RequestWithUser, + ) { + const userUuid = req.user.uuid; + const { joinData, profileData } = + await this.profileSpaceService.processData(userUuid, spaceUuid); + const data = await this.spacesService.processData(spaceUuid, profileData); + this.profileSpaceService.delete(userUuid, spaceUuid, data); + const key = this.profileSpaceService.generateKey(joinData); + return this.profileSpaceService.remove(key); + } +} diff --git a/nestjs-BE/server/src/profile-space/profile-space.module.ts b/nestjs-BE/server/src/profile-space/profile-space.module.ts new file mode 100644 index 00000000..c79af8a9 --- /dev/null +++ b/nestjs-BE/server/src/profile-space/profile-space.module.ts @@ -0,0 +1,13 @@ +import { Module, forwardRef } from '@nestjs/common'; +import { ProfileSpaceService } from './profile-space.service'; +import { ProfileSpaceController } from './profile-space.controller'; +import { ProfilesModule } from 'src/profiles/profiles.module'; +import { SpacesModule } from 'src/spaces/spaces.module'; + +@Module({ + imports: [ProfilesModule, forwardRef(() => SpacesModule)], + controllers: [ProfileSpaceController], + providers: [ProfileSpaceService], + exports: [ProfileSpaceService], +}) +export class ProfileSpaceModule {} diff --git a/nestjs-BE/server/src/profile-space/profile-space.service.ts b/nestjs-BE/server/src/profile-space/profile-space.service.ts new file mode 100644 index 00000000..50aba5ae --- /dev/null +++ b/nestjs-BE/server/src/profile-space/profile-space.service.ts @@ -0,0 +1,70 @@ +import { Injectable } from '@nestjs/common'; +import { UpdateProfileSpaceDto } from './dto/update-profile-space.dto'; +import { BaseService } from 'src/base/base.service'; +import { PrismaServiceMySQL } from 'src/prisma/prisma.service'; +import { TemporaryDatabaseService } from 'src/temporary-database/temporary-database.service'; +import { + PROFILE_SPACE_CACHE_SIZE, + SPACE_USER_CACHE_SIZE, + USER_SPACE_CACHE_SIZE, +} from 'src/config/magic-number'; +import { CreateProfileSpaceDto } from './dto/create-profile-space.dto'; +import { ProfilesService } from 'src/profiles/profiles.service'; +import { UpdateProfileDto } from 'src/profiles/dto/update-profile.dto'; +import { UpdateSpaceDto } from 'src/spaces/dto/update-space.dto'; +import LRUCache from 'src/utils/lru-cache'; +import { SpacesService } from 'src/spaces/spaces.service'; + +interface UpdateProfileAndSpaceDto { + profileData: UpdateProfileDto; + spaceData: UpdateSpaceDto; +} + +@Injectable() +export class ProfileSpaceService extends BaseService { + private readonly userCache: LRUCache; + private readonly spaceCache: LRUCache; + constructor( + protected prisma: PrismaServiceMySQL, + protected temporaryDatabaseService: TemporaryDatabaseService, + private readonly profilesService: ProfilesService, + private readonly spacesService: SpacesService, + ) { + super({ + prisma, + temporaryDatabaseService, + cacheSize: PROFILE_SPACE_CACHE_SIZE, + className: 'PROFILE_SPACE_TB', + field: 'space_uuid_profile_uuid', + }); + this.userCache = new LRUCache(USER_SPACE_CACHE_SIZE); + this.spaceCache = new LRUCache(SPACE_USER_CACHE_SIZE); + } + + generateKey(data: CreateProfileSpaceDto) { + return `space_uuid:${data.space_uuid}+profile_uuid:${data.profile_uuid}`; + } + + async create(data: CreateProfileSpaceDto) { + const response = await super.create(data, false); + return response; + } + + async processData(userUuid: string, spaceUuid: string) { + const profileResponse = await this.profilesService.findOne(userUuid); + const profileUuid = profileResponse.data?.uuid; + const joinData = { + profile_uuid: profileUuid, + space_uuid: spaceUuid, + }; + return { joinData, profileData: profileResponse.data }; + } + + put(userUuid: string, spaceUuid: string, data: UpdateProfileAndSpaceDto) { + const { spaceData, profileData } = data; + } + + delete(userUuid: string, spaceUuid: string, data: UpdateProfileAndSpaceDto) { + const { spaceData, profileData } = data; + } +} From d896807b1c00c153ebf08e198019d962d51d5dcc Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 09:10:16 +0900 Subject: [PATCH 135/170] =?UTF-8?q?fix(#188):=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EB=B0=8F=20=EC=82=AD=EC=A0=9C=20=EB=A6=AC?= =?UTF-8?q?=ED=84=B4=20=EB=AA=85=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/base/base.service.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/nestjs-BE/server/src/base/base.service.ts b/nestjs-BE/server/src/base/base.service.ts index 060f8ca1..720cd687 100644 --- a/nestjs-BE/server/src/base/base.service.ts +++ b/nestjs-BE/server/src/base/base.service.ts @@ -61,7 +61,9 @@ export abstract class BaseService { key, 'delete', ); - if (deleteCommand) return null; + if (deleteCommand) { + throw new HttpException('Not Found', HttpStatus.NOT_FOUND); + } if (data) { const mergedData = this.mergeWithUpdateCommand(data, key); this.cache.put(key, mergedData); @@ -72,10 +74,7 @@ export abstract class BaseService { }; } - return { - statusCode: HttpStatus.NOT_FOUND, - message: 'Not Found', - }; + throw new HttpException('Not Found', HttpStatus.NOT_FOUND); } async update(key: string, updateData: T) { @@ -132,6 +131,10 @@ export abstract class BaseService { value: key, }); } + return { + statusCode: HttpStatus.NO_CONTENT, + message: 'No Content', + }; } async getDataFromCacheOrDB(key: string): Promise { From a7d0c5d357efa4f39f7bb6e0c2d50f6ce2292e9f Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 09:12:44 +0900 Subject: [PATCH 136/170] =?UTF-8?q?fix(#188):=20=EC=8A=A4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EB=93=A4=EC=96=B4=EA=B0=80=EA=B8=B0,=20?= =?UTF-8?q?=EB=82=98=EA=B0=80=EA=B8=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../profile-space/profile-space.service.ts | 72 +++++++++++++++++-- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/nestjs-BE/server/src/profile-space/profile-space.service.ts b/nestjs-BE/server/src/profile-space/profile-space.service.ts index 50aba5ae..e2a720a1 100644 --- a/nestjs-BE/server/src/profile-space/profile-space.service.ts +++ b/nestjs-BE/server/src/profile-space/profile-space.service.ts @@ -13,7 +13,6 @@ import { ProfilesService } from 'src/profiles/profiles.service'; import { UpdateProfileDto } from 'src/profiles/dto/update-profile.dto'; import { UpdateSpaceDto } from 'src/spaces/dto/update-space.dto'; import LRUCache from 'src/utils/lru-cache'; -import { SpacesService } from 'src/spaces/spaces.service'; interface UpdateProfileAndSpaceDto { profileData: UpdateProfileDto; @@ -28,7 +27,6 @@ export class ProfileSpaceService extends BaseService { protected prisma: PrismaServiceMySQL, protected temporaryDatabaseService: TemporaryDatabaseService, private readonly profilesService: ProfilesService, - private readonly spacesService: SpacesService, ) { super({ prisma, @@ -60,11 +58,75 @@ export class ProfileSpaceService extends BaseService { return { joinData, profileData: profileResponse.data }; } - put(userUuid: string, spaceUuid: string, data: UpdateProfileAndSpaceDto) { + async put( + userUuid: string, + spaceUuid: string, + data: UpdateProfileAndSpaceDto, + ) { const { spaceData, profileData } = data; + const userSpaces = await this.getUserSpaces(userUuid, profileData.uuid); + userSpaces.push(spaceData); + this.userCache.put(userUuid, userSpaces); + const spaceProfiles = await this.getSpaceUsers(spaceUuid); + spaceProfiles.push(profileData); + this.spaceCache.put(spaceUuid, spaceProfiles); } - delete(userUuid: string, spaceUuid: string, data: UpdateProfileAndSpaceDto) { - const { spaceData, profileData } = data; + async delete( + userUuid: string, + spaceUuid: string, + profileData: UpdateProfileDto, + ) { + const userSpaces = await this.getUserSpaces(userUuid, profileData.uuid); + const filterUserSpaces = userSpaces.filter( + (space) => space.uuid !== spaceUuid, + ); + this.userCache.put(userUuid, filterUserSpaces); + const spaceUsers = await this.getSpaceUsers(spaceUuid); + const filterSpaceUsers = spaceUsers.filter( + (profile) => profile.uuid !== profileData.uuid, + ); + this.userCache.put(spaceUuid, filterSpaceUsers); + return filterSpaceUsers.length === 0; + } + + async getUserSpaces( + userUuid: string, + profileUuid: string, + ): Promise { + const cacheUserSpaces = this.userCache.get(userUuid); + if (cacheUserSpaces) return cacheUserSpaces; + const profileResponse = await this.prisma['PROFILE_TB'].findUnique({ + where: { uuid: profileUuid }, + include: { + spaces: { + include: { + space: true, + }, + }, + }, + }); + const storeUserSpaces = + profileResponse?.spaces.map((profileSpace) => profileSpace.space) || []; + return storeUserSpaces; + } + + async getSpaceUsers(spaceUuid: string): Promise { + const cacheSpaceProfiles = this.spaceCache.get(spaceUuid); + if (cacheSpaceProfiles) return cacheSpaceProfiles; + + const spaceResponse = await this.prisma['SPACE_TB'].findUnique({ + where: { uuid: spaceUuid }, + include: { + profiles: { + include: { + profile: true, + }, + }, + }, + }); + const storeSpaceProfiles = + spaceResponse?.profiles.map((profileSpace) => profileSpace.profile) || []; + return storeSpaceProfiles; } } From 8cc9a9dd899df91d75608c6a0bb2edae23f7545e Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 09:13:04 +0900 Subject: [PATCH 137/170] =?UTF-8?q?feat(#63):=20=EB=AA=A8=EB=93=A0=20?= =?UTF-8?q?=EC=9C=A0=EC=A0=80=EA=B0=80=20=EC=8A=A4=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=8A=A4=EC=97=90=EC=84=9C=20=EB=82=98=EA=B0=80=EB=A9=B4=20?= =?UTF-8?q?=EC=8A=A4=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../profile-space/profile-space.controller.ts | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/nestjs-BE/server/src/profile-space/profile-space.controller.ts b/nestjs-BE/server/src/profile-space/profile-space.controller.ts index 525e1a36..464f0402 100644 --- a/nestjs-BE/server/src/profile-space/profile-space.controller.ts +++ b/nestjs-BE/server/src/profile-space/profile-space.controller.ts @@ -10,15 +10,26 @@ import { ProfileSpaceService } from './profile-space.service'; import { CreateProfileSpaceDto } from './dto/create-profile-space.dto'; import { RequestWithUser } from 'src/utils/interface'; import { SpacesService } from 'src/spaces/spaces.service'; +import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; @Controller('profileSpace') +@ApiTags('profileSpace') export class ProfileSpaceController { constructor( private readonly profileSpaceService: ProfileSpaceService, private readonly spacesService: SpacesService, ) {} - @Post() + @Post('join') + @ApiOperation({ summary: 'Join space' }) + @ApiResponse({ + status: 201, + description: 'Join data has been successfully created.', + }) + @ApiResponse({ + status: 409, + description: 'Conflict. You have already joined the space.', + }) async create( @Body() createProfileSpaceDto: CreateProfileSpaceDto, @Req() req: RequestWithUser, @@ -33,7 +44,15 @@ export class ProfileSpaceController { return responseData; } - @Delete(':space_uuid') + @Delete('leave/:space_uuid') + @ApiResponse({ + status: 204, + description: 'Successfully left the space.', + }) + @ApiResponse({ + status: 404, + description: 'Space not found.', + }) async delete( @Param('space_uuid') spaceUuid: string, @Req() req: RequestWithUser, @@ -41,8 +60,13 @@ export class ProfileSpaceController { const userUuid = req.user.uuid; const { joinData, profileData } = await this.profileSpaceService.processData(userUuid, spaceUuid); - const data = await this.spacesService.processData(spaceUuid, profileData); - this.profileSpaceService.delete(userUuid, spaceUuid, data); + await this.spacesService.processData(spaceUuid, profileData); + const isSpaceEmpty = await this.profileSpaceService.delete( + userUuid, + spaceUuid, + profileData, + ); + if (isSpaceEmpty) this.spacesService.remove(spaceUuid); const key = this.profileSpaceService.generateKey(joinData); return this.profileSpaceService.remove(key); } From 550015090b837381096c2670e28c224873fbd3a2 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 09:41:29 +0900 Subject: [PATCH 138/170] =?UTF-8?q?fix(#188):=20=EC=8A=A4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EB=AA=A9=EB=A1=9D=20=ED=99=95=EC=9D=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/create-profile-space.dto.ts | 2 +- .../profile-space/profile-space.controller.ts | 26 ++++++++++++++++ .../profile-space/profile-space.service.ts | 30 +++++++++++++++++-- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/nestjs-BE/server/src/profile-space/dto/create-profile-space.dto.ts b/nestjs-BE/server/src/profile-space/dto/create-profile-space.dto.ts index fb85e2d6..fdd16f5c 100644 --- a/nestjs-BE/server/src/profile-space/dto/create-profile-space.dto.ts +++ b/nestjs-BE/server/src/profile-space/dto/create-profile-space.dto.ts @@ -6,8 +6,8 @@ export class CreateProfileSpaceDto { example: 'space uuid', description: 'Space UUID', }) - @IsString() @IsNotEmpty() + @IsString() space_uuid: string; profile_uuid: string; diff --git a/nestjs-BE/server/src/profile-space/profile-space.controller.ts b/nestjs-BE/server/src/profile-space/profile-space.controller.ts index 464f0402..8fcca5b9 100644 --- a/nestjs-BE/server/src/profile-space/profile-space.controller.ts +++ b/nestjs-BE/server/src/profile-space/profile-space.controller.ts @@ -1,5 +1,6 @@ import { Controller, + Get, Post, Body, Delete, @@ -70,4 +71,29 @@ export class ProfileSpaceController { const key = this.profileSpaceService.generateKey(joinData); return this.profileSpaceService.remove(key); } + + @Get('spaces') + @ApiOperation({ summary: 'Get user’s spaces' }) + @ApiResponse({ + status: 200, + description: 'Returns a list of spaces.', + }) + getSpaces(@Req() req: RequestWithUser) { + const userUuid = req.user.uuid; + return this.profileSpaceService.getSpaces(userUuid); + } + + @Get('users/:space_uuid') + @ApiOperation({ summary: 'Get users in the space' }) + @ApiResponse({ + status: 200, + description: 'Returns a list of users.', + }) + @ApiResponse({ + status: 404, + description: 'Space not found.', + }) + getUsers(@Param('space_uuid') spaceUuid: string) { + return this.profileSpaceService.getUsers(spaceUuid); + } } diff --git a/nestjs-BE/server/src/profile-space/profile-space.service.ts b/nestjs-BE/server/src/profile-space/profile-space.service.ts index e2a720a1..3510474e 100644 --- a/nestjs-BE/server/src/profile-space/profile-space.service.ts +++ b/nestjs-BE/server/src/profile-space/profile-space.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, HttpException, HttpStatus } from '@nestjs/common'; import { UpdateProfileSpaceDto } from './dto/update-profile-space.dto'; import { BaseService } from 'src/base/base.service'; import { PrismaServiceMySQL } from 'src/prisma/prisma.service'; @@ -107,7 +107,7 @@ export class ProfileSpaceService extends BaseService { }, }); const storeUserSpaces = - profileResponse?.spaces.map((profileSpace) => profileSpace.space) || []; + profileResponse.spaces.map((profileSpace) => profileSpace.space) || []; return storeUserSpaces; } @@ -125,8 +125,32 @@ export class ProfileSpaceService extends BaseService { }, }, }); + if (!spaceResponse) { + throw new HttpException('Not Found', HttpStatus.NOT_FOUND); + } const storeSpaceProfiles = - spaceResponse?.profiles.map((profileSpace) => profileSpace.profile) || []; + spaceResponse.profiles.map((profileSpace) => profileSpace.profile) || []; return storeSpaceProfiles; } + + async getSpaces(userUuid: string) { + const profileResponse = await this.profilesService.findOne(userUuid); + const profileUuid = profileResponse.data?.uuid; + const spaces = await this.getUserSpaces(userUuid, profileUuid); + this.userCache.put(userUuid, spaces); + return { + statusCode: HttpStatus.OK, + message: 'Success', + data: spaces, + }; + } + + async getUsers(spaceUuid: string) { + const users = await this.getSpaceUsers(spaceUuid); + return { + statusCode: HttpStatus.OK, + message: 'Success', + data: users, + }; + } } From e67ae9049d8f28a5e312842c39d465f8b43750af Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 09:42:03 +0900 Subject: [PATCH 139/170] =?UTF-8?q?fix(#136):=20=EC=8A=A4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EC=97=86=EC=9D=84=20=EC=8B=9C=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=B2=98=EB=A6=AC=20=EB=B0=8F=20=EC=8A=A4=EC=9B=A8?= =?UTF-8?q?=EA=B1=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/create-invite-code.dto.ts | 5 ++++ .../invite-codes/invite-codes.controller.ts | 28 +++++++++++++++++++ .../src/invite-codes/invite-codes.service.ts | 5 +++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/invite-codes/dto/create-invite-code.dto.ts b/nestjs-BE/server/src/invite-codes/dto/create-invite-code.dto.ts index 191a05d4..da0501c3 100644 --- a/nestjs-BE/server/src/invite-codes/dto/create-invite-code.dto.ts +++ b/nestjs-BE/server/src/invite-codes/dto/create-invite-code.dto.ts @@ -1,6 +1,11 @@ import { IsNotEmpty, IsString } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; export class CreateInviteCodeDto { + @ApiProperty({ + example: 'space uuid', + description: 'Space UUID', + }) @IsNotEmpty() @IsString() space_uuid: string; diff --git a/nestjs-BE/server/src/invite-codes/invite-codes.controller.ts b/nestjs-BE/server/src/invite-codes/invite-codes.controller.ts index 8dac1e35..f6e10e3d 100644 --- a/nestjs-BE/server/src/invite-codes/invite-codes.controller.ts +++ b/nestjs-BE/server/src/invite-codes/invite-codes.controller.ts @@ -1,17 +1,45 @@ import { Controller, Get, Post, Body, Param } from '@nestjs/common'; import { InviteCodesService } from './invite-codes.service'; import { CreateInviteCodeDto } from './dto/create-invite-code.dto'; +import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; @Controller('inviteCodes') +@ApiTags('inviteCodes') export class InviteCodesController { constructor(private readonly inviteCodesService: InviteCodesService) {} @Post() + @ApiOperation({ summary: 'Create invite code' }) + @ApiResponse({ + status: 201, + description: 'The invite code has been successfully created.', + }) + @ApiResponse({ + status: 400, + description: 'Space code input is missing.', + }) + @ApiResponse({ + status: 404, + description: 'Space not found.', + }) create(@Body() createInviteCodeDto: CreateInviteCodeDto) { return this.inviteCodesService.createCode(createInviteCodeDto); } @Get(':inviteCode') + @ApiOperation({ summary: 'Find space by invite code' }) + @ApiResponse({ + status: 200, + description: 'Returns a space associated with the invite code.', + }) + @ApiResponse({ + status: 404, + description: 'Invite code not found.', + }) + @ApiResponse({ + status: 410, + description: 'Invite code has expired', + }) findSpace(@Param('inviteCode') inviteCode: string) { return this.inviteCodesService.findSpace(inviteCode); } diff --git a/nestjs-BE/server/src/invite-codes/invite-codes.service.ts b/nestjs-BE/server/src/invite-codes/invite-codes.service.ts index af7d208f..2eb770b7 100644 --- a/nestjs-BE/server/src/invite-codes/invite-codes.service.ts +++ b/nestjs-BE/server/src/invite-codes/invite-codes.service.ts @@ -46,6 +46,9 @@ export class InviteCodesService extends BaseService { invite_code: inviteCode, expiry_date: expiryDate, }; + const { space_uuid: spaceUuid } = createInviteCodeDto; + const space = await this.spacesService.getDataFromCacheOrDB(spaceUuid); + if (!space) throw new HttpException('Not Found', HttpStatus.NOT_FOUND); super.create(data); return { statusCode: HttpStatus.CREATED, @@ -57,7 +60,7 @@ export class InviteCodesService extends BaseService { async findSpace(inviteCode: string) { const inviteCodeData = await super.getDataFromCacheOrDB(inviteCode); if (!inviteCodeData) { - throw new HttpException('Invalid invite code.', HttpStatus.BAD_REQUEST); + throw new HttpException('Invalid invite code.', HttpStatus.NOT_FOUND); } const currentTimestamp = new Date().getTime(); const expiryTimestamp = new Date(inviteCodeData.expiry_date).getTime(); From 2dc6e25bc940d2cb71bccf4b142181c41f61d5c0 Mon Sep 17 00:00:00 2001 From: Yong <108651414+tnpfldyd@users.noreply.github.com> Date: Thu, 7 Dec 2023 10:07:49 +0900 Subject: [PATCH 140/170] =?UTF-8?q?fix(#136):=20status=20code=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/invite-codes/invite-codes.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/invite-codes/invite-codes.service.ts b/nestjs-BE/server/src/invite-codes/invite-codes.service.ts index 2eb770b7..31277204 100644 --- a/nestjs-BE/server/src/invite-codes/invite-codes.service.ts +++ b/nestjs-BE/server/src/invite-codes/invite-codes.service.ts @@ -68,7 +68,7 @@ export class InviteCodesService extends BaseService { super.remove(inviteCode); throw new HttpException( 'Invite code has expired.', - HttpStatus.BAD_REQUEST, + HttpStatus.GONE, ); } const spaceUuid = inviteCodeData.space_uuid; From bbff2fadf81d8e28422bd475dc73284bd87330a3 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 7 Dec 2023 10:58:29 +0900 Subject: [PATCH 141/170] =?UTF-8?q?fix:=20updateMindmap=20=EC=9D=B4?= =?UTF-8?q?=EB=B2=A4=ED=8A=B8=20operation=20parse=20=EB=B6=80=EB=B6=84=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/board-trees/board-trees.gateway.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nestjs-BE/server/src/board-trees/board-trees.gateway.ts b/nestjs-BE/server/src/board-trees/board-trees.gateway.ts index 338fbfc7..56de6ca2 100644 --- a/nestjs-BE/server/src/board-trees/board-trees.gateway.ts +++ b/nestjs-BE/server/src/board-trees/board-trees.gateway.ts @@ -37,7 +37,6 @@ export class BoardTreesGateway { const payloadObject = JSON.parse(payload); const { boardId, operation: serializedOperation } = payloadObject; - const operationObject = JSON.parse(serializedOperation); const operationTypeMap = { add: OperationAdd.parse, delete: OperationDelete.parse, @@ -46,7 +45,7 @@ export class BoardTreesGateway { }; const operation = - operationTypeMap[operationObject.operationType](operationObject); + operationTypeMap[serializedOperation.operationType](serializedOperation); this.boardTreesService.applyOperation(boardId, operation); client.broadcast From cd5d2b232525bf03fbd2176f7aa3a5893743f9d0 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 7 Dec 2023 11:35:06 +0900 Subject: [PATCH 142/170] =?UTF-8?q?fix:=20not=20found=20exception=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/base/base.service.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/nestjs-BE/server/src/base/base.service.ts b/nestjs-BE/server/src/base/base.service.ts index 720cd687..6fa50da8 100644 --- a/nestjs-BE/server/src/base/base.service.ts +++ b/nestjs-BE/server/src/base/base.service.ts @@ -61,9 +61,7 @@ export abstract class BaseService { key, 'delete', ); - if (deleteCommand) { - throw new HttpException('Not Found', HttpStatus.NOT_FOUND); - } + if (deleteCommand) return null; if (data) { const mergedData = this.mergeWithUpdateCommand(data, key); this.cache.put(key, mergedData); @@ -74,7 +72,7 @@ export abstract class BaseService { }; } - throw new HttpException('Not Found', HttpStatus.NOT_FOUND); + return null; } async update(key: string, updateData: T) { From 19d73371b6a1e0791bd6731fc2f16058f09d73c4 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 7 Dec 2023 11:38:51 +0900 Subject: [PATCH 143/170] =?UTF-8?q?fix:=20null=20=EC=B2=B4=EC=9D=B4?= =?UTF-8?q?=EB=8B=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/auth/auth.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/auth/auth.service.ts b/nestjs-BE/server/src/auth/auth.service.ts index 513d7d5f..f995559b 100644 --- a/nestjs-BE/server/src/auth/auth.service.ts +++ b/nestjs-BE/server/src/auth/auth.service.ts @@ -131,7 +131,7 @@ export class AuthService extends BaseService { async findUser(usersService: UsersService, email: string, provider: string) { const key = `email:${email}+provider:${provider}`; const findUserData = await usersService.findOne(key); - return findUserData.data?.uuid; + return findUserData?.data?.uuid; } async createUser( From 04582a81931090ca924bd09c9ed607c80d0eba24 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 7 Dec 2023 11:51:34 +0900 Subject: [PATCH 144/170] =?UTF-8?q?fix:=20=EC=98=88=EC=99=B8=20=EB=B0=9B?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/profile-space/profile-space.controller.ts | 2 +- nestjs-BE/server/src/spaces/spaces.controller.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nestjs-BE/server/src/profile-space/profile-space.controller.ts b/nestjs-BE/server/src/profile-space/profile-space.controller.ts index 8fcca5b9..54263551 100644 --- a/nestjs-BE/server/src/profile-space/profile-space.controller.ts +++ b/nestjs-BE/server/src/profile-space/profile-space.controller.ts @@ -41,7 +41,7 @@ export class ProfileSpaceController { await this.profileSpaceService.processData(userUuid, space_uuid); const responseData = await this.profileSpaceService.create(joinData); const data = await this.spacesService.processData(space_uuid, profileData); - this.profileSpaceService.put(userUuid, space_uuid, data); + await this.profileSpaceService.put(userUuid, space_uuid, data); return responseData; } diff --git a/nestjs-BE/server/src/spaces/spaces.controller.ts b/nestjs-BE/server/src/spaces/spaces.controller.ts index e411ea7b..b6fe9bfe 100644 --- a/nestjs-BE/server/src/spaces/spaces.controller.ts +++ b/nestjs-BE/server/src/spaces/spaces.controller.ts @@ -54,7 +54,7 @@ export class SpacesController { this.profileSpaceService.create(joinData); const spaceData = response.data; const data = { profileData, spaceData }; - this.profileSpaceService.put(userUuid, spaceUuid, data); + await this.profileSpaceService.put(userUuid, spaceUuid, data); return response; } From b94ae2ede7486929ce683254bb8685f530ac0dd9 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 15:33:48 +0900 Subject: [PATCH 145/170] =?UTF-8?q?fix(#188):=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/auth/auth.service.ts | 4 ++-- nestjs-BE/server/src/base/base.service.ts | 6 ++++-- .../src/invite-codes/invite-codes.service.ts | 5 +---- .../src/profile-space/profile-space.service.ts | 6 ++---- nestjs-BE/server/src/spaces/spaces.controller.ts | 15 --------------- 5 files changed, 9 insertions(+), 27 deletions(-) diff --git a/nestjs-BE/server/src/auth/auth.service.ts b/nestjs-BE/server/src/auth/auth.service.ts index f995559b..d9ba4ff7 100644 --- a/nestjs-BE/server/src/auth/auth.service.ts +++ b/nestjs-BE/server/src/auth/auth.service.ts @@ -130,8 +130,8 @@ export class AuthService extends BaseService { async findUser(usersService: UsersService, email: string, provider: string) { const key = `email:${email}+provider:${provider}`; - const findUserData = await usersService.findOne(key); - return findUserData?.data?.uuid; + const findUserData = await usersService.getDataFromCacheOrDB(key); + return findUserData?.uuid; } async createUser( diff --git a/nestjs-BE/server/src/base/base.service.ts b/nestjs-BE/server/src/base/base.service.ts index 6fa50da8..720cd687 100644 --- a/nestjs-BE/server/src/base/base.service.ts +++ b/nestjs-BE/server/src/base/base.service.ts @@ -61,7 +61,9 @@ export abstract class BaseService { key, 'delete', ); - if (deleteCommand) return null; + if (deleteCommand) { + throw new HttpException('Not Found', HttpStatus.NOT_FOUND); + } if (data) { const mergedData = this.mergeWithUpdateCommand(data, key); this.cache.put(key, mergedData); @@ -72,7 +74,7 @@ export abstract class BaseService { }; } - return null; + throw new HttpException('Not Found', HttpStatus.NOT_FOUND); } async update(key: string, updateData: T) { diff --git a/nestjs-BE/server/src/invite-codes/invite-codes.service.ts b/nestjs-BE/server/src/invite-codes/invite-codes.service.ts index 31277204..b2580229 100644 --- a/nestjs-BE/server/src/invite-codes/invite-codes.service.ts +++ b/nestjs-BE/server/src/invite-codes/invite-codes.service.ts @@ -66,10 +66,7 @@ export class InviteCodesService extends BaseService { const expiryTimestamp = new Date(inviteCodeData.expiry_date).getTime(); if (expiryTimestamp < currentTimestamp) { super.remove(inviteCode); - throw new HttpException( - 'Invite code has expired.', - HttpStatus.GONE, - ); + throw new HttpException('Invite code has expired.', HttpStatus.GONE); } const spaceUuid = inviteCodeData.space_uuid; const spaceData = await this.spacesService.getDataFromCacheOrDB(spaceUuid); diff --git a/nestjs-BE/server/src/profile-space/profile-space.service.ts b/nestjs-BE/server/src/profile-space/profile-space.service.ts index 3510474e..17ac64b5 100644 --- a/nestjs-BE/server/src/profile-space/profile-space.service.ts +++ b/nestjs-BE/server/src/profile-space/profile-space.service.ts @@ -125,11 +125,9 @@ export class ProfileSpaceService extends BaseService { }, }, }); - if (!spaceResponse) { - throw new HttpException('Not Found', HttpStatus.NOT_FOUND); - } + const storeSpaceProfiles = - spaceResponse.profiles.map((profileSpace) => profileSpace.profile) || []; + spaceResponse?.profiles.map((profileSpace) => profileSpace.profile) || []; return storeSpaceProfiles; } diff --git a/nestjs-BE/server/src/spaces/spaces.controller.ts b/nestjs-BE/server/src/spaces/spaces.controller.ts index b6fe9bfe..565a155d 100644 --- a/nestjs-BE/server/src/spaces/spaces.controller.ts +++ b/nestjs-BE/server/src/spaces/spaces.controller.ts @@ -5,7 +5,6 @@ import { Body, Patch, Param, - Delete, UseInterceptors, UploadedFile, Request as Req, @@ -97,18 +96,4 @@ export class SpacesController { } return this.spacesService.update(spaceUuid, updateSpaceDto); } - - @Delete(':space_uuid') - @ApiOperation({ summary: 'Remove space by space_uuid' }) - @ApiResponse({ - status: 200, - description: 'Space has been successfully removed.', - }) - @ApiResponse({ - status: 404, - description: 'Space not found.', - }) - remove(@Param('space_uuid') spaceUuid: string) { - return this.spacesService.remove(spaceUuid); - } } From 95e0eecb7cec4dc0c004c107c50742cd4b6c1052 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 7 Dec 2023 16:14:28 +0900 Subject: [PATCH 146/170] =?UTF-8?q?fix:=20=ED=98=95=EC=8B=9D=EC=97=90=20?= =?UTF-8?q?=EB=A7=9E=EC=B6=B0=EC=84=9C=20=EC=9D=91=EB=8B=B5=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EB=B3=B4=EB=82=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/src/boards/boards.controller.ts | 56 +++++++++---- nestjs-BE/server/src/boards/boards.service.ts | 2 +- .../server/src/boards/swagger/boards.type.ts | 80 ++++++++++++++++++- 3 files changed, 122 insertions(+), 16 deletions(-) diff --git a/nestjs-BE/server/src/boards/boards.controller.ts b/nestjs-BE/server/src/boards/boards.controller.ts index fabbcb8e..d7b47403 100644 --- a/nestjs-BE/server/src/boards/boards.controller.ts +++ b/nestjs-BE/server/src/boards/boards.controller.ts @@ -24,7 +24,15 @@ import { import { Public } from 'src/auth/public.decorator'; import { DeleteBoardDto } from './dto/delete-board.dto'; import { RestoreBoardDto } from './dto/restore-board.dto'; -import { BoardInSpace, CreateBoardSuccess } from './swagger/boards.type'; +import { + BoardListSuccess, + CreateBoardFailure, + CreateBoardSuccess, + DeleteBoardFailure, + DeleteBoardSuccess, + RestoreBoardFailure, + RestoreBoardSuccess, +} from './swagger/boards.type'; const BOARD_EXPIRE_DAY = 7; @@ -42,14 +50,21 @@ export class BoardsController { type: CreateBoardSuccess, description: '보드 생성 완료', }) - @ApiConflictResponse({ description: '보드가 이미 존재함' }) + @ApiConflictResponse({ + type: CreateBoardFailure, + description: '보드가 이미 존재함', + }) @Public() @Post('create') @HttpCode(HttpStatus.CREATED) async createBoard(@Body() createBoardDto: CreateBoardDto) { const document = await this.boardsService.create(createBoardDto); const responseData = { boardId: document.uuid, date: document.createdAt }; - return responseData; + return { + statusCode: HttpStatus.CREATED, + message: 'Board created.', + data: responseData, + }; } @ApiOperation({ @@ -62,8 +77,7 @@ export class BoardsController { description: '보드 목록을 불러올 스페이스 id', }) @ApiOkResponse({ - type: BoardInSpace, - isArray: true, + type: BoardListSuccess, description: '보드 목록 불러오기 완료', }) @Public() @@ -92,7 +106,11 @@ export class BoardsController { }); return list; }, []); - return responseData; + return { + statusCode: HttpStatus.OK, + message: 'Retrieved board list.', + data: responseData, + }; } @ApiOperation({ @@ -100,16 +118,21 @@ export class BoardsController { description: '삭제할 보드 id를 받아서 보드를 삭제한다.', }) @ApiBody({ type: DeleteBoardDto }) - @ApiOkResponse({ description: '보드 삭제 완료' }) - @ApiNotFoundResponse({ description: '보드가 존재하지 않음' }) + @ApiOkResponse({ type: DeleteBoardSuccess, description: '보드 삭제 완료' }) + @ApiNotFoundResponse({ + type: DeleteBoardFailure, + description: '보드가 존재하지 않음', + }) @Public() @Patch('delete') async deleteBoard(@Body() deleteBoardDto: DeleteBoardDto) { const updateResult = await this.boardsService.deleteBoard( deleteBoardDto.boardId, ); - if (!updateResult.matchedCount) throw new NotFoundException(); - return 'board deleted.'; + if (!updateResult.matchedCount) { + throw new NotFoundException('Target board not found.'); + } + return { statusCode: HttpStatus.OK, message: 'Board deleted.' }; } @ApiOperation({ @@ -117,15 +140,20 @@ export class BoardsController { description: '복구할 보드 id를 받아서 보드를 복구한다.', }) @ApiBody({ type: RestoreBoardDto }) - @ApiOkResponse({ description: '보드 복구 완료' }) - @ApiNotFoundResponse({ description: '보드가 존재하지 않음' }) + @ApiOkResponse({ type: RestoreBoardSuccess, description: '보드 복구 완료' }) + @ApiNotFoundResponse({ + type: RestoreBoardFailure, + description: '보드가 존재하지 않음', + }) @Public() @Patch('restore') async restoreBoard(@Body() resotreBoardDto: RestoreBoardDto) { const updateResult = await this.boardsService.restoreBoard( resotreBoardDto.boardId, ); - if (!updateResult.matchedCount) throw new NotFoundException(); - return 'board restored.'; + if (!updateResult.matchedCount) { + throw new NotFoundException('Target board not found.'); + } + return { statusCode: HttpStatus.OK, message: 'Board restored.' }; } } diff --git a/nestjs-BE/server/src/boards/boards.service.ts b/nestjs-BE/server/src/boards/boards.service.ts index f307c421..ab57919c 100644 --- a/nestjs-BE/server/src/boards/boards.service.ts +++ b/nestjs-BE/server/src/boards/boards.service.ts @@ -15,7 +15,7 @@ export class BoardsService { const existingBoard = await this.boardModel .findOne({ boardName, spaceId }) .exec(); - if (existingBoard) throw new ConflictException(); + if (existingBoard) throw new ConflictException('Board already exist.'); const uuid = v4(); const now = new Date(); diff --git a/nestjs-BE/server/src/boards/swagger/boards.type.ts b/nestjs-BE/server/src/boards/swagger/boards.type.ts index 0e79fd4b..48429d13 100644 --- a/nestjs-BE/server/src/boards/swagger/boards.type.ts +++ b/nestjs-BE/server/src/boards/swagger/boards.type.ts @@ -1,6 +1,7 @@ +import { HttpStatus } from '@nestjs/common'; import { ApiProperty } from '@nestjs/swagger'; -export class CreateBoardSuccess { +export class CreatedBoard { @ApiProperty({ description: '생성한 보드 id' }) boardId: string; @@ -8,6 +9,28 @@ export class CreateBoardSuccess { date: Date; } +export class CreateBoardSuccess { + @ApiProperty({ example: HttpStatus.CREATED, description: '응답 코드' }) + statusCode: number; + + @ApiProperty({ example: 'Board created', description: '응답 메세지' }) + message: string; + + @ApiProperty({ description: '데이터' }) + data: CreatedBoard; +} + +export class CreateBoardFailure { + @ApiProperty({ example: HttpStatus.CONFLICT, description: '응답 코드' }) + statusCode: number; + + @ApiProperty({ example: 'Board already exist.', description: '응답 메세지' }) + message: string; + + @ApiProperty({ example: 'Conflict', description: '응답 메세지' }) + error: string; +} + export class BoardInSpace { @ApiProperty({ description: '보드 id' }) boardId: string; @@ -24,3 +47,58 @@ export class BoardInSpace { @ApiProperty({ description: '삭제 여부' }) isDeleted: boolean; } + +export class BoardListSuccess { + @ApiProperty({ example: HttpStatus.OK, description: '응답 코드' }) + statusCode: number; + + @ApiProperty({ example: 'Retrieved board list.', description: '응답 메세지' }) + message: string; + + @ApiProperty({ isArray: true, description: '데이터' }) + data: BoardInSpace; +} + +export class DeleteBoardSuccess { + @ApiProperty({ example: HttpStatus.OK, description: '응답 코드' }) + statusCode: number; + + @ApiProperty({ example: 'Board deleted.', description: '응답 메세지' }) + message: string; +} + +export class DeleteBoardFailure { + @ApiProperty({ example: HttpStatus.NOT_FOUND, description: '응답 코드' }) + statusCode: number; + + @ApiProperty({ + example: 'Target board not found.', + description: '응답 메세지', + }) + message: string; + + @ApiProperty({ example: 'Not Found', description: '응답 메세지' }) + error: string; +} + +export class RestoreBoardSuccess { + @ApiProperty({ example: HttpStatus.OK, description: '응답 코드' }) + statusCode: number; + + @ApiProperty({ example: 'Board restored.', description: '응답 메세지' }) + message: string; +} + +export class RestoreBoardFailure { + @ApiProperty({ example: HttpStatus.NOT_FOUND, description: '응답 코드' }) + statusCode: number; + + @ApiProperty({ + example: 'Target board not found.', + description: '응답 메세지', + }) + message: string; + + @ApiProperty({ example: 'Not Found', description: '응답 메세지' }) + error: string; +} From 53c1ade026bafd80ca7632fd34d25f757e1ef203 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Thu, 7 Dec 2023 17:35:06 +0900 Subject: [PATCH 147/170] =?UTF-8?q?fix(#212):=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=EA=B0=92=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/spaces/dto/create-space.dto.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nestjs-BE/server/src/spaces/dto/create-space.dto.ts b/nestjs-BE/server/src/spaces/dto/create-space.dto.ts index 209bc3b8..23317491 100644 --- a/nestjs-BE/server/src/spaces/dto/create-space.dto.ts +++ b/nestjs-BE/server/src/spaces/dto/create-space.dto.ts @@ -1,6 +1,9 @@ import { ApiProperty } from '@nestjs/swagger'; +import { IsNotEmpty, IsString } from 'class-validator'; export class CreateSpaceDto { + @IsString() + @IsNotEmpty() @ApiProperty({ example: 'Sample Space', description: 'Name of the space' }) name: string; From 8a1173554ee8fb4c5e34f482ab5841021bab28f8 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Thu, 7 Dec 2023 20:52:46 +0900 Subject: [PATCH 148/170] =?UTF-8?q?feat:=20=EB=B3=B4=EB=93=9C=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EC=8B=9C=20=EC=9A=94=EC=B2=AD=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EB=B0=9B=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/src/boards/boards.controller.ts | 32 ++++++++++++++++--- nestjs-BE/server/src/boards/boards.module.ts | 2 ++ nestjs-BE/server/src/boards/boards.service.ts | 20 +++++++----- .../server/src/boards/dto/create-board.dto.ts | 8 ++--- .../server/src/boards/swagger/boards.type.ts | 3 ++ nestjs-BE/server/src/upload/upload.module.ts | 1 + 6 files changed, 48 insertions(+), 18 deletions(-) diff --git a/nestjs-BE/server/src/boards/boards.controller.ts b/nestjs-BE/server/src/boards/boards.controller.ts index d7b47403..793aad84 100644 --- a/nestjs-BE/server/src/boards/boards.controller.ts +++ b/nestjs-BE/server/src/boards/boards.controller.ts @@ -8,12 +8,15 @@ import { Query, Patch, NotFoundException, + UseInterceptors, + UploadedFile, } from '@nestjs/common'; import { BoardsService } from './boards.service'; import { CreateBoardDto } from './dto/create-board.dto'; import { ApiBody, ApiConflictResponse, + ApiConsumes, ApiCreatedResponse, ApiNotFoundResponse, ApiOkResponse, @@ -33,13 +36,18 @@ import { RestoreBoardFailure, RestoreBoardSuccess, } from './swagger/boards.type'; +import { FileInterceptor } from '@nestjs/platform-express'; +import { UploadService } from 'src/upload/upload.service'; const BOARD_EXPIRE_DAY = 7; @Controller('boards') @ApiTags('boards') export class BoardsController { - constructor(private readonly boardsService: BoardsService) {} + constructor( + private boardsService: BoardsService, + private uploadService: UploadService, + ) {} @ApiOperation({ summary: '보드 생성', @@ -56,10 +64,24 @@ export class BoardsController { }) @Public() @Post('create') + @UseInterceptors(FileInterceptor('image')) + @ApiConsumes('multipart/form-data') @HttpCode(HttpStatus.CREATED) - async createBoard(@Body() createBoardDto: CreateBoardDto) { - const document = await this.boardsService.create(createBoardDto); - const responseData = { boardId: document.uuid, date: document.createdAt }; + async createBoard( + @Body() createBoardDto: CreateBoardDto, + @UploadedFile() image: Express.Multer.File, + ) { + await this.boardsService.findByNameAndSpaceId( + createBoardDto.boardName, + createBoardDto.spaceId, + ); + const imageUrl = image ? await this.uploadService.uploadFile(image) : null; + const document = await this.boardsService.create(createBoardDto, imageUrl); + const responseData = { + boardId: document.uuid, + date: document.createdAt, + imageUrl, + }; return { statusCode: HttpStatus.CREATED, message: 'Board created.', @@ -101,7 +123,7 @@ export class BoardsController { boardId: board.uuid, boardName: board.boardName, createdAt: board.createdAt, - imageUrl: board.imageUrl, + imageUrl: board.imageUrl ? board.imageUrl : null, isDeleted, }); return list; diff --git a/nestjs-BE/server/src/boards/boards.module.ts b/nestjs-BE/server/src/boards/boards.module.ts index 08a5729a..6a826401 100644 --- a/nestjs-BE/server/src/boards/boards.module.ts +++ b/nestjs-BE/server/src/boards/boards.module.ts @@ -3,10 +3,12 @@ import { BoardsService } from './boards.service'; import { BoardsController } from './boards.controller'; import { MongooseModule } from '@nestjs/mongoose'; import { Board, BoardSchema } from './schemas/board.schema'; +import { UploadModule } from 'src/upload/upload.module'; @Module({ imports: [ MongooseModule.forFeature([{ name: Board.name, schema: BoardSchema }]), + UploadModule, ], controllers: [BoardsController], providers: [BoardsService], diff --git a/nestjs-BE/server/src/boards/boards.service.ts b/nestjs-BE/server/src/boards/boards.service.ts index ab57919c..5034d71c 100644 --- a/nestjs-BE/server/src/boards/boards.service.ts +++ b/nestjs-BE/server/src/boards/boards.service.ts @@ -9,14 +9,11 @@ import { v4 } from 'uuid'; export class BoardsService { constructor(@InjectModel(Board.name) private boardModel: Model) {} - async create(createBoardDto: CreateBoardDto): Promise { - const { boardName, spaceId, imageUrl } = createBoardDto; - - const existingBoard = await this.boardModel - .findOne({ boardName, spaceId }) - .exec(); - if (existingBoard) throw new ConflictException('Board already exist.'); - + async create( + createBoardDto: CreateBoardDto, + imageUrl: string | null, + ): Promise { + const { boardName, spaceId } = createBoardDto; const uuid = v4(); const now = new Date(); const createdBoard = new this.boardModel({ @@ -30,6 +27,13 @@ export class BoardsService { return createdBoard.save(); } + async findByNameAndSpaceId(boardName: string, spaceId: string) { + const existingBoard = await this.boardModel + .findOne({ boardName, spaceId }) + .exec(); + if (existingBoard) throw new ConflictException('Board already exist.'); + } + async findBySpaceId(spaceId: string): Promise { return this.boardModel.find({ spaceId }).exec(); } diff --git a/nestjs-BE/server/src/boards/dto/create-board.dto.ts b/nestjs-BE/server/src/boards/dto/create-board.dto.ts index 18ffdf3a..a958215b 100644 --- a/nestjs-BE/server/src/boards/dto/create-board.dto.ts +++ b/nestjs-BE/server/src/boards/dto/create-board.dto.ts @@ -1,5 +1,5 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsNotEmpty, IsString, IsUrl } from 'class-validator'; +import { IsNotEmpty, IsString } from 'class-validator'; export class CreateBoardDto { @ApiProperty({ description: '보드 이름' }) @@ -12,8 +12,6 @@ export class CreateBoardDto { @IsNotEmpty() spaceId: string; - @ApiProperty({ description: '이미지 url' }) - @IsUrl() - @IsNotEmpty() - imageUrl: string; + @ApiProperty({ format: 'binary', description: '이미지' }) + image: string; } diff --git a/nestjs-BE/server/src/boards/swagger/boards.type.ts b/nestjs-BE/server/src/boards/swagger/boards.type.ts index 48429d13..9a36321c 100644 --- a/nestjs-BE/server/src/boards/swagger/boards.type.ts +++ b/nestjs-BE/server/src/boards/swagger/boards.type.ts @@ -7,6 +7,9 @@ export class CreatedBoard { @ApiProperty({ description: '보드를 생성한 UTC 시각' }) date: Date; + + @ApiProperty({ description: '보드 이미지 url' }) + imageUrl: string; } export class CreateBoardSuccess { diff --git a/nestjs-BE/server/src/upload/upload.module.ts b/nestjs-BE/server/src/upload/upload.module.ts index a6258a8e..71c7f770 100644 --- a/nestjs-BE/server/src/upload/upload.module.ts +++ b/nestjs-BE/server/src/upload/upload.module.ts @@ -3,5 +3,6 @@ import { UploadService } from './upload.service'; @Module({ providers: [UploadService], + exports: [UploadService], }) export class UploadModule {} From 7eb7e5fc01c5099a2b8690224ab8a977ce028ba9 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Fri, 8 Dec 2023 03:45:11 +0900 Subject: [PATCH 149/170] =?UTF-8?q?fix:=20access=20token=20=EC=98=A4?= =?UTF-8?q?=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/auth/auth.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/auth/auth.service.ts b/nestjs-BE/server/src/auth/auth.service.ts index d9ba4ff7..1a69ede4 100644 --- a/nestjs-BE/server/src/auth/auth.service.ts +++ b/nestjs-BE/server/src/auth/auth.service.ts @@ -118,7 +118,7 @@ export class AuthService extends BaseService { return { statusCode: HttpStatus.OK, message: 'Success', - data: { acecss_token: accessToken }, + data: { access_token: accessToken }, }; } catch (error) { super.remove(refreshToken); From a07e6541c5dcca887c56d7c792150aaafb708446 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Fri, 8 Dec 2023 09:55:31 +0900 Subject: [PATCH 150/170] =?UTF-8?q?fix(#212):=20else=20=EB=AC=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/base/base.service.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/nestjs-BE/server/src/base/base.service.ts b/nestjs-BE/server/src/base/base.service.ts index 720cd687..56aecfaf 100644 --- a/nestjs-BE/server/src/base/base.service.ts +++ b/nestjs-BE/server/src/base/base.service.ts @@ -72,9 +72,9 @@ export abstract class BaseService { message: 'Success', data: mergedData, }; + } else { + throw new HttpException('Not Found', HttpStatus.NOT_FOUND); } - - throw new HttpException('Not Found', HttpStatus.NOT_FOUND); } async update(key: string, updateData: T) { @@ -99,11 +99,12 @@ export abstract class BaseService { message: 'Success', data: updatedData.value, }; + } else { + return { + statusCode: HttpStatus.NOT_FOUND, + message: 'Not Found', + }; } - return { - statusCode: HttpStatus.NOT_FOUND, - message: 'Not Found', - }; } async remove(key: string) { From b7401c1914f6a8ed3396f0f4c66f4d12c0158389 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Fri, 8 Dec 2023 09:55:54 +0900 Subject: [PATCH 151/170] =?UTF-8?q?fix(#212):=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=95=84=20=EC=B5=9C=EC=8B=A0=EC=A0=95=EB=B3=B4=EB=A1=9C=20?= =?UTF-8?q?=EB=B0=9B=EC=95=84=EC=98=AC=20=EC=88=98=20=EC=9E=88=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/profile-space/profile-space.service.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/nestjs-BE/server/src/profile-space/profile-space.service.ts b/nestjs-BE/server/src/profile-space/profile-space.service.ts index 17ac64b5..1adbdea2 100644 --- a/nestjs-BE/server/src/profile-space/profile-space.service.ts +++ b/nestjs-BE/server/src/profile-space/profile-space.service.ts @@ -1,4 +1,4 @@ -import { Injectable, HttpException, HttpStatus } from '@nestjs/common'; +import { Injectable, HttpStatus } from '@nestjs/common'; import { UpdateProfileSpaceDto } from './dto/update-profile-space.dto'; import { BaseService } from 'src/base/base.service'; import { PrismaServiceMySQL } from 'src/prisma/prisma.service'; @@ -93,7 +93,7 @@ export class ProfileSpaceService extends BaseService { async getUserSpaces( userUuid: string, profileUuid: string, - ): Promise { + ): Promise { const cacheUserSpaces = this.userCache.get(userUuid); if (cacheUserSpaces) return cacheUserSpaces; const profileResponse = await this.prisma['PROFILE_TB'].findUnique({ @@ -111,7 +111,7 @@ export class ProfileSpaceService extends BaseService { return storeUserSpaces; } - async getSpaceUsers(spaceUuid: string): Promise { + async getSpaceUsers(spaceUuid: string): Promise { const cacheSpaceProfiles = this.spaceCache.get(spaceUuid); if (cacheSpaceProfiles) return cacheSpaceProfiles; @@ -145,10 +145,16 @@ export class ProfileSpaceService extends BaseService { async getUsers(spaceUuid: string) { const users = await this.getSpaceUsers(spaceUuid); + const usersData = await Promise.all( + users.map(async (user) => { + return await this.profilesService.getDataFromCacheOrDB(user.user_id); + }), + ); + this.spaceCache.put(spaceUuid, usersData); return { statusCode: HttpStatus.OK, message: 'Success', - data: users, + data: usersData, }; } } From 4c1c6422175d98cd8b30e25efc17bc383e596a47 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Fri, 8 Dec 2023 10:01:00 +0900 Subject: [PATCH 152/170] =?UTF-8?q?fix(#212):=20=EC=98=A4=ED=83=80=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/auth/auth.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/auth/auth.service.ts b/nestjs-BE/server/src/auth/auth.service.ts index d9ba4ff7..1a69ede4 100644 --- a/nestjs-BE/server/src/auth/auth.service.ts +++ b/nestjs-BE/server/src/auth/auth.service.ts @@ -118,7 +118,7 @@ export class AuthService extends BaseService { return { statusCode: HttpStatus.OK, message: 'Success', - data: { acecss_token: accessToken }, + data: { access_token: accessToken }, }; } catch (error) { super.remove(refreshToken); From c904877ff0d262063125533db4858eb9d92eff12 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Fri, 8 Dec 2023 16:15:43 +0900 Subject: [PATCH 153/170] =?UTF-8?q?fix(#212):=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=95=84=20=EC=97=86=EC=9D=84=20=EC=8B=9C=20=EC=83=9D=EA=B8=B0?= =?UTF-8?q?=EB=8A=94=20=EB=B2=84=EA=B7=B8=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/profile-space/profile-space.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/profile-space/profile-space.service.ts b/nestjs-BE/server/src/profile-space/profile-space.service.ts index 1adbdea2..be51e63a 100644 --- a/nestjs-BE/server/src/profile-space/profile-space.service.ts +++ b/nestjs-BE/server/src/profile-space/profile-space.service.ts @@ -107,7 +107,7 @@ export class ProfileSpaceService extends BaseService { }, }); const storeUserSpaces = - profileResponse.spaces.map((profileSpace) => profileSpace.space) || []; + profileResponse?.spaces.map((profileSpace) => profileSpace.space) || []; return storeUserSpaces; } From def67e37d6a1fd29b33d0179567ae551b3e536b6 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Fri, 8 Dec 2023 17:05:54 +0900 Subject: [PATCH 154/170] =?UTF-8?q?fix(#212):=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EB=B6=88=EB=9F=AC=EC=98=A4=EB=8A=94=20=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/profile-space/profile-space.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/profile-space/profile-space.service.ts b/nestjs-BE/server/src/profile-space/profile-space.service.ts index be51e63a..93534f68 100644 --- a/nestjs-BE/server/src/profile-space/profile-space.service.ts +++ b/nestjs-BE/server/src/profile-space/profile-space.service.ts @@ -147,7 +147,7 @@ export class ProfileSpaceService extends BaseService { const users = await this.getSpaceUsers(spaceUuid); const usersData = await Promise.all( users.map(async (user) => { - return await this.profilesService.getDataFromCacheOrDB(user.user_id); + return await this.profilesService.findOne(user.user_id); }), ); this.spaceCache.put(spaceUuid, usersData); From e7b8736a0b89bd3f7556ee778c2e83d88ea70c60 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 11 Dec 2023 11:01:03 +0900 Subject: [PATCH 155/170] =?UTF-8?q?fix(#212):=20=EC=9E=84=EC=8B=9C=20db=20?= =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=20=EC=BD=94=EB=93=9C=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../temporary-database.service.ts | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/nestjs-BE/server/src/temporary-database/temporary-database.service.ts b/nestjs-BE/server/src/temporary-database/temporary-database.service.ts index 6e9ec3b8..07fa0cf8 100644 --- a/nestjs-BE/server/src/temporary-database/temporary-database.service.ts +++ b/nestjs-BE/server/src/temporary-database/temporary-database.service.ts @@ -17,7 +17,6 @@ interface OperationData { @Injectable() export class TemporaryDatabaseService { private database: Map>> = new Map(); - private entriesMap: Map = new Map(); private readonly FOLDER_NAME = 'operations'; constructor( @@ -112,7 +111,7 @@ export class TemporaryDatabaseService { }); } - @Cron('* * * * * *') + @Cron('0 */10 * * * *') async executeBulkOperations() { for (const service of this.database.keys()) { const serviceMap = this.database.get(service); @@ -130,7 +129,6 @@ export class TemporaryDatabaseService { prisma: PrismaServiceMongoDB | PrismaServiceMySQL, ) { const data = this.prepareData(service, 'insert', dataMap); - this.entriesMap.clear(); if (!data.length) return; if (prisma instanceof PrismaServiceMySQL) { await prisma[service].createMany({ @@ -200,23 +198,4 @@ export class TemporaryDatabaseService { private clearFile(filename: string) { fs.writeFile(join(this.FOLDER_NAME, filename), '', 'utf8'); } - - getEntries(key: string): string[] { - return this.entriesMap.get(key) || []; - } - - addEntry(key: string, value: string): void { - const entries = this.getEntries(key); - entries.push(value); - this.entriesMap.set(key, entries); - } - - removeEntry(key: string, value: string): void { - const entries = this.getEntries(key); - const index = entries.indexOf(value); - if (index > -1) { - entries.splice(index, 1); - this.entriesMap.set(key, entries); - } - } } From 3538c47b18508f06371977840fa357f239d42870 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 11 Dec 2023 11:03:38 +0900 Subject: [PATCH 156/170] =?UTF-8?q?fix(#212):=20=EC=8A=A4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EC=83=9D=EC=84=B1=20=EC=8B=9C=20=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20url=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/BE-deploy.yml | 2 ++ nestjs-BE/server/src/spaces/spaces.controller.ts | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index 8cdca3cf..b4321865 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -28,6 +28,7 @@ jobs: echo "STORAGE_URL=$STORAGE_URL" >> ./nestjs-BE/server/.env echo "BASE_IMAGE_URL=$BASE_IMAGE_URL" >> ./nestjs-BE/server/.env echo "BUCKET_NAME=$BUCKET_NAME" >> ./nestjs-BE/server/.env + echo "APP_ICON_URL=$APP_ICON_URL" >> ./nestjs-BE/server/.env docker build -t ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync ./nestjs-BE/server docker push ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync:latest env: @@ -44,6 +45,7 @@ jobs: STORAGE_URL: ${{ secrets.STORAGE_URL }} BASE_IMAGE_URL: ${{ secrets.BASE_IMAGE_URL }} BUCKET_NAME: ${{ secrets.BUCKET_NAME }} + APP_ICON_URL: ${{ secrets.APP_ICON_URL }} deploy: needs: build diff --git a/nestjs-BE/server/src/spaces/spaces.controller.ts b/nestjs-BE/server/src/spaces/spaces.controller.ts index 565a155d..39c025fd 100644 --- a/nestjs-BE/server/src/spaces/spaces.controller.ts +++ b/nestjs-BE/server/src/spaces/spaces.controller.ts @@ -18,7 +18,7 @@ import { UploadService } from 'src/upload/upload.service'; import { ProfileSpaceService } from 'src/profile-space/profile-space.service'; import { RequestWithUser } from 'src/utils/interface'; import customEnv from 'src/config/env'; -const { BASE_IMAGE_URL } = customEnv; +const { APP_ICON_URL } = customEnv; @Controller('spaces') @ApiTags('spaces') @@ -43,7 +43,7 @@ export class SpacesController { ) { const iconUrl = icon ? await this.uploadService.uploadFile(icon) - : BASE_IMAGE_URL; + : APP_ICON_URL; createSpaceDto.icon = iconUrl; const response = await this.spacesService.create(createSpaceDto); const { uuid: spaceUuid } = response.data; From 972de9c5878d79c3418b97061e3faa24bf0c2810 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 11 Dec 2023 11:46:41 +0900 Subject: [PATCH 157/170] =?UTF-8?q?fix(#212):=20=EC=9D=BC=EB=B6=80=20any?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../temporary-database.service.ts | 41 +++++++++++++++---- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/nestjs-BE/server/src/temporary-database/temporary-database.service.ts b/nestjs-BE/server/src/temporary-database/temporary-database.service.ts index 07fa0cf8..96463bc1 100644 --- a/nestjs-BE/server/src/temporary-database/temporary-database.service.ts +++ b/nestjs-BE/server/src/temporary-database/temporary-database.service.ts @@ -6,17 +6,42 @@ import { import { Cron } from '@nestjs/schedule'; import { promises as fs } from 'fs'; import { join } from 'path'; +import { TokenData } from 'src/auth/auth.service'; +import { InviteCodeData } from 'src/invite-codes/invite-codes.service'; +import { CreateProfileSpaceDto } from 'src/profile-space/dto/create-profile-space.dto'; +import { UpdateProfileDto } from 'src/profiles/dto/update-profile.dto'; +import { UpdateSpaceDto } from 'src/spaces/dto/update-space.dto'; +import { UpdateUserDto } from 'src/users/dto/update-user.dto'; + +type DeleteDataType = { + field: string; + value: string; +}; + +type InsertDataType = + | TokenData + | InviteCodeData + | CreateProfileSpaceDto + | UpdateProfileDto + | UpdateSpaceDto + | UpdateUserDto; + +type UpdateDataType = { + field: string; + value: InsertDataType; +}; +type DataType = InsertDataType | UpdateDataType | DeleteDataType; interface OperationData { service: string; uniqueKey: string; command: string; - data: any; + data: DataType; } @Injectable() export class TemporaryDatabaseService { - private database: Map>> = new Map(); + private database: Map>> = new Map(); private readonly FOLDER_NAME = 'operations'; constructor( @@ -78,15 +103,15 @@ export class TemporaryDatabaseService { return this.database.get(service).get(command).get(uniqueKey); } - create(service: string, uniqueKey: string, data: any) { + create(service: string, uniqueKey: string, data: InsertDataType) { this.operation({ service, uniqueKey, command: 'insert', data }); } - update(service: string, uniqueKey: string, data: any) { + update(service: string, uniqueKey: string, data: UpdateDataType) { this.operation({ service, uniqueKey, command: 'update', data }); } - remove(service: string, uniqueKey: string, data: any) { + remove(service: string, uniqueKey: string, data: DeleteDataType) { this.operation({ service, uniqueKey, command: 'delete', data }); } @@ -125,7 +150,7 @@ export class TemporaryDatabaseService { private async performInsert( service: string, - dataMap: Map, + dataMap: Map, prisma: PrismaServiceMongoDB | PrismaServiceMySQL, ) { const data = this.prepareData(service, 'insert', dataMap); @@ -144,7 +169,7 @@ export class TemporaryDatabaseService { private async performUpdate( service: string, - dataMap: Map, + dataMap: Map, prisma: PrismaServiceMongoDB | PrismaServiceMySQL, ) { const data = this.prepareData(service, 'update', dataMap); @@ -166,7 +191,7 @@ export class TemporaryDatabaseService { private async performDelete( service: string, - dataMap: Map, + dataMap: Map, prisma: PrismaServiceMongoDB | PrismaServiceMySQL, ) { const data = this.prepareData(service, 'delete', dataMap); From 366fd6c1719462986f4df98c42713fd8cbda05ee Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 11 Dec 2023 15:28:12 +0900 Subject: [PATCH 158/170] =?UTF-8?q?fix(#212):=20csv=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EC=9D=84=20=EC=99=B8=EB=B6=80=EC=97=90=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=ED=95=98=EA=B8=B0=20=EC=9C=84=ED=95=B4=20=EB=B3=BC=EB=A5=A8=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/BE-deploy.yml | 8 +++++++- nestjs-BE/server/Dockerfile | 2 -- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/BE-deploy.yml b/.github/workflows/BE-deploy.yml index b4321865..0ae4aeef 100644 --- a/.github/workflows/BE-deploy.yml +++ b/.github/workflows/BE-deploy.yml @@ -29,6 +29,7 @@ jobs: echo "BASE_IMAGE_URL=$BASE_IMAGE_URL" >> ./nestjs-BE/server/.env echo "BUCKET_NAME=$BUCKET_NAME" >> ./nestjs-BE/server/.env echo "APP_ICON_URL=$APP_ICON_URL" >> ./nestjs-BE/server/.env + echo "CSV_FOLDER=$CSV_FOLDER" >> ./nestjs-BE/server/.env docker build -t ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync ./nestjs-BE/server docker push ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync:latest env: @@ -46,6 +47,7 @@ jobs: BASE_IMAGE_URL: ${{ secrets.BASE_IMAGE_URL }} BUCKET_NAME: ${{ secrets.BUCKET_NAME }} APP_ICON_URL: ${{ secrets.APP_ICON_URL }} + CSV_FOLDER: ${{ secrets.CSV_FOLDER }} deploy: needs: build @@ -63,4 +65,8 @@ jobs: docker pull ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync docker stop mindsync_server || true docker rm mindsync_server || true - docker run -d --name mindsync_server -p ${{ secrets.SERVER_PORT }}:${{ secrets.CONTAINER_PORT }} ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync + docker run -d \ + --name mindsync_server \ + -p ${{ secrets.SERVER_PORT }}:${{ secrets.CONTAINER_PORT }} \ + -v temporary-volume:${{ secrets.CSV_FOLDER }} \ + ghcr.io/${{ secrets.PACKAGE_USERNAME }}/mindsync diff --git a/nestjs-BE/server/Dockerfile b/nestjs-BE/server/Dockerfile index 9eb851c7..26d49afc 100644 --- a/nestjs-BE/server/Dockerfile +++ b/nestjs-BE/server/Dockerfile @@ -12,8 +12,6 @@ RUN npx prisma generate --schema=./prisma/mysql.schema.prisma RUN npx prisma generate --schema=./prisma/mongodb.schema.prisma -RUN mkdir operations - EXPOSE 3000 CMD ["npm", "start"] From 2cece3c36259e664c2ffed1fa28ce7d56ea5c432 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 11 Dec 2023 15:28:33 +0900 Subject: [PATCH 159/170] =?UTF-8?q?fix(#212):=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=9D=BD=EA=B3=A0=20=EC=93=B0=EB=8A=94=20=EB=B0=A9=EC=8B=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../temporary-database.service.ts | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/nestjs-BE/server/src/temporary-database/temporary-database.service.ts b/nestjs-BE/server/src/temporary-database/temporary-database.service.ts index 96463bc1..de993400 100644 --- a/nestjs-BE/server/src/temporary-database/temporary-database.service.ts +++ b/nestjs-BE/server/src/temporary-database/temporary-database.service.ts @@ -12,6 +12,8 @@ import { CreateProfileSpaceDto } from 'src/profile-space/dto/create-profile-spac import { UpdateProfileDto } from 'src/profiles/dto/update-profile.dto'; import { UpdateSpaceDto } from 'src/spaces/dto/update-space.dto'; import { UpdateUserDto } from 'src/users/dto/update-user.dto'; +import costomEnv from 'src/config/env'; +const { CSV_FOLDER } = costomEnv; type DeleteDataType = { field: string; @@ -42,15 +44,19 @@ interface OperationData { @Injectable() export class TemporaryDatabaseService { private database: Map>> = new Map(); - private readonly FOLDER_NAME = 'operations'; + private readonly FOLDER_NAME = CSV_FOLDER; constructor( private readonly prismaMysql: PrismaServiceMySQL, private readonly prismaMongoDB: PrismaServiceMongoDB, ) { + this.init(); + } + + async init() { this.initializeDatabase(); - this.readDataFromFiles(); - this.executeBulkOperations(); + await this.readDataFromFiles(); + await this.executeBulkOperations(); } private initializeDatabase() { @@ -76,11 +82,11 @@ export class TemporaryDatabaseService { private async readDataFromFiles() { const files = await fs.readdir(this.FOLDER_NAME); - files.forEach((file) => { - if (file.endsWith('.csv')) { - this.readDataFromFile(file); - } - }); + return Promise.all( + files + .filter((file) => file.endsWith('.csv')) + .map((file) => this.readDataFromFile(file)), + ); } private async readDataFromFile(file: string) { @@ -129,11 +135,7 @@ export class TemporaryDatabaseService { operation({ service, uniqueKey, command, data }: OperationData) { const filePath = join(this.FOLDER_NAME, `${service}-${command}.csv`); - fs.readFile(filePath, 'utf8').then((fileData) => { - fileData += `${uniqueKey},${JSON.stringify(data)}\n`; - fs.writeFile(filePath, fileData); - this.database.get(service).get(command).set(uniqueKey, data); - }); + fs.appendFile(filePath, `${uniqueKey},${JSON.stringify(data)}\n`, 'utf8'); } @Cron('0 */10 * * * *') From b31c5833c3e412addf39706ae83afbd7ce5fc7f9 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 11 Dec 2023 15:58:32 +0900 Subject: [PATCH 160/170] =?UTF-8?q?fix(#212):=20export=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/auth/auth.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/auth/auth.service.ts b/nestjs-BE/server/src/auth/auth.service.ts index 1a69ede4..e63a518c 100644 --- a/nestjs-BE/server/src/auth/auth.service.ts +++ b/nestjs-BE/server/src/auth/auth.service.ts @@ -16,7 +16,7 @@ import { CreateUserDto } from 'src/users/dto/create-user.dto'; import customEnv from 'src/config/env'; const { BASE_IMAGE_URL } = customEnv; -interface TokenData { +export interface TokenData { uuid?: string; token: string; expiry_date: Date; From 6eec42ebaabce6cb40a6441bc4080822a36ef624 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Mon, 11 Dec 2023 16:26:15 +0900 Subject: [PATCH 161/170] =?UTF-8?q?feat(#231):=20=EB=A7=88=EC=9D=B8?= =?UTF-8?q?=EB=93=9C=EB=A7=B5=20=EB=B3=B4=EB=93=9C=20=EC=A0=80=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updateMindmap 이벤트가 일어날 때마다 저장한다. --- nestjs-BE/server/src/board-trees/board-trees.gateway.ts | 1 + nestjs-BE/server/src/board-trees/board-trees.service.ts | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/nestjs-BE/server/src/board-trees/board-trees.gateway.ts b/nestjs-BE/server/src/board-trees/board-trees.gateway.ts index 56de6ca2..502e7182 100644 --- a/nestjs-BE/server/src/board-trees/board-trees.gateway.ts +++ b/nestjs-BE/server/src/board-trees/board-trees.gateway.ts @@ -47,6 +47,7 @@ export class BoardTreesGateway { const operation = operationTypeMap[serializedOperation.operationType](serializedOperation); this.boardTreesService.applyOperation(boardId, operation); + this.boardTreesService.updateTreeData(boardId); client.broadcast .to(boardId) diff --git a/nestjs-BE/server/src/board-trees/board-trees.service.ts b/nestjs-BE/server/src/board-trees/board-trees.service.ts index 0fc77236..06750d73 100644 --- a/nestjs-BE/server/src/board-trees/board-trees.service.ts +++ b/nestjs-BE/server/src/board-trees/board-trees.service.ts @@ -49,4 +49,11 @@ export class BoardTreesService { hasTree(boardId: string) { return this.boardTrees.has(boardId); } + + updateTreeData(boardId: string) { + const tree = this.boardTrees.get(boardId); + this.boardTreeModel + .updateOne({ boardId }, { tree: JSON.stringify(tree) }) + .exec(); + } } From bcd13a2e648a74f7d7e120599af28794ff8c279f Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 11 Dec 2023 16:33:08 +0900 Subject: [PATCH 162/170] =?UTF-8?q?fix(#212):=20=EC=98=A4=ED=83=80=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/profile-space/profile-space.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nestjs-BE/server/src/profile-space/profile-space.service.ts b/nestjs-BE/server/src/profile-space/profile-space.service.ts index 93534f68..6aa3638f 100644 --- a/nestjs-BE/server/src/profile-space/profile-space.service.ts +++ b/nestjs-BE/server/src/profile-space/profile-space.service.ts @@ -86,7 +86,7 @@ export class ProfileSpaceService extends BaseService { const filterSpaceUsers = spaceUsers.filter( (profile) => profile.uuid !== profileData.uuid, ); - this.userCache.put(spaceUuid, filterSpaceUsers); + this.spaceCache.put(spaceUuid, filterSpaceUsers); return filterSpaceUsers.length === 0; } From 6a1759c4a019ac9218d750626a16cab4fa423191 Mon Sep 17 00:00:00 2001 From: Conut-1 <1mim1@naver.com> Date: Mon, 11 Dec 2023 16:49:25 +0900 Subject: [PATCH 163/170] =?UTF-8?q?feat(#234):=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=97=86=EC=9D=84=20=EC=8B=9C=20=EB=B3=B4=EB=93=9C?= =?UTF-8?q?=20=EA=B8=B0=EB=B3=B8=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/boards/boards.controller.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/nestjs-BE/server/src/boards/boards.controller.ts b/nestjs-BE/server/src/boards/boards.controller.ts index 793aad84..4abf9c5e 100644 --- a/nestjs-BE/server/src/boards/boards.controller.ts +++ b/nestjs-BE/server/src/boards/boards.controller.ts @@ -38,6 +38,7 @@ import { } from './swagger/boards.type'; import { FileInterceptor } from '@nestjs/platform-express'; import { UploadService } from 'src/upload/upload.service'; +import customEnv from 'src/config/env'; const BOARD_EXPIRE_DAY = 7; @@ -75,7 +76,9 @@ export class BoardsController { createBoardDto.boardName, createBoardDto.spaceId, ); - const imageUrl = image ? await this.uploadService.uploadFile(image) : null; + const imageUrl = image + ? await this.uploadService.uploadFile(image) + : customEnv.APP_ICON_URL; const document = await this.boardsService.create(createBoardDto, imageUrl); const responseData = { boardId: document.uuid, @@ -123,7 +126,7 @@ export class BoardsController { boardId: board.uuid, boardName: board.boardName, createdAt: board.createdAt, - imageUrl: board.imageUrl ? board.imageUrl : null, + imageUrl: board.imageUrl, isDeleted, }); return list; From b9ec9ff710c711a0a09afff07e50fb9ca47919de Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 11 Dec 2023 17:46:04 +0900 Subject: [PATCH 164/170] =?UTF-8?q?fix(#212):=20=EC=B4=88=EB=8C=80?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EB=B6=88=ED=95=84=EC=9A=94=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/invite-codes/invite-codes.service.ts | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/nestjs-BE/server/src/invite-codes/invite-codes.service.ts b/nestjs-BE/server/src/invite-codes/invite-codes.service.ts index b2580229..760862f3 100644 --- a/nestjs-BE/server/src/invite-codes/invite-codes.service.ts +++ b/nestjs-BE/server/src/invite-codes/invite-codes.service.ts @@ -37,6 +37,8 @@ export class InviteCodesService extends BaseService { } async createCode(createInviteCodeDto: CreateInviteCodeDto) { + const { space_uuid: spaceUuid } = createInviteCodeDto; + await this.spacesService.findOne(spaceUuid); const inviteCode = await this.generateUniqueInviteCode(INVITE_CODE_LENGTH); const currentDate = new Date(); const expiryDate = new Date(currentDate); @@ -46,9 +48,6 @@ export class InviteCodesService extends BaseService { invite_code: inviteCode, expiry_date: expiryDate, }; - const { space_uuid: spaceUuid } = createInviteCodeDto; - const space = await this.spacesService.getDataFromCacheOrDB(spaceUuid); - if (!space) throw new HttpException('Not Found', HttpStatus.NOT_FOUND); super.create(data); return { statusCode: HttpStatus.CREATED, @@ -58,10 +57,8 @@ export class InviteCodesService extends BaseService { } async findSpace(inviteCode: string) { - const inviteCodeData = await super.getDataFromCacheOrDB(inviteCode); - if (!inviteCodeData) { - throw new HttpException('Invalid invite code.', HttpStatus.NOT_FOUND); - } + const inviteCodeResponse = await super.findOne(inviteCode); + const { data: inviteCodeData } = inviteCodeResponse; const currentTimestamp = new Date().getTime(); const expiryTimestamp = new Date(inviteCodeData.expiry_date).getTime(); if (expiryTimestamp < currentTimestamp) { @@ -69,12 +66,8 @@ export class InviteCodesService extends BaseService { throw new HttpException('Invite code has expired.', HttpStatus.GONE); } const spaceUuid = inviteCodeData.space_uuid; - const spaceData = await this.spacesService.getDataFromCacheOrDB(spaceUuid); - return { - statusCode: HttpStatus.OK, - message: 'Success', - data: spaceData, - }; + const spaceResponse = await this.spacesService.findOne(spaceUuid); + return spaceResponse; } generateShortInviteCode(length: number) { From 458bc00392baf1344fdecf4d9e67b1a08ee74e88 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 11 Dec 2023 17:56:08 +0900 Subject: [PATCH 165/170] =?UTF-8?q?fix(#212):=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/invite-codes/invite-codes.service.ts | 59 +++++++++++++------ 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/nestjs-BE/server/src/invite-codes/invite-codes.service.ts b/nestjs-BE/server/src/invite-codes/invite-codes.service.ts index 760862f3..b0219584 100644 --- a/nestjs-BE/server/src/invite-codes/invite-codes.service.ts +++ b/nestjs-BE/server/src/invite-codes/invite-codes.service.ts @@ -39,35 +39,52 @@ export class InviteCodesService extends BaseService { async createCode(createInviteCodeDto: CreateInviteCodeDto) { const { space_uuid: spaceUuid } = createInviteCodeDto; await this.spacesService.findOne(spaceUuid); - const inviteCode = await this.generateUniqueInviteCode(INVITE_CODE_LENGTH); - const currentDate = new Date(); - const expiryDate = new Date(currentDate); - expiryDate.setHours(currentDate.getHours() + INVITE_CODE_EXPIRY_HOURS); - const data: InviteCodeData = { + const inviteCodeData = await this.generateInviteCode(createInviteCodeDto); + super.create(inviteCodeData); + return this.createResponse(inviteCodeData.invite_code); + } + + async findSpace(inviteCode: string) { + const inviteCodeData = await this.getInviteCodeData(inviteCode); + this.checkExpiry(inviteCode, inviteCodeData.expiry_date); + const spaceResponse = await this.spacesService.findOne( + inviteCodeData.space_uuid, + ); + return spaceResponse; + } + + private async generateInviteCode(createInviteCodeDto: CreateInviteCodeDto) { + const uniqueInviteCode = + await this.generateUniqueInviteCode(INVITE_CODE_LENGTH); + const expiryDate = this.calculateExpiryDate(); + + return { ...createInviteCodeDto, - invite_code: inviteCode, + invite_code: uniqueInviteCode, expiry_date: expiryDate, }; - super.create(data); - return { - statusCode: HttpStatus.CREATED, - message: 'Created', - data: { invite_code: inviteCode }, - }; } - async findSpace(inviteCode: string) { + private calculateExpiryDate(): Date { + const currentDate = new Date(); + const expiryDate = new Date(currentDate); + expiryDate.setHours(currentDate.getHours() + INVITE_CODE_EXPIRY_HOURS); + return expiryDate; + } + + private async getInviteCodeData(inviteCode: string) { const inviteCodeResponse = await super.findOne(inviteCode); const { data: inviteCodeData } = inviteCodeResponse; + return inviteCodeData; + } + + private checkExpiry(inviteCode: string, expiryDate: Date) { const currentTimestamp = new Date().getTime(); - const expiryTimestamp = new Date(inviteCodeData.expiry_date).getTime(); + const expiryTimestamp = new Date(expiryDate).getTime(); if (expiryTimestamp < currentTimestamp) { super.remove(inviteCode); throw new HttpException('Invite code has expired.', HttpStatus.GONE); } - const spaceUuid = inviteCodeData.space_uuid; - const spaceResponse = await this.spacesService.findOne(spaceUuid); - return spaceResponse; } generateShortInviteCode(length: number) { @@ -93,4 +110,12 @@ export class InviteCodesService extends BaseService { return inviteCode; } + + private createResponse(inviteCode: string) { + return { + statusCode: HttpStatus.CREATED, + message: 'Created', + data: { invite_code: inviteCode }, + }; + } } From c3e82184619ef7f9278be99d83b0a66be380034f Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 11 Dec 2023 18:32:54 +0900 Subject: [PATCH 166/170] =?UTF-8?q?fix(#212):=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EA=B3=BC=20=ED=95=A8=EA=BB=98=20=EC=BA=90=EC=8B=9C=EC=97=90=20?= =?UTF-8?q?=EB=8B=B4=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/invite-codes/invite-codes.service.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/nestjs-BE/server/src/invite-codes/invite-codes.service.ts b/nestjs-BE/server/src/invite-codes/invite-codes.service.ts index b0219584..5041e2bc 100644 --- a/nestjs-BE/server/src/invite-codes/invite-codes.service.ts +++ b/nestjs-BE/server/src/invite-codes/invite-codes.service.ts @@ -38,9 +38,10 @@ export class InviteCodesService extends BaseService { async createCode(createInviteCodeDto: CreateInviteCodeDto) { const { space_uuid: spaceUuid } = createInviteCodeDto; - await this.spacesService.findOne(spaceUuid); + const spaceResponse = await this.spacesService.findOne(spaceUuid); const inviteCodeData = await this.generateInviteCode(createInviteCodeDto); super.create(inviteCodeData); + this.cache.put(inviteCodeData.invite_code, spaceResponse); return this.createResponse(inviteCodeData.invite_code); } @@ -87,7 +88,7 @@ export class InviteCodesService extends BaseService { } } - generateShortInviteCode(length: number) { + private generateShortInviteCode(length: number) { const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; let inviteCode = ''; @@ -99,7 +100,7 @@ export class InviteCodesService extends BaseService { return inviteCode; } - async generateUniqueInviteCode(length: number): Promise { + private async generateUniqueInviteCode(length: number): Promise { let inviteCode: string; let inviteCodeData: InviteCodeData; From 5e6e088b4d57f73befbd95ea7ee97e529fc979a3 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 11 Dec 2023 18:41:03 +0900 Subject: [PATCH 167/170] =?UTF-8?q?fix(#212):=20=EB=B9=84=EC=8A=B7?= =?UTF-8?q?=ED=95=9C=20=ED=95=A8=EC=88=98=20=EC=9D=B4=EB=A6=84=20=EB=AA=85?= =?UTF-8?q?=ED=99=95=ED=95=98=EA=B2=8C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../profile-space/profile-space.controller.ts | 4 +-- .../profile-space/profile-space.service.ts | 31 +++++++++++++------ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/nestjs-BE/server/src/profile-space/profile-space.controller.ts b/nestjs-BE/server/src/profile-space/profile-space.controller.ts index 54263551..e10e3642 100644 --- a/nestjs-BE/server/src/profile-space/profile-space.controller.ts +++ b/nestjs-BE/server/src/profile-space/profile-space.controller.ts @@ -80,7 +80,7 @@ export class ProfileSpaceController { }) getSpaces(@Req() req: RequestWithUser) { const userUuid = req.user.uuid; - return this.profileSpaceService.getSpaces(userUuid); + return this.profileSpaceService.retrieveUserSpaces(userUuid); } @Get('users/:space_uuid') @@ -94,6 +94,6 @@ export class ProfileSpaceController { description: 'Space not found.', }) getUsers(@Param('space_uuid') spaceUuid: string) { - return this.profileSpaceService.getUsers(spaceUuid); + return this.profileSpaceService.retrieveSpaceUsers(spaceUuid); } } diff --git a/nestjs-BE/server/src/profile-space/profile-space.service.ts b/nestjs-BE/server/src/profile-space/profile-space.service.ts index 6aa3638f..b8cb73cf 100644 --- a/nestjs-BE/server/src/profile-space/profile-space.service.ts +++ b/nestjs-BE/server/src/profile-space/profile-space.service.ts @@ -64,10 +64,13 @@ export class ProfileSpaceService extends BaseService { data: UpdateProfileAndSpaceDto, ) { const { spaceData, profileData } = data; - const userSpaces = await this.getUserSpaces(userUuid, profileData.uuid); + const userSpaces = await this.fetchUserSpacesFromCacheOrDB( + userUuid, + profileData.uuid, + ); userSpaces.push(spaceData); this.userCache.put(userUuid, userSpaces); - const spaceProfiles = await this.getSpaceUsers(spaceUuid); + const spaceProfiles = await this.fetchSpaceUsersFromCacheOrDB(spaceUuid); spaceProfiles.push(profileData); this.spaceCache.put(spaceUuid, spaceProfiles); } @@ -77,12 +80,15 @@ export class ProfileSpaceService extends BaseService { spaceUuid: string, profileData: UpdateProfileDto, ) { - const userSpaces = await this.getUserSpaces(userUuid, profileData.uuid); + const userSpaces = await this.fetchUserSpacesFromCacheOrDB( + userUuid, + profileData.uuid, + ); const filterUserSpaces = userSpaces.filter( (space) => space.uuid !== spaceUuid, ); this.userCache.put(userUuid, filterUserSpaces); - const spaceUsers = await this.getSpaceUsers(spaceUuid); + const spaceUsers = await this.fetchSpaceUsersFromCacheOrDB(spaceUuid); const filterSpaceUsers = spaceUsers.filter( (profile) => profile.uuid !== profileData.uuid, ); @@ -90,7 +96,7 @@ export class ProfileSpaceService extends BaseService { return filterSpaceUsers.length === 0; } - async getUserSpaces( + async fetchUserSpacesFromCacheOrDB( userUuid: string, profileUuid: string, ): Promise { @@ -111,7 +117,9 @@ export class ProfileSpaceService extends BaseService { return storeUserSpaces; } - async getSpaceUsers(spaceUuid: string): Promise { + async fetchSpaceUsersFromCacheOrDB( + spaceUuid: string, + ): Promise { const cacheSpaceProfiles = this.spaceCache.get(spaceUuid); if (cacheSpaceProfiles) return cacheSpaceProfiles; @@ -131,10 +139,13 @@ export class ProfileSpaceService extends BaseService { return storeSpaceProfiles; } - async getSpaces(userUuid: string) { + async retrieveUserSpaces(userUuid: string) { const profileResponse = await this.profilesService.findOne(userUuid); const profileUuid = profileResponse.data?.uuid; - const spaces = await this.getUserSpaces(userUuid, profileUuid); + const spaces = await this.fetchUserSpacesFromCacheOrDB( + userUuid, + profileUuid, + ); this.userCache.put(userUuid, spaces); return { statusCode: HttpStatus.OK, @@ -143,8 +154,8 @@ export class ProfileSpaceService extends BaseService { }; } - async getUsers(spaceUuid: string) { - const users = await this.getSpaceUsers(spaceUuid); + async retrieveSpaceUsers(spaceUuid: string) { + const users = await this.fetchSpaceUsersFromCacheOrDB(spaceUuid); const usersData = await Promise.all( users.map(async (user) => { return await this.profilesService.findOne(user.user_id); From acda3f00648950184448246c0703ef32c63024cc Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 11 Dec 2023 19:27:44 +0900 Subject: [PATCH 168/170] =?UTF-8?q?fix(#212):=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=ED=95=98=EB=8B=A4=20=EB=B9=A0=EC=A7=84=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/src/temporary-database/temporary-database.service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/nestjs-BE/server/src/temporary-database/temporary-database.service.ts b/nestjs-BE/server/src/temporary-database/temporary-database.service.ts index de993400..0b1182bc 100644 --- a/nestjs-BE/server/src/temporary-database/temporary-database.service.ts +++ b/nestjs-BE/server/src/temporary-database/temporary-database.service.ts @@ -136,6 +136,7 @@ export class TemporaryDatabaseService { operation({ service, uniqueKey, command, data }: OperationData) { const filePath = join(this.FOLDER_NAME, `${service}-${command}.csv`); fs.appendFile(filePath, `${uniqueKey},${JSON.stringify(data)}\n`, 'utf8'); + this.database.get(service).get(command).set(uniqueKey, data); } @Cron('0 */10 * * * *') From f1f91514236bb9047edd6e79eaa0d2bee3333d79 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 11 Dec 2023 20:04:21 +0900 Subject: [PATCH 169/170] =?UTF-8?q?fix(#212):=20response=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=ED=95=98=EC=97=AC=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=A4=91=EB=B3=B5=20=EC=BD=94=EB=93=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/auth/auth.controller.ts | 17 +--------- nestjs-BE/server/src/auth/auth.service.ts | 23 +++++-------- nestjs-BE/server/src/base/base.service.ts | 29 ++++------------ .../src/invite-codes/invite-codes.service.ts | 15 +++----- .../profile-space/profile-space.service.ts | 13 ++----- .../temporary-database.service.ts | 2 +- nestjs-BE/server/src/utils/response.ts | 34 +++++++++++++++++++ 7 files changed, 58 insertions(+), 75 deletions(-) create mode 100644 nestjs-BE/server/src/utils/response.ts diff --git a/nestjs-BE/server/src/auth/auth.controller.ts b/nestjs-BE/server/src/auth/auth.controller.ts index d16f6de4..aad67c36 100644 --- a/nestjs-BE/server/src/auth/auth.controller.ts +++ b/nestjs-BE/server/src/auth/auth.controller.ts @@ -1,14 +1,5 @@ -import { - Controller, - Post, - Request, - UseGuards, - Get, - Body, - NotFoundException, -} from '@nestjs/common'; +import { Controller, Post, Body, NotFoundException } from '@nestjs/common'; import { AuthService } from './auth.service'; -import { JwtAuthGuard } from './jwt-auth.guard'; import { Public } from './public.decorator'; import { KakaoUserDto } from './dto/kakao-user.dto'; import { UsersService } from 'src/users/users.service'; @@ -80,10 +71,4 @@ export class AuthController { const refreshToken = refreshTokenDto.refresh_token; return this.authService.remove(refreshToken); } - - @UseGuards(JwtAuthGuard) - @Get('profile') - getProfile(@Request() req) { - return req.user; - } } diff --git a/nestjs-BE/server/src/auth/auth.service.ts b/nestjs-BE/server/src/auth/auth.service.ts index e63a518c..87e931fc 100644 --- a/nestjs-BE/server/src/auth/auth.service.ts +++ b/nestjs-BE/server/src/auth/auth.service.ts @@ -14,6 +14,7 @@ import { UsersService } from 'src/users/users.service'; import { ProfilesService } from 'src/profiles/profiles.service'; import { CreateUserDto } from 'src/users/dto/create-user.dto'; import customEnv from 'src/config/env'; +import { ResponseUtils } from 'src/utils/response'; const { BASE_IMAGE_URL } = customEnv; export interface TokenData { @@ -97,14 +98,11 @@ export class AuthService extends BaseService { userUuid, ); super.create(refreshTokenData); - return { - statusCode: HttpStatus.OK, - message: 'Success', - data: { - access_token: accessToken, - refresh_token: refreshToken, - }, + const tokenData = { + access_token: accessToken, + refresh_token: refreshToken, }; + return ResponseUtils.createResponse(HttpStatus.OK, tokenData); } async renewAccessToken(refreshToken: string) { @@ -112,14 +110,11 @@ export class AuthService extends BaseService { this.jwtService.verify(refreshToken, { secret: jwtConstants.refreshSecret, }); - const tokenData = await this.getDataFromCacheOrDB(refreshToken); - if (!tokenData) throw new Error('No token data found'); + const { data: tokenData } = await this.findOne(refreshToken); const accessToken = await this.createAccessToken(tokenData.user_id); - return { - statusCode: HttpStatus.OK, - message: 'Success', - data: { access_token: accessToken }, - }; + return ResponseUtils.createResponse(HttpStatus.OK, { + access_token: accessToken, + }); } catch (error) { super.remove(refreshToken); throw new UnauthorizedException( diff --git a/nestjs-BE/server/src/base/base.service.ts b/nestjs-BE/server/src/base/base.service.ts index 56aecfaf..39980408 100644 --- a/nestjs-BE/server/src/base/base.service.ts +++ b/nestjs-BE/server/src/base/base.service.ts @@ -6,6 +6,7 @@ import { import { TemporaryDatabaseService } from '../temporary-database/temporary-database.service'; import LRUCache from '../utils/lru-cache'; import generateUuid from '../utils/uuid'; +import { ResponseUtils } from 'src/utils/response'; interface BaseServiceOptions { prisma: PrismaServiceMySQL | PrismaServiceMongoDB; @@ -47,11 +48,7 @@ export abstract class BaseService { this.temporaryDatabaseService.create(this.className, key, data); this.cache.put(key, data); - return { - statusCode: HttpStatus.CREATED, - message: 'Created', - data, - }; + return ResponseUtils.createResponse(HttpStatus.CREATED, data); } async findOne(key: string) { @@ -67,11 +64,7 @@ export abstract class BaseService { if (data) { const mergedData = this.mergeWithUpdateCommand(data, key); this.cache.put(key, mergedData); - return { - statusCode: HttpStatus.OK, - message: 'Success', - data: mergedData, - }; + return ResponseUtils.createResponse(HttpStatus.OK, mergedData); } else { throw new HttpException('Not Found', HttpStatus.NOT_FOUND); } @@ -94,16 +87,9 @@ export abstract class BaseService { this.temporaryDatabaseService.update(this.className, key, updatedData); } this.cache.put(key, updatedData.value); - return { - statusCode: HttpStatus.OK, - message: 'Success', - data: updatedData.value, - }; + return ResponseUtils.createResponse(HttpStatus.OK, updatedData.value); } else { - return { - statusCode: HttpStatus.NOT_FOUND, - message: 'Not Found', - }; + return ResponseUtils.createResponse(HttpStatus.NOT_FOUND); } } @@ -132,10 +118,7 @@ export abstract class BaseService { value: key, }); } - return { - statusCode: HttpStatus.NO_CONTENT, - message: 'No Content', - }; + return ResponseUtils.createResponse(HttpStatus.NO_CONTENT); } async getDataFromCacheOrDB(key: string): Promise { diff --git a/nestjs-BE/server/src/invite-codes/invite-codes.service.ts b/nestjs-BE/server/src/invite-codes/invite-codes.service.ts index 5041e2bc..8c8f54e7 100644 --- a/nestjs-BE/server/src/invite-codes/invite-codes.service.ts +++ b/nestjs-BE/server/src/invite-codes/invite-codes.service.ts @@ -9,6 +9,7 @@ import { INVITE_CODE_LENGTH, } from 'src/config/magic-number'; import { SpacesService } from 'src/spaces/spaces.service'; +import { ResponseUtils } from 'src/utils/response'; export interface InviteCodeData extends CreateInviteCodeDto { uuid?: string; @@ -38,11 +39,11 @@ export class InviteCodesService extends BaseService { async createCode(createInviteCodeDto: CreateInviteCodeDto) { const { space_uuid: spaceUuid } = createInviteCodeDto; - const spaceResponse = await this.spacesService.findOne(spaceUuid); + await this.spacesService.findOne(spaceUuid); const inviteCodeData = await this.generateInviteCode(createInviteCodeDto); super.create(inviteCodeData); - this.cache.put(inviteCodeData.invite_code, spaceResponse); - return this.createResponse(inviteCodeData.invite_code); + const { invite_code } = inviteCodeData; + return ResponseUtils.createResponse(HttpStatus.CREATED, { invite_code }); } async findSpace(inviteCode: string) { @@ -111,12 +112,4 @@ export class InviteCodesService extends BaseService { return inviteCode; } - - private createResponse(inviteCode: string) { - return { - statusCode: HttpStatus.CREATED, - message: 'Created', - data: { invite_code: inviteCode }, - }; - } } diff --git a/nestjs-BE/server/src/profile-space/profile-space.service.ts b/nestjs-BE/server/src/profile-space/profile-space.service.ts index b8cb73cf..a451a220 100644 --- a/nestjs-BE/server/src/profile-space/profile-space.service.ts +++ b/nestjs-BE/server/src/profile-space/profile-space.service.ts @@ -13,6 +13,7 @@ import { ProfilesService } from 'src/profiles/profiles.service'; import { UpdateProfileDto } from 'src/profiles/dto/update-profile.dto'; import { UpdateSpaceDto } from 'src/spaces/dto/update-space.dto'; import LRUCache from 'src/utils/lru-cache'; +import { ResponseUtils } from 'src/utils/response'; interface UpdateProfileAndSpaceDto { profileData: UpdateProfileDto; @@ -147,11 +148,7 @@ export class ProfileSpaceService extends BaseService { profileUuid, ); this.userCache.put(userUuid, spaces); - return { - statusCode: HttpStatus.OK, - message: 'Success', - data: spaces, - }; + return ResponseUtils.createResponse(HttpStatus.OK, spaces); } async retrieveSpaceUsers(spaceUuid: string) { @@ -162,10 +159,6 @@ export class ProfileSpaceService extends BaseService { }), ); this.spaceCache.put(spaceUuid, usersData); - return { - statusCode: HttpStatus.OK, - message: 'Success', - data: usersData, - }; + return ResponseUtils.createResponse(HttpStatus.OK, usersData); } } diff --git a/nestjs-BE/server/src/temporary-database/temporary-database.service.ts b/nestjs-BE/server/src/temporary-database/temporary-database.service.ts index 0b1182bc..4330e949 100644 --- a/nestjs-BE/server/src/temporary-database/temporary-database.service.ts +++ b/nestjs-BE/server/src/temporary-database/temporary-database.service.ts @@ -20,7 +20,7 @@ type DeleteDataType = { value: string; }; -type InsertDataType = +export type InsertDataType = | TokenData | InviteCodeData | CreateProfileSpaceDto diff --git a/nestjs-BE/server/src/utils/response.ts b/nestjs-BE/server/src/utils/response.ts new file mode 100644 index 00000000..a3c01ef4 --- /dev/null +++ b/nestjs-BE/server/src/utils/response.ts @@ -0,0 +1,34 @@ +import { HttpStatus } from '@nestjs/common'; +import { InsertDataType } from 'src/temporary-database/temporary-database.service'; +type TokenDataType = { + access_token: string; + refresh_token?: string; +}; +type InviteDataType = { + invite_code: string; +}; + +type ExtendedDataType = + | InsertDataType + | TokenDataType + | InviteDataType + | InsertDataType[]; + +export class ResponseUtils { + private static messages = new Map([ + [HttpStatus.OK, 'Success'], + [HttpStatus.CREATED, 'Created'], + [HttpStatus.NOT_FOUND, 'Not Found'], + [HttpStatus.NO_CONTENT, 'No Content'], + ]); + + static createResponse(status: HttpStatus, data?: ExtendedDataType) { + const response: any = { + statusCode: status, + message: this.messages.get(status), + }; + if (data) response.data = data; + + return response; + } +} From 042a204e61b524a8efdbba454f457bba9f6e3a55 Mon Sep 17 00:00:00 2001 From: tnpfldyd Date: Mon, 11 Dec 2023 21:34:34 +0900 Subject: [PATCH 170/170] =?UTF-8?q?fix(#212):=20key=20=EC=9E=85=EB=A0=A5?= =?UTF-8?q?=EC=9D=B4=20=EC=95=88=EB=90=90=EC=9D=84=20=EB=95=8C=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nestjs-BE/server/src/base/base.service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/nestjs-BE/server/src/base/base.service.ts b/nestjs-BE/server/src/base/base.service.ts index 39980408..b0aa14fa 100644 --- a/nestjs-BE/server/src/base/base.service.ts +++ b/nestjs-BE/server/src/base/base.service.ts @@ -122,6 +122,7 @@ export abstract class BaseService { } async getDataFromCacheOrDB(key: string): Promise { + if (!key) throw new HttpException('Bad Request', HttpStatus.BAD_REQUEST); const cacheData = this.cache.get(key); if (cacheData) return cacheData; const temporaryDatabaseData = this.temporaryDatabaseService.get(