diff --git a/chat-server/package-lock.json b/chat-server/package-lock.json index 31a492d..52e12d0 100644 --- a/chat-server/package-lock.json +++ b/chat-server/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.1", "license": "UNLICENSED", "dependencies": { + "@nestjs/bull": "^0.6.2", "@nestjs/common": "^9.0.0", "@nestjs/config": "^2.2.0", "@nestjs/core": "^9.0.0", @@ -17,9 +18,14 @@ "@nestjs/platform-socket.io": "^9.2.1", "@nestjs/typeorm": "^9.0.1", "@nestjs/websockets": "^9.2.1", - "cache-manager": "^5.1.4", + "@types/bull": "^4.10.0", + "bull": "^4.10.2", + "cache-manager": "^4.0.0", + "cache-manager-ioredis": "^2.1.0", + "ioredis": "^5.2.4", "mongoose": "^6.8.0", "mysql2": "^2.3.3", + "redis": "^3.1.2", "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", "rxjs": "^7.2.0", @@ -33,6 +39,7 @@ "@types/express": "^4.17.13", "@types/jest": "28.1.8", "@types/node": "^16.0.0", + "@types/redis": "^4.0.11", "@types/supertest": "^2.0.11", "@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/parser": "^5.0.0", @@ -1950,6 +1957,11 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "node_modules/@ioredis/commands": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", + "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==" + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -2533,6 +2545,104 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-2.2.0.tgz", + "integrity": "sha512-Z9LFPzfoJi4mflGWV+rv7o7ZbMU5oAU9VmzCgL240KnqDW65Y2HFCT3MW06/ITJSnbVLacmcEJA8phywK7JinQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-2.2.0.tgz", + "integrity": "sha512-vq0tT8sjZsy4JdSqmadWVw6f66UXqUCabLmUVHZwUFzMgtgoIIQjT4VVRHKvlof3P/dMCkbMJ5hB1oJ9OWHaaw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-2.2.0.tgz", + "integrity": "sha512-SaJ3Qq4lX9Syd2xEo9u3qPxi/OB+5JO/ngJKK97XDpa1C587H9EWYO6KD8995DAjSinWvdHKRrCOXVUC5fvGOg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-2.2.0.tgz", + "integrity": "sha512-hlxxLdRmPyq16QCutUtP8Tm6RDWcyaLsRssaHROatgnkOxdleMTgetf9JsdncL8vLh7FVy/RN9i3XR5dnb9cRA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-2.2.0.tgz", + "integrity": "sha512-94y5PJrSOqUNcFKmOl7z319FelCLAE0rz/jPCWS+UtdMZvpa4jrQd+cJPQCLp2Fes1yAW/YUQj/Di6YVT3c3Iw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-2.2.0.tgz", + "integrity": "sha512-XrC0JzsqQSvOyM3t04FMLO6z5gCuhPE6k4FXuLK5xf52ZbdvcFe1yBmo7meCew9B8G2f0T9iu9t3kfTYRYROgA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@nestjs/bull": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@nestjs/bull/-/bull-0.6.2.tgz", + "integrity": "sha512-tx5wiIGgfYEj5RAJA1B23pn/63nsmMH0f981V1/v3NKyE07NsvOXCrwKNGQnIZZlXkXh7lgx2I80/tYwPGnVIg==", + "dependencies": { + "@nestjs/bull-shared": "^0.1.2", + "tslib": "2.4.1" + }, + "peerDependencies": { + "@nestjs/common": "^6.10.11 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "@nestjs/core": "^6.10.11 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "bull": "^3.3 || ^4.0.0" + } + }, + "node_modules/@nestjs/bull-shared": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nestjs/bull-shared/-/bull-shared-0.1.2.tgz", + "integrity": "sha512-q1JqieWb2YjA6OIal5XjtbF28LgJxEflwJB9x3OnE2OUgI0kWvaMlYMaW3opFmgcWPjx4o5lVhcGnwXeIhZfgg==", + "dependencies": { + "tslib": "2.4.1" + }, + "peerDependencies": { + "@nestjs/common": "^6.10.11 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "@nestjs/core": "^6.10.11 || ^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, "node_modules/@nestjs/cli": { "version": "9.1.5", "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-9.1.5.tgz", @@ -2677,14 +2787,6 @@ "rxjs": "^6.0.0 || ^7.2.0" } }, - "node_modules/@nestjs/config/node_modules/dotenv": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", - "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", - "engines": { - "node": ">=12" - } - }, "node_modules/@nestjs/config/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -3141,6 +3243,15 @@ "@types/node": "*" } }, + "node_modules/@types/bull": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@types/bull/-/bull-4.10.0.tgz", + "integrity": "sha512-RkYW8K2H3J76HT6twmHYbzJ0GtLDDotpLP9ah9gtiA7zfF6peBH1l5fEiK0oeIZ3/642M7Jcb9sPmor8Vf4w6g==", + "deprecated": "This is a stub types definition. bull provides its own type definitions, so you do not need this installed.", + "dependencies": { + "bull": "*" + } + }, "node_modules/@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -3274,9 +3385,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "16.18.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.7.tgz", - "integrity": "sha512-SghuoXv8ghvkrKjTyvhRTeNzivPzGQ8pe09PPGdyqsExiKvBYV/6E3imvjsaJuW8ca61qQN2+SoSzyEHS9r2LA==" + "version": "16.18.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.8.tgz", + "integrity": "sha512-TrpoNiaPvBH5h8rQQenMtVsJXtGsVBRJrcp2Ik6oEt99jHfGvDLh20VTTq3ixTbjYujukYz1IlY4N8a8yfY0jA==" }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -3302,6 +3413,16 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, + "node_modules/@types/redis": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@types/redis/-/redis-4.0.11.tgz", + "integrity": "sha512-bI+gth8La8Wg/QCR1+V1fhrL9+LZUSWfcqpOj2Kc80ZQ4ffbdL173vQd5wovmoV9i071FU9oP2g6etLuEwb6Rg==", + "deprecated": "This is a stub types definition. redis provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "redis": "*" + } + }, "node_modules/@types/semver": { "version": "7.3.13", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", @@ -3921,6 +4042,11 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "dev": true }, + "node_modules/async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -4251,6 +4377,33 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "node_modules/bull": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/bull/-/bull-4.10.2.tgz", + "integrity": "sha512-xa65xtWjQsLqYU/eNaXxq9VRG8xd6qNsQEjR7yjYuae05xKrzbVMVj2QgrYsTMmSs/vsqJjHqHSRRiW1+IkGXQ==", + "dependencies": { + "cron-parser": "^4.2.1", + "debuglog": "^1.0.0", + "get-port": "^5.1.1", + "ioredis": "^5.0.0", + "lodash": "^4.17.21", + "msgpackr": "^1.5.2", + "p-timeout": "^3.2.0", + "semver": "^7.3.2", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/bull/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -4271,20 +4424,57 @@ } }, "node_modules/cache-manager": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/cache-manager/-/cache-manager-5.1.4.tgz", - "integrity": "sha512-beXzzuboV6I0AkU25udrd8tRxFbU6c5m7+3eOdmznSVNkyKe0+uTK8EtcuhTwqc/wAYrAGl62w3s58rjKnrO6g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cache-manager/-/cache-manager-4.1.0.tgz", + "integrity": "sha512-ZGM6dLxrP65bfOZmcviWMadUOCICqpLs92+P/S5tj8onz+k+tB7Gr+SAgOUHCQtfm2gYEQDHiKeul4+tYPOJ8A==", "dependencies": { + "async": "3.2.3", "lodash.clonedeep": "^4.5.0", - "lru-cache": "^7.14.0" + "lru-cache": "^7.10.1" } }, - "node_modules/cache-manager/node_modules/lru-cache": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", - "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", + "node_modules/cache-manager-ioredis": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cache-manager-ioredis/-/cache-manager-ioredis-2.1.0.tgz", + "integrity": "sha512-TCxbp9ceuFveTKWuNaCX8QjoC41rAlHen4s63u9Yd+iXlw3efYmimc/u935PKPxSdhkXpnMes4mxtK3/yb0L4g==", + "dependencies": { + "ioredis": "^4.14.1" + }, "engines": { - "node": ">=12" + "node": ">=6.0.0" + } + }, + "node_modules/cache-manager-ioredis/node_modules/denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cache-manager-ioredis/node_modules/ioredis": { + "version": "4.28.5", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.28.5.tgz", + "integrity": "sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A==", + "dependencies": { + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.1", + "denque": "^1.1.0", + "lodash.defaults": "^4.2.0", + "lodash.flatten": "^4.4.0", + "lodash.isarguments": "^3.1.0", + "p-map": "^2.1.0", + "redis-commands": "1.7.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" } }, "node_modules/call-bind": { @@ -4552,6 +4742,14 @@ "node": ">=0.8" } }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -4718,6 +4916,17 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "devOptional": true }, + "node_modules/cron-parser": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.7.0.tgz", + "integrity": "sha512-BdAELR+MCT2ZWsIBhZKDuUqIUCBjHHulPJnm53OfdRLA4EWBjva3R+KM5NeidJuGsNXdEcZkjC7SCnkW5rAFSA==", + "dependencies": { + "luxon": "^3.1.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -4760,6 +4969,14 @@ } } }, + "node_modules/debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", + "engines": { + "node": "*" + } + }, "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -4889,9 +5106,9 @@ } }, "node_modules/dotenv": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", - "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", "engines": { "node": ">=12" } @@ -5854,6 +6071,17 @@ "node": ">=8.0.0" } }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -5904,9 +6132,9 @@ "dev": true }, "node_modules/globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -6191,6 +6419,29 @@ "node": ">= 0.10" } }, + "node_modules/ioredis": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.2.4.tgz", + "integrity": "sha512-qIpuAEt32lZJQ0XyrloCRdlEdUUNGG9i0UOk6zgzK6igyudNWqEBxfH6OlbnOOoBBvr1WB02mm8fR55CnikRng==", + "dependencies": { + "@ioredis/commands": "^1.1.1", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.4", + "denque": "^2.0.1", + "lodash.defaults": "^4.2.0", + "lodash.isarguments": "^3.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, "node_modules/ip": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", @@ -7379,6 +7630,21 @@ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" + }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -7429,14 +7695,19 @@ "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", "engines": { - "node": ">=10" + "node": ">=12" + } + }, + "node_modules/luxon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.1.1.tgz", + "integrity": "sha512-Ah6DloGmvseB/pX1cAmjbFvyU/pKuwQMQqz7d0yvuDlVYLTs2WeDHQMpC8tGjm1da+BriHROW/OEIT/KfYg6xw==", + "engines": { + "node": ">=12" } }, "node_modules/macos-release": { @@ -7687,37 +7958,6 @@ "whatwg-url": "^11.0.0" } }, - "node_modules/mongodb-connection-string-url/node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "engines": { - "node": ">=12" - } - }, - "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "dependencies": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/mongodb/node_modules/bl": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", @@ -7816,6 +8056,35 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/msgpackr": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.1.tgz", + "integrity": "sha512-05fT4J8ZqjYlR4QcRDIhLCYKUOHXk7C/xa62GzMKj74l3up9k2QZ3LgFc6qWdsPHl91QA2WLWqWc8b8t7GLNNw==", + "optionalDependencies": { + "msgpackr-extract": "^2.2.0" + } + }, + "node_modules/msgpackr-extract": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-2.2.0.tgz", + "integrity": "sha512-0YcvWSv7ZOGl9Od6Y5iJ3XnPww8O7WLcpYMDwX+PAA/uXLDtyw94PJv9GLQV/nnp3cWlDhMoyKZIQLrx33sWog==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.0.3" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "2.2.0", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "2.2.0", + "@msgpackr-extract/msgpackr-extract-linux-arm": "2.2.0", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "2.2.0", + "@msgpackr-extract/msgpackr-extract-linux-x64": "2.2.0", + "@msgpackr-extract/msgpackr-extract-win32-x64": "2.2.0" + } + }, "node_modules/multer": { "version": "1.4.4-lts.1", "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz", @@ -7868,6 +8137,17 @@ "node": ">=0.10.0" } }, + "node_modules/mysql2/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -7963,6 +8243,36 @@ } } }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz", + "integrity": "sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==", + "optional": true, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -8148,6 +8458,14 @@ "node": ">=0.10.0" } }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "engines": { + "node": ">=4" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -8178,6 +8496,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -8604,19 +8941,69 @@ "picomatch": "^2.2.1" }, "engines": { - "node": ">=8.10.0" + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/redis": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/redis/-/redis-3.1.2.tgz", + "integrity": "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==", + "dependencies": { + "denque": "^1.5.0", + "redis-commands": "^1.7.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-redis" + } + }, + "node_modules/redis-commands": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", + "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==" + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dev": true, - "dependencies": { - "resolve": "^1.1.6" - }, + "node_modules/redis/node_modules/denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", "engines": { - "node": ">= 0.10" + "node": ">=0.10" } }, "node_modules/reflect-metadata": { @@ -8890,7 +9277,6 @@ "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -8901,6 +9287,17 @@ "node": ">=10" } }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -9198,6 +9595,11 @@ "node": ">=8" } }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -9596,9 +9998,15 @@ } }, "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } }, "node_modules/tree-kill": { "version": "1.2.2", @@ -10169,9 +10577,12 @@ } }, "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } }, "node_modules/webpack": { "version": "5.75.0", @@ -10240,12 +10651,15 @@ } }, "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/which": { @@ -12030,6 +12444,11 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "@ioredis/commands": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", + "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==" + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -12485,6 +12904,59 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-2.2.0.tgz", + "integrity": "sha512-Z9LFPzfoJi4mflGWV+rv7o7ZbMU5oAU9VmzCgL240KnqDW65Y2HFCT3MW06/ITJSnbVLacmcEJA8phywK7JinQ==", + "optional": true + }, + "@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-2.2.0.tgz", + "integrity": "sha512-vq0tT8sjZsy4JdSqmadWVw6f66UXqUCabLmUVHZwUFzMgtgoIIQjT4VVRHKvlof3P/dMCkbMJ5hB1oJ9OWHaaw==", + "optional": true + }, + "@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-2.2.0.tgz", + "integrity": "sha512-SaJ3Qq4lX9Syd2xEo9u3qPxi/OB+5JO/ngJKK97XDpa1C587H9EWYO6KD8995DAjSinWvdHKRrCOXVUC5fvGOg==", + "optional": true + }, + "@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-2.2.0.tgz", + "integrity": "sha512-hlxxLdRmPyq16QCutUtP8Tm6RDWcyaLsRssaHROatgnkOxdleMTgetf9JsdncL8vLh7FVy/RN9i3XR5dnb9cRA==", + "optional": true + }, + "@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-2.2.0.tgz", + "integrity": "sha512-94y5PJrSOqUNcFKmOl7z319FelCLAE0rz/jPCWS+UtdMZvpa4jrQd+cJPQCLp2Fes1yAW/YUQj/Di6YVT3c3Iw==", + "optional": true + }, + "@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-2.2.0.tgz", + "integrity": "sha512-XrC0JzsqQSvOyM3t04FMLO6z5gCuhPE6k4FXuLK5xf52ZbdvcFe1yBmo7meCew9B8G2f0T9iu9t3kfTYRYROgA==", + "optional": true + }, + "@nestjs/bull": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@nestjs/bull/-/bull-0.6.2.tgz", + "integrity": "sha512-tx5wiIGgfYEj5RAJA1B23pn/63nsmMH0f981V1/v3NKyE07NsvOXCrwKNGQnIZZlXkXh7lgx2I80/tYwPGnVIg==", + "requires": { + "@nestjs/bull-shared": "^0.1.2", + "tslib": "2.4.1" + } + }, + "@nestjs/bull-shared": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nestjs/bull-shared/-/bull-shared-0.1.2.tgz", + "integrity": "sha512-q1JqieWb2YjA6OIal5XjtbF28LgJxEflwJB9x3OnE2OUgI0kWvaMlYMaW3opFmgcWPjx4o5lVhcGnwXeIhZfgg==", + "requires": { + "tslib": "2.4.1" + } + }, "@nestjs/cli": { "version": "9.1.5", "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-9.1.5.tgz", @@ -12576,11 +13048,6 @@ "uuid": "8.3.2" }, "dependencies": { - "dotenv": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", - "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==" - }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -12912,6 +13379,14 @@ "@types/node": "*" } }, + "@types/bull": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@types/bull/-/bull-4.10.0.tgz", + "integrity": "sha512-RkYW8K2H3J76HT6twmHYbzJ0GtLDDotpLP9ah9gtiA7zfF6peBH1l5fEiK0oeIZ3/642M7Jcb9sPmor8Vf4w6g==", + "requires": { + "bull": "*" + } + }, "@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -13045,9 +13520,9 @@ "dev": true }, "@types/node": { - "version": "16.18.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.7.tgz", - "integrity": "sha512-SghuoXv8ghvkrKjTyvhRTeNzivPzGQ8pe09PPGdyqsExiKvBYV/6E3imvjsaJuW8ca61qQN2+SoSzyEHS9r2LA==" + "version": "16.18.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.8.tgz", + "integrity": "sha512-TrpoNiaPvBH5h8rQQenMtVsJXtGsVBRJrcp2Ik6oEt99jHfGvDLh20VTTq3ixTbjYujukYz1IlY4N8a8yfY0jA==" }, "@types/parse-json": { "version": "4.0.0", @@ -13073,6 +13548,15 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, + "@types/redis": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@types/redis/-/redis-4.0.11.tgz", + "integrity": "sha512-bI+gth8La8Wg/QCR1+V1fhrL9+LZUSWfcqpOj2Kc80ZQ4ffbdL173vQd5wovmoV9i071FU9oP2g6etLuEwb6Rg==", + "dev": true, + "requires": { + "redis": "*" + } + }, "@types/semver": { "version": "7.3.13", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", @@ -13544,6 +14028,11 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "dev": true }, + "async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -13787,6 +14276,29 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "bull": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/bull/-/bull-4.10.2.tgz", + "integrity": "sha512-xa65xtWjQsLqYU/eNaXxq9VRG8xd6qNsQEjR7yjYuae05xKrzbVMVj2QgrYsTMmSs/vsqJjHqHSRRiW1+IkGXQ==", + "requires": { + "cron-parser": "^4.2.1", + "debuglog": "^1.0.0", + "get-port": "^5.1.1", + "ioredis": "^5.0.0", + "lodash": "^4.17.21", + "msgpackr": "^1.5.2", + "p-timeout": "^3.2.0", + "semver": "^7.3.2", + "uuid": "^8.3.0" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } + } + }, "busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -13801,18 +14313,45 @@ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, "cache-manager": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/cache-manager/-/cache-manager-5.1.4.tgz", - "integrity": "sha512-beXzzuboV6I0AkU25udrd8tRxFbU6c5m7+3eOdmznSVNkyKe0+uTK8EtcuhTwqc/wAYrAGl62w3s58rjKnrO6g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cache-manager/-/cache-manager-4.1.0.tgz", + "integrity": "sha512-ZGM6dLxrP65bfOZmcviWMadUOCICqpLs92+P/S5tj8onz+k+tB7Gr+SAgOUHCQtfm2gYEQDHiKeul4+tYPOJ8A==", "requires": { + "async": "3.2.3", "lodash.clonedeep": "^4.5.0", - "lru-cache": "^7.14.0" + "lru-cache": "^7.10.1" + } + }, + "cache-manager-ioredis": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cache-manager-ioredis/-/cache-manager-ioredis-2.1.0.tgz", + "integrity": "sha512-TCxbp9ceuFveTKWuNaCX8QjoC41rAlHen4s63u9Yd+iXlw3efYmimc/u935PKPxSdhkXpnMes4mxtK3/yb0L4g==", + "requires": { + "ioredis": "^4.14.1" }, "dependencies": { - "lru-cache": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", - "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==" + "denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==" + }, + "ioredis": { + "version": "4.28.5", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.28.5.tgz", + "integrity": "sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A==", + "requires": { + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.1", + "denque": "^1.1.0", + "lodash.defaults": "^4.2.0", + "lodash.flatten": "^4.4.0", + "lodash.isarguments": "^3.1.0", + "p-map": "^2.1.0", + "redis-commands": "1.7.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + } } } }, @@ -13999,6 +14538,11 @@ "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true }, + "cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==" + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -14134,6 +14678,14 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "devOptional": true }, + "cron-parser": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.7.0.tgz", + "integrity": "sha512-BdAELR+MCT2ZWsIBhZKDuUqIUCBjHHulPJnm53OfdRLA4EWBjva3R+KM5NeidJuGsNXdEcZkjC7SCnkW5rAFSA==", + "requires": { + "luxon": "^3.1.0" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -14158,6 +14710,11 @@ "ms": "2.1.2" } }, + "debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==" + }, "dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -14253,9 +14810,9 @@ } }, "dotenv": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", - "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==" }, "dotenv-expand": { "version": "8.0.3", @@ -14991,6 +15548,11 @@ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true }, + "get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==" + }, "get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -15026,9 +15588,9 @@ "dev": true }, "globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -15226,6 +15788,22 @@ "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", "dev": true }, + "ioredis": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.2.4.tgz", + "integrity": "sha512-qIpuAEt32lZJQ0XyrloCRdlEdUUNGG9i0UOk6zgzK6igyudNWqEBxfH6OlbnOOoBBvr1WB02mm8fR55CnikRng==", + "requires": { + "@ioredis/commands": "^1.1.1", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.4", + "denque": "^2.0.1", + "lodash.defaults": "^4.2.0", + "lodash.isarguments": "^3.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + } + }, "ip": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", @@ -16124,6 +16702,21 @@ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -16164,12 +16757,14 @@ "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", + "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==" + }, + "luxon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.1.1.tgz", + "integrity": "sha512-Ah6DloGmvseB/pX1cAmjbFvyU/pKuwQMQqz7d0yvuDlVYLTs2WeDHQMpC8tGjm1da+BriHROW/OEIT/KfYg6xw==" }, "macos-release": { "version": "2.5.0", @@ -16364,30 +16959,6 @@ "requires": { "@types/whatwg-url": "^8.2.1", "whatwg-url": "^11.0.0" - }, - "dependencies": { - "tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "requires": { - "punycode": "^2.1.1" - } - }, - "webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" - }, - "whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "requires": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - } - } } }, "mongoose": { @@ -16441,6 +17012,29 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "msgpackr": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.1.tgz", + "integrity": "sha512-05fT4J8ZqjYlR4QcRDIhLCYKUOHXk7C/xa62GzMKj74l3up9k2QZ3LgFc6qWdsPHl91QA2WLWqWc8b8t7GLNNw==", + "requires": { + "msgpackr-extract": "^2.2.0" + } + }, + "msgpackr-extract": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-2.2.0.tgz", + "integrity": "sha512-0YcvWSv7ZOGl9Od6Y5iJ3XnPww8O7WLcpYMDwX+PAA/uXLDtyw94PJv9GLQV/nnp3cWlDhMoyKZIQLrx33sWog==", + "optional": true, + "requires": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "2.2.0", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "2.2.0", + "@msgpackr-extract/msgpackr-extract-linux-arm": "2.2.0", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "2.2.0", + "@msgpackr-extract/msgpackr-extract-linux-x64": "2.2.0", + "@msgpackr-extract/msgpackr-extract-win32-x64": "2.2.0", + "node-gyp-build-optional-packages": "5.0.3" + } + }, "multer": { "version": "1.4.4-lts.1", "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz", @@ -16483,6 +17077,14 @@ "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } } } }, @@ -16564,8 +17166,35 @@ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "requires": { "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } } }, + "node-gyp-build-optional-packages": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz", + "integrity": "sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==", + "optional": true + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -16702,6 +17331,11 @@ "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==" + }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -16720,6 +17354,19 @@ "p-limit": "^3.0.2" } }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" + }, + "p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "requires": { + "p-finally": "^1.0.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -17047,6 +17694,42 @@ "resolve": "^1.1.6" } }, + "redis": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/redis/-/redis-3.1.2.tgz", + "integrity": "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==", + "requires": { + "denque": "^1.5.0", + "redis-commands": "^1.7.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0" + }, + "dependencies": { + "denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==" + } + } + }, + "redis-commands": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", + "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==" + }, + "redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==" + }, + "redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "requires": { + "redis-errors": "^1.0.0" + } + }, "reflect-metadata": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", @@ -17229,9 +17912,18 @@ "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, "requires": { "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + } } }, "send": { @@ -17482,6 +18174,11 @@ } } }, + "standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -17771,9 +18468,12 @@ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "requires": { + "punycode": "^2.1.1" + } }, "tree-kill": { "version": "1.2.2", @@ -18097,9 +18797,9 @@ } }, "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" }, "webpack": { "version": "5.75.0", @@ -18147,12 +18847,12 @@ "dev": true }, "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" } }, "which": { diff --git a/chat-server/package.json b/chat-server/package.json index 81d627e..f22f166 100644 --- a/chat-server/package.json +++ b/chat-server/package.json @@ -21,6 +21,7 @@ "test:e2e": "jest --config ./test/jest-e2e.json" }, "dependencies": { + "@nestjs/bull": "^0.6.2", "@nestjs/common": "^9.0.0", "@nestjs/config": "^2.2.0", "@nestjs/core": "^9.0.0", @@ -29,9 +30,14 @@ "@nestjs/platform-socket.io": "^9.2.1", "@nestjs/typeorm": "^9.0.1", "@nestjs/websockets": "^9.2.1", - "cache-manager": "^5.1.4", + "@types/bull": "^4.10.0", + "bull": "^4.10.2", + "cache-manager": "^4.0.0", + "cache-manager-ioredis": "^2.1.0", + "ioredis": "^5.2.4", "mongoose": "^6.8.0", "mysql2": "^2.3.3", + "redis": "^3.1.2", "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", "rxjs": "^7.2.0", @@ -45,6 +51,7 @@ "@types/express": "^4.17.13", "@types/jest": "28.1.8", "@types/node": "^16.0.0", + "@types/redis": "^4.0.11", "@types/supertest": "^2.0.11", "@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/parser": "^5.0.0", diff --git a/chat-server/src/common/entities/chat.entity.ts b/chat-server/src/common/entities/chat.entity.ts deleted file mode 100644 index 28a99fb..0000000 --- a/chat-server/src/common/entities/chat.entity.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { - Column, - CreateDateColumn, - Entity, - JoinColumn, - ManyToOne, - OneToMany, - PrimaryGeneratedColumn, -} from 'typeorm'; - -@Entity() -export class Chat { - @PrimaryGeneratedColumn() - id: number; - - @Column({ type: 'varchar', length: 100 }) - sender: string; // userId - - @Column() - recruitId: number; - - @Column({ type: 'text' }) - content: string; - - @CreateDateColumn() - createdAt: Date; -} diff --git a/chat-server/src/common/schemas/chat.schema.ts b/chat-server/src/common/schemas/chat.schema.ts index 746204d..56bf19d 100644 --- a/chat-server/src/common/schemas/chat.schema.ts +++ b/chat-server/src/common/schemas/chat.schema.ts @@ -1,5 +1,5 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; -import { HydratedDocument } from 'mongoose'; +import { HydratedDocument, now } from 'mongoose'; export type ChatDocument = HydratedDocument; diff --git a/chat-server/src/main.ts b/chat-server/src/main.ts index 085362e..0da22b0 100644 --- a/chat-server/src/main.ts +++ b/chat-server/src/main.ts @@ -3,6 +3,7 @@ import { SocketModule } from './socket.module'; async function bootstrap() { const app = await NestFactory.create(SocketModule); + app.enableCors({ origin: '*', credentials: true }); await app.listen(8080); } bootstrap(); diff --git a/chat-server/src/queue-manager/manager.module.ts b/chat-server/src/queue-manager/manager.module.ts new file mode 100644 index 0000000..57ac565 --- /dev/null +++ b/chat-server/src/queue-manager/manager.module.ts @@ -0,0 +1,23 @@ +import { CacheModule, Module } from '@nestjs/common'; +import * as redisStore from 'cache-manager-ioredis'; +import { ManagerService } from './manager.service'; +import { BullModule } from '@nestjs/bull'; + +@Module({ + imports: [ + CacheModule.registerAsync({ + useFactory: () => { + return { + store: redisStore, + host: 'localhost', + port: 6379, + ttl: 0, + }; + }, + }), + BullModule, + ], + providers: [ManagerService, Map], + exports: [ManagerService], +}) +export class ManagerModule {} diff --git a/chat-server/src/queue-manager/manager.service.ts b/chat-server/src/queue-manager/manager.service.ts new file mode 100644 index 0000000..df0caca --- /dev/null +++ b/chat-server/src/queue-manager/manager.service.ts @@ -0,0 +1,72 @@ +import { CACHE_MANAGER, Inject, Injectable, Scope } from '@nestjs/common'; +import { Cache } from 'cache-manager'; +import * as Bull from 'bull'; +import { Socket } from 'socket.io'; + +@Injectable({ scope: Scope.DEFAULT }) +export class ManagerService { + constructor( + @Inject(CACHE_MANAGER) private redisCache: Cache, + @Inject(Map) private qMap: Map, + @Inject(Map) private sMap: Map, + ) {} + async generateQueue(name: string) { + const queue = new Bull(name); + queue.pause(); + this.qMap.set(name, queue); + return queue; + } + + async deleteOneQueue(name: string) { + const deleteWork = []; + const keyArr = await this.redisCache.store.keys(`bull:${name}:*`); + keyArr.map((key: string) => { + deleteWork.push(this.redisCache.del(key)); + }); // bull.js Queue 지우는용 + this.qMap.delete(name); // 매핑된 인스턴스 지우는용 + return Promise.all(deleteWork); + } + + async deleteManyQueue(recruitId: string) { + const deleteWork = []; + const keyArr = await this.redisCache.store.keys(`bull:${recruitId}:*`); + keyArr.map((key: string) => { + deleteWork.push(this.redisCache.del(key)); + }); // bull.js Queue 지우는용 + const keys = Array.from(this.qMap.keys()).filter( + (key) => key.split(':')[0] === recruitId, + ); + keys.map((key: string) => this.qMap.delete(key)); // 매핑된 모든 인스턴스 지우는용 + } + + // 서버 메모리에서, name(key) 값으로 Queue Instance 가져와서 반환해주기 + getQueue(name: string): Bull.Queue { + return this.qMap.get(name); + } + + getQueueList(recruitId: string) { + const keys = Array.from(this.qMap.keys()).filter( + (key) => key.split(':')[0] === recruitId, + ); + return keys.map((key) => this.qMap.get(key)); + } + + async getQueueSize(name: string) { + const queue = this.qMap.get(name); + if (!queue) return 0; + const { waiting } = await queue.getJobCounts(); + return waiting; + } + + getSocket(name: string): Socket { + return this.sMap.get(name); + } + + setSocket(userId: string, socket: Socket): void { + this.sMap.set(userId, socket); + } + + deleteSocket(userId: string): void { + this.sMap.delete(userId); + } +} diff --git a/chat-server/src/socket.controller.ts b/chat-server/src/socket.controller.ts new file mode 100644 index 0000000..485d8d3 --- /dev/null +++ b/chat-server/src/socket.controller.ts @@ -0,0 +1,68 @@ +import { Body, Controller, Delete, Get, Post, Query } from '@nestjs/common'; +import { throwIfEmpty } from 'rxjs'; +import { ManagerService } from './queue-manager/manager.service'; +import { SocketService } from './socket.service'; + +type BodyDto = { + recruitId: string; + userId?: string; +}; +@Controller() +export class SocketController { + constructor( + private managerService: ManagerService, + private socketService: SocketService, + ) {} + + @Get('unread') + async getUnreadMessage(@Query() bodyDto: BodyDto) { + const { recruitId, userId } = bodyDto; + const queue = this.managerService.getQueue(`${recruitId}:${userId}`); + const { waiting } = await queue.getJobCounts(); + return { statusCode: 201, data: { waiting } }; + } + + // POST localhost:8080/queue {recruitId, userId} + @Post('queue') + async generate(@Body() bodyDto: BodyDto) { + const { recruitId, userId } = bodyDto; + await this.managerService.generateQueue(`${recruitId}:${userId}`); + return { statusCode: 201 }; + } + + // POST localhost:8080/queue/delete/one {recruitId, userId} + @Post('queue/delete/one') + async deleteOne(@Body() bodyDto: BodyDto) { + const { recruitId, userId } = bodyDto; + await this.managerService.deleteOneQueue(`${recruitId}:${userId}`); + return { statusCode: 201 }; + } + + // POST localhost:8080/queue/delete/many {recruitId} + @Post('queue/delete/many') + async deleteMany(@Body() bodyDto: BodyDto) { + const { recruitId } = bodyDto; + await this.managerService.deleteManyQueue(recruitId); + return { statusCode: 201 }; + } + + // GET localhost:8080/chat?userId=pushedrumex&page=2&recruidId=1 + @Get('chat') + async getChat( + @Query() query: { userId: string; page: number; recruitId: number }, + ) { + const { recruitId, userId, page } = query; + const unReadCount = await this.managerService.getQueueSize( + `${recruitId}:${userId}`, + ); + const data = await this.socketService.getRecentMessage( + recruitId, + page, + unReadCount, + ); + return { + statusCode: 200, + data, + }; + } +} diff --git a/chat-server/src/socket.gateway.ts b/chat-server/src/socket.gateway.ts index dc92c16..c736d79 100644 --- a/chat-server/src/socket.gateway.ts +++ b/chat-server/src/socket.gateway.ts @@ -7,8 +7,10 @@ import { WebSocketServer, } from '@nestjs/websockets'; import { Server, Socket } from 'socket.io'; -import { Chat } from './common/entities/chat.entity'; +import { Chat } from './common/schemas/chat.schema'; +import { ManagerService } from './queue-manager/manager.service'; import { SocketService } from './socket.service'; +import * as Bull from 'bull'; @WebSocketGateway({ namespace: 'chat', @@ -18,20 +20,33 @@ import { SocketService } from './socket.service'; }, }) export class SocketGateway implements OnGatewayDisconnect { - constructor(private socketService: SocketService) {} + constructor( + private socketService: SocketService, + private queueService: ManagerService, + ) {} @WebSocketServer() public server: Server; @SubscribeMessage('join') - async handleLogin( + async handleJoin( @MessageBody() data: any, @ConnectedSocket() socket: Socket, ): Promise { - const { recruitId } = data; - socket.join(recruitId.toString()); // room에 입장 + const { recruitId, userId } = data; await this.socketService.setCacheData(socket.id, data); - const recentMsg = await this.socketService.getRecentMessage(recruitId); - socket.emit('server_sent_recent', recentMsg); + this.queueService.setSocket(userId, socket); // 소켓 인스턴스 저장 + const queue = this.queueService.getQueue(`${recruitId}:${userId}`); + if (queue) { + try { + queue.process((job, done) => { + const socketInstance = this.queueService.getSocket(userId); + socketInstance.emit('server_sent_unread', job.data); + done(); + }); + } catch (err) {} + await queue.resume(); + } + // + 이전 메시지를 리버스 인피니트 스크롤로 보내주기 } @SubscribeMessage('client_sent') @@ -39,24 +54,33 @@ export class SocketGateway implements OnGatewayDisconnect { @MessageBody() data: { content: string }, @ConnectedSocket() socket: Socket, ): Promise { + // 해당 모집에 있는 모든 사용자의 큐에 넣어주기 const { content } = data; const { userId, recruitId } = await this.socketService.getCacheData( socket.id, ); + const queueList = this.queueService.getQueueList(recruitId.toString()); const chat = new Chat(); chat.sender = userId; chat.recruitId = recruitId; chat.content = content; chat.createdAt = new Date(); - this.server - .in(recruitId.toString()) - .emit('server_sent', await this.socketService.saveRecentMessage(chat)); + const addWork = []; + queueList.map((queue: Bull.Queue) => { + addWork.push(queue.add(chat)); + }); + Promise.all(addWork); + await this.socketService.saveRecentMessage(chat); } async handleDisconnect(@ConnectedSocket() socket: Socket): Promise { + const { recruitId, userId } = await this.socketService.getCacheData( + socket.id, + ); + const queue = this.queueService.getQueue(`${recruitId}:${userId}`); + this.queueService.deleteSocket(userId); await this.socketService.delCacheData(socket.id); - } - async handleConnection(@ConnectedSocket() socket: Socket): Promise { - await this.socketService.delCacheData(socket.id); + if (!queue) return; + queue.pause(); } } diff --git a/chat-server/src/socket.module.ts b/chat-server/src/socket.module.ts index c90e038..b0fd942 100644 --- a/chat-server/src/socket.module.ts +++ b/chat-server/src/socket.module.ts @@ -1,9 +1,12 @@ import { CacheModule, Module } from '@nestjs/common'; import { SocketGateway } from './socket.gateway'; import { SocketService } from './socket.service'; +import { SocketController } from './socket.controller'; import { ConfigModule } from '@nestjs/config'; import { MongooseModule } from '@nestjs/mongoose'; import { Chat, ChatSchema } from './common/schemas/chat.schema'; +import { BullModule } from '@nestjs/bull'; +import { ManagerModule } from './queue-manager/manager.module'; @Module({ imports: [ @@ -15,7 +18,16 @@ import { Chat, ChatSchema } from './common/schemas/chat.schema'; CacheModule.register({ ttl: 0, }), + + ManagerModule, + BullModule.forRoot({ + redis: { + host: 'redis-server', + port: 6379, + }, + }), ], + controllers: [SocketController], providers: [SocketGateway, SocketService], }) export class SocketModule {} diff --git a/chat-server/src/socket.service.ts b/chat-server/src/socket.service.ts index 6638e60..c11fb60 100644 --- a/chat-server/src/socket.service.ts +++ b/chat-server/src/socket.service.ts @@ -3,6 +3,7 @@ import { Cache } from 'cache-manager'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { Chat, ChatDocument } from './common/schemas/chat.schema'; +import { ManagerService } from './queue-manager/manager.service'; type CacheValue = { userId: string; @@ -13,6 +14,7 @@ export class SocketService { constructor( @Inject(CACHE_MANAGER) private cacheManager: Cache, @InjectModel(Chat.name) private chatModel: Model, + private managerService: ManagerService, ) {} async getCacheData(socketId: string): Promise { @@ -27,23 +29,16 @@ export class SocketService { return this.cacheManager.del(`id:${socketId}`); } - async getRecentMessage(recruitId: number) { + async getRecentMessage(recruitId: number, page = 1, unReadCount = 0) { const response = await this.chatModel .find({ recruitId }) .sort({ createdAt: -1 }) - .limit(10); + .skip((page - 1) * 20 + unReadCount) + .limit(20); return response.reverse(); } async saveRecentMessage(chatEntity: Chat) { return this.chatModel.create(chatEntity); } - - async getLatestMessage(recruitId: number) { - const response = await this.chatModel - .find({ recruitId }) - .sort({ createdAt: -1 }) - .limit(1); - return response[0]; - } } diff --git a/client/src/components/Chat/Chat.tsx b/client/src/components/Chat/Chat.tsx index 942dcb1..115afcf 100644 --- a/client/src/components/Chat/Chat.tsx +++ b/client/src/components/Chat/Chat.tsx @@ -29,10 +29,11 @@ const Chat = () => { if (!userId) return; const socket = io(import.meta.env.VITE_CHAT_URL, { autoConnect: true, reconnection: false }); socket.emit(SOCKET_EVENT.JOIN, { userId, recruitId: Number(id) }); - socket.on(SOCKET_EVENT.SERVER_SENT_RECENT, setChatList); - socket.on(SOCKET_EVENT.SERVER_SENT, (data) => setChatList((prev) => [...prev, data])); + // socket.on(SOCKET_EVENT.SERVER_SENT_RECENT, setChatList); + // socket.on(SOCKET_EVENT.SERVER_SENT, (data) => setChatList((prev) => [...prev, data])); + socket.on(SOCKET_EVENT.SERVER_SENT_UNREAD, (data) => setChatList((prev) => [...prev, data])); socketRef.current = socket; - () => { + return () => { socket.disconnect(); }; }, [userId]); @@ -48,7 +49,7 @@ const Chat = () => { return ( - + ); diff --git a/client/src/components/Chat/ChatList/ChatList.tsx b/client/src/components/Chat/ChatList/ChatList.tsx index 1c1a8b1..a01e4cc 100644 --- a/client/src/components/Chat/ChatList/ChatList.tsx +++ b/client/src/components/Chat/ChatList/ChatList.tsx @@ -1,9 +1,15 @@ +import useChatHistoryQuery from "#hooks/queries/useChatQuery"; import { ChatResponse } from "#types/Chat"; -import { useEffect, useRef } from "react"; +import { Dispatch, SetStateAction, useEffect, useRef } from "react"; +import InfiniteScroll from "react-infinite-scroller"; +import { useParams } from "react-router-dom"; import styled from "styled-components"; +import { flexColumn } from "styles/flex"; import ChatItem from "../ChatItem/ChatItem"; const ChatListContainer = styled.div` + ${flexColumn({})}; + flex-direction: column-reverse; padding: 15px; width: 100%; height: inherit; @@ -17,10 +23,19 @@ const ChatListContainer = styled.div` interface ChatListProps { data: ChatResponse[]; + setChatList: Dispatch>; } -const ChatList = ({ data }: ChatListProps) => { +const ChatList = ({ data, setChatList }: ChatListProps) => { + const { id } = useParams(); const scrollRef = useRef(null); + const { data: chatHistory, fetchNextPage, hasNextPage } = useChatHistoryQuery({ recruitId: Number(id) }); + + useEffect(() => { + if (chatHistory?.pages?.at(-1)?.data === undefined) return; + // console.log(chatHistory?.pages?.at(-1)?.data); + setChatList((prev) => [...prev, ...(chatHistory?.pages?.at(-1)?.data || [])]); + }, [chatHistory]); useEffect(() => { scrollRef.current?.scrollTo(0, scrollRef.current.scrollHeight); @@ -28,9 +43,16 @@ const ChatList = ({ data }: ChatListProps) => { return ( - {data.map((el, idx) => ( - - ))} + fetchNextPage()} + hasMore={hasNextPage} + isReverse={true} + loader={
...loading
} + > + {data.map((el, idx) => ( + + ))} +
); }; diff --git a/client/src/constants/socketEvents.ts b/client/src/constants/socketEvents.ts index 1fc562f..6ab06d2 100644 --- a/client/src/constants/socketEvents.ts +++ b/client/src/constants/socketEvents.ts @@ -3,4 +3,5 @@ export enum SOCKET_EVENT { SERVER_SENT = "server_sent", CLIENT_SENT = "client_sent", SERVER_SENT_RECENT = "server_sent_recent", + SERVER_SENT_UNREAD = "server_sent_unread", } diff --git a/client/src/hooks/queries/useChatQuery.ts b/client/src/hooks/queries/useChatQuery.ts new file mode 100644 index 0000000..e157ec8 --- /dev/null +++ b/client/src/hooks/queries/useChatQuery.ts @@ -0,0 +1,29 @@ +import { userState } from "#atoms/userState"; +import { ChatResponse } from "#types/Chat"; +import HttpResponse from "#types/dto/HttpResponse"; +import { useInfiniteQuery } from "@tanstack/react-query"; +import axios from "axios"; +import { useRecoilValue } from "recoil"; + +const useChatHistoryQuery = ({ recruitId }: { recruitId: number }) => { + const { userId } = useRecoilValue(userState); + return useInfiniteQuery( + ["chats", recruitId], + ({ pageParam = 1 }) => + axios + .get>("/chat", { + baseURL: import.meta.env.VITE_CHAT_API_URL, + params: { + recruitId, + userId, + page: pageParam, + }, + }) + .then((res) => res.data), + { + getNextPageParam: (lastPage, allPages) => (lastPage ? lastPage?.data.length > 0 && allPages.length + 1 : 1), + suspense: false, + }, + ); +}; +export default useChatHistoryQuery; diff --git a/noti-server/src/app.service.ts b/noti-server/src/app.service.ts index e0fd559..13e4ecf 100644 --- a/noti-server/src/app.service.ts +++ b/noti-server/src/app.service.ts @@ -27,11 +27,12 @@ export class AppService { // 30분 전 시작 알림 createRecruitMessage(body: any) { - const { recruitId, user, title, hDong, startTime, pathLength } = body; + console.log(body); + const { recruitId, author, title, hDong, startTime, pathLength } = body; const result = {}; result['type'] = 'recruit'; - result['email'] = user.email; // 이메일 하나 + result['email'] = author.email; // 이메일 하나 result['data'] = { title, hName: hDong.name, diff --git a/server/src/recruit/recruit.controller.ts b/server/src/recruit/recruit.controller.ts index c084dd0..1830894 100644 --- a/server/src/recruit/recruit.controller.ts +++ b/server/src/recruit/recruit.controller.ts @@ -14,11 +14,16 @@ import { UnjoinRecruitRequestDto } from "./dto/request/unjoin-recruit.request"; import { HttpService } from "@nestjs/axios"; import { AxiosError } from "axios"; import { catchError, firstValueFrom } from "rxjs"; +import { UserService } from "src/user/user.service"; @Controller("recruit") @ApiTags("모집글 관리") export class RecruitController { - constructor(private readonly recruitService: RecruitService, private httpService: HttpService) {} + constructor( + private readonly recruitService: RecruitService, + private httpService: HttpService, + private userService: UserService, + ) {} @ApiOperation({ summary: "모집글 조회/검색/필터", description: "등록된 모집글들을 조회/검색/필터링한다" }) @Get() @@ -34,6 +39,23 @@ export class RecruitController { const recruitEntity = await this.recruitService.create(createRecruitDto); const recruitDetail = await this.recruitService.notiGetOne(createRecruitDto.getUserId(), recruitEntity.id); + const { id: recruitId, userId: userIdx } = recruitEntity; + const userId = await this.userService.getUserIdByUserIdx(userIdx); + + // 메시지 큐 만드는 요청 + await firstValueFrom( + this.httpService + .post(`${process.env.CHAT_SERVER_API_URL}/queue`, { + recruitId, + userId, + }) + .pipe( + catchError((error: AxiosError) => { + throw error; + }), + ), + ); + if (recruitDetail.author) { await firstValueFrom( this.httpService @@ -76,6 +98,18 @@ export class RecruitController { ); const users = await this.recruitService.getUsersByRecruitId(deleteRecruitRequestDto.getRecruitId()); + await firstValueFrom( + this.httpService + .post(`${process.env.NOTI_SERVER_API_URL}/queue/delete/many`, { + recruitId: deleteRecruitRequestDto.getRecruitId(), + }) + .pipe( + catchError((error: AxiosError) => { + throw error; + }), + ), + ); + if (users.length) { await firstValueFrom( this.httpService @@ -128,6 +162,20 @@ export class RecruitController { ); const user = await this.recruitService.getUserByIdx(joinRecruitRequestDto.getUserId()); const { email, userId } = user; + + await firstValueFrom( + this.httpService + .post(`${process.env.CHAT_SERVER_API_URL}/queue`, { + recruitId: joinRecruitRequestDto.getRecruitId(), + userId, + }) + .pipe( + catchError((error: AxiosError) => { + throw error; + }), + ), + ); + if (user) { await firstValueFrom( this.httpService @@ -159,6 +207,19 @@ export class RecruitController { const user = await this.recruitService.getUserByIdx(unjoinRecruitRequestDto.getUserId()); const { email, userId } = user; + await firstValueFrom( + this.httpService + .post(`${process.env.CHAT_SERVER_API_URL}/queue/delete/one`, { + recruitId: unjoinRecruitRequestDto.getRecruitId(), + userId: unjoinRecruitRequestDto.getUserId(), + }) + .pipe( + catchError((error: AxiosError) => { + throw error; + }), + ), + ); + if (user) { await firstValueFrom( this.httpService diff --git a/server/src/recruit/recruit.module.ts b/server/src/recruit/recruit.module.ts index 0722043..6ca9bbf 100644 --- a/server/src/recruit/recruit.module.ts +++ b/server/src/recruit/recruit.module.ts @@ -7,12 +7,14 @@ import { UserRecruitRepository } from "../common/repositories/user_recruit.repos import { RecruitRepository } from "../common/repositories/recruit.repository"; import { CustomJwtModule } from "../common/modules/custom-jwt/custom-jwt.module"; import { HttpModule } from "@nestjs/axios"; +import { UserModule } from "src/user/user.module"; @Module({ imports: [ TypeOrmCustomModule.forCustomRepository([RecruitRepository, UserRepository, UserRecruitRepository]), CustomJwtModule, HttpModule, + UserModule, ], providers: [RecruitService], controllers: [RecruitController], diff --git a/server/src/user/user.module.ts b/server/src/user/user.module.ts index ded33e2..ae8b0b3 100644 --- a/server/src/user/user.module.ts +++ b/server/src/user/user.module.ts @@ -16,5 +16,6 @@ import { HttpModule } from "@nestjs/axios"; ], providers: [UserService], controllers: [UserController], + exports: [UserService], }) export class UserModule {} diff --git a/server/src/user/user.service.ts b/server/src/user/user.service.ts index 862a524..ceaf931 100644 --- a/server/src/user/user.service.ts +++ b/server/src/user/user.service.ts @@ -63,4 +63,9 @@ export class UserService { return { userId, hDong: { name: h_dong_name }, pace }; } + + async getUserIdByUserIdx(_userIdx: number) { + const { userId } = await this.userRepository.findOneByUserIdx(_userIdx); + return userId; + } }