diff --git a/packages/backend/package.json b/packages/backend/package.json index 0f829e9..7b0b05b 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -28,6 +28,7 @@ }, "dependencies": { "@aws-sdk/client-s3": "^3.731.1", + "@nestjs/bull": "^11.0.2", "@nestjs/cache-manager": "^2.3.0", "@nestjs/common": "^10.0.0", "@nestjs/config": "^3.3.0", @@ -38,8 +39,10 @@ "@nestjs/platform-express": "^10.0.0", "@nestjs/swagger": "^8.1.0", "@prisma/client": "^6.0.1", + "@types/bull": "^4.10.4", "@types/nodemailer": "^6.4.17", "axios": "^1.7.9", + "bull": "^4.16.5", "cache-manager-redis-yet": "^5.1.5", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", diff --git a/packages/backend/src/app.module.ts b/packages/backend/src/app.module.ts index 504c1d7..c10fcf0 100644 --- a/packages/backend/src/app.module.ts +++ b/packages/backend/src/app.module.ts @@ -16,6 +16,8 @@ import { CharacterModule } from './character/character.module'; import { ProofModule } from './proof/proof.module'; import { DuplicateRequestMiddleware } from './common/duplicate-request.middleware'; import { NotificationModule } from './notification/notification.module'; +import { QueueModule } from './queue/queue.module'; +import { BullModule } from '@nestjs/bull'; @Module({ imports: [ @@ -25,6 +27,16 @@ import { NotificationModule } from './notification/notification.module'; load: [configuration], isGlobal: true, }), + BullModule.forRootAsync({ + inject: [ConfigService], + useFactory: async (config: ConfigService) => ({ + redis: { + host: config.get('redis.host'), + port: config.get('redis.port'), + password: config.get('redis.password'), + }, + }), + }), CacheModule.registerAsync({ isGlobal: true, inject: [ConfigService], @@ -48,6 +60,7 @@ import { NotificationModule } from './notification/notification.module'; CharacterModule, ProofModule, NotificationModule, + QueueModule, ], controllers: [AppController], providers: [AppService], diff --git a/packages/backend/src/group/group.service.ts b/packages/backend/src/group/group.service.ts index 555092f..ea23920 100644 --- a/packages/backend/src/group/group.service.ts +++ b/packages/backend/src/group/group.service.ts @@ -63,6 +63,9 @@ import { GetGalleryParam } from './dtos/get-gallery-param.dto'; import { GetGalleryRes } from './dtos/get-gallery-res.dto'; import { UpdateGroupQuery } from './dtos/update-group-query.dto'; import { LeaveGroupHelper } from './utils/leave-group.helper'; +import { InjectQueue } from '@nestjs/bull'; +import { NOTIFICATION_PROCESSOR } from '@/queue/utils/constants'; +import { Queue } from 'bull'; @Injectable() export class GroupService { @@ -74,6 +77,8 @@ export class GroupService { private readonly prisma: PrismaService, private readonly s3: S3Service, private readonly characterService: CharacterRewardService, + @InjectQueue(NOTIFICATION_PROCESSOR.QUEUE) + private readonly notiQueue: Queue, ) {} /** @@ -591,6 +596,7 @@ export class GroupService { group, wallet, this.prisma, + this.notiQueue, ); return join.joinRole === JoinRole.HOST diff --git a/packages/backend/src/group/utils/leave-group.helper.ts b/packages/backend/src/group/utils/leave-group.helper.ts index d2146fe..e2c75e7 100644 --- a/packages/backend/src/group/utils/leave-group.helper.ts +++ b/packages/backend/src/group/utils/leave-group.helper.ts @@ -9,6 +9,7 @@ import * as utc from 'dayjs/plugin/utc'; import * as timezone from 'dayjs/plugin/timezone'; import { PrismaService } from '@/prisma/prisma.service'; import { VisibleForTesting } from '@/common/visible-for-testing.decorator'; +import { Queue } from 'bull'; dayjs.extend(utc); dayjs.extend(timezone); @@ -31,12 +32,14 @@ export class LeaveGroupHelper { // leave group private readonly joinId: number; private readonly myWallet: Wallet; + private readonly notiQueue: Queue; constructor( join: JoinForLeave, group: GroupForLeave, wallet: Wallet, prisma: PrismaService, + notiQueue: Queue, ) { this.groupDates = group.groupDate .map((d) => dayjs(d.date).tz('Asia/Seoul')) @@ -53,6 +56,7 @@ export class LeaveGroupHelper { this.joinId = join.id; this.myWallet = wallet; this.now = dayjs().tz('Asia/Seoul'); + this.notiQueue = notiQueue; } /** @@ -211,6 +215,10 @@ export class LeaveGroupHelper { if (this.existMyProof) return false; if (this.now.diff(this.joinedAt, 'hour') < 1) return true; + if (this.groupDates.length === 0) { + throw new UnprocessableEntityException('그룹 날짜가 없습니다.'); + } + const earliestGroupDate = this.groupDates[0]; const isBeforeGroup = this.now.isBefore(earliestGroupDate.startOf('day')); diff --git a/packages/backend/src/notification/notification-store.service.ts b/packages/backend/src/notification/notification-store.service.ts deleted file mode 100644 index 55aedbb..0000000 --- a/packages/backend/src/notification/notification-store.service.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { PrismaService } from '@/prisma/prisma.service'; -import { Injectable } from '@nestjs/common'; -import { CreateDeletedGroupNotiParams } from './utils/types'; -import { NotificationType } from '@prisma/client'; - -@Injectable() -export class NotificationStoreService { - constructor(private readonly prisma: PrismaService) {} - - async createDeletedGroupNoti(params: CreateDeletedGroupNotiParams) { - const { userId, groupId, refundAmount, groupName } = params; - - return await this.prisma.notification.create({ - data: { - userId, - groupId, - moneyChange: refundAmount, - type: NotificationType.DELETED_ROOM, - title: `${groupName} 모임이 종료되었습니다.`, - content: `방을 만든 사람이 방을 폭파했습니다. 총 ${refundAmount}원을 환불 받았습니다.`, - }, - }); - } -} diff --git a/packages/backend/src/notification/notification.module.ts b/packages/backend/src/notification/notification.module.ts index 493fe73..c2ad498 100644 --- a/packages/backend/src/notification/notification.module.ts +++ b/packages/backend/src/notification/notification.module.ts @@ -1,12 +1,9 @@ -import { Global, Module } from '@nestjs/common'; +import { Module } from '@nestjs/common'; import { NotificationService } from './notification.service'; import { NotificationController } from './notification.controller'; -import { NotificationStoreService } from './notification-store.service'; -@Global() @Module({ controllers: [NotificationController], - providers: [NotificationService, NotificationStoreService], - exports: [NotificationStoreService], + providers: [NotificationService], }) export class NotificationModule {} diff --git a/packages/backend/src/queue/noti-queue.service.ts b/packages/backend/src/queue/noti-queue.service.ts new file mode 100644 index 0000000..3c30b30 --- /dev/null +++ b/packages/backend/src/queue/noti-queue.service.ts @@ -0,0 +1,55 @@ +import { + Injectable, + InternalServerErrorException, + Logger, +} from '@nestjs/common'; +import { Process, Processor } from '@nestjs/bull'; +import { Job } from 'bull'; +import { NOTIFICATION_PROCESSOR } from './utils/constants'; +import { CreateDeletedGroupNotiParams } from './utils/types'; +import { PrismaService } from '@/prisma/prisma.service'; +import { NotificationType } from '@prisma/client'; + +@Injectable() +@Processor(NOTIFICATION_PROCESSOR.QUEUE) +export class NotiQueueService { + constructor(private readonly prisma: PrismaService) {} + + private readonly logger = new Logger(NotiQueueService.name, { + timestamp: true, + }); + + @Process(NOTIFICATION_PROCESSOR.MISSION.DELETED_ROOM) + async processDeletedGroupNotification( + job: Job, + ) { + const { data } = job; + const { userId, groupId, refundAmount, groupName } = data; + + this.logger.debug( + `${groupName} 모임이 삭제되어 참여한 사용자 (userId: ${userId})에게 알림을 보냅니다.`, + ); + + return await this.prisma.notification + .create({ + data: { + userId, + groupId, + moneyChange: refundAmount, + type: NotificationType.DELETED_ROOM, + title: `${groupName} 모임이 종료되었습니다.`, + content: `방을 만든 사람이 방을 폭파했습니다. 총 ${refundAmount}원을 환불 받았습니다.`, + }, + }) + .catch((err) => { + this.logger.error( + `알림 저장 실패 (userId: ${userId}, groupId: ${groupId})`, + err, + ); + + throw new InternalServerErrorException( + `${groupName} 모임 폭파에 대한 사용자 (userId: ${userId})에게 노출될 알림을 저장할 수 없습니다.`, + ); + }); + } +} diff --git a/packages/backend/src/queue/queue.module.ts b/packages/backend/src/queue/queue.module.ts new file mode 100644 index 0000000..673f0a4 --- /dev/null +++ b/packages/backend/src/queue/queue.module.ts @@ -0,0 +1,16 @@ +import { Global, Module } from '@nestjs/common'; +import { BullModule } from '@nestjs/bull'; +import { NotiQueueService } from './noti-queue.service'; +import { NOTIFICATION_PROCESSOR } from './utils/constants'; + +@Global() +@Module({ + imports: [ + BullModule.registerQueue({ + name: NOTIFICATION_PROCESSOR.QUEUE, + }), + ], + providers: [NotiQueueService], + exports: [BullModule], +}) +export class QueueModule {} diff --git a/packages/backend/src/queue/utils/constants.ts b/packages/backend/src/queue/utils/constants.ts new file mode 100644 index 0000000..200be68 --- /dev/null +++ b/packages/backend/src/queue/utils/constants.ts @@ -0,0 +1,17 @@ +import { NotificationType } from '@prisma/client'; + +interface ProcessorDefinition { + QUEUE: string; + MISSION: { + [key in keyof T]: T[key]; + }; +} + +export const NOTIFICATION_PROCESSOR: ProcessorDefinition< + typeof NotificationType +> = { + QUEUE: 'notification', + MISSION: { + ...NotificationType, + }, +}; diff --git a/packages/backend/src/notification/utils/types.ts b/packages/backend/src/queue/utils/types.ts similarity index 100% rename from packages/backend/src/notification/utils/types.ts rename to packages/backend/src/queue/utils/types.ts diff --git a/yarn.lock b/yarn.lock index 01e83d0..bd50dd0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1980,6 +1980,11 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== +"@ioredis/commands@^1.1.1": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11" + integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg== + "@isaacs/cliui@^8.0.2": version "8.0.2" resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" @@ -2480,6 +2485,36 @@ resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.15.1.tgz#d4f6937353bc4568292654efb0a0e0532adbcba2" integrity sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw== +"@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz#9edec61b22c3082018a79f6d1c30289ddf3d9d11" + integrity sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw== + +"@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz#33677a275204898ad8acbf62734fc4dc0b6a4855" + integrity sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw== + +"@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz#19edf7cdc2e7063ee328403c1d895a86dd28f4bb" + integrity sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg== + +"@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz#94fb0543ba2e28766c3fc439cabbe0440ae70159" + integrity sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw== + +"@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz#4a0609ab5fe44d07c9c60a11e4484d3c38bbd6e3" + integrity sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg== + +"@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz#0aa5502d547b57abfc4ac492de68e2006e417242" + integrity sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ== + "@mui/core-downloads-tracker@^6.4.6": version "6.4.6" resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-6.4.6.tgz#42820be160159df81976f467ce496f5310e08eb1" @@ -2576,6 +2611,21 @@ "@babel/runtime" "^7.25.7" "@mui/utils" "^5.16.6 || ^6.0.0" +"@nestjs/bull-shared@^11.0.2": + version "11.0.2" + resolved "https://registry.yarnpkg.com/@nestjs/bull-shared/-/bull-shared-11.0.2.tgz#dd12c404c68f130b4d1c2486c533d4c6e58b9b17" + integrity sha512-dFlttJvBqIFD6M8JVFbkrR4Feb39OTAJPJpFVILU50NOJCM4qziRw3dSNG84Q3v+7/M6xUGMFdZRRGvBBKxoSA== + dependencies: + tslib "2.8.1" + +"@nestjs/bull@^11.0.2": + version "11.0.2" + resolved "https://registry.yarnpkg.com/@nestjs/bull/-/bull-11.0.2.tgz#53c5af2e87405fe1f99b562c497e7bd9df802bcf" + integrity sha512-RjyP9JZUuLmMhmq1TMNIZqolkAd14az1jyXMMVki+C9dYvaMjWzBSwcZAtKs9Pk15Rm7qN1xn3R11aMV2Xv4gg== + dependencies: + "@nestjs/bull-shared" "^11.0.2" + tslib "2.8.1" + "@nestjs/cache-manager@^2.3.0": version "2.3.0" resolved "https://registry.yarnpkg.com/@nestjs/cache-manager/-/cache-manager-2.3.0.tgz#e318ba56856c89b34f158efe9ca749fe3886dfa9" @@ -3666,6 +3716,13 @@ dependencies: "@types/node" "*" +"@types/bull@^4.10.4": + version "4.10.4" + resolved "https://registry.yarnpkg.com/@types/bull/-/bull-4.10.4.tgz#c7a09c3151d079db5088588719ba2982e2b15dcf" + integrity sha512-A+8uxa5GbzKcS7kZ9Z1OcOeSyrvVmfHtZi3VIrH1Gws0G0sTknB2SRllxTaAYhycGn7+nC0Pb8VjxIyZiTM81A== + dependencies: + bull "*" + "@types/connect-history-api-fallback@^1.3.5": version "1.5.4" resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz#7de71645a103056b48ac3ce07b3520b819c1d5b3" @@ -5223,6 +5280,19 @@ builtin-modules@^3.1.0: resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== +bull@*, bull@^4.16.5: + version "4.16.5" + resolved "https://registry.yarnpkg.com/bull/-/bull-4.16.5.tgz#855a17e7880862a231dac3c8a6392c77668ce49d" + integrity sha512-lDsx2BzkKe7gkCYiT5Acj02DpTwDznl/VNN7Psn7M3USPG7Vs/BaClZJJTAG+ufAR9++N1/NiUTdaFBWDIl5TQ== + dependencies: + cron-parser "^4.9.0" + get-port "^5.1.1" + ioredis "^5.3.2" + lodash "^4.17.21" + msgpackr "^1.11.2" + semver "^7.5.2" + uuid "^8.3.0" + busboy@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" @@ -5490,7 +5560,7 @@ clsx@^2.1.1: resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== -cluster-key-slot@1.1.2: +cluster-key-slot@1.1.2, cluster-key-slot@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== @@ -5814,6 +5884,13 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +cron-parser@^4.9.0: + version "4.9.0" + resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-4.9.0.tgz#0340694af3e46a0894978c6f52a6dbb5c0f11ad5" + integrity sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q== + dependencies: + luxon "^3.2.1" + cross-env@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" @@ -6193,6 +6270,11 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== +denque@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" + integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== + depd@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" @@ -6208,6 +6290,11 @@ destroy@1.2.0: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== +detect-libc@^2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.4.tgz#f04715b8ba815e53b4d8109655b6508a6865a7e8" + integrity sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA== + detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -7497,6 +7584,11 @@ get-package-type@^0.1.0: resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== +get-port@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" + integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== + get-stream@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" @@ -8016,6 +8108,21 @@ internal-slot@^1.0.4, internal-slot@^1.0.7: hasown "^2.0.0" side-channel "^1.0.4" +ioredis@^5.3.2: + version "5.6.1" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.6.1.tgz#1ed7dc9131081e77342503425afceaf7357ae599" + integrity sha512-UxC0Yv1Y4WRJiGQxQkP0hfdL0/5/6YvdfOOClRgJ0qppSarkhneSa6UvkMkms0AkdGimSH3Ikqm+6mkMmX7vGA== + dependencies: + "@ioredis/commands" "^1.1.1" + cluster-key-slot "^1.1.0" + debug "^4.3.4" + denque "^2.1.0" + 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" + ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" @@ -9555,11 +9662,21 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== + lodash.includes@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== +lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== + lodash.isboolean@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" @@ -9654,6 +9771,11 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" +luxon@^3.2.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.6.1.tgz#d283ffc4c0076cb0db7885ec6da1c49ba97e47b0" + integrity sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ== + lz-string@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" @@ -9847,6 +9969,27 @@ ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +msgpackr-extract@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz#e9d87023de39ce714872f9e9504e3c1996d61012" + integrity sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA== + dependencies: + node-gyp-build-optional-packages "5.2.2" + optionalDependencies: + "@msgpackr-extract/msgpackr-extract-darwin-arm64" "3.0.3" + "@msgpackr-extract/msgpackr-extract-darwin-x64" "3.0.3" + "@msgpackr-extract/msgpackr-extract-linux-arm" "3.0.3" + "@msgpackr-extract/msgpackr-extract-linux-arm64" "3.0.3" + "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.3" + "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.3" + +msgpackr@^1.11.2: + version "1.11.4" + resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.11.4.tgz#14703caead8ee0c2e7c89417de5a3ec94adf5d3e" + integrity sha512-uaff7RG9VIC4jacFW9xzL3jc0iM32DNHe4jYVycBcjUePT/Klnfj7pqtWJt9khvDFizmjN2TlYniYmSS2LIaZg== + optionalDependencies: + msgpackr-extract "^3.0.2" + multer@1.4.4-lts.1: version "1.4.4-lts.1" resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.4-lts.1.tgz#24100f701a4611211cfae94ae16ea39bb314e04d" @@ -9961,6 +10104,13 @@ node-forge@^1: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== +node-gyp-build-optional-packages@5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz#522f50c2d53134d7f3a76cd7255de4ab6c96a3a4" + integrity sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw== + dependencies: + detect-libc "^2.0.1" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -11557,6 +11707,18 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w== + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A== + dependencies: + redis-errors "^1.0.0" + redis@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/redis/-/redis-4.7.0.tgz#b401787514d25dd0cfc22406d767937ba3be55d6" @@ -11960,6 +12122,11 @@ semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.5.3, semve resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== +semver@^7.5.2: + version "7.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" + integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== + send@0.19.0: version "0.19.0" resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" @@ -12270,6 +12437,11 @@ stackframe@^1.3.4: resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310" integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw== +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + static-eval@2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.0.2.tgz#2d1759306b1befa688938454c546b7871f806a42" @@ -13284,7 +13456,7 @@ utils-merge@1.0.1, utils-merge@1.x.x, utils-merge@^1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -uuid@^8.3.2: +uuid@^8.3.0, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==