refactor module & reset token

This commit is contained in:
Paul Coral
2025-08-10 22:41:34 +02:00
parent ba90bf221b
commit 4b8348e32f
39 changed files with 386 additions and 67 deletions

View File

@@ -25,7 +25,9 @@
"@my-monorepo/common": "workspace:*", "@my-monorepo/common": "workspace:*",
"@nestjs/common": "^11.0.1", "@nestjs/common": "^11.0.1",
"@nestjs/core": "^11.0.1", "@nestjs/core": "^11.0.1",
"@nestjs/passport": "^11.0.5",
"@nestjs/platform-express": "^11.0.1", "@nestjs/platform-express": "^11.0.1",
"@types/passport-local": "^1.0.38",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"dotenv": "^17.2.1", "dotenv": "^17.2.1",
"ejs": "^3.1.10", "ejs": "^3.1.10",
@@ -33,6 +35,8 @@
"i18next-fs-backend": "^2.6.0", "i18next-fs-backend": "^2.6.0",
"kysely": "^0.28.3", "kysely": "^0.28.3",
"nodemailer": "^7.0.5", "nodemailer": "^7.0.5",
"passport": "^0.7.0",
"passport-local": "^1.0.0",
"pg": "^8.16.3", "pg": "^8.16.3",
"reflect-metadata": "^0.2.2", "reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1", "rxjs": "^7.8.1",

View File

