diff --git a/backend/src/database/migrations/20250601204322-AddDifficultyAndCategoryToIQQuestions.ts b/backend/src/database/migrations/20250601204322-AddDifficultyAndCategoryToIQQuestions.ts index de998b1..f26ecc5 100644 --- a/backend/src/database/migrations/20250601204322-AddDifficultyAndCategoryToIQQuestions.ts +++ b/backend/src/database/migrations/20250601204322-AddDifficultyAndCategoryToIQQuestions.ts @@ -1,8 +1,6 @@ import { MigrationInterface, QueryRunner } from 'typeorm'; -export class AddDifficultyAndCategoryToIQQuestions20250601204322 - implements MigrationInterface -{ +export class AddDifficultyAndCategoryToIQQuestions20250601204322 implements MigrationInterface { name = 'AddDifficultyAndCategoryToIQQuestions20250601204322'; public async up(queryRunner: QueryRunner): Promise { diff --git a/backend/src/database/migrations/20250601204323-CreateDailyStreaksTable.ts b/backend/src/database/migrations/20250601204323-CreateDailyStreaksTable.ts index c66b9cc..5930e3a 100644 --- a/backend/src/database/migrations/20250601204323-CreateDailyStreaksTable.ts +++ b/backend/src/database/migrations/20250601204323-CreateDailyStreaksTable.ts @@ -1,8 +1,6 @@ import { MigrationInterface, QueryRunner } from 'typeorm'; -export class CreateDailyStreaksTable20250601204323 - implements MigrationInterface -{ +export class CreateDailyStreaksTable20250601204323 implements MigrationInterface { name = 'CreateDailyStreaksTable20250601204323'; public async up(queryRunner: QueryRunner): Promise { diff --git a/backend/src/progress/providers/get-category-stats.provider.ts b/backend/src/progress/providers/get-category-stats.provider.ts index ac011ac..c37e00a 100644 --- a/backend/src/progress/providers/get-category-stats.provider.ts +++ b/backend/src/progress/providers/get-category-stats.provider.ts @@ -3,16 +3,6 @@ import { InjectRepository } from '@nestjs/typeorm'; import { FindOptionsWhere, Repository } from 'typeorm'; import { UserProgress } from '../entities/progress.entity'; -interface CategoryStatsRaw { - categoryId: string; - totalAttempts: string; - correctAnswers: string; -} - -interface CategoryNameRaw { - category_name: string; -} - @Injectable() export class GetCategoryStatsProvider { constructor( diff --git a/backend/src/progress/providers/get-overall-stats.provider.ts b/backend/src/progress/providers/get-overall-stats.provider.ts index c84aa21..1391930 100644 --- a/backend/src/progress/providers/get-overall-stats.provider.ts +++ b/backend/src/progress/providers/get-overall-stats.provider.ts @@ -4,13 +4,6 @@ import { FindOptionsWhere, Repository } from 'typeorm'; import { UserProgress } from '../entities/progress.entity'; import { OverallStatsDto } from '../dtos/overall-stats.dto'; -interface OverallStatsRaw { - totalAttempts: string; - totalCorrect: string; - totalPointsEarned: string; - totalTimeSpent: string; -} - @Injectable() export class GetOverallStatsProvider { constructor( diff --git a/backend/src/progress/providers/progress-calculation.provider.ts b/backend/src/progress/providers/progress-calculation.provider.ts index 61ee821..6e8d514 100644 --- a/backend/src/progress/providers/progress-calculation.provider.ts +++ b/backend/src/progress/providers/progress-calculation.provider.ts @@ -6,7 +6,6 @@ import { UserProgress } from '../entities/progress.entity'; import { SubmitAnswerDto } from '../dtos/submit-answer.dto'; import { XpLevelService } from '../../users/providers/xp-level.service'; import { User } from '../../users/user.entity'; -import { Streak } from '../../streak/entities/streak.entity'; import { DailyQuest } from '../../quests/entities/daily-quest.entity'; import { getPointsByDifficulty } from '../../puzzles/enums/puzzle-difficulty.enum'; @@ -21,13 +20,6 @@ export interface ProgressCalculationResult { validation: AnswerValidationResult; } -interface ProgressStatsRaw { - totalAttempts: string; - correctAttempts: string; - totalPoints: string; - averageTimeSpent: string; -} - @Injectable() export class ProgressCalculationProvider { constructor( @@ -38,8 +30,6 @@ export class ProgressCalculationProvider { private readonly xpLevelService: XpLevelService, @InjectRepository(User) private readonly userRepository: Repository, - @InjectRepository(Streak) - private readonly streakRepository: Repository, @InjectRepository(DailyQuest) private readonly dailyQuestRepository: Repository, ) {} diff --git a/backend/src/puzzles/dtos/create-puzzle.dto.ts b/backend/src/puzzles/dtos/create-puzzle.dto.ts index 5c02dc7..32c63e3 100644 --- a/backend/src/puzzles/dtos/create-puzzle.dto.ts +++ b/backend/src/puzzles/dtos/create-puzzle.dto.ts @@ -20,9 +20,7 @@ import { } from '../enums/puzzle-difficulty.enum'; @ValidatorConstraint({ name: 'correctAnswerInOptions', async: false }) -export class CorrectAnswerInOptionsConstraint - implements ValidatorConstraintInterface -{ +export class CorrectAnswerInOptionsConstraint implements ValidatorConstraintInterface { validate(correctAnswer: string, args: ValidationArguments) { const object = args.object as CreatePuzzleDto; return object.options?.includes(correctAnswer) || false; @@ -34,9 +32,7 @@ export class CorrectAnswerInOptionsConstraint } @ValidatorConstraint({ name: 'optionsMinimumLength', async: false }) -export class OptionsMinimumLengthConstraint - implements ValidatorConstraintInterface -{ +export class OptionsMinimumLengthConstraint implements ValidatorConstraintInterface { validate(options: string[]) { return options?.length >= 2; } diff --git a/backend/src/quests/controllers/daily-quest.controller.ts b/backend/src/quests/controllers/daily-quest.controller.ts index bb4c9d9..c6ad254 100644 --- a/backend/src/quests/controllers/daily-quest.controller.ts +++ b/backend/src/quests/controllers/daily-quest.controller.ts @@ -41,6 +41,7 @@ export class DailyQuestController { }) async getTodaysDailyQuest( @ActiveUser('sub') userId: string, + userTimeZone: string, ): Promise { console.log('REQUEST_USER_KEY:', request['user']); console.log('Full request keys:', Object.keys(request)); @@ -50,7 +51,7 @@ export class DailyQuestController { if (!userId) { throw new UnauthorizedException('User ID not found in token'); } - return this.dailyQuestService.getTodaysDailyQuest(userId); + return this.dailyQuestService.getTodaysDailyQuest(userId, userTimeZone); } @Get('status') @@ -72,11 +73,15 @@ export class DailyQuestController { }) async getTodaysDailyQuestStatus( @ActiveUser('sub') userId: string, + userTimeZone: string, ): Promise { if (!userId) { throw new UnauthorizedException('User ID not found in token'); } - return this.dailyQuestService.getTodaysDailyQuestStatus(userId); + return this.dailyQuestService.getTodaysDailyQuestStatus( + userId, + userTimeZone, + ); } @Post('complete') @@ -106,10 +111,11 @@ export class DailyQuestController { }) async completeDailyQuest( @ActiveUser('sub') userId: string, + userTimeZone: string, ): Promise { if (!userId) { throw new UnauthorizedException('User ID not found in token'); } - return this.dailyQuestService.completeDailyQuest(userId); + return this.dailyQuestService.completeDailyQuest(userId, userTimeZone); } } diff --git a/backend/src/quests/providers/complete-daily-quest.provider.ts b/backend/src/quests/providers/complete-daily-quest.provider.ts index b3bf75c..ad957be 100644 --- a/backend/src/quests/providers/complete-daily-quest.provider.ts +++ b/backend/src/quests/providers/complete-daily-quest.provider.ts @@ -5,11 +5,12 @@ import { NotFoundException, } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import { Repository, DataSource } from 'typeorm'; +import { DataSource } from 'typeorm'; import { DailyQuest } from '../entities/daily-quest.entity'; import { User } from '../../users/user.entity'; import { UpdateStreakProvider } from '../../streak/providers/update-streak.provider'; import { CompleteDailyQuestResponseDto } from '../dtos/complete-daily-quest.dto'; +import { getDateString } from '../../shared/utils/date.util'; @Injectable() export class CompleteDailyQuestProvider { @@ -17,25 +18,22 @@ export class CompleteDailyQuestProvider { private readonly BONUS_XP = 100; constructor( - @InjectRepository(DailyQuest) - private readonly dailyQuestRepository: Repository, @InjectRepository(User) - private readonly userRepository: Repository, private readonly updateStreakProvider: UpdateStreakProvider, private readonly dataSource: DataSource, ) {} - async execute(userId: string): Promise { - const todayDate = this.getTodayDateString(); + async execute( + userId: string, + userTimeZone: string, + ): Promise { + const todayDate = getDateString(userTimeZone, 0); this.logger.log( `Attempting to complete daily quest for user ${userId} on ${todayDate}`, ); // Parse userId to number for streak operations - const userIdNumber = parseInt(userId, 10); - if (isNaN(userIdNumber)) { - throw new BadRequestException('Invalid user ID format'); - } + const userIdNumber = userId; // Use transaction to ensure atomicity const transactionResult = await this.dataSource.transaction( @@ -130,6 +128,7 @@ export class CompleteDailyQuestProvider { // 7. Update streak after transaction commits const streak = await this.updateStreakProvider.updateStreak( transactionResult.userId!, + userTimeZone, ); this.logger.log( @@ -145,14 +144,10 @@ export class CompleteDailyQuestProvider { streakInfo: { currentStreak: streak.currentStreak, longestStreak: streak.longestStreak, - lastActivityDate: streak.lastActivityDate || this.getTodayDateString(), + lastActivityDate: + streak.lastActivityDate || getDateString(userTimeZone, 0), }, completedAt: transactionResult.completedAt, }; } - - private getTodayDateString(): string { - const now = new Date(); - return now.toISOString().split('T')[0]; - } } diff --git a/backend/src/quests/providers/daily-quest.service.ts b/backend/src/quests/providers/daily-quest.service.ts index d369a8b..9bc894f 100644 --- a/backend/src/quests/providers/daily-quest.service.ts +++ b/backend/src/quests/providers/daily-quest.service.ts @@ -14,8 +14,11 @@ export class DailyQuestService { private readonly completeDailyQuestProvider: CompleteDailyQuestProvider, ) {} - async getTodaysDailyQuest(userId: string): Promise { - return this.getTodaysDailyQuestProvider.execute(userId); + async getTodaysDailyQuest( + userId: string, + userTimezone: string, + ): Promise { + return this.getTodaysDailyQuestProvider.execute(userId, userTimezone); } /** @@ -23,8 +26,9 @@ export class DailyQuestService { */ async getTodaysDailyQuestStatus( userId: string, + userTimeZone: string, ): Promise { - return this.getTodaysDailyQuestStatusProvider.execute(userId); + return this.getTodaysDailyQuestStatusProvider.execute(userId, userTimeZone); } /** @@ -33,7 +37,8 @@ export class DailyQuestService { */ async completeDailyQuest( userId: string, + userTimeZone: string, ): Promise { - return this.completeDailyQuestProvider.execute(userId); + return this.completeDailyQuestProvider.execute(userId, userTimeZone); } } diff --git a/backend/src/quests/providers/getTodaysDailyQuest.provider.ts b/backend/src/quests/providers/getTodaysDailyQuest.provider.ts index c7374ef..7ba1f17 100644 --- a/backend/src/quests/providers/getTodaysDailyQuest.provider.ts +++ b/backend/src/quests/providers/getTodaysDailyQuest.provider.ts @@ -10,6 +10,7 @@ import { User } from '../../users/user.entity'; import { DailyQuestResponseDto } from '../dtos/daily-quest-response.dto'; import { PuzzleResponseDto } from '../dtos/puzzle-response.dto'; import { PuzzleDifficulty } from '../../puzzles/enums/puzzle-difficulty.enum'; +import { getDateString } from '../../shared/utils/date.util'; @Injectable() export class GetTodaysDailyQuestProvider { @@ -30,8 +31,12 @@ export class GetTodaysDailyQuestProvider { private readonly userRepository: Repository, ) {} - async execute(userId: string): Promise { - const todayDate = this.getTodayDateString(); + async execute( + userId: string, + userTimezone: string, + ): Promise { + const todayDate = getDateString(userTimezone, 0); + this.logger.log(`Fetching daily quest for user ${userId} on ${todayDate}`); let dailyQuest = await this.findExistingQuest(userId, todayDate); @@ -46,11 +51,6 @@ export class GetTodaysDailyQuestProvider { return this.buildQuestResponse(dailyQuest); } - private getTodayDateString(): string { - const now = new Date(); - return now.toISOString().split('T')[0]; - } - private async findExistingQuest( userId: string, questDate: string, diff --git a/backend/src/quests/providers/getTodaysDailyQuestStatus.provider.ts b/backend/src/quests/providers/getTodaysDailyQuestStatus.provider.ts index 773ebde..aefbae7 100644 --- a/backend/src/quests/providers/getTodaysDailyQuestStatus.provider.ts +++ b/backend/src/quests/providers/getTodaysDailyQuestStatus.provider.ts @@ -4,6 +4,7 @@ import { Repository } from 'typeorm'; import { DailyQuest } from '../entities/daily-quest.entity'; import { DailyQuestStatusDto } from '../dtos/daily-quest-status.dto'; import { GetTodaysDailyQuestProvider } from './getTodaysDailyQuest.provider'; +import { getDateString } from '../../shared/utils/date.util'; /** * Provider for fetching the status of today's Daily Quest. @@ -29,8 +30,11 @@ export class GetTodaysDailyQuestStatusProvider { * @param userId - The user's ID * @returns DailyQuestStatusDto with totalQuestions, completedQuestions, isCompleted */ - async execute(userId: string): Promise { - const todayDate = this.getTodayDateString(); + async execute( + userId: string, + userTimeZone: string, + ): Promise { + const todayDate = getDateString(userTimeZone, 0); this.logger.log( `Fetching daily quest status for user ${userId} on ${todayDate}`, ); @@ -66,14 +70,6 @@ export class GetTodaysDailyQuestStatusProvider { return this.buildStatusResponse(dailyQuest); } - /** - * Returns today's date as YYYY-MM-DD string (timezone-safe) - */ - private getTodayDateString(): string { - const now = new Date(); - return now.toISOString().split('T')[0]; - } - /** * Converts DailyQuest entity to DailyQuestStatusDto */ diff --git a/backend/src/shared/utils/date.util.ts b/backend/src/shared/utils/date.util.ts new file mode 100644 index 0000000..1583265 --- /dev/null +++ b/backend/src/shared/utils/date.util.ts @@ -0,0 +1,11 @@ +/** + * Returns a YYYY-MM-DD string in the given timezone. + * @param timeZone IANA timezone string (e.g. "America/New_York") + * @param offsetDays Number of days to offset (0 = today, -1 = yesterday) + */ +export function getDateString(timeZone: string, offsetDays = 0): string { + const now = new Date(); + now.setDate(now.getUTCDate() + offsetDays); + + return now.toLocaleDateString('en-CA', { timeZone }); +} diff --git a/backend/src/streak/providers/streaks.service.ts b/backend/src/streak/providers/streaks.service.ts index 5cc3391..b79829d 100644 --- a/backend/src/streak/providers/streaks.service.ts +++ b/backend/src/streak/providers/streaks.service.ts @@ -4,14 +4,12 @@ import { Streak } from '../entities/streak.entity'; @Injectable() export class StreaksService { - constructor( - private readonly updateStreakProvider: UpdateStreakProvider, - ) {} + constructor(private readonly updateStreakProvider: UpdateStreakProvider) {} /** * Get user's current streak */ - async getStreak(userId: number): Promise { + async getStreak(userId: string): Promise { return this.updateStreakProvider.getStreak(userId); } @@ -19,7 +17,7 @@ export class StreaksService { * Update streak after daily quest completion * Handles increment, reset, and longest streak tracking */ - async updateStreak(userId: number): Promise { - return this.updateStreakProvider.updateStreak(userId); + async updateStreak(userId: string, userTimezone: string): Promise { + return this.updateStreakProvider.updateStreak(userId, userTimezone); } } diff --git a/backend/src/streak/providers/update-streak.provider.ts b/backend/src/streak/providers/update-streak.provider.ts index 2969796..00a1b34 100644 --- a/backend/src/streak/providers/update-streak.provider.ts +++ b/backend/src/streak/providers/update-streak.provider.ts @@ -1,7 +1,8 @@ -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable, Logger, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { Streak } from '../entities/streak.entity'; +import { getDateString } from '../../shared/utils/date.util'; @Injectable() export class UpdateStreakProvider { @@ -16,19 +17,23 @@ export class UpdateStreakProvider { * Updates user streak based on daily quest completion * Handles streak continuation, breaks, and new streaks */ - async updateStreak(userId: number): Promise { - const todayDate = this.getTodayDateString(); + async updateStreak(userId: string, userTimezone: string): Promise { + const todayDate = getDateString(userTimezone, 0); this.logger.log(`Updating streak for user ${userId} on ${todayDate}`); + if (!userId) { + throw new NotFoundException(); + } + // Find or create user's streak record let streak = await this.streakRepository.findOne({ - where: { userId }, + where: { userId: parseInt(userId, 10) }, }); if (!streak) { // First time user - create new streak streak = this.streakRepository.create({ - userId, + userId: parseInt(userId, 10), currentStreak: 1, longestStreak: 1, lastActivityDate: todayDate, @@ -45,7 +50,7 @@ export class UpdateStreakProvider { } // Calculate streak continuation - const yesterday = this.getYesterdayDateString(); + const yesterday = getDateString(userTimezone, -1); const isConsecutive = streak.lastActivityDate === yesterday; if (isConsecutive) { @@ -82,20 +87,9 @@ export class UpdateStreakProvider { /** * Get user's current streak information */ - async getStreak(userId: number): Promise { + async getStreak(userId: string): Promise { return await this.streakRepository.findOne({ - where: { userId }, + where: { userId: parseInt(userId, 10) }, }); } - - private getTodayDateString(): string { - const now = new Date(); - return now.toISOString().split('T')[0]; - } - - private getYesterdayDateString(): string { - const yesterday = new Date(); - yesterday.setDate(yesterday.getDate() - 1); - return yesterday.toISOString().split('T')[0]; - } } diff --git a/backend/src/streak/streaks.controller.ts b/backend/src/streak/streaks.controller.ts index 3bf1eac..de53646 100644 --- a/backend/src/streak/streaks.controller.ts +++ b/backend/src/streak/streaks.controller.ts @@ -28,7 +28,7 @@ export class StreaksController { if (!user?.sub) { throw new UnauthorizedException('User not authenticated'); } - const userId = parseInt(user.sub, 10); + const userId = user.sub; return this.streaksService.getStreak(userId); } @@ -44,11 +44,14 @@ export class StreaksController { status: 401, description: 'Unauthorized', }) - async updateStreak(@ActiveUser() user: ActiveUserData): Promise { + async updateStreak( + @ActiveUser() user: ActiveUserData, + userTimezone: string, + ): Promise { if (!user?.sub) { throw new UnauthorizedException('User not authenticated'); } - const userId = parseInt(user.sub, 10); - return this.streaksService.updateStreak(userId); + const userId = user.sub; + return this.streaksService.updateStreak(userId, userTimezone); } } diff --git a/package-lock.json b/package-lock.json index f65f6cd..14664cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,11 @@ "contracts" ], "dependencies": { + "@nestjs/common": "^11.1.14", + "@nestjs/core": "^11.1.14", "minimatch": "^10.1.1", + "reflect-metadata": "^0.2.2", + "rxjs": "^7.8.2", "tsconfig-paths": "^4.2.0" }, "devDependencies": { @@ -197,7 +201,6 @@ "version": "0.6.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@swc/counter": "^0.1.3", "@xhmikosr/bin-wrapper": "^13.0.5", @@ -240,7 +243,6 @@ "dev": true, "hasInstallScript": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.24" @@ -277,7 +279,6 @@ "version": "22.18.0", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -288,7 +289,6 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -430,7 +430,6 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "license": "Apache-2.0", - "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -477,7 +476,6 @@ "version": "10.9.2", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -519,7 +517,6 @@ "backend/node_modules/typeorm": { "version": "0.3.26", "license": "MIT", - "peer": true, "dependencies": { "@sqltools/formatter": "^1.2.5", "ansis": "^3.17.0", @@ -646,7 +643,6 @@ "version": "5.8.3", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -1070,7 +1066,6 @@ "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", @@ -3443,11 +3438,10 @@ } }, "node_modules/@nestjs/common": { - "version": "11.1.12", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.12.tgz", - "integrity": "sha512-v6U3O01YohHO+IE3EIFXuRuu3VJILWzyMmSYZXpyBbnp0hk0mFyHxK2w3dF4I5WnbwiRbWlEXdeXFvPQ7qaZzw==", + "version": "11.1.14", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.14.tgz", + "integrity": "sha512-IN/tlqd7Nl9gl6f0jsWEuOrQDaCI9vHzxv0fisHysfBQzfQIkqlv5A7w4Qge02BUQyczXT9HHPgHtWHCxhjRng==", "license": "MIT", - "peer": true, "dependencies": { "file-type": "21.3.0", "iterare": "1.2.1", @@ -3490,12 +3484,11 @@ } }, "node_modules/@nestjs/core": { - "version": "11.1.12", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.12.tgz", - "integrity": "sha512-97DzTYMf5RtGAVvX1cjwpKRiCUpkeQ9CCzSAenqkAhOmNVVFaApbhuw+xrDt13rsCa2hHVOYPrV4dBgOYMJjsA==", + "version": "11.1.14", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.14.tgz", + "integrity": "sha512-7OXPPMoDr6z+5NkoQKu4hOhfjz/YYqM3bNilPqv1WVFWrzSmuNXxvhbX69YMmNmRYascPXiwESqf5jJdjKXEww==", "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "@nuxt/opencollective": "0.4.1", "fast-safe-stringify": "2.1.1", @@ -3592,7 +3585,6 @@ "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.12.tgz", "integrity": "sha512-GYK/vHI0SGz5m8mxr7v3Urx8b9t78Cf/dj5aJMZlGd9/1D9OI1hAl00BaphjEXINUJ/BQLxIlF2zUjrYsd6enQ==", "license": "MIT", - "peer": true, "dependencies": { "cors": "2.8.5", "express": "5.2.1", @@ -5218,7 +5210,6 @@ "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -5476,7 +5467,6 @@ "integrity": "sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -5487,7 +5477,6 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -5616,7 +5605,6 @@ "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", @@ -6336,7 +6324,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "devOptional": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -6409,7 +6396,6 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -6830,7 +6816,6 @@ "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.4.tgz", "integrity": "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==", "license": "MIT", - "peer": true, "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", @@ -7209,7 +7194,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -7541,7 +7525,6 @@ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "readdirp": "^4.0.1" }, @@ -7598,15 +7581,13 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/class-validator": { "version": "0.14.3", "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.3.tgz", "integrity": "sha512-rXXekcjofVN1LTOSw+u4u9WXVEUvNBVjORW154q/IdmYWy1nMbOU9aNtZB0t8m+FJQ9q91jlr2f9CwwUFdFMRA==", "license": "MIT", - "peer": true, "dependencies": { "@types/validator": "^13.15.3", "libphonenumber-js": "^1.11.1", @@ -8798,7 +8779,6 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -8887,7 +8867,6 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", - "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -8989,7 +8968,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -9464,7 +9442,6 @@ "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", @@ -10777,7 +10754,6 @@ "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.9.2.tgz", "integrity": "sha512-tAAg/72/VxOUW7RQSX1pIxJVucYKcjFjfvj60L57jrZpYCHC3XN0WCQ3sNYL4Gmvv+7GPvTAjc+KSdeNuE8oWQ==", "license": "MIT", - "peer": true, "dependencies": { "@ioredis/commands": "1.5.0", "cluster-key-slot": "^1.1.0", @@ -11444,7 +11420,6 @@ "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -14174,7 +14149,6 @@ "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==", "license": "MIT", - "peer": true, "dependencies": { "passport-strategy": "1.x.x", "pause": "0.0.1", @@ -14344,7 +14318,6 @@ "resolved": "https://registry.npmjs.org/pg/-/pg-8.18.0.tgz", "integrity": "sha512-xqrUDL1b9MbkydY/s+VZ6v+xiMUmOUk7SS9d/1kpyQxoJ6U9AO1oIJyUWVZojbfe5Cc/oluutcgFG4L9RDP1iQ==", "license": "MIT", - "peer": true, "dependencies": { "pg-connection-string": "^2.11.0", "pg-pool": "^3.11.0", @@ -14661,7 +14634,6 @@ "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -14921,7 +14893,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -14931,7 +14902,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.26.0" }, @@ -14951,7 +14921,6 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", "license": "MIT", - "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -15023,8 +14992,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -15039,8 +15007,7 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", - "license": "Apache-2.0", - "peer": true + "license": "Apache-2.0" }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", @@ -15343,7 +15310,6 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -15994,7 +15960,6 @@ "integrity": "sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==", "hasInstallScript": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "bindings": "^1.5.0", "node-addon-api": "^7.0.0", @@ -16765,7 +16730,6 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -16970,7 +16934,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -17392,7 +17355,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -17840,6 +17802,7 @@ "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ajv": "^8.0.0" }, @@ -17858,6 +17821,7 @@ "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3" }, @@ -17870,7 +17834,8 @@ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/webpack/node_modules/eslint-scope": { "version": "5.1.1", @@ -17878,6 +17843,7 @@ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -17892,6 +17858,7 @@ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "engines": { "node": ">=4.0" } @@ -17901,7 +17868,8 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/webpack/node_modules/schema-utils": { "version": "4.3.3", @@ -17909,6 +17877,7 @@ "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", diff --git a/package.json b/package.json index 8c0d66c..46cd867 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,11 @@ ], "homepage": "https://github.com/MindBlockLabs/mindBlock_Backend#readme", "dependencies": { + "@nestjs/common": "^11.1.14", + "@nestjs/core": "^11.1.14", "minimatch": "^10.1.1", + "reflect-metadata": "^0.2.2", + "rxjs": "^7.8.2", "tsconfig-paths": "^4.2.0" }, "devDependencies": {