import type { ApiFieldErrors } from '@/api/errorDetails' export interface ApiEnvelope { code: string message: string data: T requestId: string | null traceId: string | null timestamp: string } export type { ApiFieldErrors } from '@/api/errorDetails' export class ApiError extends Error { constructor( message: string, readonly code = 'NETWORK_ERROR', readonly status?: number, readonly fieldErrors?: ApiFieldErrors, readonly traceId?: string | null, readonly requestId?: string | null, ) { super(message) this.name = 'ApiError' } } export function isApiEnvelope(value: unknown): value is ApiEnvelope { if (!value || typeof value !== 'object') return false const record = value as Record return typeof record.code === 'string' && typeof record.message === 'string' && 'data' in record } // Security failures have no business data, unlike successful API responses. export function isApiFailure(value: unknown): value is Omit, 'data'> { if (!value || typeof value !== 'object') return false const record = value as Record return typeof record.code === 'string' && record.code !== '200' && typeof record.message === 'string' && (record.requestId == null || typeof record.requestId === 'string') && (record.traceId == null || typeof record.traceId === 'string') }