gcx/backend/services/telemetry-service/src/domain/value-objects/event-name.vo.ts

57 lines
1.8 KiB
TypeScript

/**
* Value Object: EventName
* Validates and encapsulates a telemetry event name.
* Event names must be non-empty, max 64 characters, and follow snake_case convention.
*/
export class EventName {
private static readonly MAX_LENGTH = 64;
private static readonly PATTERN = /^[a-z][a-z0-9_]*$/;
private constructor(private readonly value: string) {}
static create(name: string): EventName {
if (!name || name.trim().length === 0) {
throw new Error('Event name cannot be empty');
}
if (name.length > EventName.MAX_LENGTH) {
throw new Error(`Event name must be at most ${EventName.MAX_LENGTH} characters, got ${name.length}`);
}
if (!EventName.PATTERN.test(name)) {
throw new Error(`Event name must be snake_case (lowercase letters, digits, underscores): "${name}"`);
}
return new EventName(name);
}
/**
* Create an EventName without strict pattern validation (for legacy/external events).
* Still enforces max length.
*/
static createLenient(name: string): EventName {
if (!name || name.trim().length === 0) {
throw new Error('Event name cannot be empty');
}
if (name.length > EventName.MAX_LENGTH) {
throw new Error(`Event name must be at most ${EventName.MAX_LENGTH} characters, got ${name.length}`);
}
return new EventName(name);
}
toString(): string {
return this.value;
}
equals(other: EventName): boolean {
return this.value === other.value;
}
/** Check if this is a session-related event */
isSessionEvent(): boolean {
return this.value === 'app_session_start' || this.value === 'app_session_end';
}
/** Check if this is a heartbeat-related event */
isHeartbeatEvent(): boolean {
return this.value === 'heartbeat' || this.value === 'app_heartbeat';
}
}