import type { EmailAddress, Name, UniqueID } from "@repo/rdx-ddd"; import { AggregateRoot } from "@repo/rdx-ddd"; import { Result } from "@repo/rdx-utils"; import { IdentityError } from "./identity-error"; import type { PasswordHash } from "./value-objects/password-hash.vo"; export type UserProps = Readonly<{ name: Name; email: EmailAddress; passwordHash: PasswordHash; active: boolean; isInitialAdmin: boolean; authVersion: number; }>; export class User extends AggregateRoot { static create(props: UserProps, id?: UniqueID): Result { if ( !Number.isSafeInteger(props.authVersion) || props.authVersion < 1 || props.name.toPrimitive().length > 100 ) { return Result.fail(new IdentityError("INVALID_REQUEST")); } if (props.isInitialAdmin && !props.active) { return Result.fail(new IdentityError("ADMIN_PROTECTED")); } return Result.ok(new User(props, id)); } static rehydrate(props: UserProps, id: UniqueID): User { return new User(props, id); } get name(): Name { return this.props.name; } get email(): EmailAddress { return this.props.email; } get passwordHash(): PasswordHash { return this.props.passwordHash; } get active(): boolean { return this.props.active; } get isInitialAdmin(): boolean { return this.props.isInitialAdmin; } get authVersion(): number { return this.props.authVersion; } update( values: Readonly<{ name: Name; email: EmailAddress; active: boolean }> ): Result { if (values.name.toPrimitive().length > 100) { return Result.fail(new IdentityError("INVALID_REQUEST")); } if (this.isInitialAdmin && !values.active) { return Result.fail(new IdentityError("ADMIN_PROTECTED")); } if ( this.name.equals(values.name) && this.email.equals(values.email) && this.active === values.active ) { return Result.ok(this); } return Result.ok( new User( { ...this.props, ...values, authVersion: this.authVersion + (values.active === this.active ? 0 : 1), }, this.id ) ); } changePassword(passwordHash: PasswordHash): User { if (this.passwordHash.equals(passwordHash)) { return this; } return new User({ ...this.props, passwordHash, authVersion: this.authVersion + 1 }, this.id); } }