nickname.ts raw
1 /**
2 * Value object representing a user-defined nickname for an identity.
3 * Self-validating and immutable.
4 */
5 export class Nickname {
6 private static readonly MAX_LENGTH = 50;
7 private static readonly MIN_LENGTH = 1;
8
9 private constructor(private readonly _value: string) {}
10
11 /**
12 * Create a new Nickname from a string value.
13 * Trims whitespace and validates length.
14 *
15 * @throws Error if nickname is empty or too long
16 */
17 static create(value: string): Nickname {
18 const trimmed = value?.trim() ?? '';
19
20 if (trimmed.length < Nickname.MIN_LENGTH) {
21 throw new InvalidNicknameError('Nickname cannot be empty');
22 }
23
24 if (trimmed.length > Nickname.MAX_LENGTH) {
25 throw new InvalidNicknameError(
26 `Nickname cannot exceed ${Nickname.MAX_LENGTH} characters`
27 );
28 }
29
30 return new Nickname(trimmed);
31 }
32
33 /**
34 * Reconstitute a Nickname from storage without validation.
35 * Use only when loading from trusted storage.
36 */
37 static fromStorage(value: string): Nickname {
38 return new Nickname(value);
39 }
40
41 get value(): string {
42 return this._value;
43 }
44
45 equals(other: Nickname): boolean {
46 return this._value === other._value;
47 }
48
49 toString(): string {
50 return this._value;
51 }
52
53 toJSON(): string {
54 return this._value;
55 }
56 }
57
58 /**
59 * Error thrown when nickname validation fails.
60 */
61 export class InvalidNicknameError extends Error {
62 constructor(message: string) {
63 super(message);
64 this.name = 'InvalidNicknameError';
65 }
66 }
67