From 00f607831925696ea78aa8d63864a9129d38d45f Mon Sep 17 00:00:00 2001 From: minsuKang <90169703+minchodang@users.noreply.github.com> Date: Thu, 5 Dec 2024 11:14:35 +0900 Subject: [PATCH] =?UTF-8?q?Fix:=20gql=20=EC=85=8B=ED=8C=85=20=EB=B0=8F=20?= =?UTF-8?q?=EB=A7=88=EC=9D=B4=EA=B7=B8=EB=A0=88=EC=9D=B4=EC=85=98=20(#47)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix: gcl 셋팅 및 swagger 이중 참조 삭제 --- package.json | 6 +- pnpm-lock.yaml | 813 ++++++++++++++++-- src/app.module.ts | 19 +- src/core/errors/unauthorized-error.ts | 8 - src/main.ts | 47 +- src/modules/auth/auth.controller.ts | 185 +--- .../auth/dto/create-token-request.dto.ts | 13 +- .../auth/dto/create-token-response.dto.ts | 4 - .../dto/email-verification-request.dto.ts | 7 - .../dto/email-verification-response.dto.ts | 3 - .../auth/dto/refresh-token-request.dto.ts | 8 +- .../auth/dto/refresh-token-response.dto.ts | 4 - .../auth/dto/reset-password-request.dto.ts | 6 - .../auth/dto/social-login-request.dto.ts | 13 +- .../update-email-verification-request.dto.ts | 11 - src/modules/auth/error/create-token-error.ts | 13 - .../auth/error/email-verification-error.ts | 8 - src/modules/auth/error/refresh-token-error.ts | 11 - .../auth/error/reset-password-error.ts | 10 - .../error/update-email-verification-error.ts | 13 - .../test/dto/create-test-request.dto.ts | 19 - .../test/dto/create-test-response.dto.ts | 9 - src/modules/test/error/create-test-errror.ts | 39 +- src/modules/test/test.controller.ts | 19 - .../user/dto/create-user-info-request.dto.ts | 31 - .../user/dto/create-user-info-response.dto.ts | 29 - .../user/dto/get-user-info-response.dto.ts | 29 - .../user/dto/get-user-test-list-query.dto.ts | 24 - .../dto/get-user-test-list-response.dto.ts | 38 - .../user/dto/get-user-test-query.dto.ts | 5 - .../user/dto/get-user-test-response.dto.ts | 29 - .../user/dto/update-user-info-request.dto.ts | 23 +- .../user/dto/update-user-info-response.dto.ts | 22 - src/modules/user/entities/user.entity.ts | 7 +- .../user/error/create-user-info-error.ts | 22 +- src/modules/user/error/get-user-info-error.ts | 8 - src/modules/user/error/get-user-test-error.ts | 15 - .../user/error/get-user-test-list-error.ts | 24 +- src/modules/user/user.controller.ts | 223 +---- src/modules/user/user.module.ts | 4 +- src/modules/user/user.repository.ts | 39 +- src/modules/user/user.resolver.ts | 19 + src/modules/user/user.service.ts | 16 + src/schema.gql | 14 + 44 files changed, 942 insertions(+), 967 deletions(-) create mode 100644 src/modules/user/user.resolver.ts create mode 100644 src/schema.gql diff --git a/package.json b/package.json index 473e515..75a7252 100644 --- a/package.json +++ b/package.json @@ -28,22 +28,25 @@ "preinstall": "npx only-allow pnpm" }, "dependencies": { + "@apollo/server": "^4.11.2", "@aws-sdk/client-dynamodb": "^3.540.0", "@aws-sdk/client-ses": "^3.549.0", "@aws-sdk/lib-dynamodb": "^3.549.0", + "@nestjs/apollo": "^12.2.1", "@nestjs/common": "^10.0.0", "@nestjs/config": "^3.1.1", "@nestjs/core": "^10.0.0", + "@nestjs/graphql": "^12.2.1", "@nestjs/jwt": "^10.2.0", "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", - "@nestjs/swagger": "^7.3.0", "@supabase/supabase-js": "^2.45.3", "bcrypt": "^5.1.1", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "commander": "^12.1.0", "cookie-parser": "^1.4.6", + "graphql": "^16.9.0", "mysql2": "^3.9.1", "passport": "^0.7.0", "passport-google-oauth20": "^2.0.0", @@ -52,7 +55,6 @@ "pm2": "^5.3.1", "reflect-metadata": "^0.1.14", "rxjs": "^7.8.1", - "swagger-ui-express": "^5.0.0", "typeorm": "^0.3.20", "uuid": "^9.0.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d2422f0..3ac7a34 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@apollo/server': + specifier: ^4.11.2 + version: 4.11.2(graphql@16.9.0) '@aws-sdk/client-dynamodb': specifier: ^3.540.0 version: 3.540.0 @@ -17,6 +20,9 @@ importers: '@aws-sdk/lib-dynamodb': specifier: ^3.549.0 version: 3.549.0(@aws-sdk/client-dynamodb@3.540.0) + '@nestjs/apollo': + specifier: ^12.2.1 + version: 12.2.1(@apollo/server@4.11.2(graphql@16.9.0))(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/core@10.3.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/platform-express@10.3.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/graphql@12.2.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/core@10.3.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/platform-express@10.3.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(graphql@16.9.0)(reflect-metadata@0.1.14))(graphql@16.9.0) '@nestjs/common': specifier: ^10.0.0 version: 10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) @@ -26,6 +32,9 @@ importers: '@nestjs/core': specifier: ^10.0.0 version: 10.3.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/platform-express@10.3.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) + '@nestjs/graphql': + specifier: ^12.2.1 + version: 12.2.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/core@10.3.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/platform-express@10.3.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(graphql@16.9.0)(reflect-metadata@0.1.14) '@nestjs/jwt': specifier: ^10.2.0 version: 10.2.0(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1)) @@ -35,9 +44,6 @@ importers: '@nestjs/platform-express': specifier: ^10.0.0 version: 10.3.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/core@10.3.1) - '@nestjs/swagger': - specifier: ^7.3.0 - version: 7.3.0(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/core@10.3.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/platform-express@10.3.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14) '@supabase/supabase-js': specifier: ^2.45.3 version: 2.45.3 @@ -56,6 +62,9 @@ importers: cookie-parser: specifier: ^1.4.6 version: 1.4.6 + graphql: + specifier: ^16.9.0 + version: 16.9.0 mysql2: specifier: ^3.9.1 version: 3.9.1 @@ -80,9 +89,6 @@ importers: rxjs: specifier: ^7.8.1 version: 7.8.1 - swagger-ui-express: - specifier: ^5.0.0 - version: 5.0.0(express@4.18.2) typeorm: specifier: ^0.3.20 version: 0.3.20(mysql2@3.9.1)(ts-node@10.9.2(@types/node@20.11.16)(typescript@5.3.3)) @@ -213,6 +219,99 @@ packages: resolution: {integrity: sha512-I5wviiIqiFwar9Pdk30Lujk8FczEEc18i22A5c6Z9lbmhPQdTroDnEQdsfXjy404wPe8H62s0I15o4pmMGfTYQ==} engines: {node: ^18.13.0 || >=20.9.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + '@apollo/cache-control-types@1.0.3': + resolution: {integrity: sha512-F17/vCp7QVwom9eG7ToauIKdAxpSoadsJnqIfyryLFSkLSOEqu+eC5Z3N8OXcUVStuOMcNHlyraRsA6rRICu4g==} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/protobufjs@1.2.7': + resolution: {integrity: sha512-Lahx5zntHPZia35myYDBRuF58tlwPskwHc5CWBZC/4bMKB6siTBWwtMrkqXcsNwQiFSzSx5hKdRPUmemrEp3Gg==} + hasBin: true + + '@apollo/server-gateway-interface@1.1.1': + resolution: {integrity: sha512-pGwCl/po6+rxRmDMFgozKQo2pbsSwE91TpsDBAOgf74CRDPXHHtM88wbwjab0wMMZh95QfR45GGyDIdhY24bkQ==} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/server-plugin-landing-page-graphql-playground@4.0.0': + resolution: {integrity: sha512-PBDtKI/chJ+hHeoJUUH9Kuqu58txQl00vUGuxqiC9XcReulIg7RjsyD0G1u3drX4V709bxkL5S0nTeXfRHD0qA==} + engines: {node: '>=14.0'} + deprecated: The use of GraphQL Playground in Apollo Server was supported in previous versions, but this is no longer the case as of December 31, 2022. This package exists for v4 migration purposes only. We do not intend to resolve security issues or other bugs with this package if they arise, so please migrate away from this to [Apollo Server's default Explorer](https://www.apollographql.com/docs/apollo-server/api/plugin/landing-pages) as soon as possible. + peerDependencies: + '@apollo/server': ^4.0.0 + + '@apollo/server@4.11.2': + resolution: {integrity: sha512-WUTHY7DDek8xAMn4Woa9Bl8duQUDzRYQkosX/d1DtCsBWESZyApR7ndnI5d6+W4KSTtqBHhJFkusEI7CWuIJXg==} + engines: {node: '>=14.16.0'} + peerDependencies: + graphql: ^16.6.0 + + '@apollo/usage-reporting-protobuf@4.1.1': + resolution: {integrity: sha512-u40dIUePHaSKVshcedO7Wp+mPiZsaU6xjv9J+VyxpoU/zL6Jle+9zWeG98tr/+SZ0nZ4OXhrbb8SNr0rAPpIDA==} + + '@apollo/utils.createhash@2.0.1': + resolution: {integrity: sha512-fQO4/ZOP8LcXWvMNhKiee+2KuKyqIcfHrICA+M4lj/h/Lh1H10ICcUtk6N/chnEo5HXu0yejg64wshdaiFitJg==} + engines: {node: '>=14'} + + '@apollo/utils.dropunuseddefinitions@2.0.1': + resolution: {integrity: sha512-EsPIBqsSt2BwDsv8Wu76LK5R1KtsVkNoO4b0M5aK0hx+dGg9xJXuqlr7Fo34Dl+y83jmzn+UvEW+t1/GP2melA==} + engines: {node: '>=14'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.fetcher@2.0.1': + resolution: {integrity: sha512-jvvon885hEyWXd4H6zpWeN3tl88QcWnHp5gWF5OPF34uhvoR+DFqcNxs9vrRaBBSY3qda3Qe0bdud7tz2zGx1A==} + engines: {node: '>=14'} + + '@apollo/utils.isnodelike@2.0.1': + resolution: {integrity: sha512-w41XyepR+jBEuVpoRM715N2ZD0xMD413UiJx8w5xnAZD2ZkSJnMJBoIzauK83kJpSgNuR6ywbV29jG9NmxjK0Q==} + engines: {node: '>=14'} + + '@apollo/utils.keyvaluecache@2.1.1': + resolution: {integrity: sha512-qVo5PvUUMD8oB9oYvq4ViCjYAMWnZ5zZwEjNF37L2m1u528x5mueMlU+Cr1UinupCgdB78g+egA1G98rbJ03Vw==} + engines: {node: '>=14'} + + '@apollo/utils.logger@2.0.1': + resolution: {integrity: sha512-YuplwLHaHf1oviidB7MxnCXAdHp3IqYV8n0momZ3JfLniae92eYqMIx+j5qJFX6WKJPs6q7bczmV4lXIsTu5Pg==} + engines: {node: '>=14'} + + '@apollo/utils.printwithreducedwhitespace@2.0.1': + resolution: {integrity: sha512-9M4LUXV/fQBh8vZWlLvb/HyyhjJ77/I5ZKu+NBWV/BmYGyRmoEP9EVAy7LCVoY3t8BDcyCAGfxJaLFCSuQkPUg==} + engines: {node: '>=14'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.removealiases@2.0.1': + resolution: {integrity: sha512-0joRc2HBO4u594Op1nev+mUF6yRnxoUH64xw8x3bX7n8QBDYdeYgY4tF0vJReTy+zdn2xv6fMsquATSgC722FA==} + engines: {node: '>=14'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.sortast@2.0.1': + resolution: {integrity: sha512-eciIavsWpJ09za1pn37wpsCGrQNXUhM0TktnZmHwO+Zy9O4fu/WdB4+5BvVhFiZYOXvfjzJUcc+hsIV8RUOtMw==} + engines: {node: '>=14'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.stripsensitiveliterals@2.0.1': + resolution: {integrity: sha512-QJs7HtzXS/JIPMKWimFnUMK7VjkGQTzqD9bKD1h3iuPAqLsxd0mUNVbkYOPTsDhUKgcvUOfOqOJWYohAKMvcSA==} + engines: {node: '>=14'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.usagereporting@2.1.0': + resolution: {integrity: sha512-LPSlBrn+S17oBy5eWkrRSGb98sWmnEzo3DPTZgp8IQc8sJe0prDgDuppGq4NeQlpoqEHz0hQeYHAOA0Z3aQsxQ==} + engines: {node: '>=14'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.withrequired@2.0.1': + resolution: {integrity: sha512-YBDiuAX9i1lLc6GeTy1m7DGLFn/gMnvXqlalOIMjM7DeOgIacEjjfwPqb0M1CQ2v11HhR15d1NmxJoRCfrNqcA==} + engines: {node: '>=14'} + + '@apollographql/graphql-playground-html@1.6.29': + resolution: {integrity: sha512-xCcXpoz52rI4ksJSdOCxeOCn2DLocxwHf9dVT/Q90Pte1LX+LY+91SFtJF3KXVHH8kEin+g1KKCQPKBjZJfWNA==} + '@aws-crypto/crc32@3.0.0': resolution: {integrity: sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==} @@ -607,6 +706,44 @@ packages: resolution: {integrity: sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@graphql-tools/merge@8.4.2': + resolution: {integrity: sha512-XbrHAaj8yDuINph+sAfuq3QCZ/tKblrTLOpirK0+CAgNlZUCHs0Fa+xtMUURgwCVThLle1AF7svJCxFizygLsw==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-tools/merge@9.0.8': + resolution: {integrity: sha512-RG9NEp4fi0MoFi0te4ahqTMYuavQnXlpEZxxMomdCa6CI5tfekcVm/rsLF5Zt8O4HY+esDt9+4dCL+aOKvG79w==} + engines: {node: '>=16.0.0'} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-tools/schema@10.0.7': + resolution: {integrity: sha512-Cz1o+rf9cd3uMgG+zI9HlM5mPlnHQUlk/UQRZyUlPDfT+944taLaokjvj7AI6GcOFVf4f2D11XthQp+0GY31jQ==} + engines: {node: '>=16.0.0'} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-tools/schema@9.0.19': + resolution: {integrity: sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-tools/utils@10.5.5': + resolution: {integrity: sha512-LF/UDWmMT0mnobL2UZETwYghV7HYBzNaGj0SAkCYOMy/C3+6sQdbcTksnoFaKR9XIVD78jNXEGfivbB8Zd+cwA==} + engines: {node: '>=16.0.0'} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-tools/utils@9.2.1': + resolution: {integrity: sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-typed-document-node/core@3.2.0': + resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -759,8 +896,24 @@ packages: resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==} hasBin: true - '@microsoft/tsdoc@0.14.2': - resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==} + '@nestjs/apollo@12.2.1': + resolution: {integrity: sha512-Det66rvMZwXSxwSkMBdTd+jqVyQRDRT+GJh/CU25PR3bM4n7BpdBTzW0XR3Eoi5oyas1YB4cUxa7nR5Iy37lag==} + peerDependencies: + '@apollo/gateway': ^2.0.0 + '@apollo/server': ^4.3.2 + '@apollo/subgraph': ^2.0.0 + '@as-integrations/fastify': ^1.3.0 || ^2.0.0 + '@nestjs/common': ^9.3.8 || ^10.0.0 + '@nestjs/core': ^9.3.8 || ^10.0.0 + '@nestjs/graphql': ^12.0.0 + graphql: ^16.6.0 + peerDependenciesMeta: + '@apollo/gateway': + optional: true + '@apollo/subgraph': + optional: true + '@as-integrations/fastify': + optional: true '@nestjs/cli@10.4.8': resolution: {integrity: sha512-BQ/MIXcO2TjLVR9ZCN1MRQqijgCI7taueLdxowLS9UmAHbN7iZcQt307NTC6SFt8uVJg2CrLanD60M/Pr0ZMoQ==} @@ -811,6 +964,27 @@ packages: '@nestjs/websockets': optional: true + '@nestjs/graphql@12.2.1': + resolution: {integrity: sha512-eXbme7RcecXaz6pZOc3uR9gR7AEAS20BTkzToWab4ExdDJRLhd7ua4C/uNEPUK+82HbNfd3h3z4Mes29N2R+/w==} + peerDependencies: + '@apollo/subgraph': ^2.0.0 + '@nestjs/common': ^9.3.8 || ^10.0.0 + '@nestjs/core': ^9.3.8 || ^10.0.0 + class-transformer: '*' + class-validator: '*' + graphql: ^16.6.0 + reflect-metadata: ^0.1.13 || ^0.2.0 + ts-morph: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^24.0.0 + peerDependenciesMeta: + '@apollo/subgraph': + optional: true + class-transformer: + optional: true + class-validator: + optional: true + ts-morph: + optional: true + '@nestjs/jwt@10.2.0': resolution: {integrity: sha512-x8cG90SURkEiLOehNaN2aRlotxT0KZESUliOPKKnjWiyJOcWurkF3w345WOX0P4MgFzUjGoZ1Sy0aZnxeihT0g==} peerDependencies: @@ -846,23 +1020,6 @@ packages: peerDependencies: typescript: '>=4.8.2' - '@nestjs/swagger@7.3.0': - resolution: {integrity: sha512-zLkfKZ+ioYsIZ3dfv7Bj8YHnZMNAGWFUmx2ZDuLp/fBE4P8BSjB7hldzDueFXsmwaPL90v7lgyd82P+s7KME1Q==} - peerDependencies: - '@fastify/static': ^6.0.0 || ^7.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 || ^0.2.0 - peerDependenciesMeta: - '@fastify/static': - optional: true - class-transformer: - optional: true - class-validator: - optional: true - '@nestjs/testing@10.3.1': resolution: {integrity: sha512-74aSAugWT31jSPnStyRWDXgjHXWO3GYaUfAZ2T7Dml88UGkGy95iwaWgYy7aYM8/xVFKcDYkfL5FAYqZYce/yg==} peerDependencies: @@ -927,6 +1084,36 @@ packages: '@pm2/pm2-version-check@1.0.4': resolution: {integrity: sha512-SXsM27SGH3yTWKc2fKR4SYNxsmnvuBQ9dd6QHtEWmiZ/VqaOYPAIlS8+vMcn27YLtAEBGvNRSh3TPNvtjZgfqA==} + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.0': + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.0': + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -1201,12 +1388,18 @@ packages: '@types/jsonwebtoken@9.0.5': resolution: {integrity: sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==} + '@types/long@4.0.2': + resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} + '@types/methods@1.1.4': resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==} '@types/mime@1.3.5': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + '@types/node-fetch@2.6.12': + resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==} + '@types/node@20.11.16': resolution: {integrity: sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==} @@ -1516,6 +1709,9 @@ packages: resolution: {integrity: sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==} engines: {node: <=0.11.8 || >0.11.10} + async-retry@1.3.3: + resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} + async@2.6.4: resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==} @@ -1550,6 +1746,9 @@ packages: peerDependencies: '@babel/core': ^7.0.0 + backo2@1.0.2: + resolution: {integrity: sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -1587,6 +1786,10 @@ packages: resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + body-parser@1.20.3: + resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + bowser@2.11.0: resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} @@ -1689,6 +1892,10 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + chokidar@4.0.1: + resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} + engines: {node: '>= 14.16.0'} + chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} @@ -1841,6 +2048,10 @@ packages: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} + cookie@0.7.1: + resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} + engines: {node: '>= 0.6'} + cookiejar@2.1.4: resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} @@ -1875,10 +2086,17 @@ packages: croner@4.1.97: resolution: {integrity: sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ==} + cross-inspect@1.0.1: + resolution: {integrity: sha512-Pcw1JTvZLSJH83iiGWt6fRcT+BjZlCDRVwYLbUcHzv/CRpB7r0MlSrGbIyQvVSNyGnbt7G4AXuyCiDR3POvZ1A==} + engines: {node: '>=16.0.0'} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + cssfilter@0.0.10: + resolution: {integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==} + culvert@0.1.2: resolution: {integrity: sha512-yi1x3EAWKjQTreYWeSd98431AV+IEE0qoDyOoaHJ7KJ21gv6HtBXHVLX74opVSGqcR8/AbjJBHAHpcOy2bj5Gg==} @@ -2002,6 +2220,10 @@ packages: resolution: {integrity: sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==} engines: {node: '>=12'} + dset@3.1.4: + resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} + engines: {node: '>=4'} + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -2031,6 +2253,10 @@ packages: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + enhanced-resolve@5.15.0: resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==} engines: {node: '>=10.13.0'} @@ -2173,6 +2399,9 @@ packages: eventemitter2@6.4.9: resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==} + eventemitter3@3.1.2: + resolution: {integrity: sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==} + events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} @@ -2193,6 +2422,10 @@ packages: resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==} engines: {node: '>= 0.10.0'} + express@4.21.1: + resolution: {integrity: sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==} + engines: {node: '>= 0.10.0'} + external-editor@3.1.0: resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} engines: {node: '>=4'} @@ -2255,6 +2488,10 @@ packages: resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} engines: {node: '>= 0.8'} + finalhandler@1.3.1: + resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} + engines: {node: '>= 0.8'} + find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -2419,6 +2656,22 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + graphql-tag@2.12.6: + resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==} + engines: {node: '>=10'} + peerDependencies: + graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + + graphql-ws@5.16.0: + resolution: {integrity: sha512-Ju2RCU2dQMgSKtArPbEtsK5gNLnsQyTNIo/T7cZNp96niC1x0KdJNZV0TIoilceBPQwfb5itrGl8pkFeOUMl4A==} + engines: {node: '>=10'} + peerDependencies: + graphql: '>=0.11 <=16' + + graphql@16.9.0: + resolution: {integrity: sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} @@ -2611,6 +2864,9 @@ packages: resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} engines: {node: '>=8'} + iterall@1.3.0: + resolution: {integrity: sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==} + iterare@1.2.1: resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} engines: {node: '>=6'} @@ -2880,9 +3136,15 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.omit@4.5.0: + resolution: {integrity: sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==} + lodash.once@4.1.1: resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + lodash.sortby@4.7.0: + resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -2894,6 +3156,13 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} + loglevel@1.9.2: + resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} + engines: {node: '>= 0.6.0'} + + long@4.0.0: + resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} + long@5.2.3: resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} @@ -2952,6 +3221,9 @@ packages: merge-descriptors@1.0.1: resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -3273,6 +3545,9 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + path-to-regexp@0.1.10: + resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} + path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} @@ -3397,6 +3672,10 @@ packages: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} engines: {node: '>=0.6'} + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + engines: {node: '>=0.6'} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -3436,6 +3715,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + readdirp@4.0.2: + resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} + engines: {node: '>= 14.16.0'} + reflect-metadata@0.1.14: resolution: {integrity: sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==} @@ -3483,6 +3766,10 @@ packages: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} + retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -3547,6 +3834,10 @@ packages: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} + send@0.19.0: + resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} + engines: {node: '>= 0.8.0'} + seq-queue@0.0.5: resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} @@ -3557,6 +3848,10 @@ packages: resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} engines: {node: '>= 0.8.0'} + serve-static@1.16.2: + resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} + engines: {node: '>= 0.8.0'} + set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} @@ -3696,6 +3991,12 @@ packages: strnum@1.0.5: resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + subscriptions-transport-ws@0.11.0: + resolution: {integrity: sha512-8D4C6DIH5tGiAIpp5I0wD/xRlNiZAPGHygzCe7VzyzUoxHtawzjNAY9SUTXU05/EY2NMY9/9GF0ycizkXr1CWQ==} + deprecated: The `subscriptions-transport-ws` package is no longer maintained. We recommend you use `graphql-ws` instead. For help migrating Apollo software to `graphql-ws`, see https://www.apollographql.com/docs/apollo-server/data/subscriptions/#switching-from-subscriptions-transport-ws For general help using `graphql-ws`, see https://github.com/enisdenjo/graphql-ws/blob/master/README.md + peerDependencies: + graphql: ^15.7.2 || ^16.0.0 + superagent@8.1.2: resolution: {integrity: sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==} engines: {node: '>=6.4.0 <13 || >=14'} @@ -3721,14 +4022,9 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - swagger-ui-dist@5.11.2: - resolution: {integrity: sha512-jQG0cRgJNMZ7aCoiFofnoojeSaa/+KgWaDlfgs8QN+BXoGMpxeMVY5OEnjq4OlNvF3yjftO8c9GRAgcHlO+u7A==} - - swagger-ui-express@5.0.0: - resolution: {integrity: sha512-tsU9tODVvhyfkNSvf03E6FAk+z+5cU3lXAzMy6Pv4av2Gt2xA0++fogwC4qo19XuFf6hdxevPuVCSKFuMHJhFA==} - engines: {node: '>= v0.10.32'} - peerDependencies: - express: '>=4.0.0 || >=5.0.0-beta' + symbol-observable@1.2.0: + resolution: {integrity: sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==} + engines: {node: '>=0.10.0'} symbol-observable@4.0.0: resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} @@ -3881,6 +4177,9 @@ packages: tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + tslib@2.8.0: + resolution: {integrity: sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==} + tv4@1.3.0: resolution: {integrity: sha512-afizzfpJgvPr+eDkREK4MxJ/+r8nEEHcmitwgnPUqpaP+FpwQyadnxNoSACbgc/b1LsZYtODGoPiFxQrgJgjvw==} engines: {node: '>= 0.8.0'} @@ -4013,6 +4312,10 @@ packages: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} + uuid@10.0.0: + resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + hasBin: true + uuid@3.4.0: resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. @@ -4037,6 +4340,10 @@ packages: resolution: {integrity: sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==} engines: {node: '>= 0.10'} + value-or-promise@1.0.12: + resolution: {integrity: sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q==} + engines: {node: '>=12'} + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -4076,6 +4383,10 @@ packages: webpack-cli: optional: true + whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -4130,6 +4441,11 @@ packages: utf-8-validate: optional: true + xss@1.0.15: + resolution: {integrity: sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==} + engines: {node: '>= 0.10.0'} + hasBin: true + xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} @@ -4234,6 +4550,126 @@ snapshots: transitivePeerDependencies: - chokidar + '@apollo/cache-control-types@1.0.3(graphql@16.9.0)': + dependencies: + graphql: 16.9.0 + + '@apollo/protobufjs@1.2.7': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/long': 4.0.2 + long: 4.0.0 + + '@apollo/server-gateway-interface@1.1.1(graphql@16.9.0)': + dependencies: + '@apollo/usage-reporting-protobuf': 4.1.1 + '@apollo/utils.fetcher': 2.0.1 + '@apollo/utils.keyvaluecache': 2.1.1 + '@apollo/utils.logger': 2.0.1 + graphql: 16.9.0 + + '@apollo/server-plugin-landing-page-graphql-playground@4.0.0(@apollo/server@4.11.2(graphql@16.9.0))': + dependencies: + '@apollo/server': 4.11.2(graphql@16.9.0) + '@apollographql/graphql-playground-html': 1.6.29 + + '@apollo/server@4.11.2(graphql@16.9.0)': + dependencies: + '@apollo/cache-control-types': 1.0.3(graphql@16.9.0) + '@apollo/server-gateway-interface': 1.1.1(graphql@16.9.0) + '@apollo/usage-reporting-protobuf': 4.1.1 + '@apollo/utils.createhash': 2.0.1 + '@apollo/utils.fetcher': 2.0.1 + '@apollo/utils.isnodelike': 2.0.1 + '@apollo/utils.keyvaluecache': 2.1.1 + '@apollo/utils.logger': 2.0.1 + '@apollo/utils.usagereporting': 2.1.0(graphql@16.9.0) + '@apollo/utils.withrequired': 2.0.1 + '@graphql-tools/schema': 9.0.19(graphql@16.9.0) + '@types/express': 4.17.21 + '@types/express-serve-static-core': 4.17.42 + '@types/node-fetch': 2.6.12 + async-retry: 1.3.3 + cors: 2.8.5 + express: 4.21.1 + graphql: 16.9.0 + loglevel: 1.9.2 + lru-cache: 7.18.3 + negotiator: 0.6.3 + node-abort-controller: 3.1.1 + node-fetch: 2.7.0 + uuid: 9.0.1 + whatwg-mimetype: 3.0.0 + transitivePeerDependencies: + - encoding + - supports-color + + '@apollo/usage-reporting-protobuf@4.1.1': + dependencies: + '@apollo/protobufjs': 1.2.7 + + '@apollo/utils.createhash@2.0.1': + dependencies: + '@apollo/utils.isnodelike': 2.0.1 + sha.js: 2.4.11 + + '@apollo/utils.dropunuseddefinitions@2.0.1(graphql@16.9.0)': + dependencies: + graphql: 16.9.0 + + '@apollo/utils.fetcher@2.0.1': {} + + '@apollo/utils.isnodelike@2.0.1': {} + + '@apollo/utils.keyvaluecache@2.1.1': + dependencies: + '@apollo/utils.logger': 2.0.1 + lru-cache: 7.18.3 + + '@apollo/utils.logger@2.0.1': {} + + '@apollo/utils.printwithreducedwhitespace@2.0.1(graphql@16.9.0)': + dependencies: + graphql: 16.9.0 + + '@apollo/utils.removealiases@2.0.1(graphql@16.9.0)': + dependencies: + graphql: 16.9.0 + + '@apollo/utils.sortast@2.0.1(graphql@16.9.0)': + dependencies: + graphql: 16.9.0 + lodash.sortby: 4.7.0 + + '@apollo/utils.stripsensitiveliterals@2.0.1(graphql@16.9.0)': + dependencies: + graphql: 16.9.0 + + '@apollo/utils.usagereporting@2.1.0(graphql@16.9.0)': + dependencies: + '@apollo/usage-reporting-protobuf': 4.1.1 + '@apollo/utils.dropunuseddefinitions': 2.0.1(graphql@16.9.0) + '@apollo/utils.printwithreducedwhitespace': 2.0.1(graphql@16.9.0) + '@apollo/utils.removealiases': 2.0.1(graphql@16.9.0) + '@apollo/utils.sortast': 2.0.1(graphql@16.9.0) + '@apollo/utils.stripsensitiveliterals': 2.0.1(graphql@16.9.0) + graphql: 16.9.0 + + '@apollo/utils.withrequired@2.0.1': {} + + '@apollographql/graphql-playground-html@1.6.29': + dependencies: + xss: 1.0.15 + '@aws-crypto/crc32@3.0.0': dependencies: '@aws-crypto/util': 3.0.0 @@ -5159,6 +5595,52 @@ snapshots: dependencies: levn: 0.4.1 + '@graphql-tools/merge@8.4.2(graphql@16.9.0)': + dependencies: + '@graphql-tools/utils': 9.2.1(graphql@16.9.0) + graphql: 16.9.0 + tslib: 2.6.2 + + '@graphql-tools/merge@9.0.8(graphql@16.9.0)': + dependencies: + '@graphql-tools/utils': 10.5.5(graphql@16.9.0) + graphql: 16.9.0 + tslib: 2.8.0 + + '@graphql-tools/schema@10.0.7(graphql@16.9.0)': + dependencies: + '@graphql-tools/merge': 9.0.8(graphql@16.9.0) + '@graphql-tools/utils': 10.5.5(graphql@16.9.0) + graphql: 16.9.0 + tslib: 2.8.0 + value-or-promise: 1.0.12 + + '@graphql-tools/schema@9.0.19(graphql@16.9.0)': + dependencies: + '@graphql-tools/merge': 8.4.2(graphql@16.9.0) + '@graphql-tools/utils': 9.2.1(graphql@16.9.0) + graphql: 16.9.0 + tslib: 2.6.2 + value-or-promise: 1.0.12 + + '@graphql-tools/utils@10.5.5(graphql@16.9.0)': + dependencies: + '@graphql-typed-document-node/core': 3.2.0(graphql@16.9.0) + cross-inspect: 1.0.1 + dset: 3.1.4 + graphql: 16.9.0 + tslib: 2.8.0 + + '@graphql-tools/utils@9.2.1(graphql@16.9.0)': + dependencies: + '@graphql-typed-document-node/core': 3.2.0(graphql@16.9.0) + graphql: 16.9.0 + tslib: 2.6.2 + + '@graphql-typed-document-node/core@3.2.0(graphql@16.9.0)': + dependencies: + graphql: 16.9.0 + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.6': @@ -5418,7 +5900,17 @@ snapshots: - encoding - supports-color - '@microsoft/tsdoc@0.14.2': {} + '@nestjs/apollo@12.2.1(@apollo/server@4.11.2(graphql@16.9.0))(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/core@10.3.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/platform-express@10.3.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/graphql@12.2.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/core@10.3.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/platform-express@10.3.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(graphql@16.9.0)(reflect-metadata@0.1.14))(graphql@16.9.0)': + dependencies: + '@apollo/server': 4.11.2(graphql@16.9.0) + '@apollo/server-plugin-landing-page-graphql-playground': 4.0.0(@apollo/server@4.11.2(graphql@16.9.0)) + '@nestjs/common': 10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) + '@nestjs/core': 10.3.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/platform-express@10.3.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) + '@nestjs/graphql': 12.2.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/core@10.3.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/platform-express@10.3.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(graphql@16.9.0)(reflect-metadata@0.1.14) + graphql: 16.9.0 + iterall: 1.3.0 + lodash.omit: 4.5.0 + tslib: 2.8.0 '@nestjs/cli@10.4.8': dependencies: @@ -5482,6 +5974,33 @@ snapshots: transitivePeerDependencies: - encoding + '@nestjs/graphql@12.2.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/core@10.3.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/platform-express@10.3.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(graphql@16.9.0)(reflect-metadata@0.1.14)': + dependencies: + '@graphql-tools/merge': 9.0.8(graphql@16.9.0) + '@graphql-tools/schema': 10.0.7(graphql@16.9.0) + '@graphql-tools/utils': 10.5.5(graphql@16.9.0) + '@nestjs/common': 10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) + '@nestjs/core': 10.3.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/platform-express@10.3.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) + '@nestjs/mapped-types': 2.0.5(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14) + chokidar: 4.0.1 + fast-glob: 3.3.2 + graphql: 16.9.0 + graphql-tag: 2.12.6(graphql@16.9.0) + graphql-ws: 5.16.0(graphql@16.9.0) + lodash: 4.17.21 + normalize-path: 3.0.0 + reflect-metadata: 0.1.14 + subscriptions-transport-ws: 0.11.0(graphql@16.9.0) + tslib: 2.8.0 + uuid: 10.0.0 + ws: 8.18.0 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.1 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@nestjs/jwt@10.2.0(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))': dependencies: '@nestjs/common': 10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) @@ -5535,21 +6054,6 @@ snapshots: transitivePeerDependencies: - chokidar - '@nestjs/swagger@7.3.0(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/core@10.3.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/platform-express@10.3.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)': - dependencies: - '@microsoft/tsdoc': 0.14.2 - '@nestjs/common': 10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) - '@nestjs/core': 10.3.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/platform-express@10.3.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) - '@nestjs/mapped-types': 2.0.5(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14) - js-yaml: 4.1.0 - lodash: 4.17.21 - path-to-regexp: 3.2.0 - reflect-metadata: 0.1.14 - swagger-ui-dist: 5.11.2 - optionalDependencies: - class-transformer: 0.5.1 - class-validator: 0.14.1 - '@nestjs/testing@10.3.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/core@10.3.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/platform-express@10.3.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/platform-express@10.3.1(@nestjs/common@10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1))(@nestjs/core@10.3.1))': dependencies: '@nestjs/common': 10.3.1(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) @@ -5657,6 +6161,29 @@ snapshots: transitivePeerDependencies: - supports-color + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.4': {} + + '@protobufjs/eventemitter@1.1.0': {} + + '@protobufjs/fetch@1.1.0': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.0': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.0': {} + '@sinclair/typebox@0.27.8': {} '@sinonjs/commons@3.0.1': @@ -6078,10 +6605,17 @@ snapshots: dependencies: '@types/node': 20.11.16 + '@types/long@4.0.2': {} + '@types/methods@1.1.4': {} '@types/mime@1.3.5': {} + '@types/node-fetch@2.6.12': + dependencies: + '@types/node': 20.11.16 + form-data: 4.0.0 + '@types/node@20.11.16': dependencies: undici-types: 5.26.5 @@ -6437,6 +6971,10 @@ snapshots: semver: 5.7.2 shimmer: 1.2.1 + async-retry@1.3.3: + dependencies: + retry: 0.13.1 + async@2.6.4: dependencies: lodash: 4.17.21 @@ -6497,6 +7035,8 @@ snapshots: babel-plugin-jest-hoist: 29.6.3 babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.9) + backo2@1.0.2: {} + balanced-match@1.0.2: {} base64-js@1.5.1: {} @@ -6557,6 +7097,23 @@ snapshots: transitivePeerDependencies: - supports-color + body-parser@1.20.3: + 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.13.0 + raw-body: 2.5.2 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + bowser@2.11.0: {} brace-expansion@1.1.11: @@ -6675,6 +7232,10 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + chokidar@4.0.1: + dependencies: + readdirp: 4.0.2 + chownr@2.0.0: {} chrome-trace-event@1.0.4: {} @@ -6811,6 +7372,8 @@ snapshots: cookie@0.5.0: {} + cookie@0.7.1: {} + cookiejar@2.1.4: {} copyfiles@2.4.1: @@ -6858,12 +7421,18 @@ snapshots: croner@4.1.97: {} + cross-inspect@1.0.1: + dependencies: + tslib: 2.8.0 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 + cssfilter@0.0.10: {} + culvert@0.1.2: {} data-uri-to-buffer@6.0.2: {} @@ -6939,6 +7508,8 @@ snapshots: dotenv@16.4.1: {} + dset@3.1.4: {} + eastasianwidth@0.2.0: {} ecdsa-sig-formatter@1.0.11: @@ -6961,6 +7532,8 @@ snapshots: encodeurl@1.0.2: {} + encodeurl@2.0.0: {} + enhanced-resolve@5.15.0: dependencies: graceful-fs: 4.2.11 @@ -7104,6 +7677,8 @@ snapshots: eventemitter2@6.4.9: {} + eventemitter3@3.1.2: {} + events@3.3.0: {} execa@5.1.1: @@ -7164,6 +7739,42 @@ snapshots: transitivePeerDependencies: - supports-color + express@4.21.1: + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.3 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.7.1 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.3.1 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.10 + proxy-addr: 2.0.7 + qs: 6.13.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.0 + serve-static: 1.16.2 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + external-editor@3.1.0: dependencies: chardet: 0.7.0 @@ -7238,6 +7849,18 @@ snapshots: transitivePeerDependencies: - supports-color + finalhandler@1.3.1: + dependencies: + debug: 2.6.9 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -7423,6 +8046,17 @@ snapshots: graphemer@1.4.0: {} + graphql-tag@2.12.6(graphql@16.9.0): + dependencies: + graphql: 16.9.0 + tslib: 2.8.0 + + graphql-ws@5.16.0(graphql@16.9.0): + dependencies: + graphql: 16.9.0 + + graphql@16.9.0: {} + has-flag@3.0.0: {} has-flag@4.0.0: {} @@ -7633,6 +8267,8 @@ snapshots: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 + iterall@1.3.0: {} + iterare@1.2.1: {} jackspeak@2.3.6: @@ -8078,8 +8714,12 @@ snapshots: lodash.merge@4.6.2: {} + lodash.omit@4.5.0: {} + lodash.once@4.1.1: {} + lodash.sortby@4.7.0: {} + lodash@4.17.21: {} log-driver@1.2.7: {} @@ -8089,6 +8729,10 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 + loglevel@1.9.2: {} + + long@4.0.0: {} + long@5.2.3: {} lru-cache@10.2.0: {} @@ -8137,6 +8781,8 @@ snapshots: merge-descriptors@1.0.1: {} + merge-descriptors@1.0.3: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -8449,6 +9095,8 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 + path-to-regexp@0.1.10: {} + path-to-regexp@0.1.7: {} path-to-regexp@3.2.0: {} @@ -8610,6 +9258,10 @@ snapshots: dependencies: side-channel: 1.0.6 + qs@6.13.0: + dependencies: + side-channel: 1.0.6 + queue-microtask@1.2.3: {} randombytes@2.1.0: @@ -8665,6 +9317,8 @@ snapshots: dependencies: picomatch: 2.3.1 + readdirp@4.0.2: {} + reflect-metadata@0.1.14: {} reflect-metadata@0.2.1: {} @@ -8704,6 +9358,8 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 + retry@0.13.1: {} + reusify@1.0.4: {} rimraf@3.0.2: @@ -8766,6 +9422,24 @@ snapshots: transitivePeerDependencies: - supports-color + send@0.19.0: + 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 + transitivePeerDependencies: + - supports-color + seq-queue@0.0.5: {} serialize-javascript@6.0.2: @@ -8781,6 +9455,15 @@ snapshots: transitivePeerDependencies: - supports-color + serve-static@1.16.2: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.0 + transitivePeerDependencies: + - supports-color + set-blocking@2.0.0: {} set-function-length@1.2.2: @@ -8908,6 +9591,18 @@ snapshots: strnum@1.0.5: {} + subscriptions-transport-ws@0.11.0(graphql@16.9.0): + dependencies: + backo2: 1.0.2 + eventemitter3: 3.1.2 + graphql: 16.9.0 + iterall: 1.3.0 + symbol-observable: 1.2.0 + ws: 7.4.6 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + superagent@8.1.2: dependencies: component-emitter: 1.3.1 @@ -8944,12 +9639,7 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - swagger-ui-dist@5.11.2: {} - - swagger-ui-express@5.0.0(express@4.18.2): - dependencies: - express: 4.18.2 - swagger-ui-dist: 5.11.2 + symbol-observable@1.2.0: {} symbol-observable@4.0.0: {} @@ -9095,6 +9785,8 @@ snapshots: tslib@2.6.2: {} + tslib@2.8.0: {} + tv4@1.3.0: {} tx2@1.0.5: @@ -9172,6 +9864,8 @@ snapshots: utils-merge@1.0.1: {} + uuid@10.0.0: {} + uuid@3.4.0: {} uuid@9.0.0: {} @@ -9188,6 +9882,8 @@ snapshots: validator@13.11.0: {} + value-or-promise@1.0.12: {} + vary@1.1.2: {} vizion@2.2.1: @@ -9246,6 +9942,8 @@ snapshots: - esbuild - uglify-js + whatwg-mimetype@3.0.0: {} + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -9288,6 +9986,11 @@ snapshots: ws@8.18.0: {} + xss@1.0.15: + dependencies: + commander: 2.20.3 + cssfilter: 0.0.10 + xtend@4.0.2: {} y18n@5.0.8: {} diff --git a/src/app.module.ts b/src/app.module.ts index 840e9d4..6da0c91 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,12 +1,29 @@ import { Module } from '@nestjs/common'; +import { GraphQLModule } from '@nestjs/graphql'; +import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo'; +import { ConfigModule } from '@nestjs/config'; import { HealthCheckController } from './modules/health-check/health-check.controller'; import { DynamoDBModule } from './database/dynamodb/dynamodb.module'; import { UserModule } from './modules/user/user.module'; import { AuthModule } from './modules/auth/auth.module'; import { TestModule } from './modules/test/test.module'; +import { join } from 'path'; @Module({ - imports: [DynamoDBModule, UserModule, AuthModule, TestModule], + imports: [ + ConfigModule.forRoot({ + isGlobal: true, + }), + GraphQLModule.forRoot({ + driver: ApolloDriver, + autoSchemaFile: join(process.cwd(), 'src/schema.gql'), + sortSchema: true, + }), + DynamoDBModule, + UserModule, + AuthModule, + TestModule + ], controllers: [HealthCheckController], providers: [], }) diff --git a/src/core/errors/unauthorized-error.ts b/src/core/errors/unauthorized-error.ts index 854b44e..05515aa 100644 --- a/src/core/errors/unauthorized-error.ts +++ b/src/core/errors/unauthorized-error.ts @@ -1,13 +1,5 @@ -import { ApiProperty } from '@nestjs/swagger'; - export class UnauthorizedError { - @ApiProperty({ - example: ['No token', 'Invalid token', 'Token expired'], - }) message: string[]; - @ApiProperty({ - example: 'Unauthorized', - }) error: 'Unauthorized'; } diff --git a/src/main.ts b/src/main.ts index a2c263b..0febfd7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,53 +1,16 @@ -import 'dotenv/config'; -import { NestFactory, Reflector } from '@nestjs/core'; +import { ValidationPipe } from '@nestjs/common'; +import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; -import { ClassSerializerInterceptor, ValidationPipe } from '@nestjs/common'; -import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; -import * as cookieParser from 'cookie-parser'; -import { BaseExceptionFilter } from 'src/core/filters/base-exception-filter'; -import { writeFileSync } from 'fs'; -import { join } from 'path'; async function bootstrap() { const app = await NestFactory.create(AppModule); - // set CORS + app.useGlobalPipes(new ValidationPipe()); app.enableCors({ - origin: true, + origin: process.env.CORS_ORIGIN, credentials: true, - exposedHeaders: ['Authorization'], }); - // set swagger module - const config = new DocumentBuilder() - .setTitle('Meta Test API') - .setDescription('The Meta Test API') - .setVersion('1.0.0') - .addBearerAuth() - .build(); - const document = SwaggerModule.createDocument(app, config); - const swaggerJson = JSON.stringify(document, null, 2); - writeFileSync(join(process.cwd(), 'swagger-spec.json'), swaggerJson); - SwaggerModule.setup('api', app, document); - - app.useGlobalPipes( - new ValidationPipe({ - transform: true, - }), - ); - - app.useGlobalFilters(new BaseExceptionFilter()); - - app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector))); - app.use(cookieParser()); - // set port - const port = - process.env.NODE_ENV === 'dev' - ? 8000 - : process.env.NODE_ENV === 'production' - ? 8080 - : 3000; - - console.log('server start at', port); + const port = process.env.PORT || 3000; await app.listen(port); } bootstrap(); diff --git a/src/modules/auth/auth.controller.ts b/src/modules/auth/auth.controller.ts index 9772a00..330aea9 100644 --- a/src/modules/auth/auth.controller.ts +++ b/src/modules/auth/auth.controller.ts @@ -11,66 +11,28 @@ import { Res, UseGuards, } from '@nestjs/common'; -import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; import { Response } from 'express'; import { KakaoAuthGuard } from 'src/auth/guard/kakao.auth.guard'; import { AuthService } from './auth.service'; import { CreateTokenRequestDto } from './dto/create-token-request.dto'; -import { CreateTokenResponseDto } from './dto/create-token-response.dto'; import { RefreshTokenRequestDto } from './dto/refresh-token-request.dto'; -import { RefreshTokenResponseDto } from './dto/refresh-token-response.dto'; import { SocialLoginRequestDto } from './dto/social-login-request.dto'; import { GoogleAuthGuard } from 'src/auth/guard/google.auth.guard'; import { ResetPasswordRequestDto } from './dto/reset-password-request.dto'; import { EmailVerificationRequestDto } from './dto/email-verification-request.dto'; import { UpdateEmailVerificationRequestDto } from './dto/update-email-verification-request.dto'; import { UserType } from 'src/types/userType'; -import { CreateTokenRequestBodyError } from './error/create-token-error'; -import { RefreshTokenRequestBodyError } from './error/refresh-token-error'; -import { ResetPasswordRequestBodyError } from './error/reset-password-error'; -import { EmailVerificationRequestBodyError } from './error/email-verification-error'; -import { UpdateEmailVerificationRequestBodyError } from './error/update-email-verification-error'; -import { EmailVerificationResponseDto } from './dto/email-verification-response.dto'; -@ApiTags('auth') @Controller({ path: 'auth' }) export class AuthController { constructor(private readonly authService: AuthService) {} @Post('token') - @ApiOperation({ summary: '로그인', description: '토큰 발급' }) - @ApiResponse({ - status: 201, - description: 'Created', - type: CreateTokenResponseDto, - }) - @ApiResponse({ - status: 400, - description: 'Bad request', - type: CreateTokenRequestBodyError, - }) - @ApiResponse({ - status: 401, - description: 'Unauthorized', - content: { - 'application/json': { - example: { - message: 'User not found or password does not match', - error: 'Unauthorized', - }, - }, - }, - }) - @ApiResponse({ - status: 500, - description: 'Internal Server Error', - }) @HttpCode(HttpStatus.CREATED) async createToken( @Body() createTokenInfoDto: CreateTokenRequestDto, @Res() res: Response, ) { - //NOTE: 이 API가 호출되는 유저는 일반 유저이므로 userType = NORMAL const tokens = await this.authService.create( createTokenInfoDto, UserType.NORMAL, @@ -86,36 +48,6 @@ export class AuthController { } @Post('token/refresh') - @ApiOperation({ - summary: '토큰 재발급', - description: '토큰 재발급', - }) - @ApiResponse({ - status: 201, - description: 'Created', - type: RefreshTokenResponseDto, - }) - @ApiResponse({ - status: 400, - description: 'Bad request', - type: RefreshTokenRequestBodyError, - }) - @ApiResponse({ - status: 401, - description: 'Unauthorized', - content: { - 'application/json': { - example: { - message: 'Invalid token', - error: 'Unauthorized', - }, - }, - }, - }) - @ApiResponse({ - status: 500, - description: 'Internal Server Error', - }) @HttpCode(HttpStatus.CREATED) async refreshToken( @Body() refreshTokenInfoDto: RefreshTokenRequestDto, @@ -132,14 +64,6 @@ export class AuthController { res.status(HttpStatus.CREATED).send(); } - @ApiOperation({ - summary: '카카오 소셜로그인', - description: '기가입 유저는 로그인, 신규 유저는 회원가입 진행', - }) - @ApiResponse({ - status: 201, - description: 'Created', - }) @UseGuards(KakaoAuthGuard) @Get('login/kakao') async loginWithKakao( @@ -158,14 +82,6 @@ export class AuthController { res.status(HttpStatus.CREATED).send(); } - @ApiOperation({ - summary: '구글 소셜로그인', - description: '기가입 유저는 로그인, 신규 유저는 회원가입 진행', - }) - @ApiResponse({ - status: 201, - description: 'Created', - }) @UseGuards(GoogleAuthGuard) @Get('login/google') async loginWithGoogle( @@ -185,61 +101,13 @@ export class AuthController { } @Patch('password') - @ApiOperation({ - summary: '비밀번호 초기화', - description: '비밀번호 변경하고 이메일로 전송합니다.', - }) - @ApiResponse({ - status: 200, - description: 'OK', - }) - @ApiResponse({ - status: 400, - description: 'Bad request', - type: ResetPasswordRequestBodyError, - }) - @ApiResponse({ - status: 404, - description: 'Not Found', - content: { - 'application/json': { - example: { - message: 'User does not exist', - error: 'Not Found', - }, - }, - }, - }) - @ApiResponse({ - status: 500, - description: 'Internal Server Error', - }) @HttpCode(HttpStatus.OK) async updateUserPassword(@Body() body: ResetPasswordRequestDto) { const email = body.email; - //NOTE: reset password는 일반유저만 가능(소셜로그인 유저 X) return await this.authService.resetUserPassword(email, UserType.NORMAL); } @Post('email-verification') - @ApiOperation({ - summary: '이메일 인증 요청', - description: '이메일 인증 요청 메일을 발송', - }) - @ApiResponse({ - status: 201, - description: 'Created', - type: EmailVerificationResponseDto, - }) - @ApiResponse({ - status: 400, - description: 'Bad request', - type: EmailVerificationRequestBodyError, - }) - @ApiResponse({ - status: 500, - description: 'Internal Server Error', - }) @HttpCode(HttpStatus.CREATED) async createEmailVerificaiton( @Body() body: EmailVerificationRequestDto, @@ -251,62 +119,13 @@ export class AuthController { } @Patch('email-verification') - @ApiOperation({ - summary: '이메일 인증 검증', - description: '임시토큰으로 이메일 인증을 검증', - }) - @ApiResponse({ - status: 200, - description: 'OK', - }) - @ApiResponse({ - status: 400, - description: 'Bad request', - type: UpdateEmailVerificationRequestBodyError, - }) - @ApiResponse({ - status: 401, - description: 'Unauthorized', - content: { - 'application/json': { - examples: { - UpdateEmailVerificationUnauthorizedError: { - value: { - message: 'Invalid request_id', - error: 'Unauthorized', - }, - description: 'request_id가 유효하지 않음', - }, - UpdateEmailVerificationUnauthorizedError2: { - value: { - message: 'Invalid code', - error: 'Unauthorized', - }, - description: 'code가 유효하지 않음', - }, - UpdateEmailVerificationUnauthorizedError3: { - value: { - message: 'Expired request_id', - error: 'Unauthorized', - }, - description: 'request_id가 만료됨', - }, - }, - }, - }, - }) - @ApiResponse({ - status: 500, - description: 'Internal Server Error', - }) @HttpCode(HttpStatus.OK) async updateEmailVerificaiton( @Body() body: UpdateEmailVerificationRequestDto, @Res({ passthrough: true }) res: Response, ) { - const id = body.request_id; - const code = body.code; - await this.authService.updateEmailVerificaiton(id, code); + const { request_id, code } = body; + await this.authService.updateEmailVerificaiton(request_id, code); res.status(HttpStatus.OK).send(); } } diff --git a/src/modules/auth/dto/create-token-request.dto.ts b/src/modules/auth/dto/create-token-request.dto.ts index c3e30b1..e5f2f2c 100644 --- a/src/modules/auth/dto/create-token-request.dto.ts +++ b/src/modules/auth/dto/create-token-request.dto.ts @@ -1,22 +1,11 @@ -import { IsEmail, IsNotEmpty, MinLength, IsString } from "class-validator"; -import { ApiProperty } from "@nestjs/swagger"; +import { IsEmail, IsNotEmpty, MinLength, IsString } from 'class-validator'; export class CreateTokenRequestDto { @IsEmail() @IsNotEmpty() - @ApiProperty({ - required: true, - example: "john.doe@example.com", - description: "The email of the user", - }) email: string; @MinLength(8) @IsString() - @ApiProperty({ - required: true, - example: "Password@1234", - description: "The password of the user", - }) password: string; } diff --git a/src/modules/auth/dto/create-token-response.dto.ts b/src/modules/auth/dto/create-token-response.dto.ts index bb4cd75..95e3d19 100644 --- a/src/modules/auth/dto/create-token-response.dto.ts +++ b/src/modules/auth/dto/create-token-response.dto.ts @@ -1,9 +1,5 @@ -import { ApiProperty } from "@nestjs/swagger"; - export class CreateTokenResponseDto { - @ApiProperty({ example: "valid.access.token", description: "access token" }) access_token: string; - @ApiProperty({ example: "valid.refresh.token", description: "refresh token" }) refresh_token: string; } diff --git a/src/modules/auth/dto/email-verification-request.dto.ts b/src/modules/auth/dto/email-verification-request.dto.ts index 589022d..6113293 100644 --- a/src/modules/auth/dto/email-verification-request.dto.ts +++ b/src/modules/auth/dto/email-verification-request.dto.ts @@ -1,13 +1,6 @@ import { IsEmail, IsNotEmpty } from 'class-validator'; -import { ApiProperty } from '@nestjs/swagger'; - export class EmailVerificationRequestDto { @IsEmail() @IsNotEmpty() - @ApiProperty({ - required: true, - example: 'john.doe@example.com', - description: 'The email of the user', - }) email: string; } diff --git a/src/modules/auth/dto/email-verification-response.dto.ts b/src/modules/auth/dto/email-verification-response.dto.ts index d927636..bfed2a2 100644 --- a/src/modules/auth/dto/email-verification-response.dto.ts +++ b/src/modules/auth/dto/email-verification-response.dto.ts @@ -1,6 +1,3 @@ -import { ApiProperty } from '@nestjs/swagger'; - export class EmailVerificationResponseDto { - @ApiProperty({ example: 'e4e74363-c3ed-45fb-ba68-faad0ef45ab3' }) request_id: string; } diff --git a/src/modules/auth/dto/refresh-token-request.dto.ts b/src/modules/auth/dto/refresh-token-request.dto.ts index b10bf42..6e10332 100644 --- a/src/modules/auth/dto/refresh-token-request.dto.ts +++ b/src/modules/auth/dto/refresh-token-request.dto.ts @@ -1,14 +1,8 @@ -import { IsNotEmpty, IsString } from "class-validator"; -import { ApiProperty } from "@nestjs/swagger"; +import { IsNotEmpty, IsString } from 'class-validator'; // refresh-token-request.dto.ts export class RefreshTokenRequestDto { @IsNotEmpty() @IsString() - @ApiProperty({ - required: true, - example: "valid.refresh.token", - description: "refresh token", - }) refresh_token: string; } diff --git a/src/modules/auth/dto/refresh-token-response.dto.ts b/src/modules/auth/dto/refresh-token-response.dto.ts index 76df569..78118b8 100644 --- a/src/modules/auth/dto/refresh-token-response.dto.ts +++ b/src/modules/auth/dto/refresh-token-response.dto.ts @@ -1,9 +1,5 @@ -import { ApiProperty } from "@nestjs/swagger"; - export class RefreshTokenResponseDto { - @ApiProperty({ example: "valid.access.token", description: "access token" }) access_token: string; - @ApiProperty({ example: "valid.refresh.token", description: "refresh token" }) refresh_token: string; } diff --git a/src/modules/auth/dto/reset-password-request.dto.ts b/src/modules/auth/dto/reset-password-request.dto.ts index a9d9618..423ae52 100644 --- a/src/modules/auth/dto/reset-password-request.dto.ts +++ b/src/modules/auth/dto/reset-password-request.dto.ts @@ -1,13 +1,7 @@ import { IsEmail, IsNotEmpty } from 'class-validator'; -import { ApiProperty } from '@nestjs/swagger'; export class ResetPasswordRequestDto { @IsEmail() @IsNotEmpty() - @ApiProperty({ - required: true, - example: 'john.doe@example.com', - description: 'The email of the user', - }) email: string; } diff --git a/src/modules/auth/dto/social-login-request.dto.ts b/src/modules/auth/dto/social-login-request.dto.ts index d5e0623..983aefe 100644 --- a/src/modules/auth/dto/social-login-request.dto.ts +++ b/src/modules/auth/dto/social-login-request.dto.ts @@ -1,21 +1,10 @@ -import { ApiProperty } from "@nestjs/swagger"; -import { IsEmail, IsNotEmpty, IsString } from "class-validator"; +import { IsEmail, IsNotEmpty, IsString } from 'class-validator'; export class SocialLoginRequestDto { @IsEmail() @IsNotEmpty() - @ApiProperty({ - required: true, - example: "john.doe@example.com", - description: "The email of the user", - }) email: string; @IsString() - @ApiProperty({ - required: true, - example: "Password@1234", - description: "The password of the user", - }) password: string; } diff --git a/src/modules/auth/dto/update-email-verification-request.dto.ts b/src/modules/auth/dto/update-email-verification-request.dto.ts index caaf2b6..08050d4 100644 --- a/src/modules/auth/dto/update-email-verification-request.dto.ts +++ b/src/modules/auth/dto/update-email-verification-request.dto.ts @@ -1,22 +1,11 @@ import { IsNotEmpty, IsString, IsNumber } from 'class-validator'; -import { ApiProperty } from '@nestjs/swagger'; export class UpdateEmailVerificationRequestDto { @IsNotEmpty() @IsString() - @ApiProperty({ - required: true, - example: 'e4e74363-c3ed-45fb-ba68-faad0ef45ab3', - description: 'request id', - }) request_id: string; @IsNotEmpty() @IsNumber() - @ApiProperty({ - required: true, - example: 1234, - description: 'auth code', - }) code: number; } diff --git a/src/modules/auth/error/create-token-error.ts b/src/modules/auth/error/create-token-error.ts index e6be77e..84928a0 100644 --- a/src/modules/auth/error/create-token-error.ts +++ b/src/modules/auth/error/create-token-error.ts @@ -1,18 +1,5 @@ -import { ApiProperty } from '@nestjs/swagger'; - export class CreateTokenRequestBodyError { - @ApiProperty({ - example: [ - 'email should not be empty', - 'email must be an email', - 'password must be a string', - 'password must be longer than or equal to 8 characters', - ], - }) message: string[]; - @ApiProperty({ - example: 'Bad Request', - }) error: 'Bad Request'; } diff --git a/src/modules/auth/error/email-verification-error.ts b/src/modules/auth/error/email-verification-error.ts index 71044eb..00daa6a 100644 --- a/src/modules/auth/error/email-verification-error.ts +++ b/src/modules/auth/error/email-verification-error.ts @@ -1,13 +1,5 @@ -import { ApiProperty } from '@nestjs/swagger'; - export class EmailVerificationRequestBodyError { - @ApiProperty({ - example: ['email should not be empty', 'email must be an email'], - }) message: string[]; - @ApiProperty({ - example: 'Bad Request', - }) error: 'Bad Request'; } diff --git a/src/modules/auth/error/refresh-token-error.ts b/src/modules/auth/error/refresh-token-error.ts index acd05b4..50ce8e0 100644 --- a/src/modules/auth/error/refresh-token-error.ts +++ b/src/modules/auth/error/refresh-token-error.ts @@ -1,16 +1,5 @@ -import { ApiProperty } from '@nestjs/swagger'; - export class RefreshTokenRequestBodyError { - @ApiProperty({ - example: [ - 'refresh_token must be a string', - 'refresh_token should not be empty', - ], - }) message: string[]; - @ApiProperty({ - example: 'Bad Request', - }) error: 'Bad Request'; } diff --git a/src/modules/auth/error/reset-password-error.ts b/src/modules/auth/error/reset-password-error.ts index b192aee..cec5bf1 100644 --- a/src/modules/auth/error/reset-password-error.ts +++ b/src/modules/auth/error/reset-password-error.ts @@ -1,13 +1,3 @@ -import { ApiProperty } from '@nestjs/swagger'; - export class ResetPasswordRequestBodyError { - @ApiProperty({ - example: ['email should not be empty', 'email must be an email'], - }) - message: string[]; - - @ApiProperty({ - example: 'Bad Request', - }) error: 'Bad Request'; } diff --git a/src/modules/auth/error/update-email-verification-error.ts b/src/modules/auth/error/update-email-verification-error.ts index 2d1db21..a8a9294 100644 --- a/src/modules/auth/error/update-email-verification-error.ts +++ b/src/modules/auth/error/update-email-verification-error.ts @@ -1,18 +1,5 @@ -import { ApiProperty } from '@nestjs/swagger'; - export class UpdateEmailVerificationRequestBodyError { - @ApiProperty({ - example: [ - 'request_id must be a string', - 'request_id should not be empty', - 'code must be a number conforming to the specified constraints', - 'code should not be empty', - ], - }) message: string[]; - @ApiProperty({ - example: 'Bad Request', - }) error: 'Bad Request'; } diff --git a/src/modules/test/dto/create-test-request.dto.ts b/src/modules/test/dto/create-test-request.dto.ts index 36ca0c9..8fd8dbd 100644 --- a/src/modules/test/dto/create-test-request.dto.ts +++ b/src/modules/test/dto/create-test-request.dto.ts @@ -8,53 +8,34 @@ import { IsOptional, } from 'class-validator'; import { Type } from 'class-transformer'; -import { ApiProperty } from '@nestjs/swagger'; import { TestLevel } from '../test.entity'; export class CreateTestRequestDto { @IsOptional() @IsString() - @ApiProperty({ - example: '422838ab-3a92-4e5f-914c-5eae24249a92', - description: 'id', - }) id?: string; @IsString() @IsIn(Object.values(TestLevel)) - @ApiProperty({ - enum: TestLevel, - description: 'level', - }) level: TestLevel; @IsInt() @Type(() => Number) @Min(1) @Max(30) - @ApiProperty({ example: 10, description: 'total_count' }) total_count?: number; @IsInt() @Type(() => Number) @Min(0) @Max(30) - @ApiProperty({ example: 5, description: 'expected_count' }) expected_count?: number; @IsArray() @IsString({ each: true }) - @ApiProperty({ - example: ['word1', 'word2', 'word3', 'word4', 'word5'], - description: 'An array of total words for the test.', - }) total_words: string[]; @IsArray() @IsString({ each: true }) - @ApiProperty({ - example: ['word1', 'word2'], - description: 'An array of input words for the test.', - }) input_words: string[]; } diff --git a/src/modules/test/dto/create-test-response.dto.ts b/src/modules/test/dto/create-test-response.dto.ts index c86e628..c82d64c 100644 --- a/src/modules/test/dto/create-test-response.dto.ts +++ b/src/modules/test/dto/create-test-response.dto.ts @@ -1,16 +1,7 @@ -import { ApiProperty } from '@nestjs/swagger'; import { TestLevel } from '../test.entity'; export class CreateTestResponseDto { - @ApiProperty({ - example: '422838ab-3a92-4e5f-914c-5eae24249a92', - description: 'The id of the user', - }) id: string; - @ApiProperty({ - example: 'Test_beginner_2024-04-20T01:19:42.998Z', - description: 'The sort key of the test', - }) sort_key: string; } diff --git a/src/modules/test/error/create-test-errror.ts b/src/modules/test/error/create-test-errror.ts index 31be858..129f163 100644 --- a/src/modules/test/error/create-test-errror.ts +++ b/src/modules/test/error/create-test-errror.ts @@ -1,26 +1,19 @@ -import { ApiProperty } from '@nestjs/swagger'; +export class CreateTestBadRequestError { + message: string; + error: string; -export class CreateTestRequestBodyBadRequestError { - @ApiProperty({ - example: [ - 'level must be one of the following values: beginner, intermediate, advanced, all', - 'level must be a string', - 'total_count must not be greater than 30', - 'total_count must not be less than 1', - 'total_count must be an integer number', - 'expected_count must not be greater than 30', - 'expected_count must not be less than 0', - 'expected_count must be an integer number', - 'each value in total_words must be a string', - 'total_words must be an array', - 'each value in input_words must be a string', - 'input_words must be an array', - ], - }) - message: string[]; + constructor() { + this.message = 'At least one of nickname, gender, age is required.'; + this.error = 'Bad Request'; + } +} + +export class CreateTestConflictError { + message: string; + error: string; - @ApiProperty({ - example: 'Bad Request', - }) - error: 'Bad Request'; + constructor() { + this.message = 'User exists'; + this.error = 'Conflict'; + } } diff --git a/src/modules/test/test.controller.ts b/src/modules/test/test.controller.ts index b4c8455..6ef41c5 100644 --- a/src/modules/test/test.controller.ts +++ b/src/modules/test/test.controller.ts @@ -1,31 +1,12 @@ import { Controller, Post, Body, HttpCode, HttpStatus } from '@nestjs/common'; -import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger'; import { TestService } from './test.service'; import { CreateTestRequestDto } from './dto/create-test-request.dto'; -import { CreateTestResponseDto } from './dto/create-test-response.dto'; -import { CreateTestRequestBodyBadRequestError } from './error/create-test-errror'; -@ApiTags('test') @Controller({ path: 'test' }) export class TestController { constructor(private readonly testService: TestService) {} @Post() - @ApiOperation({ summary: '테스트 결과 등록', description: '' }) - @ApiResponse({ - status: 201, - description: 'Success', - type: CreateTestResponseDto, - }) - @ApiResponse({ - status: 400, - description: 'Bad request', - type: CreateTestRequestBodyBadRequestError, - }) - @ApiResponse({ - status: 500, - description: 'Internal Server Error', - }) @HttpCode(HttpStatus.CREATED) async createUserTest(@Body() createTestRequestDto: CreateTestRequestDto) { return await this.testService.createTest(createTestRequestDto); diff --git a/src/modules/user/dto/create-user-info-request.dto.ts b/src/modules/user/dto/create-user-info-request.dto.ts index 2d76b88..4434291 100644 --- a/src/modules/user/dto/create-user-info-request.dto.ts +++ b/src/modules/user/dto/create-user-info-request.dto.ts @@ -6,60 +6,29 @@ import { IsNumber, IsOptional, } from 'class-validator'; -import { ApiProperty } from '@nestjs/swagger'; export class CreateUserInfoRequestDto { @IsOptional() @IsString() - @ApiProperty({ - required: false, - example: '422838ab-3a92-4e5f-914c-5eae24249a92', - description: 'id', - }) id?: string; @IsEmail() @IsNotEmpty() - @ApiProperty({ - required: true, - example: 'john.doe@example.com', - description: 'The email of the user', - }) email: string; @MinLength(8) @IsString() - @ApiProperty({ - required: true, - example: 'Password@1234', - description: 'The password of the user', - }) password: string; @IsOptional() @IsString() - @ApiProperty({ - required: false, - example: 'JohnDoe', - description: 'The nickname of the user', - }) nickname?: string; @IsOptional() @IsString() - @ApiProperty({ - required: false, - example: 'm', - description: 'The gender of the user', - }) gender?: string; @IsOptional() @IsNumber() - @ApiProperty({ - required: false, - example: 20, - description: 'The age of the user', - }) age?: number; } diff --git a/src/modules/user/dto/create-user-info-response.dto.ts b/src/modules/user/dto/create-user-info-response.dto.ts index ae66bed..874d6e7 100644 --- a/src/modules/user/dto/create-user-info-response.dto.ts +++ b/src/modules/user/dto/create-user-info-response.dto.ts @@ -1,47 +1,18 @@ -import { ApiProperty } from '@nestjs/swagger'; import { IsEnum } from 'class-validator'; import { UserType } from 'src/types/userType'; // password 필드는 포함하지 않습니다. export class CreateUserInfoResponseDto { - @ApiProperty({ - example: '422838ab-3a92-4e5f-914c-5eae24249a92', - description: 'The id of the user', - }) id: string; - @ApiProperty({ - example: 'john.doe@example.com', - description: 'The email of the user', - }) email: string; - @ApiProperty({ - required: false, - example: 'JohnDoe', - description: 'The nickname of the user', - }) nickname?: string; - @ApiProperty({ - required: false, - example: 'm', - description: 'The gender of the user', - }) gender?: string; - @ApiProperty({ - required: false, - example: 20, - description: 'The age of the user', - }) age?: number; @IsEnum(UserType) - @ApiProperty({ - required: true, - example: UserType.NORMAL, - description: '유저 가입 유형(타입)', - }) userType: UserType; } diff --git a/src/modules/user/dto/get-user-info-response.dto.ts b/src/modules/user/dto/get-user-info-response.dto.ts index 4bff474..4c4ee1b 100644 --- a/src/modules/user/dto/get-user-info-response.dto.ts +++ b/src/modules/user/dto/get-user-info-response.dto.ts @@ -1,47 +1,18 @@ -import { ApiProperty } from '@nestjs/swagger'; import { IsEnum } from 'class-validator'; import { UserType } from 'src/types/userType'; // password 필드는 포함하지 않습니다. export class GetUserInfoResponseDto { - @ApiProperty({ - example: '422838ab-3a92-4e5f-914c-5eae24249a92', - description: 'The id of the user', - }) id: string; - @ApiProperty({ - example: 'john.doe@example.com', - description: 'The email of the user', - }) email: string; - @ApiProperty({ - required: false, - example: 'JohnDoe', - description: 'The nickname of the user', - }) nickname?: string; - @ApiProperty({ - required: false, - example: 'm', - description: 'The gender of the user', - }) gender?: string; - @ApiProperty({ - required: false, - example: 20, - description: 'The age of the user', - }) age?: number; @IsEnum(UserType) - @ApiProperty({ - required: true, - example: UserType.NORMAL, - description: '유저 가입 유형(타입)', - }) userType: UserType; } diff --git a/src/modules/user/dto/get-user-test-list-query.dto.ts b/src/modules/user/dto/get-user-test-list-query.dto.ts index 088be82..b23f7ae 100644 --- a/src/modules/user/dto/get-user-test-list-query.dto.ts +++ b/src/modules/user/dto/get-user-test-list-query.dto.ts @@ -1,6 +1,5 @@ import { IsInt, Max, Min, IsOptional, IsIn } from 'class-validator'; import { Type } from 'class-transformer'; -import { ApiProperty } from '@nestjs/swagger'; import { TestLevel, Order } from '../../test/test.entity'; export class GetUserTestListQueryDto { @@ -8,39 +7,16 @@ export class GetUserTestListQueryDto { @Type(() => Number) @Min(1) @Max(30) - @ApiProperty({ - required: true, - example: '10', - description: 'limit, minimum: 1', - }) limit: number; @IsOptional() @IsIn(Object.values(Order)) - @ApiProperty({ - required: false, - enum: Order, - default: 'desc', - description: 'order by created_at', - }) order?: Order; @IsOptional() @IsIn(Object.values(TestLevel)) - @ApiProperty({ - required: false, - enum: TestLevel, - default: 'all', - description: 'filter by level', - }) level?: TestLevel; @IsOptional() - @ApiProperty({ - required: false, - example: - 'eyJJZCI6IjIwNDA3YTRjLTJkNzktNGRkOC1iZDE3LTkyNzFhMzY3ZTk2YyIsIlNvcnRLZXkiOiJUZXN0IzIwMjQtMDMtMzBUMDE6NDQ6MTYuMDQ3WiJ9', - description: 'Base64 encoded startKey', - }) startKey?: string; } diff --git a/src/modules/user/dto/get-user-test-list-response.dto.ts b/src/modules/user/dto/get-user-test-list-response.dto.ts index ed27c02..0cc81ea 100644 --- a/src/modules/user/dto/get-user-test-list-response.dto.ts +++ b/src/modules/user/dto/get-user-test-list-response.dto.ts @@ -1,71 +1,33 @@ -import { ApiProperty } from '@nestjs/swagger'; import { TestLevel } from '../../test/test.entity'; export class Item { - @ApiProperty({ - example: ['애플', '메타', '테슬라'], - description: 'The total words', - }) total_words: string[]; - @ApiProperty({ example: 3, description: 'The total count' }) total_count: number; - @ApiProperty({ - example: ['애플', '메타', '테슬라'], - description: 'The correct words', - }) correct_words: string[]; - @ApiProperty({ - example: ['애플', '메타', '테슬라'], - description: 'The input words', - }) input_words: string[]; - @ApiProperty({ enum: TestLevel, description: 'The level' }) level: TestLevel; - @ApiProperty({ example: 1, description: 'The expected count' }) expected_count: number; - @ApiProperty({ example: 'test', description: 'The category' }) category: string; - @ApiProperty({ example: 0, description: 'The score' }) score: number; - @ApiProperty({ - example: '2024-03-30T01:44:00.232Z', - description: 'The creation date', - }) createdAt: string; - @ApiProperty({ - example: '20407a4c-2d79-4dd8-bd17-9271a367e96c', - description: 'The ID', - }) id: string; - @ApiProperty({ - example: 'Test_beginner_2024-03-30T01:44:00.232Z', - description: 'The SortKey', - }) sort_key: string; } export class GetUserTestListResponseDto { - @ApiProperty({ type: [Item], description: 'The list of items' }) items: Item[]; - @ApiProperty({ example: 1, description: 'The count of items' }) count: number; - @ApiProperty({ - example: - 'eyJJZCI6IjIwNDA3YTRjLTJkNzktNGRkOC1iZDE3LTkyNzFhMzY3ZTk2YyIsIlNvcnRLZXkiOiJUZXN0IzIwMjQtMDMtMzBUMDE6NDQ6MDAuMjMyWiJ9', - description: 'The last evaluated key for pagination', - required: false, - }) lastEvaluatedKey?: string; } diff --git a/src/modules/user/dto/get-user-test-query.dto.ts b/src/modules/user/dto/get-user-test-query.dto.ts index 1dcfe5c..afbf877 100644 --- a/src/modules/user/dto/get-user-test-query.dto.ts +++ b/src/modules/user/dto/get-user-test-query.dto.ts @@ -1,11 +1,6 @@ import { IsString } from 'class-validator'; -import { ApiProperty } from '@nestjs/swagger'; export class GetUserTestQueryDto { @IsString() - @ApiProperty({ - example: 'Test_advanced_2024-04-20T01:19:42.998Z', - description: 'The sort key of the test', - }) sort_key: string; } diff --git a/src/modules/user/dto/get-user-test-response.dto.ts b/src/modules/user/dto/get-user-test-response.dto.ts index c852527..e303cbf 100644 --- a/src/modules/user/dto/get-user-test-response.dto.ts +++ b/src/modules/user/dto/get-user-test-response.dto.ts @@ -1,52 +1,23 @@ -import { ApiProperty } from '@nestjs/swagger'; import { TestLevel } from '../../test/test.entity'; export class GetUserTestResponseDto { - @ApiProperty({ - example: '422838ab-3a92-4e5f-914c-5eae24249a92', - description: 'The id of the user', - }) id: string; - @ApiProperty({ - example: 'Test_beginner_2024-04-20T01:19:42.998Z', - description: 'The sort key of the test', - }) sort_key: string; - @ApiProperty({ - enum: TestLevel, - description: 'level', - }) level: TestLevel; - @ApiProperty({ example: 0.5, description: 'score' }) score: number; - @ApiProperty({ example: 10, description: 'total_count' }) total_count?: number; - @ApiProperty({ example: 5, description: 'expected_count' }) expected_count?: number; - @ApiProperty({ example: 5, description: 'expected_count' }) correct_count?: number; - @ApiProperty({ - example: ['word1', 'word2', 'word3', 'word4', 'word5'], - description: 'An array of total words for the test.', - }) total_words: string[]; - @ApiProperty({ - example: ['word1', 'word2'], - description: 'An array of input words for the test.', - }) input_words: string[]; - @ApiProperty({ - example: ['word1'], - description: 'An array of correct words for the test.', - }) correct_words: string[]; } diff --git a/src/modules/user/dto/update-user-info-request.dto.ts b/src/modules/user/dto/update-user-info-request.dto.ts index 0f92554..9301042 100644 --- a/src/modules/user/dto/update-user-info-request.dto.ts +++ b/src/modules/user/dto/update-user-info-request.dto.ts @@ -1,26 +1,23 @@ -import { IsEmail, IsString, IsOptional } from 'class-validator'; -import { ApiProperty } from '@nestjs/swagger'; +import { IsEmail, IsString, IsOptional, IsNumber } from 'class-validator'; export class UpdateUserInfoRequestDto { @IsOptional() @IsEmail() - @ApiProperty({ - required: false, - example: 'john.doe@example.com', - description: 'The email of the user', - }) email?: string; @IsOptional() @IsString() - @ApiProperty({ - required: false, - example: 'JohnDoe', - description: 'The nickname of the user', - }) nickname?: string; + + @IsOptional() + @IsString() + gender?: string; + + @IsOptional() + @IsNumber() + age?: number; + @IsOptional() @IsString() - @ApiProperty({ required: false, example: 'NewPassword@1234', description: 'The new password of the user' }) password?: string; } diff --git a/src/modules/user/dto/update-user-info-response.dto.ts b/src/modules/user/dto/update-user-info-response.dto.ts index 9d02494..f661f7c 100644 --- a/src/modules/user/dto/update-user-info-response.dto.ts +++ b/src/modules/user/dto/update-user-info-response.dto.ts @@ -1,34 +1,12 @@ -import { ApiProperty } from '@nestjs/swagger'; import { IsEnum } from 'class-validator'; import { UserType } from 'src/types/userType'; export class UpdateUserInfoResponseDto { - @ApiProperty({ - required: false, - example: 'JohnDoe', - description: 'The nickname of the user', - }) nickname?: string; - @ApiProperty({ - required: false, - example: 'm', - description: 'The gender of the user', - }) gender?: string; - @ApiProperty({ - required: false, - example: 20, - description: 'The age of the user', - }) age?: number; - @IsEnum(UserType) - @ApiProperty({ - required: true, - example: UserType.NORMAL, - description: '유저 가입 유형(타입)', - }) userType: UserType; } diff --git a/src/modules/user/entities/user.entity.ts b/src/modules/user/entities/user.entity.ts index da53c6d..1afdb73 100644 --- a/src/modules/user/entities/user.entity.ts +++ b/src/modules/user/entities/user.entity.ts @@ -1,16 +1,21 @@ import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; +import { ObjectType, Field } from '@nestjs/graphql'; +@ObjectType() @Entity() export class User { - @PrimaryGeneratedColumn() + @Field(() => String) + @PrimaryGeneratedColumn('uuid') id: string; + @Field(() => String) @Column() email: string; @Column() password: string; + @Field(() => String) @Column() nickname: string; } \ No newline at end of file diff --git a/src/modules/user/error/create-user-info-error.ts b/src/modules/user/error/create-user-info-error.ts index 6bcc5d9..c31d695 100644 --- a/src/modules/user/error/create-user-info-error.ts +++ b/src/modules/user/error/create-user-info-error.ts @@ -1,13 +1,19 @@ -import { ApiProperty } from '@nestjs/swagger'; +export class CreateUserInfoBadRequestError { + message: string; + error: string; + + constructor() { + this.message = 'Invalid request body'; + this.error = 'Bad Request'; + } +} export class CreateUserInfoConflictError { - @ApiProperty({ - example: 'User exists', - }) message: string; + error: string; - @ApiProperty({ - example: 'Conflict', - }) - error: 'Conflict'; + constructor() { + this.message = 'User exists'; + this.error = 'Conflict'; + } } diff --git a/src/modules/user/error/get-user-info-error.ts b/src/modules/user/error/get-user-info-error.ts index 3c1749b..c306464 100644 --- a/src/modules/user/error/get-user-info-error.ts +++ b/src/modules/user/error/get-user-info-error.ts @@ -1,13 +1,5 @@ -import { ApiProperty } from '@nestjs/swagger'; - export class GetUserInfoNotFoundError { - @ApiProperty({ - example: 'User does not exist', - }) message: string; - @ApiProperty({ - example: 'Not Found', - }) error: 'Not Found'; } diff --git a/src/modules/user/error/get-user-test-error.ts b/src/modules/user/error/get-user-test-error.ts index 9127370..3b6a248 100644 --- a/src/modules/user/error/get-user-test-error.ts +++ b/src/modules/user/error/get-user-test-error.ts @@ -1,25 +1,10 @@ -import { ApiProperty } from '@nestjs/swagger'; - export class GetUserTestNotFoundError { - @ApiProperty({ - example: 'User test does not exist', - }) message: string; - - @ApiProperty({ - example: 'Not Found', - }) error: 'Not Found'; } export class GetUserTestRequestQueryBadRequestError { - @ApiProperty({ - example: ['sort_key must be a string'], - }) message: string[]; - @ApiProperty({ - example: 'Bad Request', - }) error: 'Bad Request'; } diff --git a/src/modules/user/error/get-user-test-list-error.ts b/src/modules/user/error/get-user-test-list-error.ts index 7a05d18..27a253a 100644 --- a/src/modules/user/error/get-user-test-list-error.ts +++ b/src/modules/user/error/get-user-test-list-error.ts @@ -1,19 +1,9 @@ -import { ApiProperty } from '@nestjs/swagger'; +export class GetUserTestListBadRequestError { + message: string; + error: string; -export class GetUserTestListRequestQueryBadRequestError { - @ApiProperty({ - example: [ - 'limit must not be greater than 30', - 'limit must not be less than 1', - 'limit must be an integer number', - 'order must be one of the following values: desc, asc', - 'level must be one of the following values: beginner, intermediate, advanced, all', - ], - }) - message: string[]; - - @ApiProperty({ - example: 'Bad Request', - }) - error: 'Bad Request'; + constructor() { + this.message = 'Invalid request parameters'; + this.error = 'Bad Request'; + } } diff --git a/src/modules/user/user.controller.ts b/src/modules/user/user.controller.ts index cd768d0..85bcda9 100644 --- a/src/modules/user/user.controller.ts +++ b/src/modules/user/user.controller.ts @@ -1,135 +1,36 @@ import { + Body, Controller, - Request, - Post, Get, - Patch, - Body, Param, - HttpCode, - HttpStatus, - UseGuards, + Patch, + Post, Query, + Request, + UseGuards, ValidationPipe, } from '@nestjs/common'; -import { - ApiTags, - ApiResponse, - ApiOperation, - ApiBearerAuth, -} from '@nestjs/swagger'; -import { UserService } from './user.service'; import { AuthGuard } from '@nestjs/passport'; +import { UserType } from 'src/types/userType'; +import { Order, TestLevel } from '../test/test.entity'; import { CreateUserInfoRequestDto } from './dto/create-user-info-request.dto'; -import { CreateUserInfoResponseDto } from './dto/create-user-info-response.dto'; -import { GetUserInfoResponseDto } from './dto/get-user-info-response.dto'; -import { UpdateUserInfoRequestDto } from './dto/update-user-info-request.dto'; -import { UpdateUserInfoResponseDto } from './dto/update-user-info-response.dto'; import { GetUserTestListQueryDto } from './dto/get-user-test-list-query.dto'; -import { GetUserTestListResponseDto } from './dto/get-user-test-list-response.dto'; -import { TestLevel, Order } from '../test/test.entity'; -import { UnauthorizedError } from 'src/core/errors/unauthorized-error'; -import { GetUserInfoNotFoundError } from './error/get-user-info-error'; import { GetUserTestQueryDto } from './dto/get-user-test-query.dto'; -import { - GetUserTestNotFoundError, - GetUserTestRequestQueryBadRequestError, -} from './error/get-user-test-error'; -import { GetUserTestResponseDto } from './dto/get-user-test-response.dto'; -import { CreateUserInfoConflictError } from './error/create-user-info-error'; -import { GetUserTestListRequestQueryBadRequestError } from './error/get-user-test-list-error'; -import { UserType } from 'src/types/userType'; +import { UpdateUserInfoRequestDto } from './dto/update-user-info-request.dto'; +import { UserService } from './user.service'; -@ApiTags('users') @Controller({ path: 'users' }) export class UserController { constructor(private readonly userService: UserService) {} @Get() @UseGuards(AuthGuard('jwt')) - @ApiBearerAuth() - @ApiOperation({ summary: '유저 정보 조회', description: '' }) - @ApiResponse({ status: 200, description: 'OK', type: GetUserInfoResponseDto }) - @ApiResponse({ - status: 404, - description: 'Not Found', - type: GetUserInfoNotFoundError, - }) - @ApiResponse({ - status: 401, - description: 'Unauthorized', - type: UnauthorizedError, - }) - @ApiResponse({ - status: 500, - description: 'Internal Server Error', - }) - @HttpCode(HttpStatus.OK) async getUser(@Request() req) { const id = req.user.id; return await this.userService.getUserById(id); } @Post() - @ApiOperation({ summary: '회원가입', description: '유저 정보 등록' }) - @ApiResponse({ - status: 201, - description: 'Created', - type: CreateUserInfoResponseDto, - }) - @ApiResponse({ - status: 400, - description: 'Bad request', - content: { - 'application/json': { - examples: { - CreateUserInfoRequestBodyBadRequestError: { - value: { - message: 'Unexpected end of JSON input', - error: 'Bad Request', - }, - description: '요청 바디 형식이 맞지 않음', - }, - CreateUserInfoRequestBodyBadRequestError2: { - value: { - message: [ - 'email should not be empty', - 'email must be an email', - 'password must be a string', - 'password must be longer than or equal to 8 characters', - ], - error: 'Bad Request', - }, - description: '유효하지 않은 요청 바디', - }, - CreateUserInfoRequestBodyBadRequestError3: { - value: { - message: 'User exists', - error: 'Bad Request', - }, - description: '이메일과 매칭되는 유저가 이미 존재함', - }, - CreateUserInfoRequestBodyBadRequestError4: { - value: { - message: 'Invalid email verification', - error: 'Bad Request', - }, - description: '올바르지 않은 이메일 검증', - }, - }, - }, - }, - }) - @ApiResponse({ - status: 409, - description: 'User exists', - type: CreateUserInfoConflictError, - }) - @ApiResponse({ - status: 500, - description: 'Internal Server Error', - }) - @HttpCode(HttpStatus.CREATED) async createUser(@Body() createUserInfoDto: CreateUserInfoRequestDto) { //NOTE: createUser는 일반 유저의 경우만 호출가능 return await this.userService.create(createUserInfoDto, UserType.NORMAL); @@ -137,64 +38,6 @@ export class UserController { @Patch() @UseGuards(AuthGuard('jwt')) - @ApiBearerAuth() - @ApiOperation({ summary: '유저 정보 수정', description: ' ' }) - @ApiResponse({ - status: 200, - description: 'OK', - type: UpdateUserInfoResponseDto, - }) - @ApiResponse({ - status: 400, - description: 'Bad request', - content: { - 'application/json': { - examples: { - UpdateUserInfoRequestBodyBadRequestError: { - value: { - message: 'At least one of nickname, gender, age is required.', - error: 'Bad Request', - }, - description: '적어도 하나의 값이 요구됨', - }, - UpdateUserInfoRequestBodyBadRequestError2: { - value: { - message: [ - 'email must be an email', - 'nickname must be a string', - 'age must be a number conforming to the specified constraints', - 'gender must be a string', - ], - error: 'Bad Request', - }, - description: '유효하지 않은 요청 바디', - }, - }, - }, - }, - }) - @ApiResponse({ - status: 400, - description: 'Bad request', - content: { - 'application/json': { - example: { - message: 'At least one of nickname, gender, age is required.', - error: 'Bad request', - }, - }, - }, - }) - @ApiResponse({ - status: 401, - description: 'Unauthorized', - type: UnauthorizedError, - }) - @ApiResponse({ - status: 500, - description: 'Internal Server Error', - }) - @HttpCode(HttpStatus.OK) async updateUser( @Request() req, @Body( @@ -212,28 +55,6 @@ export class UserController { @Get('/test') @UseGuards(AuthGuard('jwt')) - @ApiBearerAuth() - @ApiOperation({ summary: '유저 테스트 리스트 정보 조회', description: '' }) - @ApiResponse({ - status: 200, - description: 'OK', - type: GetUserTestListResponseDto, - }) - @ApiResponse({ - status: 400, - description: 'Bad request', - type: GetUserTestListRequestQueryBadRequestError, - }) - @ApiResponse({ - status: 401, - description: 'Unauthorized', - type: UnauthorizedError, - }) - @ApiResponse({ - status: 500, - description: 'Internal Server Error', - }) - @HttpCode(HttpStatus.OK) async geteUserTestList( @Request() req, @Query() query: GetUserTestListQueryDto, @@ -246,32 +67,6 @@ export class UserController { } @Get('/test/:id') - @ApiOperation({ summary: '유저 테스트 세부 정보 조회', description: '' }) - @ApiResponse({ - status: 200, - description: 'OK', - type: GetUserTestResponseDto, - }) - @ApiResponse({ - status: 400, - description: 'Bad request', - type: GetUserTestRequestQueryBadRequestError, - }) - @ApiResponse({ - status: 401, - description: 'Unauthorized', - type: UnauthorizedError, - }) - @ApiResponse({ - status: 404, - description: 'Not Found', - type: GetUserTestNotFoundError, - }) - @ApiResponse({ - status: 500, - description: 'Internal Server Error', - }) - @HttpCode(HttpStatus.OK) async geteUserTest( @Param('id') id: string, @Query() query: GetUserTestQueryDto, diff --git a/src/modules/user/user.module.ts b/src/modules/user/user.module.ts index 2f852fe..aa25081 100644 --- a/src/modules/user/user.module.ts +++ b/src/modules/user/user.module.ts @@ -2,12 +2,14 @@ import { Module } from '@nestjs/common'; import { UserService } from './user.service'; import { UserRepository } from './user.repository'; import { UserController } from './user.controller'; +import { UserResolver } from './user.resolver'; import { AuthModule } from '../auth/auth.module'; import { DynamoDBModule } from '../../database/dynamodb/dynamodb.module'; + @Module({ imports: [DynamoDBModule, AuthModule], controllers: [UserController], - providers: [UserService, UserRepository], + providers: [UserService, UserRepository, UserResolver], exports: [UserService, UserRepository], }) export class UserModule {} diff --git a/src/modules/user/user.repository.ts b/src/modules/user/user.repository.ts index 6f48281..0fc9ec6 100644 --- a/src/modules/user/user.repository.ts +++ b/src/modules/user/user.repository.ts @@ -1,6 +1,7 @@ import { GetCommandOutput, QueryCommandOutput, + ScanCommandOutput, UpdateCommandOutput, } from '@aws-sdk/lib-dynamodb'; import { Inject, Injectable } from '@nestjs/common'; @@ -10,7 +11,7 @@ import { UserType } from 'src/types/userType'; import { v4 as uuidv4 } from 'uuid'; import { User } from './entities/user.entity'; -interface UserInfo { +export interface UserInfo { id?: string; email: string; password: string; @@ -31,6 +32,42 @@ export class UserRepository { this.tableName = process.env.AWS_DYNAMODB_TABLE_NAME; } + async findAllUsers(): Promise { + try { + // 먼저 모든 데이터를 가져와서 로그로 확인 + const allData: ScanCommandOutput = await this.dynamoDb.scan({ + TableName: this.tableName, + }); + console.log('All DynamoDB data:', JSON.stringify(allData.Items, null, 2)); + + // 그 다음 UserInfo 데이터만 필터링 + const result: ScanCommandOutput = await this.dynamoDb.scan({ + TableName: this.tableName, + FilterExpression: 'attribute_exists(email)', + }); + + console.log( + 'Filtered UserInfo data:', + JSON.stringify(result.Items, null, 2), + ); + + if (!result.Items || result.Items.length === 0) { + console.log('No users found in DynamoDB'); + return []; + } + + return result.Items.map((item) => ({ + id: item.PK, + email: item.email, + nickname: item.nickname, + ...item, + })); + } catch (e) { + console.error('Error in findAllUsers:', e); + throw new DatabaseError(); + } + } + async findOneById(id: string): Promise { try { const result: GetCommandOutput = await this.dynamoDb.get({ diff --git a/src/modules/user/user.resolver.ts b/src/modules/user/user.resolver.ts new file mode 100644 index 0000000..42125e7 --- /dev/null +++ b/src/modules/user/user.resolver.ts @@ -0,0 +1,19 @@ +import { Resolver, Query, Args, ID } from '@nestjs/graphql'; +import { User } from './entities/user.entity'; +import { UserService } from './user.service'; +import { UserInfo } from './user.repository'; + +@Resolver(() => User) +export class UserResolver { + constructor(private readonly userService: UserService) {} + + @Query(() => User, { nullable: true }) + async user(@Args('id', { type: () => ID }) id: string): Promise { + return this.userService.getUserById(id); + } + + @Query(() => [User]) + async users(): Promise { + return this.userService.getAllUsers(); + } +} diff --git a/src/modules/user/user.service.ts b/src/modules/user/user.service.ts index 1ecc433..6a0f4b5 100644 --- a/src/modules/user/user.service.ts +++ b/src/modules/user/user.service.ts @@ -83,6 +83,22 @@ export class UserService { return hashedPassword; } + async getAllUsers(): Promise { + const users = await this.usersRepository.findAllUsers(); + console.log('DynamoDB users:', JSON.stringify(users, null, 2)); + const mappedUsers = users.map((user) => { + console.log('Processing user:', JSON.stringify(user, null, 2)); + return { + id: user.id, + email: user.email, + nickname: user.nickname, + ...user, + }; + }); + console.log('Mapped users:', JSON.stringify(mappedUsers, null, 2)); + return mappedUsers; + } + async update( id: string, userInfo: UpdateUserInfoRequestDto, diff --git a/src/schema.gql b/src/schema.gql new file mode 100644 index 0000000..2e43c6c --- /dev/null +++ b/src/schema.gql @@ -0,0 +1,14 @@ +# ------------------------------------------------------ +# THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) +# ------------------------------------------------------ + +type Query { + user(id: ID!): User + users: [User!]! +} + +type User { + email: String! + id: String! + nickname: String! +} \ No newline at end of file