From ca73c44dfab2267a8ab5fc4d4281c81f3d8b2b2a Mon Sep 17 00:00:00 2001 From: nochill Date: Sun, 26 Feb 2023 16:08:28 +0700 Subject: [PATCH] update --- .../2023.02.22T05.24.58.create_users.sql | 2 + package.json | 7 ++- src/app.module.ts | 23 ++++++++- .../interceptors/exception.interceptors.ts | 2 +- src/libs/db/sql-repository.base.ts | 5 +- src/main.ts | 13 +++++ .../user/commands/create-user.command.ts | 18 +++++++ .../commands/create-user.http.controller.ts | 32 +++++++++++++ .../create-user.message.controller.ts | 20 ++++++++ .../user/commands/create-user.request.dto.ts | 21 +++++++++ .../user/commands/create-user.service.ts | 46 ++++++++++++++++++ src/modules/user/database/user.repository.ts | 36 +++++++------- .../events/user-created.domain-event.ts | 2 + src/modules/user/domain/user.entity.ts | 9 ++-- src/modules/user/domain/user.error.ts | 11 +++++ src/modules/user/domain/user.types.ts | 7 +-- .../user/dtos/user.paginated.response.dto.ts | 6 +++ src/modules/user/dtos/user.response.dto.ts | 7 +++ src/modules/user/user.di-tokens.ts | 1 + src/modules/user/user.mapper.ts | 47 ++++++++++++++++++- src/modules/user/user.module.ts | 32 ++++++++++++- yarn.lock | 29 +++++++++++- 22 files changed, 342 insertions(+), 34 deletions(-) create mode 100644 src/modules/user/commands/create-user.command.ts create mode 100644 src/modules/user/commands/create-user.http.controller.ts create mode 100644 src/modules/user/commands/create-user.message.controller.ts create mode 100644 src/modules/user/commands/create-user.request.dto.ts create mode 100644 src/modules/user/commands/create-user.service.ts create mode 100644 src/modules/user/dtos/user.paginated.response.dto.ts create mode 100644 src/modules/user/dtos/user.response.dto.ts diff --git a/database/migrations/2023.02.22T05.24.58.create_users.sql b/database/migrations/2023.02.22T05.24.58.create_users.sql index 7ea869e..0c273da 100644 --- a/database/migrations/2023.02.22T05.24.58.create_users.sql +++ b/database/migrations/2023.02.22T05.24.58.create_users.sql @@ -2,6 +2,7 @@ CREATE TABLE "users" ( "id" VARCHAR PRIMARY KEY, "phone_number" TEXT NOT NULL UNIQUE, "email" TEXT NOT NULL UNIQUE, + "password" TEXT NOT NULL, "fullname" TEXT, "avatar" TEXT, "latitude" TEXT, @@ -11,6 +12,7 @@ CREATE TABLE "users" ( "fcm_token" TEXT, "is_verified" TEXT, "is_merchant" BOOLEAN, + "role_id" INT, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now() diff --git a/package.json b/package.json index c51a32b..7af5f89 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,9 @@ "dependencies": { "@nestjs/common": "^9.0.0", "@nestjs/core": "^9.0.0", + "@nestjs/cqrs": "^9.0.3", "@nestjs/event-emitter": "^1.4.1", + "@nestjs/microservices": "^9.3.9", "@nestjs/platform-express": "^9.0.0", "@slonik/migrator": "^0.11.3", "cache-manager": "^5.1.6", @@ -66,13 +68,16 @@ "eslint-plugin-prettier": "^4.0.0", "jest": "29.3.1", "prettier": "^2.3.2", + "run-script-webpack-plugin": "^0.1.1", "source-map-support": "^0.5.20", "supertest": "^6.1.3", "ts-jest": "29.0.3", "ts-loader": "^9.2.3", "ts-node": "^10.9.1", "tsconfig-paths": "4.1.1", - "typescript": "^4.7.4" + "typescript": "^4.7.4", + "webpack": "^5.75.0", + "webpack-node-externals": "^3.0.0" }, "jest": { "moduleFileExtensions": [ diff --git a/src/app.module.ts b/src/app.module.ts index 41c4e1b..b356a43 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -3,18 +3,37 @@ import { SlonikModule } from 'nestjs-slonik'; import { RedisClientOptions } from 'redis'; import { postgresConnectionUrl } from './config/database.config'; import { redisConfig } from './config/redis.config'; -import { UserModule } from './user/user.module'; import { UserModule } from './modules/user/user.module'; +import { APP_INTERCEPTOR } from '@nestjs/core'; +import { ContextInterceptor } from './libs/application/context/ContextInterceptor'; +import { ExceptionInterceptor } from './libs/application/interceptors/exception.interceptors'; +import { RequestContextModule } from 'nestjs-request-context'; +import { CqrsModule } from '@nestjs/cqrs'; +import { EventEmitterModule } from '@nestjs/event-emitter'; + +const interceptors = [ + { + provide: APP_INTERCEPTOR, + useClass: ContextInterceptor + }, + { + provide: APP_INTERCEPTOR, + useClass: ExceptionInterceptor + } +]; @Module({ imports: [ + EventEmitterModule.forRoot(), + RequestContextModule, SlonikModule.forRoot({ connectionUri: postgresConnectionUrl, }), + CqrsModule, CacheModule.register(redisConfig), UserModule ], controllers: [], - providers: [], + providers: [...interceptors], }) export class AppModule {} diff --git a/src/libs/application/interceptors/exception.interceptors.ts b/src/libs/application/interceptors/exception.interceptors.ts index ded65d6..fd26c2c 100644 --- a/src/libs/application/interceptors/exception.interceptors.ts +++ b/src/libs/application/interceptors/exception.interceptors.ts @@ -22,7 +22,7 @@ export class ExceptionInterceptor implements NestInterceptor { Array.isArray(err?.response?.message) && typeof err?.response?.error === 'string' && err.status === 400; - + if(isClassValidatorError) { err = new BadRequestException( new ApiErrorResponse({ diff --git a/src/libs/db/sql-repository.base.ts b/src/libs/db/sql-repository.base.ts index 2f64926..6a11147 100644 --- a/src/libs/db/sql-repository.base.ts +++ b/src/libs/db/sql-repository.base.ts @@ -170,7 +170,7 @@ export abstract class SqlRepositoryBase< */ protected generateInsertQuery( models: DbModel[], - ): SqlSqlToken { + ): SqlSqlToken { // TODO: generate query from an entire array to insert multiple records at once const entries = Object.entries(models[0]); const values: any = []; @@ -186,7 +186,7 @@ export abstract class SqlRepositoryBase< } } }); - + const query = sql`INSERT INTO ${sql.identifier([ this.tableName, ])} (${sql.join(propertyNames, sql`, `)}) VALUES (${sql.join( @@ -194,6 +194,7 @@ export abstract class SqlRepositoryBase< sql`, `, )})`; + const parsedQuery = query; return parsedQuery; } diff --git a/src/main.ts b/src/main.ts index 13cad38..0577346 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,8 +1,21 @@ +import { ValidationPipe } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; +declare const module: any; + async function bootstrap() { const app = await NestFactory.create(AppModule); + + app.enableShutdownHooks(); + + app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true })); + await app.listen(3000); + + if (module.hot) { + module.hot.accept(); + module.hot.dispose(() => app.close()); + } } bootstrap(); diff --git a/src/modules/user/commands/create-user.command.ts b/src/modules/user/commands/create-user.command.ts new file mode 100644 index 0000000..765d0c9 --- /dev/null +++ b/src/modules/user/commands/create-user.command.ts @@ -0,0 +1,18 @@ +import { Command, CommandProps } from "@src/libs/ddd/base/command.base"; + +export class CreateUserCommand extends Command { + readonly email: string; + readonly password: string; + readonly fullname: string; + readonly phone_number: string; + readonly role_id: number; + + constructor(props: CommandProps) { + super(props); + this.email = props.email; + this.password = props.password; + this.phone_number = props.phone_number; + this.fullname = props.fullname; + this.role_id = props.role_id; + } +} \ No newline at end of file diff --git a/src/modules/user/commands/create-user.http.controller.ts b/src/modules/user/commands/create-user.http.controller.ts new file mode 100644 index 0000000..fd9259b --- /dev/null +++ b/src/modules/user/commands/create-user.http.controller.ts @@ -0,0 +1,32 @@ +import { Post, ConflictException as ConflictHttpException, Body, Controller, InternalServerErrorException } from "@nestjs/common"; +import { match, Result} from 'oxide.ts'; +import { routesV1 } from "@src/config/app.routes"; +import { UserAlreadyExistsError } from "../domain/user.error"; +import { UserResponseDto } from "../dtos/user.response.dto"; +import { CreateUserCommand } from "./create-user.command"; +import { CommandBus } from "@nestjs/cqrs"; +import { CreateUserRequestDto } from "./create-user.request.dto"; + +@Controller(routesV1.version) +export class CreateUserHttpController { + constructor(private readonly commandBus: CommandBus) {} + + @Post(routesV1.user.root) + async create(@Body() body: CreateUserRequestDto): Promise { + const command = new CreateUserCommand(body); + + const result: Result = + await this.commandBus.execute(command); + + console.log(result); + + return match(result, { + Ok: (res: any) => res, + Err: (error: Error) => { + if(error instanceof UserAlreadyExistsError) + throw new ConflictHttpException(error.message); + throw error; + } + }) + } +} \ No newline at end of file diff --git a/src/modules/user/commands/create-user.message.controller.ts b/src/modules/user/commands/create-user.message.controller.ts new file mode 100644 index 0000000..4b35003 --- /dev/null +++ b/src/modules/user/commands/create-user.message.controller.ts @@ -0,0 +1,20 @@ +import { Controller } from "@nestjs/common"; +import { CommandBus } from "@nestjs/cqrs"; +import { MessagePattern } from "@nestjs/microservices"; +import { UserResponseDto } from "../dtos/user.response.dto"; +import { CreateUserCommand } from "./create-user.command"; +import { CreateUserRequestDto } from "./create-user.request.dto"; + +@Controller() +export class CreateUserMessageController { + constructor(private readonly commandBus: CommandBus) {} + + @MessagePattern('user.create') + async create(message: CreateUserRequestDto): Promise { + const command = new CreateUserCommand(message); + + const id: string = await this.commandBus.execute(command); + + return id; + } +} \ No newline at end of file diff --git a/src/modules/user/commands/create-user.request.dto.ts b/src/modules/user/commands/create-user.request.dto.ts new file mode 100644 index 0000000..23b8405 --- /dev/null +++ b/src/modules/user/commands/create-user.request.dto.ts @@ -0,0 +1,21 @@ +import { IsEmail, IsNotEmpty, IsNumber, IsString, MaxLength, MinLength, } from "class-validator"; + +export class CreateUserRequestDto { + @IsEmail() + readonly email: string; + + @IsNotEmpty() + @MaxLength(14) + @MinLength(10) + readonly phone_number: string + + @IsNotEmpty() + readonly fullname: string; + + @IsNotEmpty() + readonly password: string; + + @IsNumber() + @IsNotEmpty() + readonly role_id: number; +} \ No newline at end of file diff --git a/src/modules/user/commands/create-user.service.ts b/src/modules/user/commands/create-user.service.ts new file mode 100644 index 0000000..8d2f4ea --- /dev/null +++ b/src/modules/user/commands/create-user.service.ts @@ -0,0 +1,46 @@ +import { ConflictException, Inject } from "@nestjs/common"; +import { CommandHandler, ICommandHandler } from "@nestjs/cqrs"; +import { AggregateID } from "@src/libs/ddd"; +import { Err, Ok, Result } from "oxide.ts"; +import { UserRepositoryPort } from "../database/user.repository.port"; +import { UserEntity } from "../domain/user.entity"; +import { UserAlreadyExistsError } from "../domain/user.error"; +import { UserResponseDto } from "../dtos/user.response.dto"; +import { USER_REPOSITORY } from "../user.di-tokens"; +import { CreateUserCommand } from "./create-user.command"; + +@CommandHandler(CreateUserCommand) +export class CreateUserService implements ICommandHandler { + constructor( + @Inject(USER_REPOSITORY) + protected readonly userRepo: UserRepositoryPort + ) {} + + async execute( + command: CreateUserCommand + ): Promise> { + const user = UserEntity.create({ + email: command.email, + password: command.password, + fullname: command.fullname, + phone_number: command.phone_number, + role_id: command.role_id + }); + + try { + await this.userRepo.transaction(async () => this.userRepo.insert(user)); + + const userResponse = new UserResponseDto(user); + userResponse.email = command.email; + userResponse.fullname = command.fullname; + userResponse.phone_number = command.phone_number; + + return Ok(userResponse) + } catch (error: any) { + if(error instanceof ConflictException) { + return Err(new UserAlreadyExistsError(error)); + } + throw error; + } + } +} \ No newline at end of file diff --git a/src/modules/user/database/user.repository.ts b/src/modules/user/database/user.repository.ts index 39e319a..89b67b6 100644 --- a/src/modules/user/database/user.repository.ts +++ b/src/modules/user/database/user.repository.ts @@ -2,7 +2,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { SqlRepositoryBase } from '@src/libs/db/sql-repository.base'; import { InjectPool } from 'nestjs-slonik'; -import { DatabasePool } from 'slonik'; +import { DatabasePool, sql } from 'slonik'; import { z } from 'zod'; import { UserEntity } from '../domain/user.entity'; import { UserMapper } from '../user.mapper'; @@ -12,15 +12,17 @@ export const userSchema = z.object({ id: z.string().uuid(), email: z.string().email(), phone_number: z.string().min(10).max(15), + password: z.string(), fullname: z.string(), - avatar: z.string(), - latitude: z.string(), - longitude: z.string(), - auth_token: z.string(), - verify_token: z.string(), - fcm_token: z.string(), - is_verified: z.string(), - is_merchant: z.string(), + avatar: z.string().optional(), + latitude: z.string().optional(), + longitude: z.string().optional(), + auth_token: z.string().optional(), + verify_token: z.string().optional(), + fcm_token: z.string().optional(), + is_verified: z.string().optional(), + is_merchant: z.string().optional(), + role_id: z.number(), created_at: z.preprocess((val: any) => new Date(val), z.date()), updated_at: z.preprocess((val: any) => new Date(val), z.date()), }); @@ -36,10 +38,8 @@ export class UserRepository extends SqlRepositoryBase implements UserRepositoryPort { - findOneByEmail(email: string): Promise { - throw new Error('Method not implemented.'); - } - protected tableName: 'users'; + protected tableName = 'users'; + protected schema = userSchema; constructor( @@ -49,10 +49,14 @@ export class UserRepository eventEmitter: EventEmitter2 ) { super(pool, mapper, eventEmitter, new Logger(UserRepository.name)); - } + } - async updateAddress(user: UserEntity): Promise { - const address = user.getPropsCopy().address; + async findOneByEmail(email: string): Promise { + const user = await this.pool.one( + sql.type(userSchema)`SELECT * FROM "users" WHERE email = ${email}` + ) + + return this.mapper.toDomain(user); } } \ No newline at end of file diff --git a/src/modules/user/domain/events/user-created.domain-event.ts b/src/modules/user/domain/events/user-created.domain-event.ts index 5bbcd30..2fbf59d 100644 --- a/src/modules/user/domain/events/user-created.domain-event.ts +++ b/src/modules/user/domain/events/user-created.domain-event.ts @@ -5,6 +5,7 @@ export class UserCreatedDomainEvent extends DomainEvent { readonly phone_number: string; readonly password: string; readonly fullname: string; + readonly role_id: number; constructor(props: DomainEventProps) { super(props); @@ -12,5 +13,6 @@ export class UserCreatedDomainEvent extends DomainEvent { this.phone_number = props.phone_number; this.password = props.password; this.fullname = props.fullname; + this.role_id = props.role_id; } } \ No newline at end of file diff --git a/src/modules/user/domain/user.entity.ts b/src/modules/user/domain/user.entity.ts index 6dad5e0..44ab930 100644 --- a/src/modules/user/domain/user.entity.ts +++ b/src/modules/user/domain/user.entity.ts @@ -9,7 +9,7 @@ export class UserEntity extends AggregateRoot { static create(create: CreateUserProps): UserEntity { const id = v4(); - const props: UserProps = { ...create, role: UserRoles.user }; + const props: UserProps = { ...create }; const user = new UserEntity({ id, props }); user.addEvent( new UserCreatedDomainEvent({ @@ -17,14 +17,15 @@ export class UserEntity extends AggregateRoot { email: props.email, password: props.password, phone_number: props.password, - fullname: props.fullname + fullname: props.fullname, + role_id: props.role_id }) ); return user; } get role(): UserRoles { - return this.props.role; + return this.props.role_id; } delete(): void { @@ -36,6 +37,6 @@ export class UserEntity extends AggregateRoot { } public validate(): void { - throw new Error("Method not implemented."); + // throw new Error("Method not implemented."); } } \ No newline at end of file diff --git a/src/modules/user/domain/user.error.ts b/src/modules/user/domain/user.error.ts index e69de29..f59de8a 100644 --- a/src/modules/user/domain/user.error.ts +++ b/src/modules/user/domain/user.error.ts @@ -0,0 +1,11 @@ +import { ExceptionBase } from "@src/libs/exceptions"; + +export class UserAlreadyExistsError extends ExceptionBase { + static readonly message = 'User already exists'; + + public readonly code = 'USER.ALREADY_EXISTS'; + + constructor(cause?: Error, metadata?: unknown) { + super(UserAlreadyExistsError.message, cause, metadata); + } +} \ No newline at end of file diff --git a/src/modules/user/domain/user.types.ts b/src/modules/user/domain/user.types.ts index 4e1a3dc..2fded81 100644 --- a/src/modules/user/domain/user.types.ts +++ b/src/modules/user/domain/user.types.ts @@ -1,7 +1,7 @@ export interface UserProps { password: string; phone_number: string; - role: UserRoles; + role_id: UserRoles; email: string; fullname: string; } @@ -11,6 +11,7 @@ export interface CreateUserProps { phone_number: string; password: string; fullname: string; + role_id: number; } export interface UpdateUserProps { @@ -20,6 +21,6 @@ export interface UpdateUserProps { } export enum UserRoles { - admin = 'admin', - user = 'user' + admin = 1, + user = 2 } \ No newline at end of file diff --git a/src/modules/user/dtos/user.paginated.response.dto.ts b/src/modules/user/dtos/user.paginated.response.dto.ts new file mode 100644 index 0000000..e0da41b --- /dev/null +++ b/src/modules/user/dtos/user.paginated.response.dto.ts @@ -0,0 +1,6 @@ +import { PaginatedResponseDto } from "@src/libs/api/paginated.response.base"; +import { UserResponseDto } from "./user.response.dto"; + +export class UserPaginatedResponseDto extends PaginatedResponseDto { + readonly data: readonly UserResponseDto[]; +} \ No newline at end of file diff --git a/src/modules/user/dtos/user.response.dto.ts b/src/modules/user/dtos/user.response.dto.ts new file mode 100644 index 0000000..862641b --- /dev/null +++ b/src/modules/user/dtos/user.response.dto.ts @@ -0,0 +1,7 @@ +import { ResponseBase } from "@src/libs/api/response.base"; + +export class UserResponseDto extends ResponseBase { + email: string; + phone_number: string; + fullname: string; +} \ No newline at end of file diff --git a/src/modules/user/user.di-tokens.ts b/src/modules/user/user.di-tokens.ts index e69de29..7334e98 100644 --- a/src/modules/user/user.di-tokens.ts +++ b/src/modules/user/user.di-tokens.ts @@ -0,0 +1 @@ +export const USER_REPOSITORY = Symbol('USER_REPOSITORY'); \ No newline at end of file diff --git a/src/modules/user/user.mapper.ts b/src/modules/user/user.mapper.ts index 69c82c9..0926864 100644 --- a/src/modules/user/user.mapper.ts +++ b/src/modules/user/user.mapper.ts @@ -1,5 +1,50 @@ import { Injectable } from "@nestjs/common"; import { Mapper } from "@src/libs/ddd"; +import { UserModel, userSchema } from "./database/user.repository"; +import { UserEntity } from "./domain/user.entity"; +import { UserResponseDto } from "./dtos/user.response.dto"; @Injectable() -export class UserMapper implements Mapper< \ No newline at end of file +export class UserMapper implements Mapper { + toPersistence(entity: UserEntity): UserModel { + const copy = entity.getPropsCopy(); + + const record: UserModel = { + id: copy.id, + email: copy.email, + phone_number: copy.phone_number, + password: copy.password, + role_id: copy.role_id, + fullname: copy.fullname, + created_at: copy.createdAt, + updated_at: copy.updatedAt, + } + + return userSchema.parse(record) + } + + toDomain(record: UserModel): UserEntity { + const entity = new UserEntity({ + id: record.id, + props: { + email: record.email, + fullname: record.fullname, + password: record.password, + phone_number: record.phone_number, + role_id: record.role_id + } + }); + + return entity; + } + + toResponse(entity: UserEntity): UserResponseDto { + const props = entity.getPropsCopy(); + const response = new UserResponseDto(entity); + response.email = props.email; + response.fullname = props.fullname; + response.phone_number = props.phone_number; + return response; + } + +} \ No newline at end of file diff --git a/src/modules/user/user.module.ts b/src/modules/user/user.module.ts index 309e84a..68e9308 100644 --- a/src/modules/user/user.module.ts +++ b/src/modules/user/user.module.ts @@ -1,4 +1,32 @@ -import { Module } from '@nestjs/common'; +import { Logger, Module, Provider } from '@nestjs/common'; +import { CqrsModule } from '@nestjs/cqrs'; +import { CreateUserHttpController } from './commands/create-user.http.controller'; +import { CreateUserMessageController } from './commands/create-user.message.controller'; +import { CreateUserService } from './commands/create-user.service'; +import { UserRepository } from './database/user.repository'; +import { USER_REPOSITORY } from './user.di-tokens'; +import { UserMapper } from './user.mapper'; -@Module({}) + +const httpControllers = [ + CreateUserHttpController +]; + +const messageControllers = [CreateUserMessageController]; +const commandHandlers: Provider[] = [CreateUserService]; +const mappers: Provider[] = [UserMapper]; +const repositories: Provider[] = [ + { provide: USER_REPOSITORY, useClass: UserRepository} +]; + +@Module({ + imports: [CqrsModule], + controllers: [...httpControllers, ...messageControllers], + providers: [ + Logger, + ...repositories, + ...mappers, + ...commandHandlers + ], +}) export class UserModule {} diff --git a/yarn.lock b/yarn.lock index d864e81..ae3a2db 100644 --- a/yarn.lock +++ b/yarn.lock @@ -724,6 +724,13 @@ path-to-regexp "3.2.0" tslib "2.5.0" +"@nestjs/cqrs@^9.0.3": + version "9.0.3" + resolved "https://registry.yarnpkg.com/@nestjs/cqrs/-/cqrs-9.0.3.tgz#1ccd87feffebf33b2f3b0170f98eda8c6c74796f" + integrity sha512-hmbrqf51BVdgmnnxErnLVXfPNTEqr4Hz8DyLa9dKLIW3BuOyI5RDwJ/9sKbJ47UDBhumC5nQlNK9qk27mhqHfw== + dependencies: + uuid "9.0.0" + "@nestjs/event-emitter@^1.4.1": version "1.4.1" resolved "https://registry.yarnpkg.com/@nestjs/event-emitter/-/event-emitter-1.4.1.tgz#a96fae678b0257b9cd8f6c82c9f3f82a0690e221" @@ -731,6 +738,14 @@ dependencies: eventemitter2 "6.4.9" +"@nestjs/microservices@^9.3.9": + version "9.3.9" + resolved "https://registry.yarnpkg.com/@nestjs/microservices/-/microservices-9.3.9.tgz#dbcecd5c3903ee6433be303eec0415ff9e60fb81" + integrity sha512-G4EsQpOS3l2dWjJID+z/YyDPTx+SEq/5YQ/cC8XV9Hap1S0rEmo+Z1R2OdlUt+ZnkcJp7H0GIHiB0EjaYanmjA== + dependencies: + iterare "1.2.1" + tslib "2.5.0" + "@nestjs/platform-express@^9.0.0": version "9.3.9" resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-9.3.9.tgz#557ace8589b54d4ee7bad87a1247a521058395d7" @@ -4571,6 +4586,11 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +run-script-webpack-plugin@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/run-script-webpack-plugin/-/run-script-webpack-plugin-0.1.1.tgz#dad3114be32eb864d2160306e4d9c52a2c1cfd59" + integrity sha512-PrxBRLv1K9itDKMlootSCyGhdTU+KbKGJ2wF6/k0eyo6M0YGPC58HYbS/J/QsDiwM0t7G99WcuCqto0J7omOXA== + rxjs@6.6.7, rxjs@^6.6.0: version "6.6.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" @@ -5245,6 +5265,11 @@ uuid@8.3.2, uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" + integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== + v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" @@ -5301,7 +5326,7 @@ webidl-conversions@^4.0.2: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== -webpack-node-externals@3.0.0: +webpack-node-externals@3.0.0, webpack-node-externals@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz#1a3407c158d547a9feb4229a9e3385b7b60c9917" integrity sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ== @@ -5311,7 +5336,7 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@5.75.0: +webpack@5.75.0, webpack@^5.75.0: version "5.75.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.75.0.tgz#1e440468647b2505860e94c9ff3e44d5b582c152" integrity sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==