diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d84e848..f61da30 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: strategy: matrix: - app: [driver, notification, gateway, ride, user-service, auth] + app: [driver, notification, gateway, ride, user-service, auth, user] steps: - name: Checkout code diff --git a/apps/auth/src/auth.service.ts b/apps/auth/src/auth.service.ts index c9be2da..59c8c15 100644 --- a/apps/auth/src/auth.service.ts +++ b/apps/auth/src/auth.service.ts @@ -1,6 +1,9 @@ -import { Injectable } from '@nestjs/common'; +import { UserCreateCommand } from '@app/shared/commands/auth/user.create.cmd'; +import { IResponse } from '@app/shared/interfaces/response.interface'; +import { validateCommand } from '@app/shared/utils/validate'; +import { BadRequestException, Injectable } from '@nestjs/common'; @Injectable() export class AuthService { - + } diff --git a/apps/driver/src/driver.controller.ts b/apps/driver/src/driver.controller.ts index da04968..37d5476 100644 --- a/apps/driver/src/driver.controller.ts +++ b/apps/driver/src/driver.controller.ts @@ -2,28 +2,27 @@ import { Controller, Get } from '@nestjs/common'; import { DriverService } from './driver.service'; import { MessagePattern } from '@nestjs/microservices'; import { DriverDto } from '@app/shared/events/driver/driver.dto'; -import { mapDriversToDtos } from './utils/driver.mapper'; -import { DriverCreateCmd } from '@app/shared/commands/driver/driver.create.cmd'; +import { Driver } from './models/driver.entity'; @Controller('drivers') export class DriverController { constructor(private readonly driverService: DriverService) {} @MessagePattern({ cmd: 'create'}) - async createDriver(driverCmd: DriverCreateCmd): Promise { - this.driverService.createDriver(driverCmd); + async createDriver(userId: string): Promise { + this.driverService.createDriver(userId); return "driver created successfully"; } @MessagePattern({ cmd: 'get_all_driver'}) - async findAllDriver(): Promise { + async findAllDriver(): Promise { const drivers = await this.driverService.findAllDrivers(); - return mapDriversToDtos(drivers); + return drivers; } @MessagePattern({ cmd: 'get_all_sorted_by_status'}) - async getAllDrivers(): Promise { + async getAllDrivers(): Promise { const drivers = await this.driverService.findAllSortedByStatus(); - return mapDriversToDtos(drivers); + return drivers } } diff --git a/apps/driver/src/driver.module.ts b/apps/driver/src/driver.module.ts index bcceba0..026c45b 100644 --- a/apps/driver/src/driver.module.ts +++ b/apps/driver/src/driver.module.ts @@ -1,25 +1,22 @@ import { Module } from '@nestjs/common'; import { DatabaseModule } from '@app/database'; -import { MongooseModule } from '@nestjs/mongoose'; import { DriverController } from './driver.controller'; import { DriverService } from './driver.service'; -import { Driver, DriverSchema } from './models/driver.schema'; -import { LocationSchema, Location } from './models/location.schema'; -import { VehicleSchema, Vehicle } from './models/vehicle.schema'; import * as dotenv from 'dotenv'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { Driver } from './models/driver.entity'; + dotenv.config(); @Module({ imports: [ - MongooseModule.forFeature( - [ - { name: Driver.name, schema: DriverSchema }, - { name: Location.name, schema: LocationSchema }, - { name: Vehicle.name, schema: VehicleSchema } - ] - ), - DatabaseModule.forRoot(process.env.MONGODB_URI, 'drivers'), + TypeOrmModule.forFeature([Driver]), + DatabaseModule.forRoot( + process.env.DATABASE_URI, + process.env.DATABASE_NAME, + process.env.DATABASE_TYPE as 'mongodb' | 'postgres' + ), ], controllers: [DriverController], providers: [DriverService], diff --git a/apps/driver/src/driver.service.ts b/apps/driver/src/driver.service.ts index 0fec4f6..5c8204d 100644 --- a/apps/driver/src/driver.service.ts +++ b/apps/driver/src/driver.service.ts @@ -1,52 +1,41 @@ import { Injectable, Logger } from '@nestjs/common'; -import { InjectModel } from '@nestjs/mongoose'; -import { Model } from 'mongoose'; -import * as bcrypt from 'bcrypt'; -import { Driver } from './models/driver.schema'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; import { DriverStatus } from './enums/driver.status'; -import { DriverCreateCmd } from '@app/shared/commands/driver/driver.create.cmd'; +import { Driver } from './models/driver.entity'; + + @Injectable() export class DriverService { private readonly logger = new Logger(DriverService.name); + constructor( - @InjectModel('Driver') private readonly driverModel: Model - ){} + @InjectRepository(Driver) + private readonly driverRepository: Repository + ) {} - async createDriver(driverCmd: DriverCreateCmd): Promise { - this.logger.log(`Begin creating driver with payload: ${JSON.stringify(driverCmd)}`); + async createDriver(userId: string): Promise { + this.logger.log(`Begin creating driver with userId: ${userId}`); - const hashedPassword = await this.hashPassword(driverCmd.password); - const driverData = this.buildDriverData(driverCmd, hashedPassword); - - const savedDriver = await this.saveDriver(driverData); - - this.logger.log(`Driver with firstName created: ${JSON.stringify(savedDriver)}`); - return savedDriver; - } + const driverData = this.buildDriverData(userId); + + const savedDriver = await this.driverRepository.save(driverData); - private async hashPassword(password: string): Promise { - return bcrypt.hash(password, 10); + this.logger.log(`Driver with userId created: ${JSON.stringify(savedDriver)}`); + return savedDriver; } - private buildDriverData(driverCmd: DriverCreateCmd, hashedPassword: string): Partial { + private buildDriverData(userId: string): Partial { return { - email: driverCmd.email, - password: hashedPassword, - firstName: driverCmd.firstName, - lastName: driverCmd.lastName, - driverStatus: DriverStatus.EMPTY, + user_id: userId }; } - private async saveDriver(driverData: Partial): Promise { - const driver = new this.driverModel(driverData); - return driver.save(); - } async findAllDrivers(): Promise { try { - return await this.driverModel.find().exec(); + return await this.driverRepository.find(); } catch (error) { this.logger.error(`Error while fetching drivers from database: ${error.message}`); throw error; @@ -54,7 +43,6 @@ export class DriverService { } async findAllSortedByStatus(): Promise { - try { const drivers = await this.findAllDrivers(); const order = [ @@ -71,6 +59,7 @@ export class DriverService { throw error; } } + private sortDriversByStatus(drivers: Driver[], order: DriverStatus[]): Driver[] { try { // create a custom sort function based on the order array @@ -87,6 +76,4 @@ export class DriverService { throw error; } } - - } diff --git a/apps/driver/src/models/driver.entity.ts b/apps/driver/src/models/driver.entity.ts new file mode 100644 index 0000000..1c493a9 --- /dev/null +++ b/apps/driver/src/models/driver.entity.ts @@ -0,0 +1,40 @@ +import { Entity, PrimaryGeneratedColumn, Column, BeforeInsert } from 'typeorm'; +import { v4 as uuidv4 } from 'uuid'; +import { DriverStatus } from '../enums/driver.status'; + +@Entity() +export class Driver { + + @BeforeInsert() + generateId() { + this.id = uuidv4(); + } + + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ type: 'integer' }) + user_id: string; + + @Column({ type: 'varchar', length: 50 }) + license_number: string; + + @Column({ type: 'integer', nullable: true }) + vehicle_id: number; + + @Column({ type: 'float', nullable: true }) + rating: number; + + @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }) + created_at: Date; + + @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP', onUpdate: 'CURRENT_TIMESTAMP' }) + updated_at: Date; + + @Column({ + type: 'enum', + enum: DriverStatus, + default: DriverStatus.EMPTY + }) + driverStatus: DriverStatus; +} diff --git a/apps/driver/src/models/driver.schema.ts b/apps/driver/src/models/driver.schema.ts deleted file mode 100644 index 67ded1c..0000000 --- a/apps/driver/src/models/driver.schema.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; -import { DriverStatus, DriverStatusType } from "../enums/driver.status"; -import { Types } from "mongoose"; - - -export type DriverDocument = Driver & Document; - - -@Schema({ - toJSON: { - getters: true, - virtuals: true, - }, - timestamps: true, -}) -export class Driver { - - @Prop({ required: true }) - firstName: string; - - @Prop({ required: true }) - lastName: string; - - @Prop({ required: true, unique: true }) - email: string; - - @Prop({ required: true }) - password: string; - - @Prop({ type: [Types.ObjectId], ref: 'Vehicle' }) - vehicles: Types.ObjectId[]; - - @Prop({ - type: String, - enum: [ - DriverStatus.EMPTY, - DriverStatus.ONE_SET_AVAILABLE, - DriverStatus.TWO_SET_AVAILABLE, - DriverStatus.THREE_SET_AVAILABLE - ] - }) - driverStatus: DriverStatus; - - @Prop({ default: false }) - isActive: boolean; -} - -export const DriverSchema = SchemaFactory.createForClass(Driver); - -DriverSchema.pre('save', function (next) { - if (!DriverStatusType.isValid(this.driverStatus)) { - next(new Error('Invalid user type')); - } else { - next(); - } - }); \ No newline at end of file diff --git a/apps/driver/src/models/location.schema.ts b/apps/driver/src/models/location.schema.ts deleted file mode 100644 index 410865f..0000000 --- a/apps/driver/src/models/location.schema.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; -import { Document } from 'mongoose'; - - - -export type LocationDocument = Location & Document; - -@Schema({ - toJSON: { - getters: true, - virtuals: true, - }, - timestamps: true, -}) -export class Location { - @Prop({ required: true }) - userId: string; - - @Prop({ required: true }) - latitude: number; - - @Prop({ required: true }) - longitude: number; - - @Prop({ default: Date.now }) - timestamp: Date; -} - -export const LocationSchema = SchemaFactory.createForClass(Location); \ No newline at end of file diff --git a/apps/driver/src/models/vehicle.schema.ts b/apps/driver/src/models/vehicle.schema.ts deleted file mode 100644 index 1935160..0000000 --- a/apps/driver/src/models/vehicle.schema.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; - - - -@Schema({ - toJSON: { - getters: true, - virtuals: true, - }, - timestamps: true, -}) -export class Vehicle { - - @Prop({required: true}) - driverId: string; - - @Prop({required: true}) - model: string; - - @Prop({required: true}) - year: string; - - @Prop({required: true}) - licencePlate: string; - - @Prop({required: true}) - color: string; - - @Prop({ required: true }) - capacity: number; -} - -export const VehicleSchema = SchemaFactory.createForClass(Vehicle); \ No newline at end of file diff --git a/apps/driver/src/utils/daba.config.ts b/apps/driver/src/utils/daba.config.ts deleted file mode 100644 index 2a88a3b..0000000 --- a/apps/driver/src/utils/daba.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Driver, DriverSchema } from "../models/driver.schema"; -import { Location, LocationSchema } from "../models/location.schema"; -import { Vehicle, VehicleSchema } from "../models/vehicle.schema"; - -export default [ - { name: Driver.name, schema: DriverSchema }, - { name: Location.name, schema: LocationSchema }, - { name: Vehicle.name, schema: VehicleSchema } -]; \ No newline at end of file diff --git a/apps/driver/src/utils/driver.mapper.ts b/apps/driver/src/utils/driver.mapper.ts index 0b150b3..a749cc7 100644 --- a/apps/driver/src/utils/driver.mapper.ts +++ b/apps/driver/src/utils/driver.mapper.ts @@ -1,20 +1,4 @@ import { DriverDto } from "@app/shared/events/driver/driver.dto"; -import { Driver } from "../models/driver.schema"; +import { Driver } from "typeorm"; - -export function mapDriverToDto(driver: Driver): DriverDto { - const driverDto = new DriverDto(); - - driverDto.firstName = driver.firstName; - driverDto.lastName = driver.lastName; - driverDto.email = driver.email; - driverDto.password = driver.password; - driverDto.driverStatus = driver.driverStatus; - - return driverDto; -} - -export function mapDriversToDtos(drivers: Driver[]): DriverDto[] { - return drivers.map(driver => mapDriverToDto(driver)); -} \ No newline at end of file diff --git a/apps/gateway/src/rest/auth.controller.ts b/apps/gateway/src/rest/auth.controller.ts index fd5682d..2f8c981 100644 --- a/apps/gateway/src/rest/auth.controller.ts +++ b/apps/gateway/src/rest/auth.controller.ts @@ -11,9 +11,9 @@ import { ResponseSuccess } from '@app/shared/dto/response.dto'; -@Controller('auth') +@Controller() export class AuthController { - constructor(private readonly authService: AuthService) {} + /*constructor(private readonly authService: AuthService) {} @Post('register/:userTypeId') @@ -35,5 +35,5 @@ export class AuthController { } catch (error) { throw error; } - } + }*/ } diff --git a/apps/gateway/src/rest/user.controller.ts b/apps/gateway/src/rest/user.controller.ts index 4fdaef8..1e1664e 100644 --- a/apps/gateway/src/rest/user.controller.ts +++ b/apps/gateway/src/rest/user.controller.ts @@ -1,44 +1,27 @@ -import { ApiOperation } from "@nestjs/swagger"; -import { UserService } from "../services/user-service"; -import { Controller, Get, Param, NotFoundException } from '@nestjs/common'; -import { GetUserEvent } from "@app/shared/events/user/user.get"; -import { UserTypeDto } from "@app/shared/events/user/user.type.dto"; +import { Body, Controller, Get, Param, Post } from '@nestjs/common'; +import { UserCreateCommand } from '@app/shared/commands/auth/user.create.cmd'; +import { UserService } from '../services/user-service'; - -@Controller('users') +@Controller('user') export class UserController { - - constructor(private readonly userService: UserService) {} - @Get() - @ApiOperation({ summary: 'Get all users' }) - async getAllUsers(): Promise { - return await this.userService.getAll(); - } + constructor(private readonly userService: UserService) {} + + @Get(':id') + async findUserById(@Param('id') id: string): Promise { + return this.userService.findUserById(id); + } - @Get(':id') - @ApiOperation({ summary: 'Get User by id' }) - async getUserById(@Param('id') userId: string): Promise { - const user = await this.userService.getById(userId); - if (!user) { - throw new NotFoundException(`User with ID ${userId} not found`); + @Get() + async getAllUsers(): Promise { + return this.userService.getAllUsers(); } - return user; - } - @Get('type/:id') - @ApiOperation({ summary: 'Get User Type by id' }) - async getUserTypeById(@Param('id') userTypeById: string): Promise { - const user = await this.userService.findUserTypeById(userTypeById); - if (!user) { - throw new NotFoundException(`User type with ID ${userTypeById} not found`); + + // Example of handling a POST request to create a user + @Post() + async createUser(@Body() command: UserCreateCommand): Promise { + return this.userService.createUser(command); } - return user; - } - @Get('profile') - @ApiOperation({ summary: 'Get current user' }) - async getCurrentUser(): Promise { - return this.userService.getCurrentProfile(); - } -} \ No newline at end of file +} diff --git a/apps/gateway/src/rest/user.type.controller.ts b/apps/gateway/src/rest/user.type.controller.ts new file mode 100644 index 0000000..14bdae2 --- /dev/null +++ b/apps/gateway/src/rest/user.type.controller.ts @@ -0,0 +1,21 @@ +import { Controller, Get, Param } from '@nestjs/common'; +import { UserTypeService } from '../services/user.type.service'; + + + +@Controller('user-type') +export class UserTypeController { + + + constructor(private readonly userTypeService: UserTypeService) {} + + @Get(':id') + async getUserTypeById(@Param('id') id: string): Promise { + return this.userTypeService.findUserTypeById(id); + } + + @Get() + async getAllUserTypes(): Promise { + return this.userTypeService.getUserTypes(); + } +} diff --git a/apps/gateway/src/services/auth.service.ts b/apps/gateway/src/services/auth.service.ts index 6968629..583015c 100644 --- a/apps/gateway/src/services/auth.service.ts +++ b/apps/gateway/src/services/auth.service.ts @@ -11,7 +11,7 @@ import { DriverService } from "./driver-service"; @Injectable() export class AuthService { - constructor( + /*constructor( @Inject('USER_SERVICE') private readonly userClient: ClientProxy, private readonly userService: UserService, private readonly driverService: DriverService @@ -64,5 +64,5 @@ export class AuthService { }catch(error){ throw new InternalServerErrorException('Failed to Verify'); } - } + }*/ } \ No newline at end of file diff --git a/apps/gateway/src/services/user-service.ts b/apps/gateway/src/services/user-service.ts index 25d012e..3501937 100644 --- a/apps/gateway/src/services/user-service.ts +++ b/apps/gateway/src/services/user-service.ts @@ -1,72 +1,47 @@ -import { UserCreateCommand } from '@app/shared/commands/auth/user.create.cmd'; -import { GetUserEvent } from "@app/shared/events/user/user.get"; -import { UserTypeDto } from "@app/shared/events/user/user.type.dto"; -import { BadRequestException, ConflictException, Inject, Injectable, InternalServerErrorException, LoggerService } from "@nestjs/common"; -import { ClientProxy } from "@nestjs/microservices"; -import { WINSTON_MODULE_NEST_PROVIDER } from "nest-winston"; - - +import { Injectable, Inject } from '@nestjs/common'; +import { ClientProxy } from '@nestjs/microservices'; +import { UserCreateCommand } from '@app/shared/commands/auth/user.create.cmd'; // Adjust import path as needed +import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston'; +import { Logger } from 'winston'; @Injectable() export class UserService { constructor( @Inject('USER_SERVICE') private readonly userClient: ClientProxy, - @Inject(WINSTON_MODULE_NEST_PROVIDER) private readonly logger: LoggerService, + @Inject(WINSTON_MODULE_NEST_PROVIDER) private readonly logger: Logger, ) {} - async findUserTypeById(userTypeId: string): Promise { - try { - const userType = await this.userClient.send({ cmd: 'get_user_type__by_id' }, userTypeId).toPromise(); - this.logger.log(`User type with payload ${JSON.stringify(userType)} found`); - return userType; - }catch (error) { - // log the error for debugging purposes - console.error('Error occurred during user registration:', error); - - // decide how to handle different types of errors - if (error.response && error.response.status === 409) { - throw new ConflictException('User with this email already exists'); - } else if (error.response && error.response.status === 400) { - throw new BadRequestException('Invalid user data provided'); - } else { - // if the error is unexpected, throw an Internal Server Error - throw new InternalServerErrorException('Failed to register user'); + async createUser(command: UserCreateCommand): Promise { + try { + const result = await this.userClient.send({ cmd: 'createUser' }, command).toPromise(); + this.logger.info(`Created user with id ${result.id}`); + return result; + } catch (error) { + this.logger.error(`Error creating user: ${error.message}`); + throw error; } - } } - async createUser(command: UserCreateCommand, userTypeId: string): Promise { - return await this.userClient.send({ cmd: 'register' }, { userTypeId, command: command }).toPromise(); - } - async getAll(): Promise { + + async findUserById(id: string): Promise { try { - // dend the message to the auth client to fetch all users - const users = await this.userClient.send({ cmd: 'get_all_users'}, null).toPromise(); - - // ensure that the response is an array - if (!Array.isArray(users)) { - throw new Error('Received data is not an array'); - } - - return users; + const result = await this.userClient.send({ cmd: 'findUserById' }, id).toPromise(); + this.logger.info(`Found user with id ${id}`); + return result; } catch (error) { - console.error('Error occurred while fetching all users:', error); - throw new InternalServerErrorException('Failed to fetch users'); + this.logger.error(`Error finding user with id ${id}: ${error.message}`); + throw error; } } - async getById(userId: string): Promise { + async getAllUsers(): Promise { try { - const user = await this.userClient.send({ cmd: 'get_user_by_id' }, userId).toPromise(); - //const target: GetUserEvent = mapDto(user); - return user; + const result = await this.userClient.send({ cmd: 'getAllUsers' }, {}).toPromise(); + this.logger.info(`Fetched all users, count: ${result.length}`); + return result; } catch (error) { - console.error(`Error occurred while fetching user with ID ${userId}:`, error); - throw new InternalServerErrorException(`Failed to fetch user with ID ${userId}`); + this.logger.error(`Error fetching all users: ${error.message}`); + throw error; } } - async getCurrentProfile() { - return this.userClient.send({ cmd: 'profile' }, {}).toPromise(); - } -} - +} \ No newline at end of file diff --git a/apps/gateway/src/services/user.type.service.ts b/apps/gateway/src/services/user.type.service.ts new file mode 100644 index 0000000..c96f462 --- /dev/null +++ b/apps/gateway/src/services/user.type.service.ts @@ -0,0 +1,21 @@ +import { Inject, Injectable } from "@nestjs/common"; +import { ClientProxy } from "@nestjs/microservices"; + + + + +@Injectable() +export class UserTypeService { + + constructor( + @Inject('USER_SERVICE') private readonly userClient: ClientProxy + ) {} + + async findUserTypeById(userTypeId: string): Promise { + return await this.userClient.send({ cmd: 'get_by_id' }, userTypeId).toPromise(); + } + + async getUserTypes(): Promise { + return await this.userClient.send({ cmd: 'get_all_user_types' }, {}).toPromise(); + } +} \ No newline at end of file diff --git a/apps/user-service/src/user-service.module.ts b/apps/user-service/src/user-service.module.ts index 4f84a61..847666f 100644 --- a/apps/user-service/src/user-service.module.ts +++ b/apps/user-service/src/user-service.module.ts @@ -18,7 +18,7 @@ dotenv.config(); @Module({ imports: [ MongooseModule.forFeature(forFeatureDb), - DatabaseModule.forRoot(process.env.MONGODB_URI, 'user'), + DatabaseModule.forRoot(process.env.MONGODB_URI, 'user', "mongodb"), forwardRef(() => AuthModule), ], controllers: [UserServiceController], diff --git a/apps/user/src/main.ts b/apps/user/src/main.ts new file mode 100644 index 0000000..7c8637a --- /dev/null +++ b/apps/user/src/main.ts @@ -0,0 +1,21 @@ +import { NestFactory } from '@nestjs/core'; +import { UserModule } from './user.module'; +import { MicroserviceOptions, Transport } from '@nestjs/microservices'; + + + + +async function bootstrap() { + + const app = await NestFactory.createMicroservice( + UserModule, + { + transport: Transport.TCP, + options: { + port: 3001, + }, + }, + ); + await app.listen(); +} +bootstrap(); diff --git a/apps/user/src/model/email.confirmation.ts b/apps/user/src/model/email.confirmation.ts new file mode 100644 index 0000000..e69de29 diff --git a/apps/user/src/model/user.entity.ts b/apps/user/src/model/user.entity.ts new file mode 100644 index 0000000..844da5c --- /dev/null +++ b/apps/user/src/model/user.entity.ts @@ -0,0 +1,42 @@ +import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn, BeforeInsert } from 'typeorm'; +import { UserType } from './user.type'; +import { v4 as uuidv4 } from 'uuid'; + + + +@Entity() +export class User { + + @BeforeInsert() + generateId() { + this.id = uuidv4(); + } + + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ type: 'varchar', length: 255, nullable: false }) + firstName: string; + + @Column({ type: 'varchar', length: 255, nullable: false }) + lastName: string; + + @Column({ type: 'varchar', length: 255, unique: true, nullable: false }) + email: string; + + @Column({ type: 'varchar', nullable: false }) + password: string; + + @ManyToOne(() => UserType, { eager: true, nullable: false }) + @JoinColumn({ name: 'userTypeId' }) + userType: UserType; + + @Column({ type: 'boolean', default: false }) + verified: boolean; + + @CreateDateColumn() + createdAt: Date; + + @UpdateDateColumn() + updatedAt: Date; +} diff --git a/apps/user/src/model/user.type.ts b/apps/user/src/model/user.type.ts new file mode 100644 index 0000000..1151332 --- /dev/null +++ b/apps/user/src/model/user.type.ts @@ -0,0 +1,18 @@ +import { Entity, Column, PrimaryGeneratedColumn, BeforeInsert } from 'typeorm'; +import { v4 as uuidv4 } from 'uuid'; + + +@Entity() +export class UserType { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ type: 'varchar', length: 255, nullable: false }) + type: string; + + + @BeforeInsert() + generateId() { + this.id = uuidv4(); + } +} diff --git a/apps/user/src/services/user.type.controller.ts b/apps/user/src/services/user.type.controller.ts new file mode 100644 index 0000000..5afaa2f --- /dev/null +++ b/apps/user/src/services/user.type.controller.ts @@ -0,0 +1,24 @@ +import { Controller } from "@nestjs/common"; +import { UserTypeService } from "./user.type.service"; +import { MessagePattern } from "@nestjs/microservices"; +import { UserType } from "../model/user.type"; + + + +@Controller('user-type') +export class UserTypeController { + + constructor( + private readonly userTypeService: UserTypeService + ){} + + @MessagePattern({ cmd: 'get_by_id'}) + async getUserTypeById(userTypeId: string): Promise { + return this.userTypeService.findUserTypeById(userTypeId); + } + + @MessagePattern({ cmd: 'get_all_user_types'}) + async getUserTypes(): Promise { + return this.userTypeService.getUserTypes(); + } +} \ No newline at end of file diff --git a/apps/user/src/services/user.type.service.ts b/apps/user/src/services/user.type.service.ts new file mode 100644 index 0000000..e5d429d --- /dev/null +++ b/apps/user/src/services/user.type.service.ts @@ -0,0 +1,70 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { InjectRepository } from "@nestjs/typeorm"; +import { UserType } from "../model/user.type"; +import { Repository } from "typeorm"; +import { throwException } from "@app/shared/exception/exception.util"; +import { ExceptionPayloadFactory } from "@app/shared/exception/exception.payload.factory"; + + + + +@Injectable() +export class UserTypeService { + + private readonly logger = new Logger(UserTypeService.name); + constructor( + @InjectRepository(UserType)private readonly userTypeRepository: Repository + ){} + + async createUserType(type: string): Promise { + const userType = this.userTypeRepository.create({ type }); + return this.userTypeRepository.save(userType); + } + + async seedUserTypes(): Promise { + try { + const userTypes = ['Driver', 'User']; + + for (const type of userTypes) { + await this.seedUserType(type); + } + } catch (error) { + this.logger.error('Error seeding user types:', error); + } + } + + private async seedUserType(type: string): Promise { + try { + const existingType = await this.userTypeRepository.findOne({where: {type}}); + if (!existingType) { + const userType = await this.createUserType(type); + this.logger.log(`User type '${type}' seeded successfully.`); + } else { + this.logger.debug(`User type '${type}' already exists.`); + } + } catch (error) { + this.logger.error(`Error seeding user type '${type}': ${error.message}`); + } + } + + async findUserTypeById(id: string): Promise { + this.logger.log(`Begin fetching user type with id ${id}`); + const userType = await this.userTypeRepository.findOne({ where: { id } }); + + if (!userType) { + this.logger.error(`UserType with id ${id} not found`); + throwException(ExceptionPayloadFactory.USER_TYPE_NOT_FOUND); + } + this.logger.log(`User type fetched successfully with id ${id}`); + return userType; + } + async getUserTypes(): Promise { + this.logger.log(`Begin fetching user types`); + try { + return await this.userTypeRepository.find(); + } catch (error) { + this.logger.error('Error fetching all user types:', error.message); + throw error; + } + } +} \ No newline at end of file diff --git a/apps/user/src/user.controller.spec.ts b/apps/user/src/user.controller.spec.ts new file mode 100644 index 0000000..005985f --- /dev/null +++ b/apps/user/src/user.controller.spec.ts @@ -0,0 +1,22 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { UserController } from './user.controller'; +import { UserService } from './user.service'; + +describe('UserController', () => { + let userController: UserController; + + beforeEach(async () => { + const app: TestingModule = await Test.createTestingModule({ + controllers: [UserController], + providers: [UserService], + }).compile(); + + userController = app.get(UserController); + }); + + describe('root', () => { + it('should return "Hello World!"', () => { + expect(userController.getHello()).toBe('Hello World!'); + }); + }); +}); diff --git a/apps/user/src/user.controller.ts b/apps/user/src/user.controller.ts new file mode 100644 index 0000000..1bb836c --- /dev/null +++ b/apps/user/src/user.controller.ts @@ -0,0 +1,26 @@ +import { Controller, Get } from '@nestjs/common'; +import { UserService } from './user.service'; +import { MessagePattern } from '@nestjs/microservices'; +import { UserCreateCommand } from '@app/shared/commands/auth/user.create.cmd'; +import { User } from './model/user.entity'; + +@Controller('user') +export class UserController { + + constructor(private readonly userService: UserService) {} + + @MessagePattern({ cmd: 'createUser' }) + async createUser(command: UserCreateCommand): Promise { + return this.userService.createUser(command); + } + + @MessagePattern({ cmd: 'findUserById' }) + async findUserById(id: string): Promise { + return this.userService.findUserById(id); + } + + @MessagePattern({ cmd: 'getAllUsers' }) + async getAllUsers(): Promise { + return this.userService.getAll(); + } +} diff --git a/apps/user/src/user.module.ts b/apps/user/src/user.module.ts new file mode 100644 index 0000000..6df14f7 --- /dev/null +++ b/apps/user/src/user.module.ts @@ -0,0 +1,46 @@ +import { Logger, Module, OnModuleInit } from '@nestjs/common'; +import { UserController } from './user.controller'; +import { UserService } from './user.service'; +import * as dotenv from 'dotenv'; +import { DatabaseModule } from '@app/database'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { User } from './model/user.entity'; +import { UserType } from './model/user.type'; +import { UserTypeController } from './services/user.type.controller'; +import { UserTypeService } from './services/user.type.service'; + +dotenv.config(); + + +@Module({ + imports: [ + TypeOrmModule.forFeature([User, UserType]), + DatabaseModule.forRoot( + process.env.DATABASE_URI, + process.env.DATABASE_NAME, + process.env.DATABASE_TYPE as 'mongodb' | 'postgres' + ), + ], + controllers: [UserController, UserTypeController], + providers: [UserService, UserTypeService] +}) +export class UserModule implements OnModuleInit{ + + private readonly logger = new Logger(UserModule.name); + + constructor( + private readonly userTypeService : UserTypeService + ) {} + + async onModuleInit() { + try { + this.logger.log(`Begin init the UserType`); + await this.seedUserTypes(); + } catch (error) { + this.logger.error(`Error while init User Type error: ${error}`); + } + } + private async seedUserTypes() { + this.userTypeService.seedUserTypes(); + } +} diff --git a/apps/user/src/user.service.ts b/apps/user/src/user.service.ts new file mode 100644 index 0000000..5172068 --- /dev/null +++ b/apps/user/src/user.service.ts @@ -0,0 +1,97 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { User } from './model/user.entity'; +import { Repository } from 'typeorm'; +import { ExceptionPayloadFactory } from '@app/shared/exception/exception.payload.factory'; +import { throwException } from '@app/shared/exception/exception.util'; +import { UserCreateCommand } from '@app/shared/commands/auth/user.create.cmd'; +import { hashPassword } from '@app/shared/utils/hash.pass'; +import { validateCommand } from '@app/shared/utils/validate'; +import { ClientProxy, ClientProxyFactory, Transport } from '@nestjs/microservices'; + + + +@Injectable() +export class UserService { + + private readonly logger = new Logger(UserService.name); + private driverServiceClient: ClientProxy; + + constructor( + @InjectRepository(User) + private readonly userRepository: Repository, + ) { + this.driverServiceClient = ClientProxyFactory.create({ + transport: Transport.TCP, // Choose your transport protocol + options: { + port: 3001, // Specify the port of your DriverService + }, + }); + } + + + async createUser(command: UserCreateCommand): Promise { + await validateCommand(command); + await this.checkIfEmailExists(command.email); + const hashedPassword = await hashPassword(command.password); + const createdUser = await this.saveUser(command, hashedPassword); + + await this.createDriverProxy(createdUser.id); + + return createdUser; + } + private async createDriverProxy(userId: string): Promise { + try { + const response = await this.driverServiceClient.send({ cmd: 'create' }, userId).toPromise(); + this.logger.log(`Driver created successfully with response: ${response}`); + } catch (error) { + this.logger.error('Error creating driver:', error.message); + throwException(ExceptionPayloadFactory.TECHNICAL_ERROR); + } + } + private async checkIfEmailExists(email: string): Promise { + const existingUser = await this.userRepository.findOne({ where: { email } }); + if (existingUser) { + this.logger.error(`User with email ${email} already exists`); + throwException(ExceptionPayloadFactory.EMAIL_ALREADY_EXIST); + } + } + private async saveUser(command: UserCreateCommand, hashedPassword: string): Promise { + const { firstName, lastName, email } = command; + const newUser = this.userRepository.create({ + firstName, + lastName, + email, + password: hashedPassword, + }); + + try { + const savedUser = await this.userRepository.save(newUser); + this.logger.log(`User created successfully with id ${savedUser.id}`); + return savedUser; + } catch (error) { + this.logger.error('Error creating user:', error.message); + throwException(ExceptionPayloadFactory.TECHNICAL_ERROR); + } + } + async findUserById(id: string): Promise { + this.logger.log(`Begin fetching user with id ${id}`); + const user = await this.userRepository.findOne({ where: {id}}); + + if(!user){ + this.logger.error(`User with id ${id} not found`); + throwException(ExceptionPayloadFactory.USER_NAME_NOT_FOUND); + } + this.logger.log(`User fetched successfully with id ${id}`); + return user; + } + async getAll(): Promise { + this.logger.log(`Begin fetching users`); + try { + return await this.userRepository.find(); + } catch (error) { + this.logger.error('Error fetching all users:', error.message); + throw error; + } + } +} diff --git a/apps/user/test/app.e2e-spec.ts b/apps/user/test/app.e2e-spec.ts new file mode 100644 index 0000000..8b872b2 --- /dev/null +++ b/apps/user/test/app.e2e-spec.ts @@ -0,0 +1,24 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { INestApplication } from '@nestjs/common'; +import * as request from 'supertest'; +import { UserModule } from './../src/user.module'; + +describe('UserController (e2e)', () => { + let app: INestApplication; + + beforeEach(async () => { + const moduleFixture: TestingModule = await Test.createTestingModule({ + imports: [UserModule], + }).compile(); + + app = moduleFixture.createNestApplication(); + await app.init(); + }); + + it('/ (GET)', () => { + return request(app.getHttpServer()) + .get('/') + .expect(200) + .expect('Hello World!'); + }); +}); diff --git a/apps/user/test/jest-e2e.json b/apps/user/test/jest-e2e.json new file mode 100644 index 0000000..e9d912f --- /dev/null +++ b/apps/user/test/jest-e2e.json @@ -0,0 +1,9 @@ +{ + "moduleFileExtensions": ["js", "json", "ts"], + "rootDir": ".", + "testEnvironment": "node", + "testRegex": ".e2e-spec.ts$", + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + } +} diff --git a/apps/user/tsconfig.app.json b/apps/user/tsconfig.app.json new file mode 100644 index 0000000..118b506 --- /dev/null +++ b/apps/user/tsconfig.app.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "declaration": false, + "outDir": "../../dist/apps/user" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] +} diff --git a/libs/database/src/database.module.ts b/libs/database/src/database.module.ts index 2b7cfdd..c83e6c8 100644 --- a/libs/database/src/database.module.ts +++ b/libs/database/src/database.module.ts @@ -1,33 +1,73 @@ import { Module, DynamicModule, Logger } from '@nestjs/common'; +import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm'; import { MongooseModule, MongooseModuleOptions } from '@nestjs/mongoose'; -import { ConnectOptions } from 'mongoose'; + + + @Module({}) export class DatabaseModule { - + private static logger = new Logger(DatabaseModule.name); - static forRoot(uri: string, dbName: string): DynamicModule { - return { - module: DatabaseModule, - imports: [ - MongooseModule.forRoot(uri, { - dbName, - } as ConnectOptions), - ], - exports: [MongooseModule], - }; + static forRoot(uri: string, dbName: string, dbType: 'mongodb' | 'postgres'): DynamicModule { + if (dbType === 'mongodb') { + return { + module: DatabaseModule, + imports: [ + MongooseModule.forRoot(uri, { + dbName, + } as MongooseModuleOptions), + ], + exports: [MongooseModule], + }; + } else if (dbType === 'postgres') { + const typeOrmOptions: TypeOrmModuleOptions = { + type: 'postgres', + url: uri, + database: dbName, + synchronize: true, // Set to false in production + autoLoadEntities: true, + }; + + return { + module: DatabaseModule, + imports: [ + TypeOrmModule.forRoot(typeOrmOptions), + ], + exports: [TypeOrmModule], + }; + } else { + throw new Error(`Unsupported database type: ${dbType}`); + } } - static forFeature(schemas: { name: string; schema: any }[], connectionName: string): DynamicModule { - return { - module: DatabaseModule, - imports: [ - MongooseModule.forFeature(schemas, connectionName), - ], - exports: [MongooseModule], - }; + static forFeature( + schemas: { name: string; schema: any }[], + connectionName: string, + dbType: 'mongodb' | 'postgres' + ): DynamicModule { + if (dbType === 'mongodb') { + return { + module: DatabaseModule, + imports: [ + MongooseModule.forFeature(schemas, connectionName), + ], + exports: [MongooseModule], + }; + } else if (dbType === 'postgres') { + return { + module: DatabaseModule, + imports: [ + TypeOrmModule.forFeature(schemas.map(schema => schema.schema)), + ], + exports: [TypeOrmModule], + }; + } else { + throw new Error(`Unsupported database type: ${dbType}`); + } } + static logConnection(dbName: string, error?: any) { if (error) { this.logger.error(`Failed to connect to database '${dbName}': ${error.message}`, error.stack); diff --git a/libs/shared/src/exception/exception.payload.factory.ts b/libs/shared/src/exception/exception.payload.factory.ts index fecd3c5..e22d0f3 100644 --- a/libs/shared/src/exception/exception.payload.factory.ts +++ b/libs/shared/src/exception/exception.payload.factory.ts @@ -11,14 +11,8 @@ enum ExceptionPayloadFactory { CUSTOMER_NOT_FOUND = 6, DRIVER_NOT_FOUND = 7, DRIVER_LOCATION_NOT_FOUND = 8, - CAR_NOT_FOUND = 9, - LOCATION_NOT_FOUND = 10, - RATING_NOT_FOUND = 11, - ORDER_NOT_FOUND = 12, - BANK_ACCOUNT_NOT_FOUND = 13, - WALLET_NOT_FOUND = 14, - CREDIT_CARD_NOT_FOUND = 15, - WALLER_FOR_ACCOUNT_NOT_FOUND = 16 + USER_TYPE_NOT_FOUND = 9, + } const exceptionPayloadDetails: { [key in ExceptionPayloadFactory]: { status: HttpStatus, message: string } } = { @@ -31,14 +25,7 @@ const exceptionPayloadDetails: { [key in ExceptionPayloadFactory]: { status: Htt [ExceptionPayloadFactory.CUSTOMER_NOT_FOUND]: { status: HttpStatus.NOT_FOUND, message: 'customer.not.found' }, [ExceptionPayloadFactory.DRIVER_NOT_FOUND]: { status: HttpStatus.NOT_FOUND, message: 'driver.not.found' }, [ExceptionPayloadFactory.DRIVER_LOCATION_NOT_FOUND]: { status: HttpStatus.NOT_FOUND, message: 'driver.location.not.found' }, - [ExceptionPayloadFactory.CAR_NOT_FOUND]: { status: HttpStatus.NOT_FOUND, message: 'car.not.found' }, - [ExceptionPayloadFactory.LOCATION_NOT_FOUND]: { status: HttpStatus.NOT_FOUND, message: 'location.not.found' }, - [ExceptionPayloadFactory.RATING_NOT_FOUND]: { status: HttpStatus.NOT_FOUND, message: 'rating.not.found' }, - [ExceptionPayloadFactory.ORDER_NOT_FOUND]: { status: HttpStatus.NOT_FOUND, message: 'order.not.found' }, - [ExceptionPayloadFactory.BANK_ACCOUNT_NOT_FOUND]: { status: HttpStatus.NOT_FOUND, message: 'bank.account.not.found' }, - [ExceptionPayloadFactory.WALLET_NOT_FOUND]: { status: HttpStatus.NOT_FOUND, message: 'wallet.not.found' }, - [ExceptionPayloadFactory.CREDIT_CARD_NOT_FOUND]: { status: HttpStatus.NOT_FOUND, message: 'credit.card.not.found' }, - [ExceptionPayloadFactory.WALLER_FOR_ACCOUNT_NOT_FOUND]: { status: HttpStatus.NOT_FOUND, message: 'wallet.for.account.not.found' }, + [ExceptionPayloadFactory.USER_TYPE_NOT_FOUND]: { status: HttpStatus.NOT_FOUND, message: 'user.type.not.found' } }; function createExceptionPayload(type: ExceptionPayloadFactory): ExceptionPayload { diff --git a/libs/shared/src/exception/exception.util.ts b/libs/shared/src/exception/exception.util.ts new file mode 100644 index 0000000..5a6cc49 --- /dev/null +++ b/libs/shared/src/exception/exception.util.ts @@ -0,0 +1,9 @@ +import { NotFoundException } from '@nestjs/common'; +import { createExceptionPayload, ExceptionPayloadFactory } from './exception.payload.factory'; + + + +export function throwException(type: ExceptionPayloadFactory): void { + const exceptionPayload = createExceptionPayload(type); + throw new NotFoundException(exceptionPayload.message); +} diff --git a/libs/shared/src/utils/hash.pass.ts b/libs/shared/src/utils/hash.pass.ts new file mode 100644 index 0000000..9119ef9 --- /dev/null +++ b/libs/shared/src/utils/hash.pass.ts @@ -0,0 +1,11 @@ +import * as bcrypt from 'bcrypt'; + + +export async function hashPassword(password: string): Promise { + try { + return await bcrypt.hash(password, 10); + } catch (error) { + this.logger.error(`Error hashing password: ${error.message}`); + throw error; + } +} \ No newline at end of file diff --git a/libs/shared/src/utils/validate.ts b/libs/shared/src/utils/validate.ts new file mode 100644 index 0000000..22ff9b0 --- /dev/null +++ b/libs/shared/src/utils/validate.ts @@ -0,0 +1,14 @@ +import { validate } from "class-validator"; +import { UserCreateCommand } from "../commands/auth/user.create.cmd"; +import { ExceptionPayloadFactory } from "../exception/exception.payload.factory"; +import { throwException } from "../exception/exception.util"; + + + +export async function validateCommand(command: UserCreateCommand): Promise { + const errors = await validate(command); + if (errors.length > 0) { + this.logger.error(`Validation failed: ${JSON.stringify(errors)}`); + throwException(ExceptionPayloadFactory.INVALID_PAYLOAD); + } + } \ No newline at end of file diff --git a/nest-cli.json b/nest-cli.json index 4940535..737c585 100644 --- a/nest-cli.json +++ b/nest-cli.json @@ -90,6 +90,15 @@ "compilerOptions": { "tsConfigPath": "apps/auth/tsconfig.app.json" } + }, + "user": { + "type": "application", + "root": "apps/user", + "entryFile": "main", + "sourceRoot": "apps/user/src", + "compilerOptions": { + "tsConfigPath": "apps/user/tsconfig.app.json" + } } } } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b1e4558..f49cc3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", "@nestjs/swagger": "^7.3.1", + "@nestjs/typeorm": "^10.0.2", "@willsoto/nestjs-prometheus": "^6.0.1", "ajv-keywords": "^5.1.0", "amqp-connection-manager": "^4.1.14", @@ -37,6 +38,7 @@ "rxjs": "^7.8.1", "schema-utils": "^4.2.0", "swagger-ui-express": "^5.0.1", + "typeorm": "^0.3.20", "uuid": "^9.0.1" }, "devDependencies": { @@ -933,7 +935,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -946,7 +948,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -1884,7 +1886,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1915,7 +1917,7 @@ "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -2616,6 +2618,22 @@ } } }, + "node_modules/@nestjs/typeorm": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@nestjs/typeorm/-/typeorm-10.0.2.tgz", + "integrity": "sha512-H738bJyydK4SQkRCTeh1aFBxoO1E9xdL/HaLGThwrqN95os5mEyAtK7BLADOS+vldP4jDZ2VQPLj4epWwRqCeQ==", + "license": "MIT", + "dependencies": { + "uuid": "9.0.1" + }, + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0", + "reflect-metadata": "^0.1.13 || ^0.2.0", + "rxjs": "^7.2.0", + "typeorm": "^0.3.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2752,32 +2770,38 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@sqltools/formatter": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", + "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==", + "license": "MIT" + }, "node_modules/@tsconfig/node10": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/babel__core": { @@ -3555,7 +3579,7 @@ "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -3588,7 +3612,7 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -3805,6 +3829,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -3832,6 +3862,15 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/app-root-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", + "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/append-field": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", @@ -3876,7 +3915,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/argparse": { @@ -4081,7 +4120,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -4622,6 +4660,103 @@ "node": ">=8" } }, + "node_modules/cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "license": "ISC", + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cli-highlight/node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "license": "MIT" + }, + "node_modules/cli-highlight/node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "license": "MIT", + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/cli-highlight/node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "license": "MIT" + }, + "node_modules/cli-highlight/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-highlight/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/cli-spinners": { "version": "2.9.2", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", @@ -4665,7 +4800,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "devOptional": true, "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -4680,7 +4814,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "devOptional": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -5026,7 +5159,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/cross-spawn": { @@ -5073,6 +5206,12 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/dayjs": { + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", + "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==", + "license": "MIT" + }, "node_modules/debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", @@ -5248,7 +5387,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -5594,7 +5733,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -6692,7 +6830,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "devOptional": true, "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" @@ -6757,7 +6894,6 @@ "version": "10.3.10", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", - "devOptional": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -7000,6 +7136,15 @@ "node": ">=8" } }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -7128,7 +7273,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, "funding": [ { "type": "github", @@ -9064,7 +9208,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/makeerror": { @@ -9927,6 +10071,17 @@ "dev": true, "license": "ISC" }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -11333,7 +11488,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11878,6 +12032,19 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -12709,6 +12876,27 @@ "dev": true, "license": "MIT" }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -12897,7 +13085,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -13038,11 +13226,156 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "license": "MIT" }, + "node_modules/typeorm": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.20.tgz", + "integrity": "sha512-sJ0T08dV5eoZroaq9uPKBoNcGslHBR4E4y+EBHs//SiGbblGe7IeduP/IH4ddCcj0qp3PHwDwGnuvqEAnKlq/Q==", + "license": "MIT", + "dependencies": { + "@sqltools/formatter": "^1.2.5", + "app-root-path": "^3.1.0", + "buffer": "^6.0.3", + "chalk": "^4.1.2", + "cli-highlight": "^2.1.11", + "dayjs": "^1.11.9", + "debug": "^4.3.4", + "dotenv": "^16.0.3", + "glob": "^10.3.10", + "mkdirp": "^2.1.3", + "reflect-metadata": "^0.2.1", + "sha.js": "^2.4.11", + "tslib": "^2.5.0", + "uuid": "^9.0.0", + "yargs": "^17.6.2" + }, + "bin": { + "typeorm": "cli.js", + "typeorm-ts-node-commonjs": "cli-ts-node-commonjs.js", + "typeorm-ts-node-esm": "cli-ts-node-esm.js" + }, + "engines": { + "node": ">=16.13.0" + }, + "funding": { + "url": "https://opencollective.com/typeorm" + }, + "peerDependencies": { + "@google-cloud/spanner": "^5.18.0", + "@sap/hana-client": "^2.12.25", + "better-sqlite3": "^7.1.2 || ^8.0.0 || ^9.0.0", + "hdb-pool": "^0.1.6", + "ioredis": "^5.0.4", + "mongodb": "^5.8.0", + "mssql": "^9.1.1 || ^10.0.1", + "mysql2": "^2.2.5 || ^3.0.1", + "oracledb": "^6.3.0", + "pg": "^8.5.1", + "pg-native": "^3.0.0", + "pg-query-stream": "^4.0.0", + "redis": "^3.1.1 || ^4.0.0", + "sql.js": "^1.4.0", + "sqlite3": "^5.0.3", + "ts-node": "^10.7.0", + "typeorm-aurora-data-api-driver": "^2.0.0" + }, + "peerDependenciesMeta": { + "@google-cloud/spanner": { + "optional": true + }, + "@sap/hana-client": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "hdb-pool": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "mongodb": { + "optional": true + }, + "mssql": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "oracledb": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-native": { + "optional": true + }, + "pg-query-stream": { + "optional": true + }, + "redis": { + "optional": true + }, + "sql.js": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "ts-node": { + "optional": true + }, + "typeorm-aurora-data-api-driver": { + "optional": true + } + } + }, + "node_modules/typeorm/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/typeorm/node_modules/mkdirp": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", + "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==", + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/typescript": { "version": "5.4.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -13198,7 +13531,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { @@ -13799,7 +14132,6 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "devOptional": true, "license": "ISC", "engines": { "node": ">=10" @@ -13816,7 +14148,6 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "devOptional": true, "license": "MIT", "dependencies": { "cliui": "^8.0.1", @@ -13835,7 +14166,6 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "devOptional": true, "license": "ISC", "engines": { "node": ">=12" @@ -13845,7 +14175,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" diff --git a/package.json b/package.json index 75d33ac..3e6175c 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", "@nestjs/swagger": "^7.3.1", + "@nestjs/typeorm": "^10.0.2", "@willsoto/nestjs-prometheus": "^6.0.1", "ajv-keywords": "^5.1.0", "amqp-connection-manager": "^4.1.14", @@ -48,6 +49,7 @@ "rxjs": "^7.8.1", "schema-utils": "^4.2.0", "swagger-ui-express": "^5.0.1", + "typeorm": "^0.3.20", "uuid": "^9.0.1" }, "devDependencies": {