refactor(desktop): split kernel_commands/pipeline_commands into modules, add SaaS client libs and gateway modules

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>
This commit is contained in:
iven
2026-03-31 11:12:47 +08:00
parent d0ae7d2770
commit f79560a911
71 changed files with 8521 additions and 5997 deletions

View File

@@ -0,0 +1,108 @@
/**
* 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}`;
}