refactor to adapters

This commit is contained in:
2025-12-15 18:34:20 +01:00
parent fc671482c8
commit c817d76092
145 changed files with 906 additions and 361 deletions

View File

@@ -1,11 +1,14 @@
import type { EmailValidationResult } from '../types/EmailAddress';
import { validateEmail } from '../types/EmailAddress';
import { UserId } from '../value-objects/UserId';
import { PasswordHash } from '../value-objects/PasswordHash';
import { StoredUser } from '../repositories/IUserRepository';
export interface UserProps {
id: UserId;
displayName: string;
email?: string;
passwordHash?: PasswordHash;
iracingCustomerId?: string;
primaryDriverId?: string;
avatarUrl?: string;
@@ -15,6 +18,7 @@ export class User {
private readonly id: UserId;
private displayName: string;
private email: string | undefined;
private passwordHash: PasswordHash | undefined;
private iracingCustomerId: string | undefined;
private primaryDriverId: string | undefined;
private avatarUrl: string | undefined;
@@ -47,6 +51,22 @@ export class User {
return new User(props);
}
public static fromStored(stored: StoredUser): User {
const passwordHash = stored.passwordHash ? PasswordHash.fromHash(stored.passwordHash) : undefined;
const userProps: any = {
id: UserId.fromString(stored.id),
displayName: stored.displayName,
email: stored.email,
};
if (passwordHash) {
userProps.passwordHash = passwordHash;
}
if (stored.primaryDriverId) {
userProps.primaryDriverId = stored.primaryDriverId;
}
return new User(userProps);
}
public getId(): UserId {
return this.id;
}
@@ -59,6 +79,10 @@ export class User {
return this.email;
}
public getPasswordHash(): PasswordHash | undefined {
return this.passwordHash;
}
public getIracingCustomerId(): string | undefined {
return this.iracingCustomerId;
}

View File

@@ -0,0 +1,19 @@
import { EmailAddress } from '../value-objects/EmailAddress';
import { User } from '../entities/User';
/**
* Domain Repository: IAuthRepository
*
* Repository interface for authentication operations.
*/
export interface IAuthRepository {
/**
* Find user by email
*/
findByEmail(email: EmailAddress): Promise<User | null>;
/**
* Save a user
*/
save(user: User): Promise<void>;
}

View File

@@ -0,0 +1,26 @@
import { PasswordHash } from '../value-objects/PasswordHash';
/**
* Domain Service: PasswordHashingService
*
* Service for password hashing and verification.
*/
export interface IPasswordHashingService {
hash(plain: string): Promise<string>;
verify(plain: string, hash: string): Promise<boolean>;
}
/**
* Implementation using bcrypt via PasswordHash VO.
*/
export class PasswordHashingService implements IPasswordHashingService {
async hash(plain: string): Promise<string> {
const passwordHash = await PasswordHash.create(plain);
return passwordHash.value;
}
async verify(plain: string, hash: string): Promise<boolean> {
const passwordHash = PasswordHash.fromHash(hash);
return passwordHash.verify(plain);
}
}

View File

@@ -0,0 +1,41 @@
import bcrypt from 'bcrypt';
import type { IValueObject } from '@gridpilot/shared/domain';
export interface PasswordHashProps {
value: string;
}
/**
* Value Object: PasswordHash
*
* Wraps a bcrypt-hashed password string and provides verification.
*/
export class PasswordHash implements IValueObject<PasswordHashProps> {
public readonly props: PasswordHashProps;
private constructor(value: string) {
this.props = { value };
}
static async create(plain: string): Promise<PasswordHash> {
const saltRounds = 12;
const hash = await bcrypt.hash(plain, saltRounds);
return new PasswordHash(hash);
}
static fromHash(hash: string): PasswordHash {
return new PasswordHash(hash);
}
get value(): string {
return this.props.value;
}
async verify(plain: string): Promise<boolean> {
return bcrypt.compare(plain, this.props.value);
}
equals(other: IValueObject<PasswordHashProps>): boolean {
return this.props.value === other.props.value;
}
}

View File

@@ -1,3 +1,4 @@
import { v4 as uuidv4 } from 'uuid';
import type { IValueObject } from '@gridpilot/shared/domain';
export interface UserIdProps {
@@ -14,6 +15,10 @@ export class UserId implements IValueObject<UserIdProps> {
this.props = { value };
}
public static create(): UserId {
return new UserId(uuidv4());
}
public static fromString(value: string): UserId {
return new UserId(value);
}