diff --git a/packages/server-nest/package.json b/packages/server-nest/package.json index 9ae666cf1..5f6c47683 100644 --- a/packages/server-nest/package.json +++ b/packages/server-nest/package.json @@ -24,6 +24,7 @@ "@bigcapital/pdf-templates": "*", "@bigcapital/server": "*", "@bigcapital/utils": "*", + "@liaoliaots/nestjs-redis": "^10.0.0", "@nestjs/bull": "^10.2.1", "@nestjs/bullmq": "^10.2.2", "@nestjs/cache-manager": "^2.2.2", @@ -55,6 +56,7 @@ "express-validator": "^7.2.0", "form-data": "^4.0.0", "fp-ts": "^2.16.9", + "ioredis": "^5.6.0", "is-my-json-valid": "^2.20.5", "js-money": "^0.6.3", "knex": "^3.1.0", @@ -66,6 +68,7 @@ "mysql2": "^3.11.3", "nestjs-cls": "^5.2.0", "nestjs-i18n": "^10.4.9", + "nestjs-redis": "^1.3.3", "nodemailer": "^6.3.0", "object-hash": "^2.0.3", "objection": "^3.1.5", diff --git a/packages/server-nest/src/common/config/redis.ts b/packages/server-nest/src/common/config/redis.ts new file mode 100644 index 000000000..8545489b7 --- /dev/null +++ b/packages/server-nest/src/common/config/redis.ts @@ -0,0 +1,8 @@ +import { registerAs } from '@nestjs/config'; + +export default registerAs('redis', () => ({ + host: process.env.REDIS_HOST || 'localhost', + port: parseInt(process.env.REDIS_PORT, 10) || 6379, + password: process.env.REDIS_PASSWORD || undefined, + db: parseInt(process.env.REDIS_DB, 10) || 0, +})); diff --git a/packages/server-nest/src/modules/Accounts/repositories/Account.repository.ts b/packages/server-nest/src/modules/Accounts/repositories/Account.repository.ts index bf93f3eee..bad983ea3 100644 --- a/packages/server-nest/src/modules/Accounts/repositories/Account.repository.ts +++ b/packages/server-nest/src/modules/Accounts/repositories/Account.repository.ts @@ -23,7 +23,7 @@ export class AccountRepository extends TenantRepository { private readonly tenancyContext: TenancyContext, @Inject(TENANCY_DB_CONNECTION) - private readonly tenantDBKnex: Knex, + private readonly tenantDBKnex: () => Knex, ) { super(); } @@ -32,7 +32,7 @@ export class AccountRepository extends TenantRepository { * Gets the repository's model. */ get model(): typeof Account { - return Account.bindKnex(this.tenantDBKnex); + return Account.bindKnex(this.tenantDBKnex()); } /** diff --git a/packages/server-nest/src/modules/App/App.module.ts b/packages/server-nest/src/modules/App/App.module.ts index bbacc4100..fca7c6d55 100644 --- a/packages/server-nest/src/modules/App/App.module.ts +++ b/packages/server-nest/src/modules/App/App.module.ts @@ -71,6 +71,7 @@ import { StripePaymentModule } from '../StripePayment/StripePayment.module'; import { FeaturesModule } from '../Features/Features.module'; import { InventoryCostModule } from '../InventoryCost/InventoryCost.module'; import { WarehousesTransfersModule } from '../WarehousesTransfers/WarehouseTransfers.module'; +import { RedisModule } from '@liaoliaots/nestjs-redis'; @Module({ imports: [ @@ -124,6 +125,16 @@ import { WarehousesTransfersModule } from '../WarehousesTransfers/WarehouseTrans saveReq: true, }, }), + RedisModule.forRootAsync({ + imports: [ConfigModule], + useFactory: (configService: ConfigService) => ({ + config: { + host: configService.get('redis.host') || 'localhost', + port: configService.get('redis.port') || 6379, + }, + }), + inject: [ConfigService], + }), TenancyDatabaseModule, TenancyModelsModule, ChromiumlyTenancyModule, diff --git a/packages/server-nest/src/modules/App/App.service.ts b/packages/server-nest/src/modules/App/App.service.ts index df40128b2..9456b62c9 100644 --- a/packages/server-nest/src/modules/App/App.service.ts +++ b/packages/server-nest/src/modules/App/App.service.ts @@ -12,13 +12,10 @@ export class AppService { ) {} getHello(): string { - console.log(this.configService.get('DATABASE_PORT')); const payload = {}; const accessToken = this.jwtService.sign(payload); - console.log(accessToken); - return accessToken; } } diff --git a/packages/server-nest/src/modules/Import/Import.module.ts b/packages/server-nest/src/modules/Import/Import.module.ts new file mode 100644 index 000000000..6e007f702 --- /dev/null +++ b/packages/server-nest/src/modules/Import/Import.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { ImportAls } from './ImportALS'; + +@Module({ + providers: [ImportAls], + exports: [ImportAls], +}) +export class ImportModule {} diff --git a/packages/server-nest/src/modules/InventoryCost/InventoryCost.module.ts b/packages/server-nest/src/modules/InventoryCost/InventoryCost.module.ts index 5e0be9452..c9d2891bd 100644 --- a/packages/server-nest/src/modules/InventoryCost/InventoryCost.module.ts +++ b/packages/server-nest/src/modules/InventoryCost/InventoryCost.module.ts @@ -1,4 +1,4 @@ -import { Module } from '@nestjs/common'; +import { forwardRef, Module } from '@nestjs/common'; import { InventoryCostGLStorage } from './commands/InventoryCostGLStorage.service'; import { RegisterTenancyModel } from '../Tenancy/TenancyModels/Tenancy.module'; import { InventoryCostLotTracker } from './models/InventoryCostLotTracker'; @@ -20,6 +20,9 @@ import { BullModule } from '@nestjs/bullmq'; import { InventoryAverageCostMethodService } from './commands/InventoryAverageCostMethod.service'; import { InventoryItemCostService } from './commands/InventoryCosts.service'; import { InventoryItemOpeningAvgCostService } from './commands/InventoryItemOpeningAvgCost.service'; +import { InventoryCostSubscriber } from './subscribers/InventoryCost.subscriber'; +import { SaleInvoicesModule } from '../SaleInvoices/SaleInvoices.module'; +import { ImportModule } from '../Import/Import.module'; const models = [ RegisterTenancyModel(InventoryCostLotTracker), @@ -34,6 +37,8 @@ const models = [ BullModule.registerQueue({ name: WriteInventoryTransactionsGLEntriesQueue, }), + forwardRef(() => SaleInvoicesModule), + ImportModule, ], providers: [ InventoryCostGLBeforeWriteSubscriber, @@ -48,7 +53,13 @@ const models = [ InventoryAverageCostMethodService, InventoryItemCostService, InventoryItemOpeningAvgCostService, + InventoryCostSubscriber, + ], + exports: [ + ...models, + InventoryTransactionsService, + InventoryItemCostService, + InventoryComputeCostService, ], - exports: [...models, InventoryTransactionsService, InventoryItemCostService], }) export class InventoryCostModule {} diff --git a/packages/server-nest/src/modules/InventoryCost/commands/InventoryComputeCost.service.ts b/packages/server-nest/src/modules/InventoryCost/commands/InventoryComputeCost.service.ts index b6a98526d..9103e97a5 100644 --- a/packages/server-nest/src/modules/InventoryCost/commands/InventoryComputeCost.service.ts +++ b/packages/server-nest/src/modules/InventoryCost/commands/InventoryComputeCost.service.ts @@ -1,30 +1,51 @@ -import { pick } from 'lodash'; +import { Queue } from 'bullmq'; +import { ClsService } from 'nestjs-cls'; +import Redis from 'ioredis'; import { Inject, Injectable } from '@nestjs/common'; import { Knex } from 'knex'; import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service'; import { Item } from '../../Items/models/Item'; import { SETTINGS_PROVIDER } from '../../Settings/Settings.types'; import { SettingsStore } from '../../Settings/SettingsStore'; -import { InventoryTransaction } from '../models/InventoryTransaction'; -import { IItemEntryTransactionType } from '../../TransactionItemEntry/ItemEntry.types'; -import { ModelObject } from 'objection'; -import { ItemEntry } from '../../TransactionItemEntry/models/ItemEntry'; -import { TInventoryTransactionDirection } from '../types/InventoryCost.types'; +import { + ComputeItemCostQueue, + ComputeItemCostQueueJob, +} from '../types/InventoryCost.types'; import { InventoryAverageCostMethodService } from './InventoryAverageCostMethod.service'; import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; +import { InjectQueue } from '@nestjs/bullmq'; +import { RedisService } from '@liaoliaots/nestjs-redis'; @Injectable() export class InventoryComputeCostService { + private readonly redisClient: Redis; + + /** + * @param {UnitOfWork} uow - Unit of work. + * @param {InventoryAverageCostMethodService} inventoryAverageCostMethod - Inventory average cost method. + * @param {RedisService} redisService - Redis service. + * @param {ClsService} clsService - Cls service. + * @param {Queue} computeItemCostProcessor - Compute item cost processor. + * @param {TenantModelProxy} itemModel - Item model. + * @param {() => SettingsStore} settingsStore - Settings store. + */ constructor( private readonly uow: UnitOfWork, private readonly inventoryAverageCostMethod: InventoryAverageCostMethodService, + private readonly clsService: ClsService, + private readonly redisService: RedisService, + + @InjectQueue(ComputeItemCostQueue) + private readonly computeItemCostProcessor: Queue, @Inject(Item.name) private readonly itemModel: TenantModelProxy, @Inject(SETTINGS_PROVIDER) private readonly settingsStore: () => SettingsStore, - ) {} + ) { + this.redisClient = this.redisService.getOrThrow(); + } /** * Compute item cost. @@ -67,63 +88,45 @@ export class InventoryComputeCostService { /** * Schedule item cost compute job. - * @param {number} tenantId * @param {number} itemId * @param {Date} startingDate */ - async scheduleComputeItemCost( - itemId: number, - startingDate: Date | string, - ) { - // const agenda = Container.get('agenda'); - // const commonJobsQuery = { - // name: 'compute-item-cost', - // lastRunAt: { $exists: false }, - // 'data.tenantId': tenantId, - // 'data.itemId': itemId, - // }; - // // Cancel any `compute-item-cost` in the queue has upper starting date - // // with the same given item. - // await agenda.cancel({ - // ...commonJobsQuery, - // 'data.startingDate': { $lte: startingDate }, - // }); - // // Retrieve any `compute-item-cost` in the queue has lower starting date - // // with the same given item. - // const dependsJobs = await agenda.jobs({ - // ...commonJobsQuery, - // 'data.startingDate': { $gte: startingDate }, - // }); - // // If the depends jobs cleared. - // if (dependsJobs.length === 0) { - // await agenda.schedule( - // this.config.get('inventory.scheduleComputeItemCost'), - // 'compute-item-cost', - // { - // startingDate, - // itemId, - // tenantId, - // }, - // ); - // // Triggers `onComputeItemCostJobScheduled` event. - // await this.eventEmitter.emitAsync( - // events.inventory.onComputeItemCostJobScheduled, - // { - // startingDate, - // itemId, - // tenantId, - // } as IInventoryItemCostScheduledPayload, - // ); - // } else { - // // Re-schedule the jobs that have higher date from current moment. - // await Promise.all( - // dependsJobs.map((job) => - // job - // .schedule(this.config.get('inventory.scheduleComputeItemCost')) - // .save(), - // ), - // ); - // } + async scheduleComputeItemCost(itemId: number, startingDate: Date | string) { + const debounceKey = `inventory-cost-compute-debounce:${itemId}`; + const debounceTime = 1000 * 60; // 1 minute + + // Generate a unique job ID or use a custom identifier + const jobId = `task-${Date.now()}-${Math.random().toString(36).substring(2)}`; + + // Check if there's an existing debounced job + const existingJobId = await this.redisClient.get(debounceKey); + + if (existingJobId) { + // Attempt to remove or mark the previous job as skippable + const existingJob = + await this.computeItemCostProcessor.getJob(existingJobId); + const state = await existingJob?.getState(); + + if (existingJob && ['waiting', 'delayed'].includes(state)) { + await existingJob.remove(); // Remove the previous job if it's still waiting + } + } + const organizationId = this.clsService.get('organizationId'); + const userId = this.clsService.get('userId'); + + // Add the new job with a delay (debounce period) + const job = await this.computeItemCostProcessor.add( + ComputeItemCostQueueJob, + { itemId, startingDate, jobId, organizationId, userId }, + { + jobId, // Custom job ID + delay: debounceTime, // Delay execution by 1 minute + }, + ); + // Store the latest job ID in Redis with an expiration + await this.redisClient.set(debounceKey, jobId, 'PX', debounceTime); + + return { jobId, message: 'Task added with debounce' }; } /** diff --git a/packages/server-nest/src/modules/InventoryCost/commands/InventoryItemsQuantitySync.service.ts b/packages/server-nest/src/modules/InventoryCost/commands/InventoryItemsQuantitySync.service.ts index 927cab52a..db8dc1721 100644 --- a/packages/server-nest/src/modules/InventoryCost/commands/InventoryItemsQuantitySync.service.ts +++ b/packages/server-nest/src/modules/InventoryCost/commands/InventoryItemsQuantitySync.service.ts @@ -92,7 +92,7 @@ export class InventoryItemsQuantitySyncService { const changeQuantityOper = this.itemModel() .query(trx) .where({ id: itemQuantity.itemId, type: 'inventory' }) - .modify('quantityOnHand', itemQuantity.balanceChange); + .modify('updateQuantityOnHand', itemQuantity.balanceChange); opers.push(changeQuantityOper); }); diff --git a/packages/server-nest/src/modules/InventoryCost/processors/ComputeItemCost.processor.ts b/packages/server-nest/src/modules/InventoryCost/processors/ComputeItemCost.processor.ts index dcf244576..60772a6ef 100644 --- a/packages/server-nest/src/modules/InventoryCost/processors/ComputeItemCost.processor.ts +++ b/packages/server-nest/src/modules/InventoryCost/processors/ComputeItemCost.processor.ts @@ -6,14 +6,18 @@ import { ClsService } from 'nestjs-cls'; import { TenantJobPayload } from '@/interfaces/Tenant'; import { InventoryComputeCostService } from '../commands/InventoryComputeCost.service'; import { events } from '@/common/events/events'; -import { ComputeItemCostQueueJob } from '../types/InventoryCost.types'; +import { + ComputeItemCostQueue, + ComputeItemCostQueueJob, +} from '../types/InventoryCost.types'; +import { Process } from '@nestjs/bull'; interface ComputeItemCostJobPayload extends TenantJobPayload { itemId: number; startingDate: Date; } @Processor({ - name: ComputeItemCostQueueJob, + name: ComputeItemCostQueue, scope: Scope.REQUEST, }) export class ComputeItemCostProcessor extends WorkerHost { @@ -34,9 +38,12 @@ export class ComputeItemCostProcessor extends WorkerHost { * Process the compute item cost job. * @param {Job} job - The job to process */ + @Process(ComputeItemCostQueueJob) async process(job: Job) { const { itemId, startingDate, organizationId, userId } = job.data; + console.log(`Compute item cost for item ${itemId} started`); + this.clsService.set('organizationId', organizationId); this.clsService.set('userId', userId); @@ -50,6 +57,8 @@ export class ComputeItemCostProcessor extends WorkerHost { events.inventory.onComputeItemCostJobCompleted, { startingDate, itemId, organizationId, userId }, ); + + console.log(`Compute item cost for item ${itemId} completed`); } catch (error) { console.error('Error computing item cost:', error); throw error; diff --git a/packages/server-nest/src/modules/InventoryCost/subscribers/InventoryCost.subscriber.ts b/packages/server-nest/src/modules/InventoryCost/subscribers/InventoryCost.subscriber.ts index eb0cc6a81..3b0e5c2e4 100644 --- a/packages/server-nest/src/modules/InventoryCost/subscribers/InventoryCost.subscriber.ts +++ b/packages/server-nest/src/modules/InventoryCost/subscribers/InventoryCost.subscriber.ts @@ -14,7 +14,7 @@ import { Injectable } from '@nestjs/common'; import { InventoryComputeCostService } from '../commands/InventoryComputeCost.service'; @Injectable() -export default class InventorySubscriber { +export class InventoryCostSubscriber { constructor( private readonly saleInvoicesCost: SaleInvoicesCost, private readonly itemsQuantitySync: InventoryItemsQuantitySyncService, diff --git a/packages/server-nest/src/modules/Items/models/Item.ts b/packages/server-nest/src/modules/Items/models/Item.ts index 23ed00f2c..4a9960d97 100644 --- a/packages/server-nest/src/modules/Items/models/Item.ts +++ b/packages/server-nest/src/modules/Items/models/Item.ts @@ -32,6 +32,25 @@ export class Item extends TenantBaseModel { return 'items'; } + /** + * Model modifiers. + */ + static get modifiers() { + return { + updateQuantityOnHand(query, value: number) { + const q = query.where('type', 'inventory'); + + if (value > 0) { + q.increment('quantityOnHand', value); + } + if (value < 0) { + q.decrement('quantityOnHand', Math.abs(value)); + } + return q; + }, + }; + } + /** * Relationship mapping. */ diff --git a/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.module.ts b/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.module.ts index c7fe35d8b..d0540bde9 100644 --- a/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.module.ts +++ b/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.module.ts @@ -1,4 +1,4 @@ -import { Module } from '@nestjs/common'; +import { forwardRef, Module } from '@nestjs/common'; import { TenancyContext } from '../Tenancy/TenancyContext.service'; import { TenancyDatabaseModule } from '../Tenancy/TenancyDB/TenancyDB.module'; import { TransformerInjectable } from '../Transformer/TransformerInjectable.service'; @@ -55,6 +55,7 @@ import { SaleInvoiceWriteInventoryTransactionsSubscriber } from './subscribers/I import { SaleInvoiceCostGLEntries } from './SaleInvoiceCostGLEntries'; import { InvoicePaymentsGLEntriesRewrite } from './InvoicePaymentsGLRewrite'; import { PaymentsReceivedModule } from '../PaymentReceived/PaymentsReceived.module'; +import { SaleInvoicesCost } from './SalesInvoicesCost'; @Module({ imports: [ @@ -70,7 +71,7 @@ import { PaymentsReceivedModule } from '../PaymentReceived/PaymentsReceived.modu AccountsModule, MailModule, MailNotificationModule, - InventoryCostModule, + forwardRef(() => InventoryCostModule), DynamicListModule, BullModule.registerQueue({ name: SendSaleInvoiceQueue }), ], @@ -115,8 +116,9 @@ import { PaymentsReceivedModule } from '../PaymentReceived/PaymentsReceived.modu InvoiceCostGLEntriesSubscriber, InvoicePaymentGLRewriteSubscriber, SaleInvoiceWriteInventoryTransactionsSubscriber, - InvoicePaymentsGLEntriesRewrite + InvoicePaymentsGLEntriesRewrite, + SaleInvoicesCost, ], - exports: [GetSaleInvoice], + exports: [GetSaleInvoice, SaleInvoicesCost], }) export class SaleInvoicesModule {} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c9f5c413c..ab7e12023 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -490,9 +490,15 @@ importers: '@bigcapital/pdf-templates': specifier: '*' version: link:../../shared/pdf-templates + '@bigcapital/server': + specifier: '*' + version: link:../server '@bigcapital/utils': specifier: '*' version: link:../../shared/bigcapital-utils + '@liaoliaots/nestjs-redis': + specifier: ^10.0.0 + version: 10.0.0(@nestjs/common@10.4.7)(@nestjs/core@10.4.7)(ioredis@5.6.0) '@nestjs/bull': specifier: ^10.2.1 version: 10.2.2(@nestjs/common@10.4.7)(@nestjs/core@10.4.7)(bull@4.16.4) @@ -586,6 +592,9 @@ importers: fp-ts: specifier: ^2.16.9 version: 2.16.9 + ioredis: + specifier: ^5.6.0 + version: 5.6.0 is-my-json-valid: specifier: ^2.20.5 version: 2.20.6 @@ -619,6 +628,9 @@ importers: nestjs-i18n: specifier: ^10.4.9 version: 10.5.0(@nestjs/common@10.4.7)(@nestjs/core@10.4.7)(class-validator@0.14.1)(rxjs@7.8.1) + nestjs-redis: + specifier: ^1.3.3 + version: 1.3.3(@nestjs/platform-express@10.4.7)(cache-manager@6.1.3)(class-transformer@0.5.1)(class-validator@0.14.1) nodemailer: specifier: ^6.3.0 version: 6.9.13 @@ -7168,6 +7180,20 @@ packages: npmlog: 6.0.2 dev: true + /@liaoliaots/nestjs-redis@10.0.0(@nestjs/common@10.4.7)(@nestjs/core@10.4.7)(ioredis@5.6.0): + resolution: {integrity: sha512-uCTmlzM4q+UYADwsJEQph0mbf4u0MrktFhByi50M5fNy/+fJoWlhSqrgvjtVKjHnqydxy1gyuU6vHJEOBp9cjg==} + engines: {node: '>=16.13.0'} + peerDependencies: + '@nestjs/common': ^10.0.0 + '@nestjs/core': ^10.0.0 + ioredis: ^5.0.0 + dependencies: + '@nestjs/common': 10.4.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.7(@nestjs/common@10.4.7)(@nestjs/platform-express@10.4.7)(reflect-metadata@0.2.2)(rxjs@7.8.1) + ioredis: 5.6.0 + tslib: 2.7.0 + dev: false + /@ljharb/through@2.3.13: resolution: {integrity: sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==} engines: {node: '>= 0.4'} @@ -7415,6 +7441,35 @@ packages: tslib: 2.7.0 uid: 2.0.2 + /@nestjs/common@7.6.18(cache-manager@6.1.3)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@6.6.7): + resolution: {integrity: sha512-BUJQHNhWzwWOkS4Ryndzd4HTeRObcAWV2Fh+ermyo3q3xYQQzNoEWclJVL/wZec8AONELwIJ+PSpWI53VP0leg==} + peerDependencies: + cache-manager: '*' + class-transformer: '*' + class-validator: '*' + reflect-metadata: ^0.1.12 + rxjs: ^6.0.0 + peerDependenciesMeta: + cache-manager: + optional: true + class-transformer: + optional: true + class-validator: + optional: true + dependencies: + axios: 0.21.1 + cache-manager: 6.1.3 + class-transformer: 0.5.1 + class-validator: 0.14.1 + iterare: 1.2.1 + reflect-metadata: 0.2.2 + rxjs: 6.6.7 + tslib: 2.2.0 + uuid: 8.3.2 + transitivePeerDependencies: + - debug + dev: false + /@nestjs/common@8.4.7(cache-manager@6.1.3)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1): resolution: {integrity: sha512-m/YsbcBal+gA5CFrDpqXqsSfylo+DIQrkFY3qhVIltsYRfu8ct8J9pqsTO6OPf3mvqdOpFGrV5sBjoyAzOBvsw==} peerDependencies: @@ -7488,6 +7543,39 @@ packages: transitivePeerDependencies: - encoding + /@nestjs/core@7.6.18(@nestjs/common@7.6.18)(@nestjs/platform-express@10.4.7)(reflect-metadata@0.2.2)(rxjs@6.6.7): + resolution: {integrity: sha512-CGu20OjIxgFDY7RJT5t1TDGL8wSlTSlbZEkn8U5OlICZEB3WIpi98G7ajJpnRWmEgW8S4aDJmRKGjT+Ntj5U4A==} + requiresBuild: true + peerDependencies: + '@nestjs/common': ^7.0.0 + '@nestjs/microservices': ^7.0.0 + '@nestjs/platform-express': ^7.0.0 + '@nestjs/websockets': ^7.0.0 + reflect-metadata: ^0.1.12 + rxjs: ^6.0.0 + peerDependenciesMeta: + '@nestjs/microservices': + optional: true + '@nestjs/platform-express': + optional: true + '@nestjs/websockets': + optional: true + dependencies: + '@nestjs/common': 7.6.18(cache-manager@6.1.3)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@6.6.7) + '@nestjs/platform-express': 10.4.7(@nestjs/common@10.4.7)(@nestjs/core@10.4.7) + '@nuxtjs/opencollective': 0.3.2 + fast-safe-stringify: 2.0.7 + iterare: 1.2.1 + object-hash: 2.1.1 + path-to-regexp: 3.2.0 + reflect-metadata: 0.2.2 + rxjs: 6.6.7 + tslib: 2.2.0 + uuid: 8.3.2 + transitivePeerDependencies: + - encoding + dev: false + /@nestjs/event-emitter@2.1.1(@nestjs/common@10.4.7)(@nestjs/core@10.4.7): resolution: {integrity: sha512-6L6fBOZTyfFlL7Ih/JDdqlCzZeCW0RjCX28wnzGyg/ncv5F/EOeT1dfopQr1loBRQ3LTgu8OWM7n4zLN4xigsg==} peerDependencies: @@ -7833,7 +7921,7 @@ packages: nx: 19.0.7 semver: 7.6.2 tmp: 0.2.3 - tslib: 2.6.2 + tslib: 2.8.0 yargs-parser: 21.1.1 dev: true @@ -12199,6 +12287,15 @@ packages: resolution: {integrity: sha512-RI4LFAraGrimMTxXkediCMXGVLC6ksXIIo3U+d3E4n+Mhw3uIDbmokO7DHlPB/eu6Tn6KBv4IUE1WrrEDRdNUQ==} dev: false + /@types/ioredis@5.0.0: + resolution: {integrity: sha512-zJbJ3FVE17CNl5KXzdeSPtdltc4tMT3TzC6fxQS0sQngkbFZ6h+0uTafsRqu+eSLIugf6Yb0Ea0SUuRr42Nk9g==} + deprecated: This is a stub types definition. ioredis provides its own type definitions, so you do not need this installed. + dependencies: + ioredis: 5.6.0 + transitivePeerDependencies: + - supports-color + dev: false + /@types/istanbul-lib-coverage@2.0.6: resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -12618,6 +12715,10 @@ packages: resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} dev: true + /@types/uuid@10.0.0: + resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + dev: false + /@types/validator@13.12.2: resolution: {integrity: sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==} @@ -12746,7 +12847,7 @@ packages: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.0)(typescript@4.9.5) '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@4.9.5) - debug: 4.3.4 + debug: 4.3.7(supports-color@5.5.0) eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.1 @@ -12867,7 +12968,7 @@ packages: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5) - debug: 4.3.4 + debug: 4.3.7(supports-color@5.5.0) eslint: 8.57.0 typescript: 4.9.5 transitivePeerDependencies: @@ -12922,7 +13023,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 5.62.0(typescript@3.9.10) '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@3.9.10) - debug: 4.3.4 + debug: 4.3.7(supports-color@5.5.0) eslint: 8.57.0 tsutils: 3.21.0(typescript@3.9.10) typescript: 3.9.10 @@ -12942,7 +13043,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5) '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@4.9.5) - debug: 4.3.4 + debug: 4.3.7(supports-color@5.5.0) eslint: 8.57.0 tsutils: 3.21.0(typescript@4.9.5) typescript: 4.9.5 @@ -13010,7 +13111,7 @@ packages: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.4 + debug: 4.3.7(supports-color@5.5.0) globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.2 @@ -13031,7 +13132,7 @@ packages: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.4 + debug: 4.3.7(supports-color@5.5.0) globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.2 @@ -13052,7 +13153,7 @@ packages: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.4 + debug: 4.3.7(supports-color@5.5.0) globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.2 @@ -14487,6 +14588,14 @@ packages: engines: {node: '>=4'} dev: false + /axios@0.21.1: + resolution: {integrity: sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==} + dependencies: + follow-redirects: 1.15.6 + transitivePeerDependencies: + - debug + dev: false + /axios@0.21.4: resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} dependencies: @@ -15456,7 +15565,7 @@ packages: dependencies: cron-parser: 4.9.0 get-port: 5.1.1 - ioredis: 5.4.1 + ioredis: 5.6.0 lodash: 4.17.21 msgpackr: 1.11.2 semver: 7.6.2 @@ -15469,7 +15578,7 @@ packages: resolution: {integrity: sha512-jxpa/DB02V20CqBAgyqpQazT630CJm0r4fky8EchH3mcJAomRtKXLS6tRA0J8tb29BDGlr/LXhlUuZwdBJBSdA==} dependencies: cron-parser: 4.9.0 - ioredis: 5.4.1 + ioredis: 5.6.0 msgpackr: 1.11.2 node-abort-controller: 3.1.1 semver: 7.6.2 @@ -18104,7 +18213,7 @@ packages: base64id: 2.0.0 cookie: 0.4.2 cors: 2.8.5 - debug: 4.3.4 + debug: 4.3.7(supports-color@5.5.0) engine.io-parser: 5.2.2 ws: 8.11.0 transitivePeerDependencies: @@ -19555,7 +19664,7 @@ packages: engines: {node: '>= 10.17.0'} hasBin: true dependencies: - debug: 4.3.1 + debug: 4.3.7(supports-color@5.5.0) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -19634,6 +19743,10 @@ packages: resolution: {integrity: sha512-8EZzEP0eKkEEVX+drtd9mtuQ+/QrlfW/5MlwcwK5Nds6EkZ/tRzEexkzUY2mIssnAyVLT+TKHuRXmFNNXYUd6g==} dev: false + /fast-safe-stringify@2.0.7: + resolution: {integrity: sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==} + dev: false + /fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} @@ -21538,7 +21651,7 @@ packages: engines: {node: '>= 6'} dependencies: agent-base: 6.0.2 - debug: 4.3.1 + debug: 4.3.7(supports-color@5.5.0) transitivePeerDependencies: - supports-color dev: false @@ -21865,8 +21978,27 @@ packages: engines: {node: '>=0.10.0'} dev: false - /ioredis@5.4.1: - resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==} + /ioredis@4.29.1: + resolution: {integrity: sha512-iq4u3AC9h9/P/gBXH1cUR7Ln0exKexqMaYDwUaoZJzkvvgJs9W5+CLQFS0APyG8uyvJJjn6q6Vx7LwmZQu3h5A==} + engines: {node: '>=6'} + dependencies: + '@ioredis/commands': 1.2.0 + cluster-key-slot: 1.1.2 + debug: 4.3.7(supports-color@5.5.0) + denque: 1.5.1 + lodash.defaults: 4.2.0 + lodash.flatten: 4.4.0 + lodash.isarguments: 3.1.0 + p-map: 2.1.0 + redis-errors: 1.2.0 + redis-parser: 3.0.0 + standard-as-callback: 2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + /ioredis@5.6.0: + resolution: {integrity: sha512-tBZlIIWbndeWBWCXWZiqtOF/yxf6yZX3tAlTJ7nfo5jhd6dctNxF7QnYlZLZ1a0o0pDoen7CgZqO+zjNaFbJAg==} engines: {node: '>=12.22.0'} dependencies: '@ioredis/commands': 1.2.0 @@ -22534,7 +22666,7 @@ packages: resolution: {integrity: sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==} engines: {node: '>=6'} dependencies: - debug: 4.3.4 + debug: 4.3.7(supports-color@5.5.0) istanbul-lib-coverage: 2.0.5 make-dir: 2.1.0 rimraf: 2.7.1 @@ -24522,6 +24654,10 @@ packages: resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} dev: false + /lodash.flatten@4.4.0: + resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + dev: false + /lodash.flattendeep@4.4.0: resolution: {integrity: sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==} dev: true @@ -25869,6 +26005,29 @@ packages: string-format: 2.0.0 dev: false + /nestjs-redis@1.3.3(@nestjs/platform-express@10.4.7)(cache-manager@6.1.3)(class-transformer@0.5.1)(class-validator@0.14.1): + resolution: {integrity: sha512-YLvWtVKP38Uica7pL8T955jPi0MFmJ4+Wj3R/IHbLpsdCJkdA9wtfO9NoUpiZpM1aO1dEGcOBoStvgb0Uy7MGA==} + dependencies: + '@nestjs/common': 7.6.18(cache-manager@6.1.3)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@6.6.7) + '@nestjs/core': 7.6.18(@nestjs/common@7.6.18)(@nestjs/platform-express@10.4.7)(reflect-metadata@0.2.2)(rxjs@6.6.7) + '@types/ioredis': 5.0.0 + '@types/uuid': 10.0.0 + ioredis: 4.29.1 + reflect-metadata: 0.2.2 + rxjs: 6.6.7 + uuid: 8.3.2 + transitivePeerDependencies: + - '@nestjs/microservices' + - '@nestjs/platform-express' + - '@nestjs/websockets' + - cache-manager + - class-transformer + - class-validator + - debug + - encoding + - supports-color + dev: false + /newrelic@11.17.0: resolution: {integrity: sha512-gI5FGsfvHyGLUW/+q3op1SsF8jisW5wV+NVOoxV9J58GOEEsP1B4/9D5jyL3iiL5QO1REeWtK5n15d2OsiYAIg==} engines: {node: '>=16', npm: '>=6.0.0'} @@ -26407,7 +26566,7 @@ packages: tar-stream: 2.2.0 tmp: 0.2.3 tsconfig-paths: 4.2.0 - tslib: 2.6.2 + tslib: 2.8.0 yargs: 17.7.2 yargs-parser: 21.1.1 optionalDependencies: @@ -26502,6 +26661,11 @@ packages: engines: {node: '>= 0.10.0'} dev: true + /object-hash@2.1.1: + resolution: {integrity: sha512-VOJmgmS+7wvXf8CjbQmimtCnEx3IAoLxI3fp2fbWehxrWBcAQFbk+vcwb6vzR0VZv/eNCJ/27j151ZTwqW/JeQ==} + engines: {node: '>= 6'} + dev: false + /object-hash@2.2.0: resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==} engines: {node: '>= 6'} @@ -27292,6 +27456,10 @@ packages: dependencies: isarray: 0.0.1 + /path-to-regexp@3.2.0: + resolution: {integrity: sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==} + dev: false + /path-to-regexp@3.3.0: resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} @@ -30944,6 +31112,13 @@ packages: resolution: {integrity: sha512-cLgakCUf6PedEu15t8kbsjnwIFFR2D4RfL+W3iWFJ4iac7z4B0ZI8fxy4R3J956kAI68HclCFGL8MPoUVC3qVA==} dev: false + /rxjs@6.6.7: + resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} + engines: {npm: '>=2.0.0'} + dependencies: + tslib: 1.14.1 + dev: false + /rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} dependencies: @@ -31587,7 +31762,7 @@ packages: /socket.io-adapter@2.5.4: resolution: {integrity: sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==} dependencies: - debug: 4.3.4 + debug: 4.3.7(supports-color@5.5.0) ws: 8.11.0 transitivePeerDependencies: - bufferutil @@ -31614,7 +31789,7 @@ packages: engines: {node: '>=10.0.0'} dependencies: '@socket.io/component-emitter': 3.1.2 - debug: 4.3.4 + debug: 4.3.7(supports-color@5.5.0) transitivePeerDependencies: - supports-color dev: false @@ -32449,7 +32624,7 @@ packages: dependencies: component-emitter: 1.3.1 cookiejar: 2.1.4 - debug: 4.3.4 + debug: 4.3.7(supports-color@5.5.0) fast-safe-stringify: 2.1.1 form-data: 4.0.0 formidable: 2.1.2 @@ -33423,6 +33598,10 @@ packages: /tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + /tslib@2.2.0: + resolution: {integrity: sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==} + dev: false + /tslib@2.4.0: resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} dev: false