Split monolithic kernel_commands.rs (2185 lines) and pipeline_commands.rs (1391 lines) into focused sub-modules under kernel_commands/ and pipeline_commands/ directories. Add gateway module (commands, config, io, runtime), health_check, and 15 new TypeScript client libraries for SaaS relay, auth, admin, telemetry, and kernel sub-systems (a2a, agent, chat, hands, skills, triggers). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
109 lines
2.8 KiB
TypeScript
109 lines
2.8 KiB
TypeScript
/**
|
|
* 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}`;
|
|
}
|