import type { IApplicationError, CommonApplicationErrorKind } from '@gridpilot/shared/errors'; export abstract class RacingApplicationError extends Error implements IApplicationError { readonly type = 'application' as const; readonly context = 'racing-application'; abstract readonly kind: CommonApplicationErrorKind | string; constructor(message: string) { super(message); Object.setPrototypeOf(this, new.target.prototype); } } export type RacingEntityType = | 'race' | 'league' | 'team' | 'season' | 'sponsorship' | 'sponsorshipRequest' | 'driver' | 'membership' | 'sponsor' | 'protest'; export interface EntityNotFoundDetails { entity: RacingEntityType; id: string; } export class EntityNotFoundError extends RacingApplicationError implements IApplicationError<'not_found', EntityNotFoundDetails> { readonly kind = 'not_found' as const; readonly details: EntityNotFoundDetails; constructor(details: EntityNotFoundDetails) { super(`${details.entity} not found for id: ${details.id}`); this.details = details; } } export type PermissionDeniedReason = | 'NOT_LEAGUE_ADMIN' | 'NOT_LEAGUE_OWNER' | 'NOT_TEAM_OWNER' | 'NOT_ACTIVE_MEMBER' | 'NOT_MEMBER' | 'TEAM_OWNER_CANNOT_LEAVE' | 'UNAUTHORIZED'; export class PermissionDeniedError extends RacingApplicationError implements IApplicationError<'forbidden', PermissionDeniedReason> { readonly kind = 'forbidden' as const; constructor(public readonly reason: PermissionDeniedReason, message?: string) { super(message ?? `Permission denied: ${reason}`); } get details(): PermissionDeniedReason { return this.reason; } } export class BusinessRuleViolationError extends RacingApplicationError implements IApplicationError<'conflict', undefined> { readonly kind = 'conflict' as const; constructor(message: string) { super(message); } }