feat: add JWT authentication, user registration, and device management
- AuthService with register, login, refresh token flows - JWT strategy + guard (Passport) - User, Home, Device services - REST endpoints: /auth/register, /auth/login, /auth/me, /auth/refresh - Device registration with long-lived JWT tokens (365d) - Device listing per home - bcrypt password hashing (cost 12) and device token hashing - Fix snake_case column names on all entity date columns Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
674109ea22
commit
0115669464
@ -25,12 +25,17 @@
|
||||
"@nestjs/common": "^11.1.17",
|
||||
"@nestjs/config": "^4.0.3",
|
||||
"@nestjs/core": "^11.1.17",
|
||||
"@nestjs/jwt": "^11.0.2",
|
||||
"@nestjs/passport": "^11.0.5",
|
||||
"@nestjs/platform-express": "^11.1.17",
|
||||
"@nestjs/typeorm": "^11.0.0",
|
||||
"bcrypt": "^6.0.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.15.1",
|
||||
"dotenv": "^17.3.1",
|
||||
"ioredis": "^5.10.1",
|
||||
"passport": "^0.7.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
"pg": "^8.20.0",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.2",
|
||||
@ -40,8 +45,10 @@
|
||||
"@nestjs/cli": "^11.0.16",
|
||||
"@nestjs/schematics": "^11.0.9",
|
||||
"@nestjs/testing": "^11.1.17",
|
||||
"@types/bcrypt": "^6.0.0",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/node": "^25.5.0",
|
||||
"@types/passport-jwt": "^4.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.57.2",
|
||||
"@typescript-eslint/parser": "^8.57.2",
|
||||
"eslint": "^10.1.0",
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
import { Controller, Post, Body, UseGuards, Request, Get } from '@nestjs/common';
|
||||
import { AuthService } from '../../../../core/services/auth.service';
|
||||
import { RegisterDto } from './dto/register.dto';
|
||||
import { LoginDto } from './dto/login.dto';
|
||||
import { JwtAuthGuard } from './guards/jwt-auth.guard';
|
||||
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
constructor(private readonly authService: AuthService) {}
|
||||
|
||||
@Post('register')
|
||||
async register(@Body() dto: RegisterDto) {
|
||||
return this.authService.register({
|
||||
email: dto.email,
|
||||
password: dto.password,
|
||||
displayName: dto.displayName,
|
||||
homeName: dto.homeName,
|
||||
});
|
||||
}
|
||||
|
||||
@Post('login')
|
||||
async login(@Body() dto: LoginDto) {
|
||||
return this.authService.login(dto.email, dto.password);
|
||||
}
|
||||
|
||||
@Post('refresh')
|
||||
async refresh(@Body('refreshToken') refreshToken: string) {
|
||||
return this.authService.refreshAccessToken(refreshToken);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('me')
|
||||
async me(@Request() req: { user: { id: string; email: string; homeId: string } }) {
|
||||
return req.user;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
import { IsEmail, IsString } from 'class-validator';
|
||||
|
||||
export class LoginDto {
|
||||
@IsEmail()
|
||||
email!: string;
|
||||
|
||||
@IsString()
|
||||
password!: string;
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
import { IsEmail, IsString, MinLength, MaxLength } from 'class-validator';
|
||||
|
||||
export class RegisterDto {
|
||||
@IsEmail()
|
||||
email!: string;
|
||||
|
||||
@IsString()
|
||||
@MinLength(8)
|
||||
@MaxLength(128)
|
||||
password!: string;
|
||||
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(100)
|
||||
displayName!: string;
|
||||
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(100)
|
||||
homeName!: string;
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
|
||||
@Injectable()
|
||||
export class JwtAuthGuard extends AuthGuard('jwt') {}
|
||||
@ -0,0 +1,31 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||
|
||||
export interface JwtPayload {
|
||||
sub: string;
|
||||
email: string;
|
||||
homeId: string;
|
||||
type: 'user' | 'device';
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class JwtStrategy extends PassportStrategy(Strategy) {
|
||||
constructor(configService: ConfigService) {
|
||||
super({
|
||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
ignoreExpiration: false,
|
||||
secretOrKey: configService.get<string>('auth.jwtSecret', 'dev-secret-change-in-production'),
|
||||
});
|
||||
}
|
||||
|
||||
validate(payload: JwtPayload) {
|
||||
return {
|
||||
id: payload.sub,
|
||||
email: payload.email,
|
||||
homeId: payload.homeId,
|
||||
type: payload.type,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
import { Controller, Post, Get, Body, UseGuards, Request } from '@nestjs/common';
|
||||
import { AuthService } from '../../../../core/services/auth.service';
|
||||
import { DeviceService } from '../../../../core/services/device.service';
|
||||
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
|
||||
import { RegisterDeviceDto } from './dto/register-device.dto';
|
||||
|
||||
@Controller('devices')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
export class DeviceController {
|
||||
constructor(
|
||||
private readonly authService: AuthService,
|
||||
private readonly deviceService: DeviceService,
|
||||
) {}
|
||||
|
||||
@Post()
|
||||
async registerDevice(
|
||||
@Body() dto: RegisterDeviceDto,
|
||||
@Request() req: { user: { homeId: string } },
|
||||
) {
|
||||
return this.authService.registerDevice(req.user.homeId, dto.name);
|
||||
}
|
||||
|
||||
@Get()
|
||||
async listDevices(@Request() req: { user: { homeId: string } }) {
|
||||
return this.deviceService.findByHomeId(req.user.homeId);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
import { IsString, MinLength, MaxLength } from 'class-validator';
|
||||
|
||||
export class RegisterDeviceDto {
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(100)
|
||||
name!: string;
|
||||
}
|
||||
@ -1,23 +1,45 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { PassportModule } from '@nestjs/passport';
|
||||
import { typeormConfig } from './config/typeorm.config';
|
||||
import { redisConfig } from './config/redis.config';
|
||||
import { appConfig } from './config/app.config';
|
||||
import { authConfig } from './config/auth.config';
|
||||
import { Home } from './core/domain/entities/home.entity';
|
||||
import { User } from './core/domain/entities/user.entity';
|
||||
import { Device } from './core/domain/entities/device.entity';
|
||||
import { AuthService } from './core/services/auth.service';
|
||||
import { UserService } from './core/services/user.service';
|
||||
import { HomeService } from './core/services/home.service';
|
||||
import { DeviceService } from './core/services/device.service';
|
||||
import { JwtStrategy } from './adapters/inbound/rest/auth/strategies/jwt.strategy';
|
||||
import { AuthController } from './adapters/inbound/rest/auth/auth.controller';
|
||||
import { DeviceController } from './adapters/inbound/rest/device/device.controller';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
load: [appConfig, redisConfig],
|
||||
load: [appConfig, redisConfig, authConfig],
|
||||
}),
|
||||
TypeOrmModule.forRootAsync({
|
||||
imports: [ConfigModule],
|
||||
inject: [ConfigService],
|
||||
useFactory: (configService: ConfigService) => typeormConfig(configService),
|
||||
}),
|
||||
TypeOrmModule.forFeature([Home, User, Device]),
|
||||
PassportModule,
|
||||
JwtModule.registerAsync({
|
||||
imports: [ConfigModule],
|
||||
inject: [ConfigService],
|
||||
useFactory: (configService: ConfigService) => ({
|
||||
secret: configService.get<string>('auth.jwtSecret', 'dev-secret-change-in-production'),
|
||||
}),
|
||||
}),
|
||||
],
|
||||
controllers: [],
|
||||
providers: [],
|
||||
controllers: [AuthController, DeviceController],
|
||||
providers: [AuthService, UserService, HomeService, DeviceService, JwtStrategy],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
||||
8
apps/backend/src/config/auth.config.ts
Normal file
8
apps/backend/src/config/auth.config.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export const authConfig = registerAs('auth', () => ({
|
||||
jwtSecret: process.env.JWT_SECRET || 'dev-secret-change-in-production',
|
||||
jwtExpiresIn: process.env.JWT_EXPIRES_IN || '15m',
|
||||
jwtRefreshExpiresIn: process.env.JWT_REFRESH_EXPIRES_IN || '7d',
|
||||
deviceTokenExpiresIn: process.env.DEVICE_TOKEN_EXPIRES_IN || '365d',
|
||||
}));
|
||||
@ -64,6 +64,6 @@ export class ConversationSession {
|
||||
@OneToMany(() => MemoryEntry, (memory) => memory.session)
|
||||
memories!: MemoryEntry[];
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
@CreateDateColumn({ type: 'timestamptz', name: 'created_at' })
|
||||
createdAt!: Date;
|
||||
}
|
||||
|
||||
@ -45,9 +45,9 @@ export class Device {
|
||||
@Column({ type: 'timestamptz', nullable: true, name: 'last_seen_at' })
|
||||
lastSeenAt!: Date | null;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
@CreateDateColumn({ type: 'timestamptz', name: 'created_at' })
|
||||
createdAt!: Date;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
@UpdateDateColumn({ type: 'timestamptz', name: 'updated_at' })
|
||||
updatedAt!: Date;
|
||||
}
|
||||
|
||||
@ -23,9 +23,9 @@ export class Home {
|
||||
@OneToMany(() => Device, (device) => device.home)
|
||||
devices!: Device[];
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
@CreateDateColumn({ type: 'timestamptz', name: 'created_at' })
|
||||
createdAt!: Date;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
@UpdateDateColumn({ type: 'timestamptz', name: 'updated_at' })
|
||||
updatedAt!: Date;
|
||||
}
|
||||
|
||||
@ -32,6 +32,6 @@ export class MemoryEmbedding {
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
embedding!: string | null;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
@CreateDateColumn({ type: 'timestamptz', name: 'created_at' })
|
||||
createdAt!: Date;
|
||||
}
|
||||
|
||||
@ -54,9 +54,9 @@ export class MemoryEntry {
|
||||
@Column({ type: 'boolean', default: true, name: 'is_active' })
|
||||
isActive!: boolean;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
@CreateDateColumn({ type: 'timestamptz', name: 'created_at' })
|
||||
createdAt!: Date;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
@UpdateDateColumn({ type: 'timestamptz', name: 'updated_at' })
|
||||
updatedAt!: Date;
|
||||
}
|
||||
|
||||
@ -45,6 +45,6 @@ export class Message {
|
||||
@Column({ type: 'integer', default: 0, name: 'tokens_used' })
|
||||
tokensUsed!: number;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
@CreateDateColumn({ type: 'timestamptz', name: 'created_at' })
|
||||
createdAt!: Date;
|
||||
}
|
||||
|
||||
@ -54,6 +54,6 @@ export class Timer {
|
||||
@Column({ type: 'enum', enum: TimerStatus, default: TimerStatus.ACTIVE })
|
||||
status!: TimerStatus;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
@CreateDateColumn({ type: 'timestamptz', name: 'created_at' })
|
||||
createdAt!: Date;
|
||||
}
|
||||
|
||||
@ -41,9 +41,9 @@ export class UserServiceCredential {
|
||||
@Column({ type: 'timestamptz', nullable: true, name: 'expires_at' })
|
||||
expiresAt!: Date | null;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
@CreateDateColumn({ type: 'timestamptz', name: 'created_at' })
|
||||
createdAt!: Date;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
@UpdateDateColumn({ type: 'timestamptz', name: 'updated_at' })
|
||||
updatedAt!: Date;
|
||||
}
|
||||
|
||||
@ -21,13 +21,13 @@ export class User {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id!: string;
|
||||
|
||||
@Column({ type: 'uuid' })
|
||||
homeId!: string;
|
||||
|
||||
@ManyToOne(() => Home, (home) => home.users, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'home_id' })
|
||||
home!: Home;
|
||||
|
||||
@Column({ type: 'uuid', name: 'home_id' })
|
||||
homeId!: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 255, unique: true })
|
||||
email!: string;
|
||||
|
||||
@ -46,9 +46,9 @@ export class User {
|
||||
@OneToMany(() => UserServiceCredential, (cred) => cred.user)
|
||||
serviceCredentials!: UserServiceCredential[];
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
@CreateDateColumn({ type: 'timestamptz', name: 'created_at' })
|
||||
createdAt!: Date;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
@UpdateDateColumn({ type: 'timestamptz', name: 'updated_at' })
|
||||
updatedAt!: Date;
|
||||
}
|
||||
|
||||
112
apps/backend/src/core/services/auth.service.ts
Normal file
112
apps/backend/src/core/services/auth.service.ts
Normal file
@ -0,0 +1,112 @@
|
||||
import { Injectable, UnauthorizedException, ConflictException } from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import * as crypto from 'crypto';
|
||||
import { UserService } from './user.service';
|
||||
import { HomeService } from './home.service';
|
||||
import { DeviceService } from './device.service';
|
||||
import { UserRole } from '../domain/entities/user.entity';
|
||||
import { JwtPayload } from '../../adapters/inbound/rest/auth/strategies/jwt.strategy';
|
||||
|
||||
export interface AuthTokens {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
}
|
||||
|
||||
export interface DeviceTokenResult {
|
||||
deviceId: string;
|
||||
token: string;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
constructor(
|
||||
private readonly userService: UserService,
|
||||
private readonly homeService: HomeService,
|
||||
private readonly deviceService: DeviceService,
|
||||
private readonly jwtService: JwtService,
|
||||
) {}
|
||||
|
||||
async register(data: {
|
||||
email: string;
|
||||
password: string;
|
||||
displayName: string;
|
||||
homeName: string;
|
||||
}): Promise<AuthTokens> {
|
||||
const existing = await this.userService.findByEmail(data.email);
|
||||
if (existing) {
|
||||
throw new ConflictException('Email already registered');
|
||||
}
|
||||
|
||||
const home = await this.homeService.create(data.homeName);
|
||||
|
||||
const passwordHash = await bcrypt.hash(data.password, 12);
|
||||
const user = await this.userService.create({
|
||||
email: data.email,
|
||||
passwordHash,
|
||||
displayName: data.displayName,
|
||||
homeId: home.id,
|
||||
role: UserRole.OWNER,
|
||||
});
|
||||
|
||||
return this.generateTokens(user.id, user.email, user.homeId);
|
||||
}
|
||||
|
||||
async login(email: string, password: string): Promise<AuthTokens> {
|
||||
const user = await this.userService.findByEmail(email);
|
||||
if (!user) {
|
||||
throw new UnauthorizedException('Invalid credentials');
|
||||
}
|
||||
|
||||
const valid = await bcrypt.compare(password, user.passwordHash);
|
||||
if (!valid) {
|
||||
throw new UnauthorizedException('Invalid credentials');
|
||||
}
|
||||
|
||||
return this.generateTokens(user.id, user.email, user.homeId);
|
||||
}
|
||||
|
||||
async registerDevice(homeId: string, deviceName: string): Promise<DeviceTokenResult> {
|
||||
const rawToken = crypto.randomBytes(32).toString('hex');
|
||||
const tokenHash = await bcrypt.hash(rawToken, 10);
|
||||
|
||||
const device = await this.deviceService.create({
|
||||
name: deviceName,
|
||||
homeId,
|
||||
tokenHash,
|
||||
});
|
||||
|
||||
const token = this.jwtService.sign(
|
||||
{ sub: device.id, email: '', homeId, type: 'device' },
|
||||
{ expiresIn: '365d' as const },
|
||||
);
|
||||
|
||||
return { deviceId: device.id, token };
|
||||
}
|
||||
|
||||
async refreshAccessToken(refreshToken: string): Promise<AuthTokens> {
|
||||
try {
|
||||
const payload = this.jwtService.verify<JwtPayload>(refreshToken);
|
||||
if (payload.type !== 'user') {
|
||||
throw new UnauthorizedException('Invalid refresh token');
|
||||
}
|
||||
return this.generateTokens(payload.sub, payload.email, payload.homeId);
|
||||
} catch {
|
||||
throw new UnauthorizedException('Invalid refresh token');
|
||||
}
|
||||
}
|
||||
|
||||
private generateTokens(userId: string, email: string, homeId: string): AuthTokens {
|
||||
const payload = { sub: userId, email, homeId, type: 'user' } as Record<string, unknown>;
|
||||
|
||||
const accessToken = this.jwtService.sign(payload, {
|
||||
expiresIn: '15m' as const,
|
||||
});
|
||||
|
||||
const refreshToken = this.jwtService.sign(payload, {
|
||||
expiresIn: '7d' as const,
|
||||
});
|
||||
|
||||
return { accessToken, refreshToken };
|
||||
}
|
||||
}
|
||||
40
apps/backend/src/core/services/device.service.ts
Normal file
40
apps/backend/src/core/services/device.service.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import { Device } from '../domain/entities/device.entity';
|
||||
|
||||
@Injectable()
|
||||
export class DeviceService {
|
||||
constructor(
|
||||
@InjectRepository(Device)
|
||||
private readonly deviceRepository: Repository<Device>,
|
||||
) {}
|
||||
|
||||
async findById(id: string): Promise<Device | null> {
|
||||
return this.deviceRepository.findOne({ where: { id } });
|
||||
}
|
||||
|
||||
async findByHomeId(homeId: string): Promise<Device[]> {
|
||||
return this.deviceRepository.find({ where: { homeId } });
|
||||
}
|
||||
|
||||
async create(data: { name: string; homeId: string; tokenHash: string }): Promise<Device> {
|
||||
const device = this.deviceRepository.create({
|
||||
name: data.name,
|
||||
homeId: data.homeId,
|
||||
deviceTokenHash: data.tokenHash,
|
||||
});
|
||||
return this.deviceRepository.save(device);
|
||||
}
|
||||
|
||||
async validateToken(deviceId: string, token: string): Promise<boolean> {
|
||||
const device = await this.findById(deviceId);
|
||||
if (!device) return false;
|
||||
return bcrypt.compare(token, device.deviceTokenHash);
|
||||
}
|
||||
|
||||
async updateLastSeen(id: string): Promise<void> {
|
||||
await this.deviceRepository.update(id, { lastSeenAt: new Date() });
|
||||
}
|
||||
}
|
||||
21
apps/backend/src/core/services/home.service.ts
Normal file
21
apps/backend/src/core/services/home.service.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Home } from '../domain/entities/home.entity';
|
||||
|
||||
@Injectable()
|
||||
export class HomeService {
|
||||
constructor(
|
||||
@InjectRepository(Home)
|
||||
private readonly homeRepository: Repository<Home>,
|
||||
) {}
|
||||
|
||||
async create(name: string): Promise<Home> {
|
||||
const home = this.homeRepository.create({ name });
|
||||
return this.homeRepository.save(home);
|
||||
}
|
||||
|
||||
async findById(id: string): Promise<Home | null> {
|
||||
return this.homeRepository.findOne({ where: { id } });
|
||||
}
|
||||
}
|
||||
25
apps/backend/src/core/services/user.service.ts
Normal file
25
apps/backend/src/core/services/user.service.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { User } from '../domain/entities/user.entity';
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
constructor(
|
||||
@InjectRepository(User)
|
||||
private readonly userRepository: Repository<User>,
|
||||
) {}
|
||||
|
||||
async findById(id: string): Promise<User | null> {
|
||||
return this.userRepository.findOne({ where: { id } });
|
||||
}
|
||||
|
||||
async findByEmail(email: string): Promise<User | null> {
|
||||
return this.userRepository.findOne({ where: { email } });
|
||||
}
|
||||
|
||||
async create(data: Partial<User>): Promise<User> {
|
||||
const user = this.userRepository.create(data);
|
||||
return this.userRepository.save(user);
|
||||
}
|
||||
}
|
||||
287
pnpm-lock.yaml
generated
287
pnpm-lock.yaml
generated
@ -19,12 +19,21 @@ importers:
|
||||
'@nestjs/core':
|
||||
specifier: ^11.1.17
|
||||
version: 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||
'@nestjs/jwt':
|
||||
specifier: ^11.0.2
|
||||
version: 11.0.2(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))
|
||||
'@nestjs/passport':
|
||||
specifier: ^11.0.5
|
||||
version: 11.0.5(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0)
|
||||
'@nestjs/platform-express':
|
||||
specifier: ^11.1.17
|
||||
version: 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)
|
||||
'@nestjs/typeorm':
|
||||
specifier: ^11.0.0
|
||||
version: 11.0.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.28(ioredis@5.10.1)(pg@8.20.0)(ts-node@10.9.2(@types/node@25.5.0)(typescript@5.8.3)))
|
||||
bcrypt:
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0
|
||||
class-transformer:
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1
|
||||
@ -37,6 +46,12 @@ importers:
|
||||
ioredis:
|
||||
specifier: ^5.10.1
|
||||
version: 5.10.1
|
||||
passport:
|
||||
specifier: ^0.7.0
|
||||
version: 0.7.0
|
||||
passport-jwt:
|
||||
specifier: ^4.0.1
|
||||
version: 4.0.1
|
||||
pg:
|
||||
specifier: ^8.20.0
|
||||
version: 8.20.0
|
||||
@ -59,12 +74,18 @@ importers:
|
||||
'@nestjs/testing':
|
||||
specifier: ^11.1.17
|
||||
version: 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(@nestjs/platform-express@11.1.17)
|
||||
'@types/bcrypt':
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0
|
||||
'@types/jest':
|
||||
specifier: ^30.0.0
|
||||
version: 30.0.0
|
||||
'@types/node':
|
||||
specifier: ^25.5.0
|
||||
version: 25.5.0
|
||||
'@types/passport-jwt':
|
||||
specifier: ^4.0.1
|
||||
version: 4.0.1
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: ^8.57.2
|
||||
version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@10.1.0)(typescript@5.8.3))(eslint@10.1.0)(typescript@5.8.3)
|
||||
@ -841,6 +862,17 @@ packages:
|
||||
'@nestjs/websockets':
|
||||
optional: true
|
||||
|
||||
'@nestjs/jwt@11.0.2':
|
||||
resolution: {integrity: sha512-rK8aE/3/Ma45gAWfCksAXUNbOoSOUudU0Kn3rT39htPF7wsYXtKfjALKeKKJbFrIWbLjsbqfXX5bIJNvgBugGA==}
|
||||
peerDependencies:
|
||||
'@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0
|
||||
|
||||
'@nestjs/passport@11.0.5':
|
||||
resolution: {integrity: sha512-ulQX6mbjlws92PIM15Naes4F4p2JoxGnIJuUsdXQPT+Oo2sqQmENEZXM7eYuimocfHnKlcfZOuyzbA33LwUlOQ==}
|
||||
peerDependencies:
|
||||
'@nestjs/common': ^10.0.0 || ^11.0.0
|
||||
passport: ^0.5.0 || ^0.6.0 || ^0.7.0
|
||||
|
||||
'@nestjs/platform-express@11.1.17':
|
||||
resolution: {integrity: sha512-mAf4eOsSBsTOn/VbrUO1gsjW6dVh91qqXPMXun4dN8SnNjf7PTQagM9o8d6ab8ZBpNe6UdZftdrZoDetU+n4Qg==}
|
||||
peerDependencies:
|
||||
@ -933,6 +965,15 @@ packages:
|
||||
'@types/babel__traverse@7.28.0':
|
||||
resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==}
|
||||
|
||||
'@types/bcrypt@6.0.0':
|
||||
resolution: {integrity: sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==}
|
||||
|
||||
'@types/body-parser@1.19.6':
|
||||
resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==}
|
||||
|
||||
'@types/connect@3.4.38':
|
||||
resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
|
||||
|
||||
'@types/eslint-scope@3.7.7':
|
||||
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
|
||||
|
||||
@ -945,6 +986,15 @@ packages:
|
||||
'@types/estree@1.0.8':
|
||||
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||
|
||||
'@types/express-serve-static-core@5.1.1':
|
||||
resolution: {integrity: sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==}
|
||||
|
||||
'@types/express@5.0.6':
|
||||
resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==}
|
||||
|
||||
'@types/http-errors@2.0.5':
|
||||
resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==}
|
||||
|
||||
'@types/istanbul-lib-coverage@2.0.6':
|
||||
resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
|
||||
|
||||
@ -960,9 +1010,36 @@ packages:
|
||||
'@types/json-schema@7.0.15':
|
||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||
|
||||
'@types/jsonwebtoken@9.0.10':
|
||||
resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==}
|
||||
|
||||
'@types/ms@2.1.0':
|
||||
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
|
||||
|
||||
'@types/node@25.5.0':
|
||||
resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==}
|
||||
|
||||
'@types/passport-jwt@4.0.1':
|
||||
resolution: {integrity: sha512-Y0Ykz6nWP4jpxgEUYq8NoVZeCQPo1ZndJLfapI249g1jHChvRfZRO/LS3tqu26YgAS/laI1qx98sYGz0IalRXQ==}
|
||||
|
||||
'@types/passport-strategy@0.2.38':
|
||||
resolution: {integrity: sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==}
|
||||
|
||||
'@types/passport@1.0.17':
|
||||
resolution: {integrity: sha512-aciLyx+wDwT2t2/kJGJR2AEeBz0nJU4WuRX04Wu9Dqc5lSUtwu0WERPHYsLhF9PtseiAMPBGNUOtFjxZ56prsg==}
|
||||
|
||||
'@types/qs@6.15.0':
|
||||
resolution: {integrity: sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==}
|
||||
|
||||
'@types/range-parser@1.2.7':
|
||||
resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
|
||||
|
||||
'@types/send@1.2.1':
|
||||
resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==}
|
||||
|
||||
'@types/serve-static@2.2.0':
|
||||
resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==}
|
||||
|
||||
'@types/stack-utils@2.0.3':
|
||||
resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
|
||||
|
||||
@ -1349,6 +1426,10 @@ packages:
|
||||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
|
||||
bcrypt@6.0.0:
|
||||
resolution: {integrity: sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
bl@4.1.0:
|
||||
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
|
||||
|
||||
@ -1378,6 +1459,9 @@ packages:
|
||||
bser@2.1.1:
|
||||
resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
|
||||
|
||||
buffer-equal-constant-time@1.0.1:
|
||||
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
|
||||
|
||||
buffer-from@1.1.2:
|
||||
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
||||
|
||||
@ -1633,6 +1717,9 @@ packages:
|
||||
eastasianwidth@0.2.0:
|
||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||
|
||||
ecdsa-sig-formatter@1.0.11:
|
||||
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
|
||||
|
||||
ee-first@1.1.1:
|
||||
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
||||
|
||||
@ -2273,6 +2360,16 @@ packages:
|
||||
jsonfile@6.2.0:
|
||||
resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==}
|
||||
|
||||
jsonwebtoken@9.0.3:
|
||||
resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==}
|
||||
engines: {node: '>=12', npm: '>=6'}
|
||||
|
||||
jwa@2.0.1:
|
||||
resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==}
|
||||
|
||||
jws@4.0.1:
|
||||
resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==}
|
||||
|
||||
keyv@4.5.4:
|
||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||
|
||||
@ -2309,12 +2406,33 @@ packages:
|
||||
lodash.defaults@4.2.0:
|
||||
resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
|
||||
|
||||
lodash.includes@4.3.0:
|
||||
resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==}
|
||||
|
||||
lodash.isarguments@3.1.0:
|
||||
resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
|
||||
|
||||
lodash.isboolean@3.0.3:
|
||||
resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
|
||||
|
||||
lodash.isinteger@4.0.4:
|
||||
resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==}
|
||||
|
||||
lodash.isnumber@3.0.3:
|
||||
resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==}
|
||||
|
||||
lodash.isplainobject@4.0.6:
|
||||
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
|
||||
|
||||
lodash.isstring@4.0.1:
|
||||
resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==}
|
||||
|
||||
lodash.memoize@4.1.2:
|
||||
resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
|
||||
|
||||
lodash.once@4.1.1:
|
||||
resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
|
||||
|
||||
lodash@4.17.23:
|
||||
resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==}
|
||||
|
||||
@ -2435,9 +2553,17 @@ packages:
|
||||
node-abort-controller@3.1.1:
|
||||
resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==}
|
||||
|
||||
node-addon-api@8.7.0:
|
||||
resolution: {integrity: sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==}
|
||||
engines: {node: ^18 || ^20 || >= 21}
|
||||
|
||||
node-emoji@1.11.0:
|
||||
resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==}
|
||||
|
||||
node-gyp-build@4.8.4:
|
||||
resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==}
|
||||
hasBin: true
|
||||
|
||||
node-int64@0.4.0:
|
||||
resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
|
||||
|
||||
@ -2514,6 +2640,17 @@ packages:
|
||||
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
passport-jwt@4.0.1:
|
||||
resolution: {integrity: sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==}
|
||||
|
||||
passport-strategy@1.0.0:
|
||||
resolution: {integrity: sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
|
||||
passport@0.7.0:
|
||||
resolution: {integrity: sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
|
||||
path-exists@4.0.0:
|
||||
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||
engines: {node: '>=8'}
|
||||
@ -2541,6 +2678,9 @@ packages:
|
||||
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
pause@0.0.1:
|
||||
resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==}
|
||||
|
||||
pg-cloudflare@1.3.0:
|
||||
resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==}
|
||||
|
||||
@ -3144,6 +3284,10 @@ packages:
|
||||
util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
|
||||
utils-merge@1.0.1:
|
||||
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
|
||||
uuid@11.1.0:
|
||||
resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==}
|
||||
hasBin: true
|
||||
@ -4085,6 +4229,17 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@nestjs/platform-express': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)
|
||||
|
||||
'@nestjs/jwt@11.0.2(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))':
|
||||
dependencies:
|
||||
'@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||
'@types/jsonwebtoken': 9.0.10
|
||||
jsonwebtoken: 9.0.3
|
||||
|
||||
'@nestjs/passport@11.0.5(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0)':
|
||||
dependencies:
|
||||
'@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||
passport: 0.7.0
|
||||
|
||||
'@nestjs/platform-express@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)':
|
||||
dependencies:
|
||||
'@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||
@ -4199,6 +4354,19 @@ snapshots:
|
||||
dependencies:
|
||||
'@babel/types': 7.29.0
|
||||
|
||||
'@types/bcrypt@6.0.0':
|
||||
dependencies:
|
||||
'@types/node': 25.5.0
|
||||
|
||||
'@types/body-parser@1.19.6':
|
||||
dependencies:
|
||||
'@types/connect': 3.4.38
|
||||
'@types/node': 25.5.0
|
||||
|
||||
'@types/connect@3.4.38':
|
||||
dependencies:
|
||||
'@types/node': 25.5.0
|
||||
|
||||
'@types/eslint-scope@3.7.7':
|
||||
dependencies:
|
||||
'@types/eslint': 9.6.1
|
||||
@ -4213,6 +4381,21 @@ snapshots:
|
||||
|
||||
'@types/estree@1.0.8': {}
|
||||
|
||||
'@types/express-serve-static-core@5.1.1':
|
||||
dependencies:
|
||||
'@types/node': 25.5.0
|
||||
'@types/qs': 6.15.0
|
||||
'@types/range-parser': 1.2.7
|
||||
'@types/send': 1.2.1
|
||||
|
||||
'@types/express@5.0.6':
|
||||
dependencies:
|
||||
'@types/body-parser': 1.19.6
|
||||
'@types/express-serve-static-core': 5.1.1
|
||||
'@types/serve-static': 2.2.0
|
||||
|
||||
'@types/http-errors@2.0.5': {}
|
||||
|
||||
'@types/istanbul-lib-coverage@2.0.6': {}
|
||||
|
||||
'@types/istanbul-lib-report@3.0.3':
|
||||
@ -4230,10 +4413,44 @@ snapshots:
|
||||
|
||||
'@types/json-schema@7.0.15': {}
|
||||
|
||||
'@types/jsonwebtoken@9.0.10':
|
||||
dependencies:
|
||||
'@types/ms': 2.1.0
|
||||
'@types/node': 25.5.0
|
||||
|
||||
'@types/ms@2.1.0': {}
|
||||
|
||||
'@types/node@25.5.0':
|
||||
dependencies:
|
||||
undici-types: 7.18.2
|
||||
|
||||
'@types/passport-jwt@4.0.1':
|
||||
dependencies:
|
||||
'@types/jsonwebtoken': 9.0.10
|
||||
'@types/passport-strategy': 0.2.38
|
||||
|
||||
'@types/passport-strategy@0.2.38':
|
||||
dependencies:
|
||||
'@types/express': 5.0.6
|
||||
'@types/passport': 1.0.17
|
||||
|
||||
'@types/passport@1.0.17':
|
||||
dependencies:
|
||||
'@types/express': 5.0.6
|
||||
|
||||
'@types/qs@6.15.0': {}
|
||||
|
||||
'@types/range-parser@1.2.7': {}
|
||||
|
||||
'@types/send@1.2.1':
|
||||
dependencies:
|
||||
'@types/node': 25.5.0
|
||||
|
||||
'@types/serve-static@2.2.0':
|
||||
dependencies:
|
||||
'@types/http-errors': 2.0.5
|
||||
'@types/node': 25.5.0
|
||||
|
||||
'@types/stack-utils@2.0.3': {}
|
||||
|
||||
'@types/validator@13.15.10': {}
|
||||
@ -4636,6 +4853,11 @@ snapshots:
|
||||
|
||||
baseline-browser-mapping@2.10.11: {}
|
||||
|
||||
bcrypt@6.0.0:
|
||||
dependencies:
|
||||
node-addon-api: 8.7.0
|
||||
node-gyp-build: 4.8.4
|
||||
|
||||
bl@4.1.0:
|
||||
dependencies:
|
||||
buffer: 5.7.1
|
||||
@ -4685,6 +4907,8 @@ snapshots:
|
||||
dependencies:
|
||||
node-int64: 0.4.0
|
||||
|
||||
buffer-equal-constant-time@1.0.1: {}
|
||||
|
||||
buffer-from@1.1.2: {}
|
||||
|
||||
buffer@5.7.1:
|
||||
@ -4892,6 +5116,10 @@ snapshots:
|
||||
|
||||
eastasianwidth@0.2.0: {}
|
||||
|
||||
ecdsa-sig-formatter@1.0.11:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
ee-first@1.1.1: {}
|
||||
|
||||
electron-to-chromium@1.5.328: {}
|
||||
@ -5778,6 +6006,30 @@ snapshots:
|
||||
optionalDependencies:
|
||||
graceful-fs: 4.2.11
|
||||
|
||||
jsonwebtoken@9.0.3:
|
||||
dependencies:
|
||||
jws: 4.0.1
|
||||
lodash.includes: 4.3.0
|
||||
lodash.isboolean: 3.0.3
|
||||
lodash.isinteger: 4.0.4
|
||||
lodash.isnumber: 3.0.3
|
||||
lodash.isplainobject: 4.0.6
|
||||
lodash.isstring: 4.0.1
|
||||
lodash.once: 4.1.1
|
||||
ms: 2.1.3
|
||||
semver: 7.7.4
|
||||
|
||||
jwa@2.0.1:
|
||||
dependencies:
|
||||
buffer-equal-constant-time: 1.0.1
|
||||
ecdsa-sig-formatter: 1.0.11
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
jws@4.0.1:
|
||||
dependencies:
|
||||
jwa: 2.0.1
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
keyv@4.5.4:
|
||||
dependencies:
|
||||
json-buffer: 3.0.1
|
||||
@ -5807,10 +6059,24 @@ snapshots:
|
||||
|
||||
lodash.defaults@4.2.0: {}
|
||||
|
||||
lodash.includes@4.3.0: {}
|
||||
|
||||
lodash.isarguments@3.1.0: {}
|
||||
|
||||
lodash.isboolean@3.0.3: {}
|
||||
|
||||
lodash.isinteger@4.0.4: {}
|
||||
|
||||
lodash.isnumber@3.0.3: {}
|
||||
|
||||
lodash.isplainobject@4.0.6: {}
|
||||
|
||||
lodash.isstring@4.0.1: {}
|
||||
|
||||
lodash.memoize@4.1.2: {}
|
||||
|
||||
lodash.once@4.1.1: {}
|
||||
|
||||
lodash@4.17.23: {}
|
||||
|
||||
log-symbols@4.1.0:
|
||||
@ -5905,10 +6171,14 @@ snapshots:
|
||||
|
||||
node-abort-controller@3.1.1: {}
|
||||
|
||||
node-addon-api@8.7.0: {}
|
||||
|
||||
node-emoji@1.11.0:
|
||||
dependencies:
|
||||
lodash: 4.17.23
|
||||
|
||||
node-gyp-build@4.8.4: {}
|
||||
|
||||
node-int64@0.4.0: {}
|
||||
|
||||
node-releases@2.0.36: {}
|
||||
@ -5989,6 +6259,19 @@ snapshots:
|
||||
|
||||
parseurl@1.3.3: {}
|
||||
|
||||
passport-jwt@4.0.1:
|
||||
dependencies:
|
||||
jsonwebtoken: 9.0.3
|
||||
passport-strategy: 1.0.0
|
||||
|
||||
passport-strategy@1.0.0: {}
|
||||
|
||||
passport@0.7.0:
|
||||
dependencies:
|
||||
passport-strategy: 1.0.0
|
||||
pause: 0.0.1
|
||||
utils-merge: 1.0.1
|
||||
|
||||
path-exists@4.0.0: {}
|
||||
|
||||
path-is-absolute@1.0.1: {}
|
||||
@ -6009,6 +6292,8 @@ snapshots:
|
||||
|
||||
path-type@4.0.0: {}
|
||||
|
||||
pause@0.0.1: {}
|
||||
|
||||
pg-cloudflare@1.3.0:
|
||||
optional: true
|
||||
|
||||
@ -6568,6 +6853,8 @@ snapshots:
|
||||
|
||||
util-deprecate@1.0.2: {}
|
||||
|
||||
utils-merge@1.0.1: {}
|
||||
|
||||
uuid@11.1.0: {}
|
||||
|
||||
v8-compile-cache-lib@3.0.1: {}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user