@@ -1,27 +1,9 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { AuthController } from './app/auth/auth.controller'; import { AuthModule } from './app/auth/auth.module';
import { DatabaseService } from './services/database/database.service'; import { UsersModule } from './app/users/users.module';
import { AuthService } from './app/auth/auth.service'; import { CoreModule } from './services/core/core.module';
import { UsersService } from './app/users/users.service';
import { EnvService } from './services/env/env.service';
import { UsersRegistry } from './app/users/users-registry';
import { UsersController } from './app/users/users.controller';
import { MailerService } from './services/mailer/mailer.service';
import { LOCALIZATION_SERVICE_PROVIDER } from './services/localization/localization.service';
import { TemplateRendererService } from './services/template-renderer/template-renderer.service';
@Module({ @Module({
imports: [], imports: [CoreModule, AuthModule, UsersModule],
controllers: [AuthController, UsersController],
providers: [
DatabaseService,
AuthService,
UsersService,
EnvService,
UsersRegistry,
MailerService,
LOCALIZATION_SERVICE_PROVIDER,
TemplateRendererService,
],
}) })
export class AppModule {} export class AppModule {}

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AuthControllerService } from './auth-controller.service';
describe('AuthControllerService', () => {
let service: AuthControllerService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [AuthControllerService],
}).compile();
service = module.get<AuthControllerService>(AuthControllerService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@@ -0,0 +1,14 @@
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { UsersCoreService } from '../users/users-core.service';
@Injectable()
export class AuthControllerService {
constructor(private userCoreService: UsersCoreService) {}
async verifyCredentials() {
const isValidCredential = await this.userCoreService.existsEmailPassword();
if (!isValidCredential) {
throw new UnauthorizedException('invalid credentials');
}
}
}

View File

@@ -1,15 +1,15 @@
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
import { UsersService } from './users.service'; import { AuthCoreService } from './auth-core.service';
describe('UsersService', () => { describe('AuthCoreService', () => {
let service: UsersService; let service: AuthCoreService;
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ const module: TestingModule = await Test.createTestingModule({
providers: [UsersService], providers: [AuthCoreService],
}).compile(); }).compile();
service = module.get<UsersService>(UsersService); service = module.get<AuthCoreService>(AuthCoreService);
}); });
it('should be defined', () => { it('should be defined', () => {

View File

@@ -0,0 +1,19 @@
import { Injectable } from '@nestjs/common';
import { AuthRegistry } from './auth-registry';
import { generateSecureToken } from '../../lib/crypto';
import * as dayjs from 'dayjs';
const RESET_TOKEN_VALIDITY_MINUTES = 15;
@Injectable()
export class AuthCoreService {
constructor(private authRegistry: AuthRegistry) {}
async addNewResetToken(userId: string): Promise<void> {
return this.authRegistry.addResetToken({
token: generateSecureToken(),
userId,
validUntil: dayjs().add(RESET_TOKEN_VALIDITY_MINUTES, 'minutes'),
});
}
}

View File

@@ -1,15 +1,15 @@
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
import { AuthService } from './auth.service'; import { AuthRegistry } from './auth-registry';
describe('AuthService', () => { describe('AuthRegistry', () => {
let service: AuthService; let service: AuthRegistry;
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ const module: TestingModule = await Test.createTestingModule({
providers: [AuthService], providers: [AuthRegistry],
}).compile(); }).compile();
service = module.get<AuthService>(AuthService); service = module.get<AuthRegistry>(AuthRegistry);
}); });
it('should be defined', () => { it('should be defined', () => {

View File

@@ -0,0 +1,29 @@
import { Injectable } from '@nestjs/common';
import { DatabaseService } from '../../services/core/database/database.service';
import * as dayjs from 'dayjs';
export interface CreateResetToken {
userId: string;
token: string;
validUntil: dayjs.Dayjs;
}
@Injectable()
export class AuthRegistry {
get database() {
return this.databaseService.database;
}
constructor(private databaseService: DatabaseService) {}
async addResetToken(resetAuth: CreateResetToken): Promise<void> {
return this.database
.insertInto('reset_tokens')
.values({
user_id: resetAuth.userId,
token: resetAuth.token,
valid_until: resetAuth.validUntil.toDate(),
})
.execute()
.then(() => {});
}
}

View File

@@ -1,12 +1,26 @@
import { Controller, Post } from '@nestjs/common'; import {
import { AuthService } from './auth.service'; Body,
Controller,
NotImplementedException,
Post,
} from '@nestjs/common';
import { AuthControllerService } from './auth-controller.service';
import { ZodValidationPipe } from '../../lib/nestjs/zod-validation/zod-validation.pipe';
import { ResetAuth, resetAuthParser } from '@my-monorepo/common';
@Controller('auth') @Controller('auth')
export class AuthController { export class AuthController {
constructor(private authService: AuthService) {} constructor(private authService: AuthControllerService) {}
@Post('credentials') @Post('credentials')
async postCredentials() { async postCredentials() {
return this.authService.verifyCredentials(); return this.authService.verifyCredentials();
} }
@Post('reset')
async postReset(
@Body(new ZodValidationPipe(resetAuthParser)) resetData: ResetAuth,
): Promise<void> {
throw new NotImplementedException();
}
} }

View File

@@ -0,0 +1,14 @@
import { Module } from '@nestjs/common';
import { AuthController } from './auth.controller';
import { AuthRegistry } from './auth-registry';
import { AuthControllerService } from './auth-controller.service';
import { AuthCoreService } from './auth-core.service';
import { UsersModule } from '../users/users.module';
@Module({
controllers: [AuthController],
providers: [AuthRegistry, AuthControllerService, AuthCoreService],
imports: [UsersModule],
exports: [AuthCoreService, AuthRegistry],
})
export class AuthModule {}

View File

@@ -1,17 +0,0 @@
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { UsersRegistry } from '../users/users-registry';
@Injectable()
export class AuthService {
constructor(private userRegistry: UsersRegistry) {}
async verifyCredentials() {
const isValidCredential = await this.userRegistry.existsEmailPassword(
'',
'',
);
if (!isValidCredential) {
throw new UnauthorizedException('invalid credentials');
}
}
}

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { UsersControllerService } from './users-controller.service';
describe('UsersControllerService', () => {
let service: UsersControllerService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [UsersControllerService],
}).compile();
service = module.get<UsersControllerService>(UsersControllerService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@@ -1,27 +1,33 @@
import { CreateUser } from '@my-monorepo/common'; import { CreateUser } from '@my-monorepo/common';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { MailerService } from '../../services/mailer/mailer.service';
import { UsersRegistry } from './users-registry';
import { import {
LOCALIZATION_SERVICE, LOCALIZATION_SERVICE,
LocalizationService, LocalizationService,
} from '../../services/localization/localization.service'; } from '../../services/core/localization/localization.service';
import { TemplateRendererService } from '../../services/template-renderer/template-renderer.service'; import { MailerService } from '../../services/core/mailer/mailer.service';
import { MailTemplateEnum } from '../../services/template-renderer/mail-template-data'; import { MailTemplateEnum } from '../../services/core/template-renderer/mail-template-data';
import { TemplateRendererService } from '../../services/core/template-renderer/template-renderer.service';
import { AuthCoreService } from '../auth/auth-core.service';
import { UsersCoreService } from './users-core.service';
@Injectable() @Injectable()
export class UsersService { export class UsersControllerService {
constructor( constructor(
private userRegistry: UsersRegistry, private userCoreService: UsersCoreService,
private mailerService: MailerService, private mailerService: MailerService,
@Inject(LOCALIZATION_SERVICE) @Inject(LOCALIZATION_SERVICE)
private localizationService: LocalizationService, private localizationService: LocalizationService,
private templateRendererService: TemplateRendererService, private templateRendererService: TemplateRendererService,
private authCoreService: AuthCoreService,
) {} ) {}
async createUser(newUser: CreateUser): Promise<void> { async createUser(newUser: CreateUser): Promise<void> {
// FIXME : return result once auth is done // FIXME : return result once auth is done
await this.userRegistry.addUser(newUser); const createUserResult = await this.userCoreService.addUser(newUser);
if (createUserResult.ok) {
const createdUser = createUserResult.data;
await this.authCoreService.addNewResetToken(createdUser.id);
}
const mailTitle = this.localizationService.translate( const mailTitle = this.localizationService.translate(
'mail.create-user.title', 'mail.create-user.title',

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { UsersCoreService } from './users-core.service';
describe('UsersCoreService', () => {
let service: UsersCoreService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [UsersCoreService],
}).compile();
service = module.get<UsersCoreService>(UsersCoreService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@@ -0,0 +1,19 @@
import { Injectable } from '@nestjs/common';
import { UsersRegistry } from './users-registry';
import { CreateUser, Result, User } from '@my-monorepo/common';
import { UserEmailAlreadyExistError } from './users-error';
@Injectable()
export class UsersCoreService {
constructor(private userRegistry: UsersRegistry) {}
async existsEmailPassword() {
return await this.userRegistry.existsEmailPassword('', '');
}
async addUser(
newUser: CreateUser,
): Promise<Result<User, UserEmailAlreadyExistError>> {
return await this.userRegistry.addUser(newUser);
}
}

View File

@@ -1,5 +1,5 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { DatabaseService } from '../../services/database/database.service'; import { DatabaseService } from '../../services/core/database/database.service';
import { CreateUser, isDefined, Result, User } from '@my-monorepo/common'; import { CreateUser, isDefined, Result, User } from '@my-monorepo/common';
import { UserEmailAlreadyExistError } from './users-error'; import { UserEmailAlreadyExistError } from './users-error';

View File

@@ -1,15 +1,16 @@
import { CreateUser, createUserParser } from '@my-monorepo/common'; import { CreateUser, createUserParser } from '@my-monorepo/common';
import { Body, Controller, Post, UsePipes } from '@nestjs/common'; import { Body, Controller, Post } from '@nestjs/common';
import { ZodValidationPipe } from '../../lib/nestjs/zod-validation/zod-validation.pipe'; import { ZodValidationPipe } from '../../lib/nestjs/zod-validation/zod-validation.pipe';
import { UsersService } from './users.service'; import { UsersControllerService } from './users-controller.service';
@Controller('users') @Controller('users')
export class UsersController { export class UsersController {
constructor(private userService: UsersService) {} constructor(private userService: UsersControllerService) {}
@Post() @Post()
@UsePipes(new ZodValidationPipe(createUserParser)) async createUser(
async createUser(@Body() newUser: CreateUser) { @Body(new ZodValidationPipe(createUserParser)) newUser: CreateUser,
) {
return this.userService.createUser(newUser); return this.userService.createUser(newUser);
} }
} }

View File

@@ -0,0 +1,14 @@
import { forwardRef, Module } from '@nestjs/common';
import { UsersRegistry } from './users-registry';
import { UsersController } from './users.controller';
import { UsersControllerService } from './users-controller.service';
import { UsersCoreService } from './users-core.service';
import { AuthModule } from '../auth/auth.module';
@Module({
providers: [UsersRegistry, UsersControllerService, UsersCoreService],
controllers: [UsersController],
imports: [forwardRef(() => AuthModule)],
exports: [UsersCoreService, UsersRegistry],
})
export class UsersModule {}

View File

@@ -13,6 +13,16 @@ export type Int8 = ColumnType<string, bigint | number | string, bigint | number
export type Timestamp = ColumnType<Date, Date | string, Date | string>; export type Timestamp = ColumnType<Date, Date | string, Date | string>;
export interface ResetTokens {
created_at: Generated<Timestamp>;
deleted_at: Timestamp | null;
id: Generated<Int8>;
token: string;
updated_at: Generated<Timestamp>;
user_id: Generated<Int8>;
valid_until: Timestamp;
}
export interface Users { export interface Users {
created_at: Generated<Timestamp>; created_at: Generated<Timestamp>;
deleted_at: Timestamp | null; deleted_at: Timestamp | null;
@@ -25,5 +35,6 @@ export interface Users {
} }
export interface DB { export interface DB {
reset_tokens: ResetTokens;
users: Users; users: Users;
} }

View File

@@ -0,0 +1,5 @@
import * as crypto from 'crypto';
export function generateSecureToken(length = 32) {
return crypto.randomBytes(length).toString('hex');
}

View File

@@ -0,0 +1,33 @@
import { Kysely, sql } from 'kysely';
export async function up(db: Kysely<unknown>): Promise<void> {
await db.schema
.createTable('reset_tokens')
.addColumn('id', 'bigserial', (col) => col.primaryKey())
.addColumn('user_id', 'bigserial', (col) => col.notNull())
.addForeignKeyConstraint(
'fk_user_id_reset_tokens_users',
['user_id'],
'users',
['id'],
(col) => col.onDelete('cascade'),
)
.addColumn('token', 'text', (col) => col.notNull())
.addUniqueConstraint('uniq_user_id_tokens_reset_tokens', [
'user_id',
'token',
])
.addColumn('valid_until', 'timestamptz', (col) => col.notNull())
.addColumn('created_at', 'timestamptz', (col) =>
col.notNull().defaultTo(sql`now()`),
)
.addColumn('updated_at', 'timestamptz', (col) =>
col.notNull().defaultTo(sql`now()`),
)
.addColumn('deleted_at', 'timestamptz')
.execute();
}
export async function down(db: Kysely<unknown>): Promise<void> {
await db.schema.dropTable('reset_tokens').execute();
}

View File

@@ -0,0 +1,23 @@
import { Global, Module } from '@nestjs/common';
import { DatabaseService } from './database/database.service';
import { EnvService } from './env/env.service';
import { LOCALIZATION_SERVICE_PROVIDER } from './localization/localization.service';
import { LoggerService } from './logger/logger.service';
import { MailerService } from './mailer/mailer.service';
import { TemplateRendererService } from './template-renderer/template-renderer.service';
const DECLARATIONS = [
DatabaseService,
EnvService,
LOCALIZATION_SERVICE_PROVIDER,
LoggerService,
MailerService,
TemplateRendererService,
];
@Global()
@Module({
providers: DECLARATIONS,
exports: DECLARATIONS,
})
export class CoreModule {}

View File

@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
import { Pool } from 'pg'; import { Pool } from 'pg';
import { Kysely, PostgresDialect } from 'kysely'; import { Kysely, PostgresDialect } from 'kysely';
import { DB } from '../../database/db'; import { DB } from '../../../database/db';
import { EnvService } from '../env/env.service'; import { EnvService } from '../env/env.service';
@Injectable() @Injectable()

View File

@@ -0,0 +1,2 @@
export * from "./credential-auth";
export * from "./reset-auth";

View File

@@ -0,0 +1,9 @@
import z from "zod";
export const resetAuthParser = z.object({
userId: z.string(),
resetToken: z.string(),
newPassword: z.string(),
});
export type ResetAuth = z.infer<typeof resetAuthParser>;

View File

@@ -1,2 +1,3 @@
export * from "./users"; export * from "./users";
export * from "./lang"; export * from "./lang";
export * from "./auth";

82
pnpm-lock.yaml generated
View File

@@ -19,9 +19,15 @@ importers:
'@nestjs/core': '@nestjs/core':
specifier: ^11.0.1 specifier: ^11.0.1
version: 11.1.3(@nestjs/common@11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.3)(reflect-metadata@0.2.2)(rxjs@7.8.2) version: 11.1.3(@nestjs/common@11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/passport':
specifier: ^11.0.5
version: 11.0.5(@nestjs/common@11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0)
'@nestjs/platform-express': '@nestjs/platform-express':
specifier: ^11.0.1 specifier: ^11.0.1
version: 11.1.3(@nestjs/common@11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.3) version: 11.1.3(@nestjs/common@11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.3)
'@types/passport-local':
specifier: ^1.0.38
version: 1.0.38
dayjs: dayjs:
specifier: ^1.11.13 specifier: ^1.11.13
version: 1.11.13 version: 1.11.13
@@ -43,6 +49,12 @@ importers:
nodemailer: nodemailer:
specifier: ^7.0.5 specifier: ^7.0.5
version: 7.0.5 version: 7.0.5
passport:
specifier: ^0.7.0
version: 0.7.0
passport-local:
specifier: ^1.0.0
version: 1.0.0
pg: pg:
specifier: ^8.16.3 specifier: ^8.16.3
version: 8.16.3 version: 8.16.3
@@ -813,6 +825,12 @@ packages:
'@nestjs/websockets': '@nestjs/websockets':
optional: true optional: true
'@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.3': '@nestjs/platform-express@11.1.3':
resolution: {integrity: sha512-hEDNMlaPiBO72fxxX/CuRQL3MEhKRc/sIYGVoXjrnw6hTxZdezvvM6A95UaLsYknfmcZZa/CdG1SMBZOu9agHQ==} resolution: {integrity: sha512-hEDNMlaPiBO72fxxX/CuRQL3MEhKRc/sIYGVoXjrnw6hTxZdezvvM6A95UaLsYknfmcZZa/CdG1SMBZOu9agHQ==}
peerDependencies: peerDependencies:
@@ -1065,6 +1083,15 @@ packages:
'@types/nodemailer@6.4.17': '@types/nodemailer@6.4.17':
resolution: {integrity: sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww==} resolution: {integrity: sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww==}
'@types/passport-local@1.0.38':
resolution: {integrity: sha512-nsrW4A963lYE7lNTv9cr5WmiUD1ibYJvWrpE13oxApFsRt77b0RdtZvKbCdNIY4v/QZ6TRQWaDDEwV1kCTmcXg==}
'@types/passport-strategy@0.2.38':
resolution: {integrity: sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==}
'@types/passport@1.0.17':
resolution: {integrity: sha512-aciLyx+wDwT2t2/kJGJR2AEeBz0nJU4WuRX04Wu9Dqc5lSUtwu0WERPHYsLhF9PtseiAMPBGNUOtFjxZ56prsg==}
'@types/pg@8.15.4': '@types/pg@8.15.4':
resolution: {integrity: sha512-I6UNVBAoYbvuWkkU3oosC8yxqH21f4/Jc4DK71JLG3dT2mdlGe1z+ep/LQGXaKaOgcvUrsQoPRqfgtMcvZiJhg==} resolution: {integrity: sha512-I6UNVBAoYbvuWkkU3oosC8yxqH21f4/Jc4DK71JLG3dT2mdlGe1z+ep/LQGXaKaOgcvUrsQoPRqfgtMcvZiJhg==}
@@ -2841,6 +2868,18 @@ packages:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
passport-local@1.0.0:
resolution: {integrity: sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==}
engines: {node: '>= 0.4.0'}
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: path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -2868,6 +2907,9 @@ packages:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'} engines: {node: '>=8'}
pause@0.0.1:
resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==}
peek-readable@5.4.2: peek-readable@5.4.2:
resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==} resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==}
engines: {node: '>=14.16'} engines: {node: '>=14.16'}
@@ -3519,6 +3561,10 @@ packages:
util-deprecate@1.0.2: util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
utils-merge@1.0.1:
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
engines: {node: '>= 0.4.0'}
v8-compile-cache-lib@3.0.1: v8-compile-cache-lib@3.0.1:
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
@@ -4535,6 +4581,11 @@ snapshots:
optionalDependencies: optionalDependencies:
'@nestjs/platform-express': 11.1.3(@nestjs/common@11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.3) '@nestjs/platform-express': 11.1.3(@nestjs/common@11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.3)
'@nestjs/passport@11.0.5(@nestjs/common@11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0)':
dependencies:
'@nestjs/common': 11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2)
passport: 0.7.0
'@nestjs/platform-express@11.1.3(@nestjs/common@11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.3)': '@nestjs/platform-express@11.1.3(@nestjs/common@11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.3)':
dependencies: dependencies:
'@nestjs/common': 11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/common': 11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2)
@@ -4800,6 +4851,21 @@ snapshots:
dependencies: dependencies:
'@types/node': 22.16.3 '@types/node': 22.16.3
'@types/passport-local@1.0.38':
dependencies:
'@types/express': 5.0.3
'@types/passport': 1.0.17
'@types/passport-strategy': 0.2.38
'@types/passport-strategy@0.2.38':
dependencies:
'@types/express': 5.0.3
'@types/passport': 1.0.17
'@types/passport@1.0.17':
dependencies:
'@types/express': 5.0.3
'@types/pg@8.15.4': '@types/pg@8.15.4':
dependencies: dependencies:
'@types/node': 22.16.3 '@types/node': 22.16.3
@@ -6854,6 +6920,18 @@ snapshots:
parseurl@1.3.3: {} parseurl@1.3.3: {}
passport-local@1.0.0:
dependencies:
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-exists@4.0.0: {}
path-is-absolute@1.0.1: {} path-is-absolute@1.0.1: {}
@@ -6871,6 +6949,8 @@ snapshots:
path-type@4.0.0: {} path-type@4.0.0: {}
pause@0.0.1: {}
peek-readable@5.4.2: {} peek-readable@5.4.2: {}
pend@1.2.0: {} pend@1.2.0: {}
@@ -7501,6 +7581,8 @@ snapshots:
util-deprecate@1.0.2: {} util-deprecate@1.0.2: {}
utils-merge@1.0.1: {}
v8-compile-cache-lib@3.0.1: {} v8-compile-cache-lib@3.0.1: {}
v8-to-istanbul@9.3.0: v8-to-istanbul@9.3.0: