/** * gateway-errors.ts - Gateway Error Classes & Security Utilities * * Extracted from gateway-client.ts for modularity. * Contains error classes and WebSocket security validation. */ import { isLocalhost } from './gateway-storage'; // === Error Classes === /** * Security error for invalid WebSocket connections. * Thrown when non-localhost URLs use ws:// instead of wss://. */ export class SecurityError extends Error { constructor(message: string) { super(message); this.name = 'SecurityError'; } } /** * Connection error for WebSocket/HTTP connection failures. */ export class ConnectionError extends Error { public readonly code?: string; public readonly recoverable: boolean; constructor(message: string, code?: string, recoverable: boolean = true) { super(message); this.name = 'ConnectionError'; this.code = code; this.recoverable = recoverable; } } /** * Timeout error for request/response timeouts. */ export class TimeoutError extends Error { public readonly timeout: number; constructor(message: string, timeout: number) { super(message); this.name = 'TimeoutError'; this.timeout = timeout; } } /** * Authentication error for handshake/token failures. */ export class AuthenticationError extends Error { public readonly code?: string; constructor(message: string, code?: string) { super(message); this.name = 'AuthenticationError'; this.code = code; } } /** * HTTP error for REST API responses with non-2xx status codes. */ export class GatewayHttpError extends Error { public readonly status: number; public readonly body?: unknown; constructor(message: string, status: number, body?: unknown) { super(message); this.name = 'GatewayHttpError'; this.status = status; this.body = body; } } // === Utility Functions === /** * Validate WebSocket URL security. * Ensures non-localhost connections use WSS protocol. * * @param url - The WebSocket URL to validate * @throws SecurityError if non-localhost URL uses ws:// instead of wss:// */ export function validateWebSocketSecurity(url: string): void { if (!url.startsWith('wss://') && !isLocalhost(url)) { throw new SecurityError( 'Non-localhost connections must use WSS protocol for security. ' + `URL: ${url.replace(/:[^:@]+@/, ':****@')}` ); } } /** * Create a unique idempotency key for requests. * Uses crypto.randomUUID when available, otherwise falls back to manual generation. */ export function createIdempotencyKey(): string { if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') { return crypto.randomUUID(); } const bytes = crypto.getRandomValues(new Uint8Array(6)); const suffix = Array.from(bytes).map(b => b.toString(36).padStart(2, '0')).join(''); return `idem_${Date.now()}_${suffix}`; }