From 71017f6a0728fadbb801a5f5df8d27d28e471563 Mon Sep 17 00:00:00 2001 From: YfengJ <166808804+YfengJ@users.noreply.github.com> Date: Wed, 24 Jun 2026 05:42:12 +0800 Subject: [PATCH 1/2] Add compound transaction builder endpoint --- src/app.module.ts | 4 +- .../transactions.controller.spec.ts | 68 ++++++ src/transactions/transactions.controller.ts | 35 +++ src/transactions/transactions.module.ts | 9 + src/transactions/transactions.service.spec.ts | 66 ++++++ src/transactions/transactions.service.ts | 218 ++++++++++++++++++ 6 files changed, 399 insertions(+), 1 deletion(-) create mode 100644 src/transactions/transactions.controller.spec.ts create mode 100644 src/transactions/transactions.controller.ts create mode 100644 src/transactions/transactions.module.ts create mode 100644 src/transactions/transactions.service.spec.ts create mode 100644 src/transactions/transactions.service.ts diff --git a/src/app.module.ts b/src/app.module.ts index d9285b6..87bae63 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -16,6 +16,7 @@ import { ConfigModule } from '@nestjs/config'; import { MaintenanceMiddleware } from './common/middleware/maintenance.middleware'; import { RequestIdMiddleware } from './common/middleware/request-id.middleware'; import { RedisModule } from './common/redis/redis.module'; +import { TransactionsModule } from './transactions/transactions.module'; /** * Root module of the application. @@ -33,7 +34,8 @@ import { RedisModule } from './common/redis/redis.module'; SwapModule, TokensModule, OgModule, - TradeModule + TradeModule, + TransactionsModule ], controllers: [AppController], providers: [ diff --git a/src/transactions/transactions.controller.spec.ts b/src/transactions/transactions.controller.spec.ts new file mode 100644 index 0000000..bd39158 --- /dev/null +++ b/src/transactions/transactions.controller.spec.ts @@ -0,0 +1,68 @@ +import { INestApplication } from '@nestjs/common'; +import { Test, TestingModule } from '@nestjs/testing'; +import { Keypair, Networks } from '@stellar/stellar-sdk'; +import * as request from 'supertest'; +import { TransactionsModule } from './transactions.module'; +import { TransactionsService } from './transactions.service'; + +describe('TransactionsController', () => { + let app: INestApplication; + const source = Keypair.random().publicKey(); + const destination = Keypair.random().publicKey(); + + const transactionsService = { + buildTransaction: jest.fn(), + }; + + beforeAll(async () => { + const moduleFixture: TestingModule = await Test.createTestingModule({ + imports: [TransactionsModule], + }) + .overrideProvider(TransactionsService) + .useValue(transactionsService) + .compile(); + + app = moduleFixture.createNestApplication(); + await app.init(); + }); + + beforeEach(() => { + transactionsService.buildTransaction.mockResolvedValue({ + xdr: 'AAAA', + source, + operationCount: 1, + networkPassphrase: Networks.TESTNET, + }); + }); + + afterAll(async () => { + await app.close(); + }); + + it('POST /api/v1/transactions/build delegates to the transaction builder service', async () => { + const payload = { + source, + operations: [ + { + type: 'payment', + destination, + asset: { type: 'native' }, + amount: '1.0000000', + }, + ], + }; + + const response = await request(app.getHttpServer()) + .post('/api/v1/transactions/build') + .send(payload) + .expect(200); + + expect(transactionsService.buildTransaction).toHaveBeenCalledWith(payload); + expect(response.body).toEqual({ + xdr: 'AAAA', + source, + operationCount: 1, + networkPassphrase: Networks.TESTNET, + }); + }); +}); diff --git a/src/transactions/transactions.controller.ts b/src/transactions/transactions.controller.ts new file mode 100644 index 0000000..6068bff --- /dev/null +++ b/src/transactions/transactions.controller.ts @@ -0,0 +1,35 @@ +import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common'; +import { ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; +import { BuildTransactionDto, TransactionsService } from './transactions.service'; + +@ApiTags('transactions') +@Controller('api/v1/transactions') +export class TransactionsController { + constructor(private readonly transactionsService: TransactionsService) {} + + @Post('build') + @HttpCode(HttpStatus.OK) + @ApiOperation({ summary: 'Build an unsigned Stellar transaction envelope' }) + @ApiBody({ + schema: { + type: 'object', + required: ['source', 'operations'], + properties: { + source: { type: 'string', description: 'Source Stellar public key' }, + fee: { type: 'string', description: 'Optional per-operation fee in stroops' }, + networkPassphrase: { type: 'string', description: 'Optional Stellar network passphrase' }, + timeoutSeconds: { type: 'number', description: 'Optional transaction timeout in seconds' }, + operations: { + type: 'array', + description: 'Sequential payment or pathPaymentStrictSend intents', + items: { type: 'object' }, + }, + }, + }, + }) + @ApiResponse({ status: 200, description: 'Unsigned base64 XDR envelope built successfully' }) + @ApiResponse({ status: 400, description: 'Invalid transaction build request' }) + async buildTransaction(@Body() body: BuildTransactionDto) { + return this.transactionsService.buildTransaction(body); + } +} diff --git a/src/transactions/transactions.module.ts b/src/transactions/transactions.module.ts new file mode 100644 index 0000000..87ecd2a --- /dev/null +++ b/src/transactions/transactions.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { TransactionsController } from './transactions.controller'; +import { TransactionsService } from './transactions.service'; + +@Module({ + controllers: [TransactionsController], + providers: [TransactionsService], +}) +export class TransactionsModule {} diff --git a/src/transactions/transactions.service.spec.ts b/src/transactions/transactions.service.spec.ts new file mode 100644 index 0000000..94fbe19 --- /dev/null +++ b/src/transactions/transactions.service.spec.ts @@ -0,0 +1,66 @@ +import { Account, Keypair, Networks, TransactionBuilder } from '@stellar/stellar-sdk'; +import { BadRequestException } from '@nestjs/common'; +import { TransactionsService } from './transactions.service'; + +describe('TransactionsService', () => { + const source = Keypair.random().publicKey(); + const firstDestination = Keypair.random().publicKey(); + const secondDestination = Keypair.random().publicKey(); + const issuer = Keypair.random().publicKey(); + + const accountLoader = { + loadAccount: jest.fn(), + }; + + beforeEach(() => { + accountLoader.loadAccount.mockResolvedValue(new Account(source, '123')); + }); + + it('builds an unsigned XDR envelope from sequential swap intents', async () => { + const service = new TransactionsService(accountLoader); + + const result = await service.buildTransaction({ + source, + fee: '200', + networkPassphrase: Networks.TESTNET, + operations: [ + { + type: 'pathPaymentStrictSend', + sendAsset: { type: 'native' }, + sendAmount: '10.0000000', + destination: firstDestination, + destAsset: { type: 'credit_alphanum4', code: 'USDC', issuer }, + destMin: '9.5000000', + path: [{ type: 'credit_alphanum4', code: 'EURC', issuer }], + }, + { + type: 'payment', + destination: secondDestination, + asset: { type: 'native' }, + amount: '1.0000000', + }, + ], + }); + + expect(accountLoader.loadAccount).toHaveBeenCalledWith(source); + expect(result.source).toBe(source); + expect(result.operationCount).toBe(2); + expect(typeof result.xdr).toBe('string'); + + const transaction = TransactionBuilder.fromXDR(result.xdr, Networks.TESTNET) as any; + expect(transaction.operations).toHaveLength(2); + expect(transaction.operations[0].type).toBe('pathPaymentStrictSend'); + expect(transaction.operations[1].type).toBe('payment'); + }); + + it('rejects empty operation arrays', async () => { + const service = new TransactionsService(accountLoader); + + await expect( + service.buildTransaction({ + source, + operations: [], + }), + ).rejects.toBeInstanceOf(BadRequestException); + }); +}); diff --git a/src/transactions/transactions.service.ts b/src/transactions/transactions.service.ts new file mode 100644 index 0000000..2ef41d3 --- /dev/null +++ b/src/transactions/transactions.service.ts @@ -0,0 +1,218 @@ +import { BadRequestException, Injectable } from '@nestjs/common'; +import { + Account, + Asset, + BASE_FEE, + Horizon, + Networks, + Operation, + StrKey, + TransactionBuilder, +} from '@stellar/stellar-sdk'; + +type BuildAssetDto = + | { type: 'native' } + | { type: 'credit_alphanum4' | 'credit_alphanum12'; code: string; issuer: string }; + +type PaymentIntentDto = { + type: 'payment'; + destination: string; + asset: BuildAssetDto; + amount: string; +}; + +type PathPaymentStrictSendIntentDto = { + type: 'pathPaymentStrictSend'; + sendAsset: BuildAssetDto; + sendAmount: string; + destination: string; + destAsset: BuildAssetDto; + destMin: string; + path?: BuildAssetDto[]; +}; + +export type BuildTransactionDto = { + source: string; + operations: Array; + fee?: string; + networkPassphrase?: string; + timeoutSeconds?: number; +}; + +export type BuildTransactionResult = { + xdr: string; + source: string; + operationCount: number; + networkPassphrase: string; +}; + +export interface StellarAccountLoader { + loadAccount(source: string): Promise; +} + +class HorizonAccountLoader implements StellarAccountLoader { + private readonly server: Horizon.Server; + + constructor(horizonUrl = process.env.STELLAR_HORIZON_URL ?? 'https://horizon-testnet.stellar.org') { + this.server = new Horizon.Server(horizonUrl); + } + + async loadAccount(source: string): Promise { + return this.server.loadAccount(source); + } +} + +@Injectable() +export class TransactionsService { + constructor(private readonly accountLoader: StellarAccountLoader = new HorizonAccountLoader()) {} + + async buildTransaction(body: BuildTransactionDto): Promise { + this.validateSource(body?.source); + + if (!Array.isArray(body.operations) || body.operations.length === 0) { + throw new BadRequestException('operations must contain at least one item'); + } + + if (body.operations.length > 20) { + throw new BadRequestException('operations cannot contain more than 20 items'); + } + + const sourceAccount = await this.accountLoader.loadAccount(body.source); + const networkPassphrase = body.networkPassphrase ?? Networks.TESTNET; + const fee = this.normalizeFee(body.fee); + + const builder = new TransactionBuilder(sourceAccount, { + fee, + networkPassphrase, + }); + + for (const intent of body.operations) { + builder.addOperation(this.toOperation(intent)); + } + + builder.setTimeout(this.normalizeTimeout(body.timeoutSeconds)); + + return { + xdr: builder.build().toXDR(), + source: body.source, + operationCount: body.operations.length, + networkPassphrase, + }; + } + + private toOperation(intent: PaymentIntentDto | PathPaymentStrictSendIntentDto) { + if (!intent || typeof intent !== 'object') { + throw new BadRequestException('operation must be an object'); + } + + switch (intent.type) { + case 'payment': + this.validateDestination(intent.destination); + this.validateAmount(intent.amount, 'amount'); + return Operation.payment({ + destination: intent.destination, + asset: this.toAsset(intent.asset), + amount: intent.amount, + }); + + case 'pathPaymentStrictSend': + this.validateDestination(intent.destination); + this.validateAmount(intent.sendAmount, 'sendAmount'); + this.validateAmount(intent.destMin, 'destMin'); + return Operation.pathPaymentStrictSend({ + sendAsset: this.toAsset(intent.sendAsset), + sendAmount: intent.sendAmount, + destination: intent.destination, + destAsset: this.toAsset(intent.destAsset), + destMin: intent.destMin, + path: (intent.path ?? []).map((asset) => this.toAsset(asset)), + }); + + default: + throw new BadRequestException(`unsupported operation type: ${(intent as any).type}`); + } + } + + private toAsset(asset: BuildAssetDto): Asset { + if (!asset || typeof asset !== 'object') { + throw new BadRequestException('asset must be an object'); + } + + if (asset.type === 'native') { + return Asset.native(); + } + + if (asset.type !== 'credit_alphanum4' && asset.type !== 'credit_alphanum12') { + throw new BadRequestException(`unsupported asset type: ${(asset as any).type}`); + } + + const code = String(asset.code ?? '').trim(); + if (!/^[A-Z0-9]{1,12}$/.test(code)) { + throw new BadRequestException('asset code must be 1-12 uppercase alphanumeric characters'); + } + + if (asset.type === 'credit_alphanum4' && code.length > 4) { + throw new BadRequestException('credit_alphanum4 asset codes cannot exceed 4 characters'); + } + + this.validateIssuer(asset.issuer); + return new Asset(code, asset.issuer); + } + + private normalizeFee(fee?: string): string { + if (fee === undefined) { + return String(BASE_FEE); + } + + if (!/^\d+$/.test(String(fee))) { + throw new BadRequestException('fee must be a positive integer string'); + } + + const parsedFee = Number(fee); + if (!Number.isSafeInteger(parsedFee) || parsedFee < Number(BASE_FEE)) { + throw new BadRequestException(`fee must be at least ${BASE_FEE}`); + } + + return String(parsedFee); + } + + private normalizeTimeout(timeoutSeconds?: number): number { + if (timeoutSeconds === undefined) { + return 300; + } + + if (!Number.isInteger(timeoutSeconds) || timeoutSeconds < 0 || timeoutSeconds > 3600) { + throw new BadRequestException('timeoutSeconds must be an integer between 0 and 3600'); + } + + return timeoutSeconds; + } + + private validateAmount(amount: string, field: string): void { + if (!/^\d+(\.\d{1,7})?$/.test(String(amount))) { + throw new BadRequestException(`${field} must be a positive Stellar amount string`); + } + + if (Number(amount) <= 0) { + throw new BadRequestException(`${field} must be greater than zero`); + } + } + + private validateSource(source: string): void { + if (!StrKey.isValidEd25519PublicKey(source)) { + throw new BadRequestException('source must be a valid Stellar public key'); + } + } + + private validateDestination(destination: string): void { + if (!StrKey.isValidEd25519PublicKey(destination)) { + throw new BadRequestException('destination must be a valid Stellar public key'); + } + } + + private validateIssuer(issuer: string): void { + if (!StrKey.isValidEd25519PublicKey(issuer)) { + throw new BadRequestException('asset issuer must be a valid Stellar public key'); + } + } +} From 16ca24e0915e60200883468ce37509299de710d4 Mon Sep 17 00:00:00 2001 From: YfengJ <166808804+YfengJ@users.noreply.github.com> Date: Wed, 24 Jun 2026 21:30:37 +0800 Subject: [PATCH 2/2] Fix TradeFlow API CI build --- package-lock.json | 977 +++++++++++++++++++---------- package.json | 4 +- src/common/logger/custom.logger.ts | 4 +- src/dynamic/dynamic.module.ts | 4 +- src/pools/pools.controller.ts | 25 +- src/trade/trade.gateway.ts | 4 +- 6 files changed, 665 insertions(+), 353 deletions(-) diff --git a/package-lock.json b/package-lock.json index 50bc4d8..5d02286 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,11 +13,11 @@ "@nestjs/config": "^3.2.3", "@nestjs/core": "^10.4.22", "@nestjs/platform-express": "^10.4.22", - "@nestjs/platform-socket.io": "^10.0.0", + "@nestjs/platform-socket.io": "^10.4.22", "@nestjs/swagger": "^7.1.1", "@nestjs/throttler": "^6.5.0", "@nestjs/typeorm": "^10.0.2", - "@nestjs/websockets": "^10.0.0", + "@nestjs/websockets": "^10.4.22", "@prisma/client": "^5.19.1", "@stellar/stellar-sdk": "^11.0.0", "@types/jsonwebtoken": "^9.0.10", @@ -679,7 +679,7 @@ }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -690,7 +690,7 @@ }, "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -1567,7 +1567,7 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1584,7 +1584,7 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -1912,13 +1912,13 @@ } }, "node_modules/@nestjs/platform-socket.io": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@nestjs/platform-socket.io/-/platform-socket.io-10.0.0.tgz", - "integrity": "sha512-sYW72flbnlfw7VcBuEamUp45nNr/OUGzBvqfnmraYJ9aJDqcd5vM0w2zn/S6YvLu2ZEgGrnyx8KEIXYf5iMfuQ==", + "version": "10.4.22", + "resolved": "https://registry.npmjs.org/@nestjs/platform-socket.io/-/platform-socket.io-10.4.22.tgz", + "integrity": "sha512-xxGw3R0Ihr51/Omq23z3//bKmCXyVKaikxbH0/pkwqMsQrxkUv9NabNUZ22b4Jnlwwi02X+zlwo8GRa9u8oV9g==", "license": "MIT", "dependencies": { - "socket.io": "4.6.2", - "tslib": "2.5.3" + "socket.io": "4.8.1", + "tslib": "2.8.1" }, "funding": { "type": "opencollective", @@ -1930,190 +1930,6 @@ "rxjs": "^7.1.0" } }, - "node_modules/@nestjs/platform-socket.io/node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@nestjs/platform-socket.io/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@nestjs/platform-socket.io/node_modules/engine.io": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.2.tgz", - "integrity": "sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==", - "license": "MIT", - "dependencies": { - "@types/cookie": "^0.4.1", - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.4.1", - "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~5.0.3", - "ws": "~8.11.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@nestjs/platform-socket.io/node_modules/engine.io-parser": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.7.tgz", - "integrity": "sha512-P+jDFbvK6lE3n1OL+q9KuzdOFWkkZ/cMV9gol/SbVfpyqfvrfrFTOFJ6fQm2VC3PZHlU3QPhVwmbsCnauHF2MQ==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@nestjs/platform-socket.io/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/@nestjs/platform-socket.io/node_modules/socket.io": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.2.tgz", - "integrity": "sha512-Vp+lSks5k0dewYTfwgPT9UeGGd+ht7sCpB7p0e83VgO4X/AHYWhXITMrNk/pg8syY2bpx23ptClCQuHhqi2BgQ==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "debug": "~4.3.2", - "engine.io": "~6.4.2", - "socket.io-adapter": "~2.5.2", - "socket.io-parser": "~4.2.4" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@nestjs/platform-socket.io/node_modules/socket.io-adapter": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.6.tgz", - "integrity": "sha512-DkkO/dz7MGln0dHn5bmN3pPy+JmywNICWrJqVWiVOyvXjWQFIv9c2h24JrQLLFJ2aQVQf/Cvl1vblnd4r2apLQ==", - "license": "MIT", - "dependencies": { - "debug": "~4.4.1", - "ws": "~8.18.3" - } - }, - "node_modules/@nestjs/platform-socket.io/node_modules/socket.io-adapter/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@nestjs/platform-socket.io/node_modules/socket.io-adapter/node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/@nestjs/platform-socket.io/node_modules/socket.io-parser": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.6.tgz", - "integrity": "sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==", - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.4.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@nestjs/platform-socket.io/node_modules/socket.io-parser/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@nestjs/platform-socket.io/node_modules/tslib": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", - "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", - "license": "0BSD" - }, - "node_modules/@nestjs/platform-socket.io/node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/@nestjs/schematics": { "version": "11.0.9", "dev": true, @@ -2266,20 +2082,20 @@ } }, "node_modules/@nestjs/websockets": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-10.0.0.tgz", - "integrity": "sha512-Qv7KKdJ7bNnR2jaA8rXhhqTuwbFoAV29TKA1EZIUWGL6OHb2do/JB14mJ9yDQfi1fbfb0xjxWno7iPgaO+LHUw==", + "version": "10.4.22", + "resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-10.4.22.tgz", + "integrity": "sha512-OLd4i0Faq7vgdtB5vVUrJ54hWEtcXy9poJ6n7kbbh/5ms+KffUl+wwGsbe7uSXLrkoyI8xXU6fZPkFArI+XiRg==", "license": "MIT", "dependencies": { "iterare": "1.2.1", "object-hash": "3.0.0", - "tslib": "2.5.3" + "tslib": "2.8.1" }, "peerDependencies": { "@nestjs/common": "^10.0.0", "@nestjs/core": "^10.0.0", "@nestjs/platform-socket.io": "^10.0.0", - "reflect-metadata": "^0.1.12", + "reflect-metadata": "^0.1.12 || ^0.2.0", "rxjs": "^7.1.0" }, "peerDependenciesMeta": { @@ -2288,12 +2104,6 @@ } } }, - "node_modules/@nestjs/websockets/node_modules/tslib": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", - "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", - "license": "0BSD" - }, "node_modules/@noble/hashes": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", @@ -2519,22 +2329,22 @@ }, "node_modules/@tsconfig/node10": { "version": "1.0.12", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tybys/wasm-util": { @@ -2592,12 +2402,6 @@ "@types/node": "*" } }, - "node_modules/@types/component-emitter": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.14.tgz", - "integrity": "sha512-lmPil1g82wwWg/qHSxMWkSKyJGQOK+ejXeMAAWyxNtVUD0/Ycj2maL63RAqpxVfdtvTfZkRnqzB0A9ft59y69g==", - "license": "MIT" - }, "node_modules/@types/compression": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", @@ -2616,12 +2420,6 @@ "@types/node": "*" } }, - "node_modules/@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "license": "MIT" - }, "node_modules/@types/cookiejar": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", @@ -2833,6 +2631,15 @@ "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz", "integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==" }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/yargs": { "version": "17.0.35", "dev": true, @@ -3019,7 +2826,7 @@ }, "node_modules/acorn": { "version": "8.16.0", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -3041,7 +2848,7 @@ }, "node_modules/acorn-walk": { "version": "8.3.5", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -3177,7 +2984,7 @@ }, "node_modules/arg": { "version": "4.1.3", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/argparse": { @@ -3365,14 +3172,6 @@ "node": ">=0.12.0" } }, - "node_modules/base64-arraybuffer": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", - "integrity": "sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg==", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/base64-js": { "version": "1.5.1", "funding": [ @@ -3901,6 +3700,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3973,6 +3773,20 @@ "version": "2.15.3", "license": "MIT" }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/content-type": { "version": "1.0.5", "license": "MIT", @@ -3996,7 +3810,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.6.0" @@ -4052,7 +3865,7 @@ }, "node_modules/create-require": { "version": "1.1.1", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/cross-spawn": { @@ -4176,7 +3989,7 @@ }, "node_modules/diff": { "version": "4.0.4", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -4254,48 +4067,39 @@ } }, "node_modules/engine.io": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-5.0.0.tgz", - "integrity": "sha512-BATIdDV3H1SrE9/u2BAotvsmjJg0t1P4+vGedImSs1lkFAtQdvk4Ev1y4LDiPF7BPWgXWEG+NDY+nLvW3UrMWw==", + "version": "6.6.9", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.9.tgz", + "integrity": "sha512-clKkw4C7nJ22mGgoVcCg6V/W/TxdNyIOTr89k2ONZu81qqkddPFDF0LXcbAwhzPD8DjkiRCjzuiO6Y+fkpD4vg==", "license": "MIT", "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "@types/ws": "^8.5.12", "accepts": "~1.3.4", "base64id": "2.0.0", - "cookie": "~0.4.1", + "cookie": "~0.7.2", "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~4.0.0", - "ws": "~7.4.2" + "debug": "~4.4.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.21.0" }, "engines": { - "node": ">=10.0.0" + "node": ">=10.2.0" } }, "node_modules/engine.io-parser": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-4.0.3.tgz", - "integrity": "sha512-xEAAY0msNnESNPc00e19y5heTPX4y/TJ36gr8t1voOaNmTojP9b3oK3BbJLFufW2XFPQaaijpFewm2g2Um3uqA==", - "license": "MIT", - "dependencies": { - "base64-arraybuffer": "0.1.4" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/engine.io/node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=10.0.0" } }, "node_modules/engine.io/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -4462,62 +4266,305 @@ "node": ">=0.8.x" } }, - "node_modules/eventsource": { - "version": "2.0.2", + "node_modules/eventsource": { + "version": "2.0.2", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "license": "ISC" + }, + "node_modules/exit-x": { + "version": "0.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "30.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.3.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.3.0", + "jest-message-util": "30.3.0", + "jest-mock": "30.3.0", + "jest-util": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "peer": true, + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.2.tgz", + "integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==", + "license": "MIT", + "peer": true, + "dependencies": { + "ip-address": "^10.2.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/express/node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "peer": true, + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "license": "MIT", + "peer": true, + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/express/node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "peer": true, + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "peer": true + }, + "node_modules/express/node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/qs": { + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/express/node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "license": "MIT", + "peer": true, + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, "engines": { - "node": ">=12.0.0" + "node": ">= 0.10" } }, - "node_modules/execa": { - "version": "5.1.1", - "dev": true, + "node_modules/express/node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", "license": "MIT", + "peer": true, "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">= 18" }, "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/execa/node_modules/signal-exit": { - "version": "3.0.7", - "dev": true, - "license": "ISC" - }, - "node_modules/exit-x": { - "version": "0.2.2", - "dev": true, + "node_modules/express/node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", "license": "MIT", + "peer": true, "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "30.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/expect-utils": "30.3.0", - "@jest/get-type": "30.1.0", - "jest-matcher-utils": "30.3.0", - "jest-message-util": "30.3.0", - "jest-mock": "30.3.0", - "jest-util": "30.3.0" + "node": ">=18" }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/fast-deep-equal": { @@ -4577,6 +4624,53 @@ "url": "https://github.com/sindresorhus/file-type?sponsor=1" } }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "peer": true + }, "node_modules/find-up": { "version": "4.1.0", "dev": true, @@ -4699,6 +4793,16 @@ "node": ">= 0.6" } }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/fs-extra": { "version": "10.1.0", "dev": true, @@ -4990,7 +5094,6 @@ }, "node_modules/iconv-lite": { "version": "0.7.2", - "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -5122,6 +5225,16 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 12" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "license": "MIT", @@ -5167,6 +5280,13 @@ "node": ">=8" } }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT", + "peer": true + }, "node_modules/is-stream": { "version": "2.0.1", "dev": true, @@ -6230,7 +6350,7 @@ }, "node_modules/make-error": { "version": "1.3.6", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/makeerror": { @@ -6266,6 +6386,19 @@ "node": ">= 4.0.0" } }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "dev": true, @@ -6562,7 +6695,6 @@ }, "node_modules/once": { "version": "1.4.0", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -7177,6 +7309,59 @@ "dev": true, "license": "ISC" }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/router/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/router/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "peer": true + }, + "node_modules/router/node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/rxjs": { "version": "7.8.2", "license": "Apache-2.0", @@ -7261,6 +7446,95 @@ "node": ">=10" } }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/send/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/send/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "peer": true, + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "peer": true + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "peer": true, + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/set-function-length": { "version": "1.2.2", "license": "MIT", @@ -7398,49 +7672,73 @@ } }, "node_modules/socket.io": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.0.0.tgz", - "integrity": "sha512-/c1riZMV/4yz7KEpaMhDQbwhJDIoO55whXaRKgyEBQrLU9zUHXo9rzeTMvTOqwL9mbKfHKdrXcMoCeQ/1YtMsg==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", + "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", "license": "MIT", "dependencies": { - "@types/cookie": "^0.4.0", - "@types/cors": "^2.8.8", - "@types/node": ">=10.0.0", "accepts": "~1.3.4", "base64id": "~2.0.0", - "debug": "~4.3.1", - "engine.io": "~5.0.0", - "socket.io-adapter": "~2.2.0", - "socket.io-parser": "~4.0.3" + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" }, "engines": { - "node": ">=10.0.0" + "node": ">=10.2.0" } }, "node_modules/socket.io-adapter": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.2.0.tgz", - "integrity": "sha512-rG49L+FwaVEwuAdeBRq49M97YI3ElVabJPzvHT9S6a2CWhDKnjSFasvwAwSYPRhQzfn4NtDIbCaGYgOCOU/rlg==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.8.tgz", + "integrity": "sha512-6Oy52pbg+kvdCVvjcN+FnY7BvxZ7cIHNScbvztT/It5d0vbwoJoVZmF2gjJmnV0/4WlXRfG15zc45ySk9Ah8bw==", + "license": "MIT", + "dependencies": { + "debug": "~4.4.1", + "ws": "~8.21.0" + } + }, + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-adapter/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/socket.io-parser": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.5.tgz", - "integrity": "sha512-sNjbT9dX63nqUFIOv95tTVm6elyIU4RvB1m8dOeZt+IgWwcWklFDOdmGcfo3zSiRsnR/3pJkjY5lfoGqEe4Eig==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.6.tgz", + "integrity": "sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==", "license": "MIT", "dependencies": { - "@types/component-emitter": "^1.2.10", - "component-emitter": "~1.3.0", - "debug": "~4.3.1" + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1" }, "engines": { "node": ">=10.0.0" } }, "node_modules/socket.io-parser/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -8089,7 +8387,7 @@ }, "node_modules/ts-node": { "version": "10.9.2", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -8417,7 +8715,7 @@ }, "node_modules/typescript": { "version": "5.9.3", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -8813,7 +9111,7 @@ }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { @@ -9049,7 +9347,6 @@ }, "node_modules/wrappy": { "version": "1.0.2", - "dev": true, "license": "ISC" }, "node_modules/write-file-atomic": { @@ -9065,16 +9362,16 @@ } }, "node_modules/ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "license": "MIT", "engines": { - "node": ">=8.3.0" + "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -9131,7 +9428,7 @@ }, "node_modules/yn": { "version": "3.1.1", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" diff --git a/package.json b/package.json index 2c3f9fa..d10ef0b 100644 --- a/package.json +++ b/package.json @@ -35,11 +35,11 @@ "@nestjs/config": "^3.2.3", "@nestjs/core": "^10.4.22", "@nestjs/platform-express": "^10.4.22", - "@nestjs/platform-socket.io": "^10.0.0", + "@nestjs/platform-socket.io": "^10.4.22", "@nestjs/swagger": "^7.1.1", "@nestjs/throttler": "^6.5.0", "@nestjs/typeorm": "^10.0.2", - "@nestjs/websockets": "^10.0.0", + "@nestjs/websockets": "^10.4.22", "@prisma/client": "^5.19.1", "@stellar/stellar-sdk": "^11.0.0", "@types/jsonwebtoken": "^9.0.10", diff --git a/src/common/logger/custom.logger.ts b/src/common/logger/custom.logger.ts index 14108fe..bdbd685 100644 --- a/src/common/logger/custom.logger.ts +++ b/src/common/logger/custom.logger.ts @@ -1,4 +1,4 @@ -import { ConsoleLogger, Injectable, Scope } from '@nestjs/common'; +import { ConsoleLogger, Injectable, LogLevel, Scope } from '@nestjs/common'; import { requestContextStorage } from '../storage/request-context.storage'; /** @@ -19,7 +19,7 @@ export class CustomLogger extends ConsoleLogger { * @returns The fully formatted log string. */ formatMessage( - logLevel: string, + logLevel: LogLevel, message: unknown, pidMessage: string, formattedLogLevel: string, diff --git a/src/dynamic/dynamic.module.ts b/src/dynamic/dynamic.module.ts index 057f800..50ecd9f 100644 --- a/src/dynamic/dynamic.module.ts +++ b/src/dynamic/dynamic.module.ts @@ -1,6 +1,6 @@ import { Module } from '@nestjs/common'; -import { InvoicesController } from './invoices.controller'; -import { PdfService } from './pdf.service'; +import { InvoicesController } from '../invoices/invoices.controller'; +import { PdfService } from '../invoices/pdf.service'; @Module({ controllers: [InvoicesController], diff --git a/src/pools/pools.controller.ts b/src/pools/pools.controller.ts index 5464e1a..f2cd5c4 100644 --- a/src/pools/pools.controller.ts +++ b/src/pools/pools.controller.ts @@ -3,6 +3,11 @@ import { ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger'; import { ApyHistoryPoint, generateMockApyHistory } from './apy-history.helper'; import { PoolIdParamDto } from './dto/pool-id-param.dto'; +interface ApyHistoryResponse { + status: 'success'; + data: ApyHistoryPoint[]; +} + /** * Controller for liquidity pool information and history. * Provides simulated APY history and recent trade data for pools. @@ -23,11 +28,22 @@ export class PoolsController { @ApiResponse({ status: 200, description: 'APY history retrieved successfully', - type: ApyHistoryPoint, - isArray: true, + schema: { + type: 'object', + properties: { + status: { type: 'string', example: 'success' }, + data: { + type: 'array', + items: { $ref: '#/components/schemas/ApyHistoryPoint' }, + }, + }, + }, }) - getApyHistory(@Param() params: PoolIdParamDto): ApyHistoryPoint[] { - return generateMockApyHistory(params.poolId); + getApyHistory(@Param() params: PoolIdParamDto): ApyHistoryResponse { + return { + status: 'success', + data: generateMockApyHistory(params.poolId), + }; } /** @@ -97,4 +113,3 @@ export class PoolsController { }; } } - diff --git a/src/trade/trade.gateway.ts b/src/trade/trade.gateway.ts index 902b7f5..d4e2f64 100644 --- a/src/trade/trade.gateway.ts +++ b/src/trade/trade.gateway.ts @@ -1,7 +1,7 @@ -import { WebSocketGateway, WebSocketServer, OnModuleInit } from '@nestjs/websockets'; +import { OnModuleInit, Logger } from '@nestjs/common'; +import { WebSocketGateway, WebSocketServer } from '@nestjs/websockets'; import { Server } from 'socket.io'; import { RedisService } from '../common/redis/redis.service'; -import { Logger } from '@nestjs/common'; /** * WebSocket Gateway for real-time trade updates.