From 783d911f8d64e43850265e217fb601bc6cfbc562 Mon Sep 17 00:00:00 2001 From: Mir Arif Hasan Date: Mon, 29 Jul 2024 13:06:18 +0600 Subject: [PATCH] HSB-462 feat: infra token module and sh apis (#4191) * feat: infra token module added * feat: infra token guard added * feat: token prefix removed * feat: get pending invites api added * docs: swagger doc added for get user invites api * feat: delete user invitation api added * feat: get users api added * feat: update user api added * feat: update admin status api added * feat: create invitation api added * chore: swagger doc update for create user invite * feat: interceptor added to track last used on * feat: change db schema * chore: readonly tag added * feat: get user by id api added * fix: return type of a function * feat: controller name change * chore: improve token extractino * chore: added email validation logic --------- Co-authored-by: Balu Babu --- packages/hoppscotch-backend/package.json | 3 + .../20240726121956_infra_token/migration.sql | 15 + .../hoppscotch-backend/prisma/schema.prisma | 10 + .../src/access-token/access-token.service.ts | 17 +- .../src/admin/admin.service.ts | 7 + packages/hoppscotch-backend/src/app.module.ts | 2 + .../src/decorators/bearer-token.decorator.ts | 15 + packages/hoppscotch-backend/src/errors.ts | 43 +++ packages/hoppscotch-backend/src/gql-schema.ts | 2 + .../src/guards/infra-token.guard.ts | 47 +++ .../src/infra-token/infra-token.controller.ts | 248 +++++++++++++++ .../src/infra-token/infra-token.model.ts | 43 +++ .../src/infra-token/infra-token.module.ts | 14 + .../src/infra-token/infra-token.resolver.ts | 68 ++++ .../src/infra-token/infra-token.service.ts | 160 ++++++++++ .../src/infra-token/request-response.dto.ts | 115 +++++++ .../interceptors/infra-token.interceptor.ts | 30 ++ packages/hoppscotch-backend/src/main.ts | 39 ++- .../src/types/input-types.args.ts | 11 + packages/hoppscotch-backend/src/utils.ts | 11 + pnpm-lock.yaml | 301 +++++++++++------- 21 files changed, 1075 insertions(+), 126 deletions(-) create mode 100644 packages/hoppscotch-backend/prisma/migrations/20240726121956_infra_token/migration.sql create mode 100644 packages/hoppscotch-backend/src/decorators/bearer-token.decorator.ts create mode 100644 packages/hoppscotch-backend/src/guards/infra-token.guard.ts create mode 100644 packages/hoppscotch-backend/src/infra-token/infra-token.controller.ts create mode 100644 packages/hoppscotch-backend/src/infra-token/infra-token.model.ts create mode 100644 packages/hoppscotch-backend/src/infra-token/infra-token.module.ts create mode 100644 packages/hoppscotch-backend/src/infra-token/infra-token.resolver.ts create mode 100644 packages/hoppscotch-backend/src/infra-token/infra-token.service.ts create mode 100644 packages/hoppscotch-backend/src/infra-token/request-response.dto.ts create mode 100644 packages/hoppscotch-backend/src/interceptors/infra-token.interceptor.ts diff --git a/packages/hoppscotch-backend/package.json b/packages/hoppscotch-backend/package.json index 519757416..dc5e03090 100644 --- a/packages/hoppscotch-backend/package.json +++ b/packages/hoppscotch-backend/package.json @@ -35,11 +35,14 @@ "@nestjs/passport": "10.0.2", "@nestjs/platform-express": "10.2.7", "@nestjs/schedule": "4.0.1", + "@nestjs/swagger": "7.4.0", "@nestjs/terminus": "10.2.3", "@nestjs/throttler": "5.0.1", "@prisma/client": "5.8.1", "argon2": "0.30.3", "bcrypt": "5.1.0", + "class-transformer": "0.5.1", + "class-validator": "0.14.1", "cookie": "0.5.0", "cookie-parser": "1.4.6", "cron": "3.1.6", diff --git a/packages/hoppscotch-backend/prisma/migrations/20240726121956_infra_token/migration.sql b/packages/hoppscotch-backend/prisma/migrations/20240726121956_infra_token/migration.sql new file mode 100644 index 000000000..10971ba62 --- /dev/null +++ b/packages/hoppscotch-backend/prisma/migrations/20240726121956_infra_token/migration.sql @@ -0,0 +1,15 @@ +-- CreateTable +CREATE TABLE "InfraToken" ( + "id" TEXT NOT NULL, + "creatorUid" TEXT NOT NULL, + "label" TEXT NOT NULL, + "token" TEXT NOT NULL, + "expiresOn" TIMESTAMP(3), + "createdOn" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedOn" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "InfraToken_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "InfraToken_token_key" ON "InfraToken"("token"); diff --git a/packages/hoppscotch-backend/prisma/schema.prisma b/packages/hoppscotch-backend/prisma/schema.prisma index 7a3fad4bf..b0731c957 100644 --- a/packages/hoppscotch-backend/prisma/schema.prisma +++ b/packages/hoppscotch-backend/prisma/schema.prisma @@ -232,3 +232,13 @@ model PersonalAccessToken { createdOn DateTime @default(now()) @db.Timestamp(3) updatedOn DateTime @updatedAt @db.Timestamp(3) } + +model InfraToken { + id String @id @default(cuid()) + creatorUid String + label String + token String @unique @default(uuid()) + expiresOn DateTime? @db.Timestamp(3) + createdOn DateTime @default(now()) @db.Timestamp(3) + updatedOn DateTime @default(now()) @db.Timestamp(3) +} diff --git a/packages/hoppscotch-backend/src/access-token/access-token.service.ts b/packages/hoppscotch-backend/src/access-token/access-token.service.ts index 3b5f3c87a..e6a997746 100644 --- a/packages/hoppscotch-backend/src/access-token/access-token.service.ts +++ b/packages/hoppscotch-backend/src/access-token/access-token.service.ts @@ -2,7 +2,7 @@ import { HttpStatus, Injectable } from '@nestjs/common'; import { PrismaService } from 'src/prisma/prisma.service'; import { CreateAccessTokenDto } from './dto/create-access-token.dto'; import { AuthUser } from 'src/types/AuthUser'; -import { isValidLength } from 'src/utils'; +import { calculateExpirationDate, isValidLength } from 'src/utils'; import * as E from 'fp-ts/Either'; import { ACCESS_TOKEN_EXPIRY_INVALID, @@ -20,17 +20,6 @@ export class AccessTokenService { VALID_TOKEN_DURATIONS = [7, 30, 60, 90]; TOKEN_PREFIX = 'pat-'; - /** - * Calculate the expiration date of the token - * - * @param expiresOn Number of days the token is valid for - * @returns Date object of the expiration date - */ - private calculateExpirationDate(expiresOn: null | number) { - if (expiresOn === null) return null; - return new Date(Date.now() + expiresOn * 24 * 60 * 60 * 1000); - } - /** * Validate the expiration date of the token * @@ -97,9 +86,7 @@ export class AccessTokenService { data: { userUid: user.uid, label: createAccessTokenDto.label, - expiresOn: this.calculateExpirationDate( - createAccessTokenDto.expiryInDays, - ), + expiresOn: calculateExpirationDate(createAccessTokenDto.expiryInDays), }, }); diff --git a/packages/hoppscotch-backend/src/admin/admin.service.ts b/packages/hoppscotch-backend/src/admin/admin.service.ts index 982b7c79a..a55524a87 100644 --- a/packages/hoppscotch-backend/src/admin/admin.service.ts +++ b/packages/hoppscotch-backend/src/admin/admin.service.ts @@ -161,6 +161,13 @@ export class AdminService { * @returns an Either of boolean or error string */ async revokeUserInvitations(inviteeEmails: string[]) { + const areAllEmailsValid = inviteeEmails.every((email) => + validateEmail(email), + ); + if (!areAllEmailsValid) { + return E.left(INVALID_EMAIL); + } + try { await this.prisma.invitedUsers.deleteMany({ where: { diff --git a/packages/hoppscotch-backend/src/app.module.ts b/packages/hoppscotch-backend/src/app.module.ts index a4c62cf11..f86db38c2 100644 --- a/packages/hoppscotch-backend/src/app.module.ts +++ b/packages/hoppscotch-backend/src/app.module.ts @@ -29,6 +29,7 @@ import { ScheduleModule } from '@nestjs/schedule'; import { HealthModule } from './health/health.module'; import { AccessTokenModule } from './access-token/access-token.module'; import { UserLastActiveOnInterceptor } from './interceptors/user-last-active-on.interceptor'; +import { InfraTokenModule } from './infra-token/infra-token.module'; @Module({ imports: [ @@ -105,6 +106,7 @@ import { UserLastActiveOnInterceptor } from './interceptors/user-last-active-on. ScheduleModule.forRoot(), HealthModule, AccessTokenModule, + InfraTokenModule, ], providers: [ GQLComplexityPlugin, diff --git a/packages/hoppscotch-backend/src/decorators/bearer-token.decorator.ts b/packages/hoppscotch-backend/src/decorators/bearer-token.decorator.ts new file mode 100644 index 000000000..648ed549f --- /dev/null +++ b/packages/hoppscotch-backend/src/decorators/bearer-token.decorator.ts @@ -0,0 +1,15 @@ +import { createParamDecorator, ExecutionContext } from '@nestjs/common'; + +/** + ** Decorator to fetch refresh_token from cookie + */ +export const BearerToken = createParamDecorator( + (data: unknown, context: ExecutionContext) => { + const request = context.switchToHttp().getRequest(); + + // authorization token will be "Bearer " + const authorization = request.headers['authorization']; + // Remove "Bearer " and return the token only + return authorization.split(' ')[1]; + }, +); diff --git a/packages/hoppscotch-backend/src/errors.ts b/packages/hoppscotch-backend/src/errors.ts index 48f353e9e..1d424c066 100644 --- a/packages/hoppscotch-backend/src/errors.ts +++ b/packages/hoppscotch-backend/src/errors.ts @@ -810,3 +810,46 @@ export const ACCESS_TOKEN_INVALID = 'TOKEN_INVALID'; * (AccessTokenService) */ export const ACCESS_TOKENS_INVALID_DATA_ID = 'INVALID_ID'; + +/** + * The provided label for the infra-token is short (less than 3 characters) + * (InfraTokenService) + */ +export const INFRA_TOKEN_LABEL_SHORT = 'infra_token/label_too_short'; + +/** + * The provided expiryInDays value is not valid + * (InfraTokenService) + */ +export const INFRA_TOKEN_EXPIRY_INVALID = 'infra_token/expiry_days_invalid'; + +/** + * The provided Infra Token ID is invalid + * (InfraTokenService) + */ +export const INFRA_TOKEN_NOT_FOUND = 'infra_token/infra_token_not_found'; + +/** + * Authorization missing in header (Check 'Authorization' Header) + * (InfraTokenGuard) + */ +export const INFRA_TOKEN_HEADER_MISSING = + 'infra_token/authorization_token_missing'; + +/** + * Infra Token is invalid + * (InfraTokenGuard) + */ +export const INFRA_TOKEN_INVALID_TOKEN = 'infra_token/invalid_token'; + +/** + * Infra Token is expired + * (InfraTokenGuard) + */ +export const INFRA_TOKEN_EXPIRED = 'infra_token/expired'; + +/** + * Token creator not found + * (InfraTokenService) + */ +export const INFRA_TOKEN_CREATOR_NOT_FOUND = 'infra_token/creator_not_found'; diff --git a/packages/hoppscotch-backend/src/gql-schema.ts b/packages/hoppscotch-backend/src/gql-schema.ts index d8146e027..87d6dffd0 100644 --- a/packages/hoppscotch-backend/src/gql-schema.ts +++ b/packages/hoppscotch-backend/src/gql-schema.ts @@ -29,6 +29,7 @@ import { UserHistoryUserResolver } from './user-history/user.resolver'; import { UserSettingsUserResolver } from './user-settings/user.resolver'; import { InfraResolver } from './admin/infra.resolver'; import { InfraConfigResolver } from './infra-config/infra-config.resolver'; +import { InfraTokenResolver } from './infra-token/infra-token.resolver'; /** * All the resolvers present in the application. @@ -60,6 +61,7 @@ const RESOLVERS = [ UserSettingsResolver, UserSettingsUserResolver, InfraConfigResolver, + InfraTokenResolver, ]; /** diff --git a/packages/hoppscotch-backend/src/guards/infra-token.guard.ts b/packages/hoppscotch-backend/src/guards/infra-token.guard.ts new file mode 100644 index 000000000..bc5e56903 --- /dev/null +++ b/packages/hoppscotch-backend/src/guards/infra-token.guard.ts @@ -0,0 +1,47 @@ +import { + CanActivate, + ExecutionContext, + Injectable, + UnauthorizedException, +} from '@nestjs/common'; +import { PrismaService } from 'src/prisma/prisma.service'; +import { DateTime } from 'luxon'; +import { + INFRA_TOKEN_EXPIRED, + INFRA_TOKEN_HEADER_MISSING, + INFRA_TOKEN_INVALID_TOKEN, +} from 'src/errors'; + +@Injectable() +export class InfraTokenGuard implements CanActivate { + constructor(private readonly prisma: PrismaService) {} + + async canActivate(context: ExecutionContext): Promise { + const request = context.switchToHttp().getRequest(); + const authorization = request.headers['authorization']; + + if (!authorization) + throw new UnauthorizedException(INFRA_TOKEN_HEADER_MISSING); + + if (!authorization.startsWith('Bearer ')) + throw new UnauthorizedException(INFRA_TOKEN_INVALID_TOKEN); + + const token = authorization.split(' ')[1]; + + if (!token) throw new UnauthorizedException(INFRA_TOKEN_INVALID_TOKEN); + + const infraToken = await this.prisma.infraToken.findUnique({ + where: { token }, + }); + + if (infraToken === null) + throw new UnauthorizedException(INFRA_TOKEN_INVALID_TOKEN); + + const currentTime = DateTime.now().toISO(); + if (currentTime > infraToken.expiresOn.toISOString()) { + throw new UnauthorizedException(INFRA_TOKEN_EXPIRED); + } + + return true; + } +} diff --git a/packages/hoppscotch-backend/src/infra-token/infra-token.controller.ts b/packages/hoppscotch-backend/src/infra-token/infra-token.controller.ts new file mode 100644 index 000000000..67b12e5c9 --- /dev/null +++ b/packages/hoppscotch-backend/src/infra-token/infra-token.controller.ts @@ -0,0 +1,248 @@ +import { + Body, + Controller, + Delete, + Get, + HttpStatus, + Param, + Patch, + Post, + Query, + UseGuards, + UseInterceptors, +} from '@nestjs/common'; +import { plainToInstance } from 'class-transformer'; +import { AdminService } from 'src/admin/admin.service'; +import { InfraTokenGuard } from 'src/guards/infra-token.guard'; +import { ThrottlerBehindProxyGuard } from 'src/guards/throttler-behind-proxy.guard'; +import { + DeleteUserInvitationRequest, + DeleteUserInvitationResponse, + ExceptionResponse, + GetUserInvitationResponse, + GetUsersRequestQuery, + GetUserResponse, + UpdateUserRequest, + UpdateUserAdminStatusRequest, + UpdateUserAdminStatusResponse, + CreateUserInvitationRequest, + CreateUserInvitationResponse, +} from './request-response.dto'; +import * as E from 'fp-ts/Either'; +import * as O from 'fp-ts/Option'; +import { OffsetPaginationArgs } from 'src/types/input-types.args'; +import { + ApiBadRequestResponse, + ApiCreatedResponse, + ApiNotFoundResponse, + ApiOkResponse, + ApiSecurity, + ApiTags, +} from '@nestjs/swagger'; +import { throwHTTPErr } from 'src/utils'; +import { UserService } from 'src/user/user.service'; +import { + INFRA_TOKEN_CREATOR_NOT_FOUND, + USER_NOT_FOUND, + USERS_NOT_FOUND, +} from 'src/errors'; +import { InfraTokenService } from './infra-token.service'; +import { InfraTokenInterceptor } from 'src/interceptors/infra-token.interceptor'; +import { BearerToken } from 'src/decorators/bearer-token.decorator'; + +@ApiTags('User Management API') +@ApiSecurity('infra-token') +@UseGuards(ThrottlerBehindProxyGuard, InfraTokenGuard) +@UseInterceptors(InfraTokenInterceptor) +@Controller({ path: 'infra', version: '1' }) +export class InfraTokensController { + constructor( + private readonly infraTokenService: InfraTokenService, + private readonly adminService: AdminService, + private readonly userService: UserService, + ) {} + + @Post('user-invitations') + @ApiCreatedResponse({ + description: 'Create a user invitation', + type: CreateUserInvitationResponse, + }) + @ApiBadRequestResponse({ type: ExceptionResponse }) + @ApiNotFoundResponse({ type: ExceptionResponse }) + async createUserInvitation( + @BearerToken() token: string, + @Body() dto: CreateUserInvitationRequest, + ) { + const createdInvitations = + await this.infraTokenService.createUserInvitation(token, dto); + + if (E.isLeft(createdInvitations)) { + const statusCode = + (createdInvitations.left as string) === INFRA_TOKEN_CREATOR_NOT_FOUND + ? HttpStatus.NOT_FOUND + : HttpStatus.BAD_REQUEST; + + throwHTTPErr({ message: createdInvitations.left, statusCode }); + } + + return plainToInstance( + CreateUserInvitationResponse, + { invitationLink: process.env.VITE_BASE_URL }, + { + excludeExtraneousValues: true, + enableImplicitConversion: true, + }, + ); + } + + @Get('user-invitations') + @ApiOkResponse({ + description: 'Get pending user invitations', + type: [GetUserInvitationResponse], + }) + async getPendingUserInvitation( + @Query() paginationQuery: OffsetPaginationArgs, + ) { + const pendingInvitedUsers = await this.adminService.fetchInvitedUsers( + paginationQuery, + ); + + return plainToInstance(GetUserInvitationResponse, pendingInvitedUsers, { + excludeExtraneousValues: true, + enableImplicitConversion: true, + }); + } + + @Delete('user-invitations') + @ApiOkResponse({ + description: 'Delete a pending user invitation', + type: DeleteUserInvitationResponse, + }) + @ApiBadRequestResponse({ type: ExceptionResponse }) + async deleteUserInvitation(@Body() dto: DeleteUserInvitationRequest) { + const isDeleted = await this.adminService.revokeUserInvitations( + dto.inviteeEmails, + ); + + if (E.isLeft(isDeleted)) { + throwHTTPErr({ + message: isDeleted.left, + statusCode: HttpStatus.BAD_REQUEST, + }); + } + + return plainToInstance( + DeleteUserInvitationResponse, + { message: isDeleted.right }, + { + excludeExtraneousValues: true, + enableImplicitConversion: true, + }, + ); + } + + @Get('users') + @ApiOkResponse({ + description: 'Get users list', + type: [GetUserResponse], + }) + async getUsers(@Query() query: GetUsersRequestQuery) { + const users = await this.userService.fetchAllUsersV2(query.searchString, { + take: query.take, + skip: query.skip, + }); + + return plainToInstance(GetUserResponse, users, { + excludeExtraneousValues: true, + enableImplicitConversion: true, + }); + } + + @Get('users/:uid') + @ApiOkResponse({ + description: 'Get user details', + type: GetUserResponse, + }) + @ApiNotFoundResponse({ type: ExceptionResponse }) + async getUser(@Param('uid') uid: string) { + const user = await this.userService.findUserById(uid); + + if (O.isNone(user)) { + throwHTTPErr({ + message: USER_NOT_FOUND, + statusCode: HttpStatus.NOT_FOUND, + }); + } + + return plainToInstance(GetUserResponse, user.value, { + excludeExtraneousValues: true, + enableImplicitConversion: true, + }); + } + + @Patch('users/:uid') + @ApiOkResponse({ + description: 'Update user display name', + type: GetUserResponse, + }) + @ApiBadRequestResponse({ type: ExceptionResponse }) + @ApiNotFoundResponse({ type: ExceptionResponse }) + async updateUser(@Param('uid') uid: string, @Body() body: UpdateUserRequest) { + const updatedUser = await this.userService.updateUserDisplayName( + uid, + body.displayName, + ); + + if (E.isLeft(updatedUser)) { + const statusCode = + (updatedUser.left as string) === USER_NOT_FOUND + ? HttpStatus.NOT_FOUND + : HttpStatus.BAD_REQUEST; + + throwHTTPErr({ message: updatedUser.left, statusCode }); + } + + return plainToInstance(GetUserResponse, updatedUser.right, { + excludeExtraneousValues: true, + enableImplicitConversion: true, + }); + } + + @Patch('users/:uid/admin-status') + @ApiOkResponse({ + description: 'Update user admin status', + type: UpdateUserAdminStatusResponse, + }) + @ApiBadRequestResponse({ type: ExceptionResponse }) + @ApiNotFoundResponse({ type: ExceptionResponse }) + async updateUserAdminStatus( + @Param('uid') uid: string, + @Body() body: UpdateUserAdminStatusRequest, + ) { + let updatedUser; + + if (body.isAdmin) { + updatedUser = await this.adminService.makeUsersAdmin([uid]); + } else { + updatedUser = await this.adminService.demoteUsersByAdmin([uid]); + } + + if (E.isLeft(updatedUser)) { + const statusCode = + (updatedUser.left as string) === USERS_NOT_FOUND + ? HttpStatus.NOT_FOUND + : HttpStatus.BAD_REQUEST; + + throwHTTPErr({ message: updatedUser.left as string, statusCode }); + } + + return plainToInstance( + UpdateUserAdminStatusResponse, + { message: updatedUser.right }, + { + excludeExtraneousValues: true, + enableImplicitConversion: true, + }, + ); + } +} diff --git a/packages/hoppscotch-backend/src/infra-token/infra-token.model.ts b/packages/hoppscotch-backend/src/infra-token/infra-token.model.ts new file mode 100644 index 000000000..9790830fe --- /dev/null +++ b/packages/hoppscotch-backend/src/infra-token/infra-token.model.ts @@ -0,0 +1,43 @@ +import { Field, ID, ObjectType } from '@nestjs/graphql'; + +@ObjectType() +export class InfraToken { + @Field(() => ID, { + description: 'ID of the infra token', + }) + id: string; + + @Field(() => String, { + description: 'Label of the infra token', + }) + label: string; + + @Field(() => Date, { + description: 'Date when the infra token was created', + }) + createdOn: Date; + + @Field(() => Date, { + description: 'Date when the infra token expires', + nullable: true, + }) + expiresOn: Date; + + @Field(() => Date, { + description: 'Date when the infra token was last used', + }) + lastUsedOn: Date; +} + +@ObjectType() +export class CreateInfraTokenResponse { + @Field(() => String, { + description: 'The infra token', + }) + token: string; + + @Field(() => InfraToken, { + description: 'Infra token info', + }) + info: InfraToken; +} diff --git a/packages/hoppscotch-backend/src/infra-token/infra-token.module.ts b/packages/hoppscotch-backend/src/infra-token/infra-token.module.ts new file mode 100644 index 000000000..a8e6f58c8 --- /dev/null +++ b/packages/hoppscotch-backend/src/infra-token/infra-token.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common'; +import { PrismaModule } from 'src/prisma/prisma.module'; +import { InfraTokenResolver } from './infra-token.resolver'; +import { InfraTokenService } from './infra-token.service'; +import { InfraTokensController } from './infra-token.controller'; +import { AdminModule } from 'src/admin/admin.module'; +import { UserModule } from 'src/user/user.module'; + +@Module({ + imports: [PrismaModule, AdminModule, UserModule], + controllers: [InfraTokensController], + providers: [InfraTokenResolver, InfraTokenService], +}) +export class InfraTokenModule {} diff --git a/packages/hoppscotch-backend/src/infra-token/infra-token.resolver.ts b/packages/hoppscotch-backend/src/infra-token/infra-token.resolver.ts new file mode 100644 index 000000000..c342732e0 --- /dev/null +++ b/packages/hoppscotch-backend/src/infra-token/infra-token.resolver.ts @@ -0,0 +1,68 @@ +import { Args, ID, Mutation, Query, Resolver } from '@nestjs/graphql'; +import { CreateInfraTokenResponse, InfraToken } from './infra-token.model'; +import { UseGuards } from '@nestjs/common'; +import { GqlThrottlerGuard } from 'src/guards/gql-throttler.guard'; +import { InfraTokenService } from './infra-token.service'; +import { GqlAuthGuard } from 'src/guards/gql-auth.guard'; +import { GqlAdminGuard } from 'src/admin/guards/gql-admin.guard'; +import { OffsetPaginationArgs } from 'src/types/input-types.args'; +import { GqlAdmin } from 'src/admin/decorators/gql-admin.decorator'; +import { Admin } from 'src/admin/admin.model'; +import * as E from 'fp-ts/Either'; +import { throwErr } from 'src/utils'; + +@UseGuards(GqlThrottlerGuard) +@Resolver(() => InfraToken) +export class InfraTokenResolver { + constructor(private readonly infraTokenService: InfraTokenService) {} + + /* Query */ + + @Query(() => [InfraToken], { + description: 'Get list of infra tokens', + }) + @UseGuards(GqlAuthGuard, GqlAdminGuard) + infraTokens(@Args() args: OffsetPaginationArgs) { + return this.infraTokenService.getAll(args.take, args.skip); + } + + /* Mutations */ + + @Mutation(() => CreateInfraTokenResponse, { + description: 'Create a new infra token', + }) + @UseGuards(GqlAuthGuard, GqlAdminGuard) + async createInfraToken( + @GqlAdmin() admin: Admin, + @Args({ name: 'label', description: 'Label of the token' }) label: string, + @Args({ + name: 'expiryInDays', + description: 'Number of days the token is valid for', + nullable: true, + }) + expiryInDays: number, + ) { + const infraToken = await this.infraTokenService.create( + label, + expiryInDays, + admin, + ); + + if (E.isLeft(infraToken)) throwErr(infraToken.left); + return infraToken.right; + } + + @Mutation(() => Boolean, { + description: 'Revoke an infra token', + }) + @UseGuards(GqlAuthGuard, GqlAdminGuard) + async revokeInfraToken( + @Args({ name: 'id', type: () => ID, description: 'ID of the infra token' }) + id: string, + ) { + const res = await this.infraTokenService.revoke(id); + + if (E.isLeft(res)) throwErr(res.left); + return res.right; + } +} diff --git a/packages/hoppscotch-backend/src/infra-token/infra-token.service.ts b/packages/hoppscotch-backend/src/infra-token/infra-token.service.ts new file mode 100644 index 000000000..887dfb350 --- /dev/null +++ b/packages/hoppscotch-backend/src/infra-token/infra-token.service.ts @@ -0,0 +1,160 @@ +import { Injectable } from '@nestjs/common'; +import { InfraToken as dbInfraToken } from '@prisma/client'; +import { PrismaService } from 'src/prisma/prisma.service'; +import { CreateInfraTokenResponse, InfraToken } from './infra-token.model'; +import { calculateExpirationDate, isValidLength } from 'src/utils'; +import { Admin } from 'src/admin/admin.model'; +import { + INFRA_TOKEN_CREATOR_NOT_FOUND, + INFRA_TOKEN_EXPIRY_INVALID, + INFRA_TOKEN_LABEL_SHORT, + INFRA_TOKEN_NOT_FOUND, +} from 'src/errors'; +import * as E from 'fp-ts/Either'; +import { CreateUserInvitationRequest } from './request-response.dto'; +import { AdminService } from 'src/admin/admin.service'; + +@Injectable() +export class InfraTokenService { + constructor( + private readonly prisma: PrismaService, + private readonly adminService: AdminService, + ) {} + + TITLE_LENGTH = 3; + VALID_TOKEN_DURATIONS = [7, 30, 60, 90]; + + /** + * Validate the expiration date of the token + * + * @param expiresOn Number of days the token is valid for + * @returns Boolean indicating if the expiration date is valid + */ + private validateExpirationDate(expiresOn: null | number) { + if (expiresOn === null || this.VALID_TOKEN_DURATIONS.includes(expiresOn)) + return true; + return false; + } + + /** + * Typecast a database InfraToken to a InfraToken model + * @param dbInfraToken database InfraToken + * @returns InfraToken model + */ + private cast(dbInfraToken: dbInfraToken): InfraToken { + return { + id: dbInfraToken.id, + label: dbInfraToken.label, + createdOn: dbInfraToken.createdOn, + expiresOn: dbInfraToken.expiresOn, + lastUsedOn: dbInfraToken.updatedOn, + }; + } + + /** + * Fetch all infra tokens with pagination + * @param take take for pagination + * @param skip skip for pagination + * @returns List of InfraToken models + */ + async getAll(take = 10, skip = 0) { + const infraTokens = await this.prisma.infraToken.findMany({ + take, + skip, + orderBy: { createdOn: 'desc' }, + }); + + return infraTokens.map((token) => this.cast(token)); + } + + /** + * Create a new infra token + * @param label label of the token + * @param expiryInDays expiry duration of the token + * @param admin admin who created the token + * @returns Either of error message or CreateInfraTokenResponse + */ + async create(label: string, expiryInDays: number, admin: Admin) { + if (!isValidLength(label, this.TITLE_LENGTH)) { + return E.left(INFRA_TOKEN_LABEL_SHORT); + } + + if (!this.validateExpirationDate(expiryInDays ?? null)) { + return E.left(INFRA_TOKEN_EXPIRY_INVALID); + } + + const createdInfraToken = await this.prisma.infraToken.create({ + data: { + creatorUid: admin.uid, + label, + expiresOn: calculateExpirationDate(expiryInDays ?? null) ?? undefined, + }, + }); + + const res: CreateInfraTokenResponse = { + token: createdInfraToken.token, + info: this.cast(createdInfraToken), + }; + + return E.right(res); + } + + /** + * Revoke an infra token + * @param id ID of the infra token + * @returns Either of error or true + */ + async revoke(id: string) { + try { + await this.prisma.infraToken.delete({ + where: { id }, + }); + } catch (error) { + return E.left(INFRA_TOKEN_NOT_FOUND); + } + return E.right(true); + } + + /** + * Update the last used on of an infra token + * @param token token to update + * @returns Either of error or InfraToken + */ + async updateLastUsedOn(token: string) { + try { + const infraToken = await this.prisma.infraToken.update({ + where: { token }, + data: { updatedOn: new Date() }, + }); + return E.right(this.cast(infraToken)); + } catch (error) { + return E.left(INFRA_TOKEN_NOT_FOUND); + } + } + + /** + * Create a user invitation using an infra token + * @param token token used to create the invitation + * @param dto CreateUserInvitationRequest + * @returns Either of error or InvitedUser + */ + async createUserInvitation(token: string, dto: CreateUserInvitationRequest) { + const infraToken = await this.prisma.infraToken.findUnique({ + where: { token }, + }); + + const tokenCreator = await this.prisma.user.findUnique({ + where: { uid: infraToken.creatorUid }, + }); + if (!tokenCreator) return E.left(INFRA_TOKEN_CREATOR_NOT_FOUND); + + const invitedUser = await this.adminService.inviteUserToSignInViaEmail( + tokenCreator.uid, + tokenCreator.email, + dto.inviteeEmail, + ); + if (E.isLeft(invitedUser)) return E.left(invitedUser.left); + + return E.right(invitedUser); + } +} diff --git a/packages/hoppscotch-backend/src/infra-token/request-response.dto.ts b/packages/hoppscotch-backend/src/infra-token/request-response.dto.ts new file mode 100644 index 000000000..9bacfbf12 --- /dev/null +++ b/packages/hoppscotch-backend/src/infra-token/request-response.dto.ts @@ -0,0 +1,115 @@ +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { Expose, Transform, Type } from 'class-transformer'; +import { + ArrayMinSize, + IsArray, + IsBoolean, + IsEmail, + IsNotEmpty, + IsOptional, + IsString, + MinLength, +} from 'class-validator'; +import { OffsetPaginationArgs } from 'src/types/input-types.args'; + +// POST v1/infra/user-invitations +export class CreateUserInvitationRequest { + @Type(() => String) + @IsNotEmpty() + @ApiProperty() + inviteeEmail: string; +} +export class CreateUserInvitationResponse { + @ApiProperty() + @Expose() + invitationLink: string; +} + +// GET v1/infra/user-invitations +export class GetUserInvitationResponse { + @ApiProperty() + @Expose() + inviteeEmail: string; + + @ApiProperty() + @Expose() + invitedOn: Date; +} + +// DELETE v1/infra/user-invitations +export class DeleteUserInvitationRequest { + @IsArray() + @ArrayMinSize(1) + @Type(() => String) + @IsNotEmpty() + @ApiProperty() + inviteeEmails: string[]; +} +export class DeleteUserInvitationResponse { + @ApiProperty() + @Expose() + message: string; +} + +// POST v1/infra/users +export class GetUsersRequestQuery extends OffsetPaginationArgs { + @IsOptional() + @IsString() + @MinLength(1) + @ApiPropertyOptional() + searchString: string; +} +export class GetUserResponse { + @ApiProperty() + @Expose() + uid: string; + + @ApiProperty() + @Expose() + displayName: string; + + @ApiProperty() + @Expose() + email: string; + + @ApiProperty() + @Expose() + photoURL: string; + + @ApiProperty() + @Expose() + isAdmin: boolean; +} + +// PATCH v1/infra/users/:uid +export class UpdateUserRequest { + @IsOptional() + @IsString() + @MinLength(1) + @ApiPropertyOptional() + displayName: string; +} + +// PATCH v1/infra/users/:uid/admin-status +export class UpdateUserAdminStatusRequest { + @IsBoolean() + @IsNotEmpty() + @ApiProperty() + isAdmin: boolean; +} +export class UpdateUserAdminStatusResponse { + @ApiProperty() + @Expose() + message: string; +} + +// Used for Swagger doc only, in codebase throwHTTPErr function is used to throw errors +export class ExceptionResponse { + @ApiProperty() + @Expose() + message: string; + + @ApiProperty() + @Expose() + statusCode: number; +} diff --git a/packages/hoppscotch-backend/src/interceptors/infra-token.interceptor.ts b/packages/hoppscotch-backend/src/interceptors/infra-token.interceptor.ts new file mode 100644 index 000000000..bfddda748 --- /dev/null +++ b/packages/hoppscotch-backend/src/interceptors/infra-token.interceptor.ts @@ -0,0 +1,30 @@ +import { + BadRequestException, + CallHandler, + ExecutionContext, + Injectable, + NestInterceptor, +} from '@nestjs/common'; +import { Observable } from 'rxjs'; +import { INFRA_TOKEN_NOT_FOUND } from 'src/errors'; +import { InfraTokenService } from 'src/infra-token/infra-token.service'; + +@Injectable() +export class InfraTokenInterceptor implements NestInterceptor { + constructor(private readonly infraTokenService: InfraTokenService) {} + + intercept(context: ExecutionContext, handler: CallHandler): Observable { + const req = context.switchToHttp().getRequest(); + const authHeader = req.headers.authorization; + + if (!authHeader || !authHeader.startsWith('Bearer ')) { + throw new BadRequestException(INFRA_TOKEN_NOT_FOUND); + } + + const token = authHeader.split(' ')[1]; + + this.infraTokenService.updateLastUsedOn(token); + + return handler.handle(); + } +} diff --git a/packages/hoppscotch-backend/src/main.ts b/packages/hoppscotch-backend/src/main.ts index a32079c74..c8eed7724 100644 --- a/packages/hoppscotch-backend/src/main.ts +++ b/packages/hoppscotch-backend/src/main.ts @@ -2,11 +2,40 @@ import { NestFactory } from '@nestjs/core'; import { json } from 'express'; import { AppModule } from './app.module'; import * as cookieParser from 'cookie-parser'; -import { VersioningType } from '@nestjs/common'; +import { ValidationPipe, VersioningType } from '@nestjs/common'; import * as session from 'express-session'; import { emitGQLSchemaFile } from './gql-schema'; import { checkEnvironmentAuthProvider } from './utils'; import { ConfigService } from '@nestjs/config'; +import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; +import { InfraTokensController } from './infra-token/infra-token.controller'; +import { InfraTokenModule } from './infra-token/infra-token.module'; + +function setupSwagger(app) { + const swaggerDocPath = '/api-docs'; + + const config = new DocumentBuilder() + .setTitle('Hoppscotch API Documentation') + .setDescription('APIs for external integration') + .addApiKey( + { + type: 'apiKey', + name: 'Authorization', + in: 'header', + scheme: 'bearer', + bearerFormat: 'Bearer', + }, + 'infra-token', + ) + .build(); + + const document = SwaggerModule.createDocument(app, config, { + include: [InfraTokenModule], + }); + SwaggerModule.setup(swaggerDocPath, app, document, { + swaggerOptions: { persistAuthorization: true, ignoreGlobalPrefix: true }, + }); +} async function bootstrap() { const app = await NestFactory.create(AppModule); @@ -53,6 +82,14 @@ async function bootstrap() { type: VersioningType.URI, }); app.use(cookieParser()); + app.useGlobalPipes( + new ValidationPipe({ + transform: true, + }), + ); + + await setupSwagger(app); + await app.listen(configService.get('PORT') || 3170); // Graceful shutdown diff --git a/packages/hoppscotch-backend/src/types/input-types.args.ts b/packages/hoppscotch-backend/src/types/input-types.args.ts index 14a324997..414b60cf9 100644 --- a/packages/hoppscotch-backend/src/types/input-types.args.ts +++ b/packages/hoppscotch-backend/src/types/input-types.args.ts @@ -1,4 +1,7 @@ import { ArgsType, Field, ID, InputType } from '@nestjs/graphql'; +import { ApiPropertyOptional } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; +import { IsNotEmpty, IsOptional } from 'class-validator'; @ArgsType() @InputType() @@ -21,6 +24,10 @@ export class PaginationArgs { @ArgsType() @InputType() export class OffsetPaginationArgs { + @IsOptional() + @IsNotEmpty() + @Type(() => Number) + @ApiPropertyOptional() @Field({ nullable: true, defaultValue: 0, @@ -28,6 +35,10 @@ export class OffsetPaginationArgs { }) skip: number; + @IsOptional() + @IsNotEmpty() + @Type(() => Number) + @ApiPropertyOptional() @Field({ nullable: true, defaultValue: 10, diff --git a/packages/hoppscotch-backend/src/utils.ts b/packages/hoppscotch-backend/src/utils.ts index f201a37b3..cc32967cb 100644 --- a/packages/hoppscotch-backend/src/utils.ts +++ b/packages/hoppscotch-backend/src/utils.ts @@ -286,3 +286,14 @@ export function escapeSqlLikeString(str: string) { } }); } + +/** + * Calculate the expiration date of the token + * + * @param expiresOn Number of days the token is valid for + * @returns Date object of the expiration date + */ +export function calculateExpirationDate(expiresOn: null | number) { + if (expiresOn === null) return null; + return new Date(Date.now() + expiresOn * 24 * 60 * 60 * 1000); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index adb9da987..152bb69a8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -76,40 +76,43 @@ importers: version: 4.9.5(graphql@16.8.1) '@nestjs-modules/mailer': specifier: 1.9.1 - version: 1.9.1(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(nodemailer@6.9.1) + version: 1.9.1(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(nodemailer@6.9.1) '@nestjs/apollo': specifier: 12.0.9 - version: 12.0.9(@apollo/server@4.9.5(graphql@16.8.1))(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/graphql@12.0.9(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(graphql@16.8.1)(reflect-metadata@0.1.13))(graphql@16.8.1) + version: 12.0.9(@apollo/server@4.9.5(graphql@16.8.1))(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/graphql@12.0.9(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(class-transformer@0.5.1)(class-validator@0.14.1)(graphql@16.8.1)(reflect-metadata@0.1.13))(graphql@16.8.1) '@nestjs/common': specifier: 10.2.7 - version: 10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0) + version: 10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0) '@nestjs/config': specifier: 3.1.1 - version: 3.1.1(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(reflect-metadata@0.1.13) + version: 3.1.1(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(reflect-metadata@0.1.13) '@nestjs/core': specifier: 10.2.7 - version: 10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) + version: 10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) '@nestjs/graphql': specifier: 12.0.9 - version: 12.0.9(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(graphql@16.8.1)(reflect-metadata@0.1.13) + version: 12.0.9(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(class-transformer@0.5.1)(class-validator@0.14.1)(graphql@16.8.1)(reflect-metadata@0.1.13) '@nestjs/jwt': specifier: 10.1.1 - version: 10.1.1(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0)) + version: 10.1.1(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0)) '@nestjs/passport': specifier: 10.0.2 - version: 10.0.2(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(passport@0.6.0) + version: 10.0.2(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(passport@0.6.0) '@nestjs/platform-express': specifier: 10.2.7 - version: 10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7) + version: 10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7) '@nestjs/schedule': specifier: 4.0.1 - version: 4.0.1(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0)) + version: 4.0.1(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0)) + '@nestjs/swagger': + specifier: 7.4.0 + version: 7.4.0(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13) '@nestjs/terminus': specifier: 10.2.3 - version: 10.2.3(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@prisma/client@5.8.1(prisma@5.8.1))(reflect-metadata@0.1.13)(rxjs@7.6.0) + version: 10.2.3(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@prisma/client@5.8.1(prisma@5.8.1))(reflect-metadata@0.1.13)(rxjs@7.6.0) '@nestjs/throttler': specifier: 5.0.1 - version: 5.0.1(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(reflect-metadata@0.1.13) + version: 5.0.1(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(reflect-metadata@0.1.13) '@prisma/client': specifier: 5.8.1 version: 5.8.1(prisma@5.8.1) @@ -119,6 +122,12 @@ importers: bcrypt: specifier: 5.1.0 version: 5.1.0 + class-transformer: + specifier: 0.5.1 + version: 0.5.1 + class-validator: + specifier: 0.14.1 + version: 0.14.1 cookie: specifier: 0.5.0 version: 0.5.0 @@ -203,7 +212,7 @@ importers: version: 10.0.3(chokidar@3.5.3)(typescript@4.9.3) '@nestjs/testing': specifier: 10.2.7 - version: 10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7)) + version: 10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7)) '@relmify/jest-fp-ts': specifier: 2.0.2 version: 2.0.2(fp-ts@2.13.1)(io-ts@2.2.16(fp-ts@2.13.1)) @@ -763,7 +772,7 @@ importers: version: 4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0) vite-plugin-checker: specifier: 0.6.2 - version: 0.6.2(eslint@8.57.0)(meow@8.1.2)(optionator@0.9.4)(typescript@5.3.2)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0))(vue-tsc@1.8.24(typescript@5.3.2)) + version: 0.6.2(eslint@8.57.0)(optionator@0.9.4)(typescript@5.3.2)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0))(vue-tsc@1.8.24(typescript@5.3.2)) vite-plugin-fonts: specifier: 0.7.0 version: 0.7.0(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0)) @@ -882,7 +891,7 @@ importers: version: 2.8.4 ts-jest: specifier: 27.1.5 - version: 27.1.5(@babel/core@7.24.5)(@types/jest@27.5.2)(babel-jest@29.7.0(@babel/core@7.24.5))(jest@29.7.0(@types/node@17.0.45)(ts-node@10.9.1(@swc/core@1.4.2)(@types/node@17.0.45)(typescript@4.9.5)))(typescript@4.9.5) + version: 27.1.5(@babel/core@7.24.5)(@types/jest@27.5.2)(jest@29.7.0(@types/node@17.0.45)(ts-node@10.9.1(@swc/core@1.4.2)(@types/node@17.0.45)(typescript@4.9.5)))(typescript@4.9.5) typescript: specifier: 4.9.5 version: 4.9.5 @@ -1066,7 +1075,7 @@ importers: version: 0.14.9(@vue/compiler-sfc@3.3.10)(vue-template-compiler@2.7.16) unplugin-vue-components: specifier: 0.21.0 - version: 0.21.0(@babel/parser@7.24.5)(esbuild@0.20.2)(rollup@3.29.4)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0))(vue@3.3.9(typescript@4.9.5))(webpack@5.91.0(@swc/core@1.4.2)(esbuild@0.20.2)) + version: 0.21.0(@babel/parser@7.24.5)(esbuild@0.20.2)(rollup@2.79.1)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0))(vue@3.3.9(typescript@4.9.5))(webpack@5.91.0(@swc/core@1.4.2)(esbuild@0.20.2)) vite: specifier: 4.5.0 version: 4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0) @@ -1075,7 +1084,7 @@ importers: version: 1.0.11(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0)) vite-plugin-inspect: specifier: 0.7.38 - version: 0.7.38(rollup@3.29.4)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0)) + version: 0.7.38(rollup@2.79.1)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0)) vite-plugin-pages: specifier: 0.26.0 version: 0.26.0(@vue/compiler-sfc@3.3.10)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0)) @@ -1235,7 +1244,7 @@ importers: version: 0.17.4(@vue/compiler-sfc@3.3.10)(vue-template-compiler@2.7.16) unplugin-vue-components: specifier: 0.25.2 - version: 0.25.2(@babel/parser@7.24.5)(rollup@3.29.4)(vue@3.3.9(typescript@5.3.2)) + version: 0.25.2(@babel/parser@7.24.5)(rollup@4.17.2)(vue@3.3.9(typescript@5.3.2)) vite: specifier: 4.5.0 version: 4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0) @@ -1247,7 +1256,7 @@ importers: version: 1.0.11(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0)) vite-plugin-inspect: specifier: 0.7.42 - version: 0.7.42(rollup@3.29.4)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0)) + version: 0.7.42(rollup@4.17.2)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0)) vite-plugin-pages: specifier: 0.31.0 version: 0.31.0(@vue/compiler-sfc@3.3.10)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0)) @@ -1289,7 +1298,7 @@ importers: version: 0.1.0(vue@3.3.9(typescript@4.9.3)) '@intlify/unplugin-vue-i18n': specifier: 1.2.0 - version: 1.2.0(rollup@3.29.4)(vue-i18n@9.2.2(vue@3.3.9(typescript@4.9.3))) + version: 1.2.0(rollup@2.79.1)(vue-i18n@9.2.2(vue@3.3.9(typescript@4.9.3))) '@types/cors': specifier: 2.8.13 version: 2.8.13 @@ -1355,7 +1364,7 @@ importers: version: 0.14.9(@vue/compiler-sfc@3.2.45)(vue-template-compiler@2.7.16) unplugin-vue-components: specifier: 0.21.0 - version: 0.21.0(@babel/parser@7.24.5)(esbuild@0.20.2)(rollup@3.29.4)(vite@3.2.4(@types/node@18.18.8)(sass@1.58.0)(terser@5.31.0))(vue@3.3.9(typescript@4.9.3))(webpack@5.91.0(@swc/core@1.4.2)(esbuild@0.20.2)) + version: 0.21.0(@babel/parser@7.24.5)(esbuild@0.20.2)(rollup@2.79.1)(vite@3.2.4(@types/node@18.18.8)(sass@1.58.0)(terser@5.31.0))(vue@3.3.9(typescript@4.9.3))(webpack@5.91.0(@swc/core@1.4.2)(esbuild@0.20.2)) vue: specifier: 3.3.9 version: 3.3.9(typescript@4.9.3) @@ -3404,10 +3413,12 @@ packages: '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/config-array@0.9.5': resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} @@ -3415,9 +3426,11 @@ packages: '@humanwhocodes/object-schema@1.2.1': resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + deprecated: Use @eslint/object-schema instead '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead '@iconify-json/lucide@1.1.144': resolution: {integrity: sha512-MdpwW2zrSmxgUUyZs5zX7GqlqoTMvK1fpIFQKkXOwsxWfijAjyEWP2oWFFdVIKUoDyMSbJzXXIwon68D/Q4PcQ==} @@ -3775,6 +3788,9 @@ packages: '@mdn/browser-compat-data@5.5.25': resolution: {integrity: sha512-0AobSA9fCuAoJnBSIIWWpoAEuyWC3gCG5u2TshSDHzMOAO4/ef2Lv6Qma+u/wMnH3oPP3tOWsNeZMbazgkiuDg==} + '@microsoft/tsdoc@0.15.0': + resolution: {integrity: sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==} + '@nestjs-modules/mailer@1.9.1': resolution: {integrity: sha512-9kSDgg4qA6+2BXOzfY4IltL70uMGXDeE8u/dhkzM2gnCCOKu8Y+wIxWmh8xyLGYcrFHQ3Mke+ap0O1T98Tyjaw==} peerDependencies: @@ -3889,6 +3905,19 @@ packages: class-validator: optional: true + '@nestjs/mapped-types@2.0.5': + resolution: {integrity: sha512-bSJv4pd6EY99NX9CjBIyn4TVDoSit82DUZlL4I3bqNfy5Gt+gXTa86i3I/i0iIV9P4hntcGM5GyO+FhZAhxtyg==} + peerDependencies: + '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 + class-transformer: ^0.4.0 || ^0.5.0 + class-validator: ^0.13.0 || ^0.14.0 + reflect-metadata: ^0.1.12 || ^0.2.0 + peerDependenciesMeta: + class-transformer: + optional: true + class-validator: + optional: true + '@nestjs/passport@10.0.2': resolution: {integrity: sha512-od31vfB2z3y05IDB5dWSbCGE2+pAf2k2WCBinNuTTOxN0O0+wtO1L3kawj/aCW3YR9uxsTOVbTDwtwgpNNsnjQ==} peerDependencies: @@ -3912,6 +3941,23 @@ packages: peerDependencies: typescript: '>=4.8.2' + '@nestjs/swagger@7.4.0': + resolution: {integrity: sha512-dCiwKkRxcR7dZs5jtrGspBAe/nqJd1AYzOBTzw9iCdbq3BGrLpwokelk6lFZPe4twpTsPQqzNKBwKzVbI6AR/g==} + peerDependencies: + '@fastify/static': ^6.0.0 || ^7.0.0 + '@nestjs/common': ^9.0.0 || ^10.0.0 + '@nestjs/core': ^9.0.0 || ^10.0.0 + class-transformer: '*' + class-validator: '*' + reflect-metadata: ^0.1.12 || ^0.2.0 + peerDependenciesMeta: + '@fastify/static': + optional: true + class-transformer: + optional: true + class-validator: + optional: true + '@nestjs/terminus@10.2.3': resolution: {integrity: sha512-iX7gXtAooePcyQqFt57aDke5MzgdkBeYgF5YsFNNFwOiAFdIQEhfv3PR0G+HlH9F6D7nBCDZt9U87Pks/qHijg==} peerDependencies: @@ -4722,6 +4768,9 @@ packages: '@types/uuid@9.0.7': resolution: {integrity: sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==} + '@types/validator@13.12.0': + resolution: {integrity: sha512-nH45Lk7oPIJ1RVOF6JgFI6Dy0QpHEzq4QecZhvguxYPDwT8c93prCMqAtiIttm39voZ+DDR+qkNnMpJmMBRqag==} + '@types/web-bluetooth@0.0.14': resolution: {integrity: sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A==} @@ -5615,6 +5664,7 @@ packages: are-we-there-yet@2.0.0: resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} engines: {node: '>=10'} + deprecated: This package is no longer supported. arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -6031,6 +6081,12 @@ packages: cjs-module-lexer@1.3.1: resolution: {integrity: sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==} + class-transformer@0.5.1: + resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==} + + class-validator@0.14.1: + resolution: {integrity: sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ==} + clean-css@4.2.4: resolution: {integrity: sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==} engines: {node: '>= 4.0'} @@ -7566,6 +7622,7 @@ packages: gauge@3.0.2: resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} engines: {node: '>=10'} + deprecated: This package is no longer supported. gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} @@ -7645,9 +7702,11 @@ packages: glob@7.2.0: resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} + deprecated: Glob versions prior to v9 are no longer supported glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported glob@9.3.5: resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} @@ -8016,6 +8075,7 @@ packages: inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. inherits@2.0.3: resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} @@ -8745,6 +8805,9 @@ packages: libmime@5.3.5: resolution: {integrity: sha512-nSlR1yRZ43L3cZCiWEw7ali3jY29Hz9CQQ96Oy+sSspYnIP5N54ucOPHqooBsXzwrX1pwn13VUE05q4WmzfaLg==} + libphonenumber-js@1.11.4: + resolution: {integrity: sha512-F/R50HQuWWYcmU/esP5jrH5LiWYaN7DpN0a/99U8+mnGGtnx8kmRE+649dQh3v+CowXXZc8vpkf5AmYkO0AQ7Q==} + libqp@2.0.1: resolution: {integrity: sha512-Ka0eC5LkF3IPNQHJmYBWljJsw0UvM6j+QdKRbWyCdTmYwvIDE6a7bCm0UkTAL/K+3KXK5qXT/ClcInU01OpdLg==} @@ -9409,6 +9472,7 @@ packages: npmlog@5.0.1: resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} + deprecated: This package is no longer supported. nprogress@0.2.0: resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==} @@ -10281,10 +10345,12 @@ packages: rimraf@2.7.1: resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@4.4.1: @@ -10852,6 +10918,9 @@ packages: swagger-parser@8.0.3: resolution: {integrity: sha512-y2gw+rTjn7Z9J+J1qwbBm0UL93k/VREDCveKBK6iGjf7KXC6QGshbnpEmeHL0ZkCgmIghsXzpNzPSbBH91BAEQ==} + swagger-ui-dist@5.17.14: + resolution: {integrity: sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw==} + swap-case@2.0.2: resolution: {integrity: sha512-kc6S2YS/2yXbtkSMunBtKdah4VFETZ8Oh6ONSmSd9bRxhqTrtARUCBUiWXH3xVPpvR7tz2CSnkuXVE42EcGnMw==} @@ -15594,11 +15663,11 @@ snapshots: '@intlify/shared@9.8.0': {} - '@intlify/unplugin-vue-i18n@1.2.0(rollup@3.29.4)(vue-i18n@9.2.2(vue@3.3.9(typescript@4.9.3)))': + '@intlify/unplugin-vue-i18n@1.2.0(rollup@2.79.1)(vue-i18n@9.2.2(vue@3.3.9(typescript@4.9.3)))': dependencies: '@intlify/bundle-utils': 7.5.1(vue-i18n@9.2.2(vue@3.3.9(typescript@4.9.3))) '@intlify/shared': 9.13.1 - '@rollup/pluginutils': 5.1.0(rollup@3.29.4) + '@rollup/pluginutils': 5.1.0(rollup@2.79.1) '@vue/compiler-sfc': 3.3.10 debug: 4.3.4(supports-color@9.4.0) fast-glob: 3.3.2 @@ -15978,10 +16047,12 @@ snapshots: '@mdn/browser-compat-data@5.5.25': {} - '@nestjs-modules/mailer@1.9.1(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(nodemailer@6.9.1)': + '@microsoft/tsdoc@0.15.0': {} + + '@nestjs-modules/mailer@1.9.1(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(nodemailer@6.9.1)': dependencies: - '@nestjs/common': 10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0) - '@nestjs/core': 10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/common': 10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/core': 10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) glob: 10.3.3 inline-css: 4.0.2 mjml: 4.15.3 @@ -15997,13 +16068,13 @@ snapshots: - debug - encoding - '@nestjs/apollo@12.0.9(@apollo/server@4.9.5(graphql@16.8.1))(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/graphql@12.0.9(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(graphql@16.8.1)(reflect-metadata@0.1.13))(graphql@16.8.1)': + '@nestjs/apollo@12.0.9(@apollo/server@4.9.5(graphql@16.8.1))(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/graphql@12.0.9(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(class-transformer@0.5.1)(class-validator@0.14.1)(graphql@16.8.1)(reflect-metadata@0.1.13))(graphql@16.8.1)': dependencies: '@apollo/server': 4.9.5(graphql@16.8.1) '@apollo/server-plugin-landing-page-graphql-playground': 4.0.0(@apollo/server@4.9.5(graphql@16.8.1)) - '@nestjs/common': 10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0) - '@nestjs/core': 10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) - '@nestjs/graphql': 12.0.9(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(graphql@16.8.1)(reflect-metadata@0.1.13) + '@nestjs/common': 10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/core': 10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/graphql': 12.0.9(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(class-transformer@0.5.1)(class-validator@0.14.1)(graphql@16.8.1)(reflect-metadata@0.1.13) graphql: 16.8.1 iterall: 1.3.0 lodash.omit: 4.5.0 @@ -16041,26 +16112,29 @@ snapshots: - uglify-js - webpack-cli - '@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0)': + '@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0)': dependencies: iterare: 1.2.1 reflect-metadata: 0.1.13 rxjs: 7.6.0 tslib: 2.6.2 uid: 2.0.2 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.1 - '@nestjs/config@3.1.1(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(reflect-metadata@0.1.13)': + '@nestjs/config@3.1.1(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(reflect-metadata@0.1.13)': dependencies: - '@nestjs/common': 10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/common': 10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0) dotenv: 16.3.1 dotenv-expand: 10.0.0 lodash: 4.17.21 reflect-metadata: 0.1.13 uuid: 9.0.0 - '@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0)': + '@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0)': dependencies: - '@nestjs/common': 10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/common': 10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0) '@nuxtjs/opencollective': 0.3.2 fast-safe-stringify: 2.1.1 iterare: 1.2.1 @@ -16070,18 +16144,18 @@ snapshots: tslib: 2.6.2 uid: 2.0.2 optionalDependencies: - '@nestjs/platform-express': 10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7) + '@nestjs/platform-express': 10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7) transitivePeerDependencies: - encoding - '@nestjs/graphql@12.0.9(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(graphql@16.8.1)(reflect-metadata@0.1.13)': + '@nestjs/graphql@12.0.9(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(class-transformer@0.5.1)(class-validator@0.14.1)(graphql@16.8.1)(reflect-metadata@0.1.13)': dependencies: '@graphql-tools/merge': 9.0.0(graphql@16.8.1) '@graphql-tools/schema': 10.0.0(graphql@16.8.1) '@graphql-tools/utils': 10.0.6(graphql@16.8.1) - '@nestjs/common': 10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0) - '@nestjs/core': 10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) - '@nestjs/mapped-types': 2.0.2(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(reflect-metadata@0.1.13) + '@nestjs/common': 10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/core': 10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/mapped-types': 2.0.2(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13) chokidar: 3.5.3 fast-glob: 3.3.1 graphql: 16.8.1 @@ -16094,30 +16168,44 @@ snapshots: tslib: 2.6.2 uuid: 9.0.0 ws: 8.13.0 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.1 transitivePeerDependencies: - bufferutil - utf-8-validate - '@nestjs/jwt@10.1.1(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))': + '@nestjs/jwt@10.1.1(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))': dependencies: - '@nestjs/common': 10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/common': 10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0) '@types/jsonwebtoken': 9.0.2 jsonwebtoken: 9.0.0 - '@nestjs/mapped-types@2.0.2(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(reflect-metadata@0.1.13)': + '@nestjs/mapped-types@2.0.2(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)': dependencies: - '@nestjs/common': 10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/common': 10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0) reflect-metadata: 0.1.13 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.1 - '@nestjs/passport@10.0.2(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(passport@0.6.0)': + '@nestjs/mapped-types@2.0.5(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)': dependencies: - '@nestjs/common': 10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/common': 10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0) + reflect-metadata: 0.1.13 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.1 + + '@nestjs/passport@10.0.2(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(passport@0.6.0)': + dependencies: + '@nestjs/common': 10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0) passport: 0.6.0 - '@nestjs/platform-express@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7)': + '@nestjs/platform-express@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7)': dependencies: - '@nestjs/common': 10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0) - '@nestjs/core': 10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/common': 10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/core': 10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) body-parser: 1.20.2 cors: 2.8.5 express: 4.18.2 @@ -16126,10 +16214,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@nestjs/schedule@4.0.1(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))': + '@nestjs/schedule@4.0.1(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))': dependencies: - '@nestjs/common': 10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0) - '@nestjs/core': 10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/common': 10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/core': 10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) cron: 3.1.6 uuid: 9.0.1 @@ -16155,10 +16243,25 @@ snapshots: transitivePeerDependencies: - chokidar - '@nestjs/terminus@10.2.3(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@prisma/client@5.8.1(prisma@5.8.1))(reflect-metadata@0.1.13)(rxjs@7.6.0)': + '@nestjs/swagger@7.4.0(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)': dependencies: - '@nestjs/common': 10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0) - '@nestjs/core': 10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@microsoft/tsdoc': 0.15.0 + '@nestjs/common': 10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/core': 10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/mapped-types': 2.0.5(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13) + js-yaml: 4.1.0 + lodash: 4.17.21 + path-to-regexp: 3.2.0 + reflect-metadata: 0.1.13 + swagger-ui-dist: 5.17.14 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.1 + + '@nestjs/terminus@10.2.3(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@prisma/client@5.8.1(prisma@5.8.1))(reflect-metadata@0.1.13)(rxjs@7.6.0)': + dependencies: + '@nestjs/common': 10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/core': 10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) boxen: 5.1.2 check-disk-space: 3.4.0 reflect-metadata: 0.1.13 @@ -16166,18 +16269,18 @@ snapshots: optionalDependencies: '@prisma/client': 5.8.1(prisma@5.8.1) - '@nestjs/testing@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7))': + '@nestjs/testing@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7))': dependencies: - '@nestjs/common': 10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0) - '@nestjs/core': 10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/common': 10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/core': 10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) tslib: 2.6.2 optionalDependencies: - '@nestjs/platform-express': 10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7) + '@nestjs/platform-express': 10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7) - '@nestjs/throttler@5.0.1(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(reflect-metadata@0.1.13)': + '@nestjs/throttler@5.0.1(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/core@10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0))(reflect-metadata@0.1.13)': dependencies: - '@nestjs/common': 10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0) - '@nestjs/core': 10.2.7(@nestjs/common@10.2.7(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/common': 10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0) + '@nestjs/core': 10.2.7(@nestjs/common@10.2.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.6.0))(@nestjs/platform-express@10.2.7)(reflect-metadata@0.1.13)(rxjs@7.6.0) md5: 2.3.0 reflect-metadata: 0.1.13 @@ -16919,6 +17022,8 @@ snapshots: '@types/uuid@9.0.7': {} + '@types/validator@13.12.0': {} + '@types/web-bluetooth@0.0.14': {} '@types/web-bluetooth@0.0.16': {} @@ -18905,6 +19010,14 @@ snapshots: cjs-module-lexer@1.3.1: {} + class-transformer@0.5.1: {} + + class-validator@0.14.1: + dependencies: + '@types/validator': 13.12.0 + libphonenumber-js: 1.11.4 + validator: 13.11.0 + clean-css@4.2.4: dependencies: source-map: 0.6.1 @@ -22554,6 +22667,8 @@ snapshots: libbase64: 1.3.0 libqp: 2.1.0 + libphonenumber-js@1.11.4: {} + libqp@2.0.1: {} libqp@2.1.0: {} @@ -24991,6 +25106,8 @@ snapshots: swagger-methods: 2.0.2 z-schema: 4.2.4 + swagger-ui-dist@5.17.14: {} + swap-case@2.0.2: dependencies: tslib: 2.5.3 @@ -25280,7 +25397,7 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-jest@27.1.5(@babel/core@7.24.5)(@types/jest@27.5.2)(babel-jest@29.7.0(@babel/core@7.24.5))(jest@29.7.0(@types/node@17.0.45)(ts-node@10.9.1(@swc/core@1.4.2)(@types/node@17.0.45)(typescript@4.9.5)))(typescript@4.9.5): + ts-jest@27.1.5(@babel/core@7.24.5)(@types/jest@27.5.2)(jest@29.7.0(@types/node@17.0.45)(ts-node@10.9.1(@swc/core@1.4.2)(@types/node@17.0.45)(typescript@4.9.5)))(typescript@4.9.5): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -25295,7 +25412,6 @@ snapshots: optionalDependencies: '@babel/core': 7.24.5 '@types/jest': 27.5.2 - babel-jest: 29.7.0(@babel/core@7.24.5) ts-jest@29.0.5(@babel/core@7.24.5)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.5))(jest@29.4.1(@types/node@18.11.10)(ts-node@10.9.1(@swc/core@1.4.2)(@types/node@18.11.10)(typescript@4.9.3)))(typescript@4.9.3): dependencies: @@ -25739,7 +25855,7 @@ snapshots: transitivePeerDependencies: - supports-color - unplugin-vue-components@0.21.0(@babel/parser@7.24.5)(esbuild@0.20.2)(rollup@3.29.4)(vite@3.2.4(@types/node@18.18.8)(sass@1.58.0)(terser@5.31.0))(vue@3.3.9(typescript@4.9.3))(webpack@5.91.0(@swc/core@1.4.2)(esbuild@0.20.2)): + unplugin-vue-components@0.21.0(@babel/parser@7.24.5)(esbuild@0.20.2)(rollup@2.79.1)(vite@3.2.4(@types/node@18.18.8)(sass@1.58.0)(terser@5.31.0))(vue@3.3.9(typescript@4.9.3))(webpack@5.91.0(@swc/core@1.4.2)(esbuild@0.20.2)): dependencies: '@antfu/utils': 0.5.2 '@rollup/pluginutils': 4.2.1 @@ -25750,7 +25866,7 @@ snapshots: magic-string: 0.26.7 minimatch: 5.1.6 resolve: 1.22.8 - unplugin: 0.7.2(esbuild@0.20.2)(rollup@3.29.4)(vite@3.2.4(@types/node@18.18.8)(sass@1.58.0)(terser@5.31.0))(webpack@5.91.0(@swc/core@1.4.2)(esbuild@0.20.2)) + unplugin: 0.7.2(esbuild@0.20.2)(rollup@2.79.1)(vite@3.2.4(@types/node@18.18.8)(sass@1.58.0)(terser@5.31.0))(webpack@5.91.0(@swc/core@1.4.2)(esbuild@0.20.2)) vue: 3.3.9(typescript@4.9.3) optionalDependencies: '@babel/parser': 7.24.5 @@ -25761,7 +25877,7 @@ snapshots: - vite - webpack - unplugin-vue-components@0.21.0(@babel/parser@7.24.5)(esbuild@0.20.2)(rollup@3.29.4)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0))(vue@3.3.9(typescript@4.9.5))(webpack@5.91.0(@swc/core@1.4.2)(esbuild@0.20.2)): + unplugin-vue-components@0.21.0(@babel/parser@7.24.5)(esbuild@0.20.2)(rollup@2.79.1)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0))(vue@3.3.9(typescript@4.9.5))(webpack@5.91.0(@swc/core@1.4.2)(esbuild@0.20.2)): dependencies: '@antfu/utils': 0.5.2 '@rollup/pluginutils': 4.2.1 @@ -25772,7 +25888,7 @@ snapshots: magic-string: 0.26.7 minimatch: 5.1.6 resolve: 1.22.8 - unplugin: 0.7.2(esbuild@0.20.2)(rollup@3.29.4)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0))(webpack@5.91.0(@swc/core@1.4.2)(esbuild@0.20.2)) + unplugin: 0.7.2(esbuild@0.20.2)(rollup@2.79.1)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0))(webpack@5.91.0(@swc/core@1.4.2)(esbuild@0.20.2)) vue: 3.3.9(typescript@4.9.5) optionalDependencies: '@babel/parser': 7.24.5 @@ -25783,25 +25899,6 @@ snapshots: - vite - webpack - unplugin-vue-components@0.25.2(@babel/parser@7.24.5)(rollup@3.29.4)(vue@3.3.9(typescript@5.3.2)): - dependencies: - '@antfu/utils': 0.7.7 - '@rollup/pluginutils': 5.1.0(rollup@3.29.4) - chokidar: 3.6.0 - debug: 4.3.4(supports-color@9.4.0) - fast-glob: 3.3.2 - local-pkg: 0.4.3 - magic-string: 0.30.10 - minimatch: 9.0.4 - resolve: 1.22.8 - unplugin: 1.10.1 - vue: 3.3.9(typescript@5.3.2) - optionalDependencies: - '@babel/parser': 7.24.5 - transitivePeerDependencies: - - rollup - - supports-color - unplugin-vue-components@0.25.2(@babel/parser@7.24.5)(rollup@4.17.2)(vue@3.3.9(typescript@5.3.2)): dependencies: '@antfu/utils': 0.7.7 @@ -25821,7 +25918,7 @@ snapshots: - rollup - supports-color - unplugin@0.7.2(esbuild@0.20.2)(rollup@3.29.4)(vite@3.2.4(@types/node@18.18.8)(sass@1.58.0)(terser@5.31.0))(webpack@5.91.0(@swc/core@1.4.2)(esbuild@0.20.2)): + unplugin@0.7.2(esbuild@0.20.2)(rollup@2.79.1)(vite@3.2.4(@types/node@18.18.8)(sass@1.58.0)(terser@5.31.0))(webpack@5.91.0(@swc/core@1.4.2)(esbuild@0.20.2)): dependencies: acorn: 8.11.3 chokidar: 3.6.0 @@ -25829,11 +25926,11 @@ snapshots: webpack-virtual-modules: 0.4.6 optionalDependencies: esbuild: 0.20.2 - rollup: 3.29.4 + rollup: 2.79.1 vite: 3.2.4(@types/node@18.18.8)(sass@1.58.0)(terser@5.31.0) webpack: 5.91.0(@swc/core@1.4.2)(esbuild@0.20.2) - unplugin@0.7.2(esbuild@0.20.2)(rollup@3.29.4)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0))(webpack@5.91.0(@swc/core@1.4.2)(esbuild@0.20.2)): + unplugin@0.7.2(esbuild@0.20.2)(rollup@2.79.1)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0))(webpack@5.91.0(@swc/core@1.4.2)(esbuild@0.20.2)): dependencies: acorn: 8.11.3 chokidar: 3.6.0 @@ -25841,7 +25938,7 @@ snapshots: webpack-virtual-modules: 0.4.6 optionalDependencies: esbuild: 0.20.2 - rollup: 3.29.4 + rollup: 2.79.1 vite: 4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0) webpack: 5.91.0(@swc/core@1.4.2)(esbuild@0.20.2) @@ -25982,7 +26079,7 @@ snapshots: - supports-color - terser - vite-plugin-checker@0.6.2(eslint@8.57.0)(meow@8.1.2)(optionator@0.9.4)(typescript@5.3.2)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0))(vue-tsc@1.8.24(typescript@5.3.2)): + vite-plugin-checker@0.6.2(eslint@8.57.0)(optionator@0.9.4)(typescript@5.3.2)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0))(vue-tsc@1.8.24(typescript@5.3.2)): dependencies: '@babel/code-frame': 7.24.2 ansi-escapes: 4.3.2 @@ -26004,7 +26101,6 @@ snapshots: vscode-uri: 3.0.8 optionalDependencies: eslint: 8.57.0 - meow: 8.1.2 optionator: 0.9.4 typescript: 5.3.2 vue-tsc: 1.8.24(typescript@5.3.2) @@ -26050,25 +26146,10 @@ snapshots: dependencies: vite: 4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0) - vite-plugin-inspect@0.7.38(rollup@3.29.4)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0)): + vite-plugin-inspect@0.7.38(rollup@2.79.1)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0)): dependencies: '@antfu/utils': 0.7.7 - '@rollup/pluginutils': 5.1.0(rollup@3.29.4) - debug: 4.3.4(supports-color@9.4.0) - error-stack-parser-es: 0.1.1 - fs-extra: 11.2.0 - open: 9.1.0 - picocolors: 1.0.0 - sirv: 2.0.4 - vite: 4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0) - transitivePeerDependencies: - - rollup - - supports-color - - vite-plugin-inspect@0.7.42(rollup@3.29.4)(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.31.0)): - dependencies: - '@antfu/utils': 0.7.7 - '@rollup/pluginutils': 5.1.0(rollup@3.29.4) + '@rollup/pluginutils': 5.1.0(rollup@2.79.1) debug: 4.3.4(supports-color@9.4.0) error-stack-parser-es: 0.1.1 fs-extra: 11.2.0