refactor(store): split gatewayStore into specialized domain stores
Major restructuring: - Split monolithic gatewayStore into 5 focused stores: - connectionStore: WebSocket connection and gateway lifecycle - configStore: quickConfig, workspaceInfo, MCP services - agentStore: clones, usage stats, agent management - handStore: hands, approvals, triggers, hand runs - workflowStore: workflows, workflow runs, execution - Update all components to use new stores with selector pattern - Remove
This commit is contained in:
118
desktop/src/lib/gateway-storage.ts
Normal file
118
desktop/src/lib/gateway-storage.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* gateway-storage.ts - Gateway URL/Token Storage & Normalization
|
||||
*
|
||||
* Extracted from gateway-client.ts for modularity.
|
||||
* Manages WSS configuration, URL normalization, and
|
||||
* localStorage persistence for gateway URL and token.
|
||||
*/
|
||||
|
||||
// === WSS Configuration ===
|
||||
|
||||
/**
|
||||
* Whether to use WSS (WebSocket Secure) instead of WS.
|
||||
* - Production: defaults to WSS for security
|
||||
* - Development: defaults to WS for convenience
|
||||
* - Override: set VITE_USE_WSS=false to force WS in production
|
||||
*/
|
||||
const USE_WSS = import.meta.env.VITE_USE_WSS !== 'false' && import.meta.env.PROD;
|
||||
|
||||
/**
|
||||
* Default protocol based on WSS configuration.
|
||||
*/
|
||||
const DEFAULT_WS_PROTOCOL = USE_WSS ? 'wss://' : 'ws://';
|
||||
|
||||
/**
|
||||
* Check if a URL points to localhost.
|
||||
*/
|
||||
export function isLocalhost(url: string): boolean {
|
||||
try {
|
||||
const parsed = new URL(url);
|
||||
return parsed.hostname === 'localhost' ||
|
||||
parsed.hostname === '127.0.0.1' ||
|
||||
parsed.hostname === '[::1]';
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// === URL Constants ===
|
||||
|
||||
// OpenFang endpoints (port 50051 - actual running port)
|
||||
// Note: REST API uses relative path to leverage Vite proxy for CORS bypass
|
||||
export const DEFAULT_GATEWAY_URL = `${DEFAULT_WS_PROTOCOL}127.0.0.1:50051/ws`;
|
||||
export const REST_API_URL = ''; // Empty = use relative path (Vite proxy)
|
||||
export const FALLBACK_GATEWAY_URLS = [
|
||||
DEFAULT_GATEWAY_URL,
|
||||
`${DEFAULT_WS_PROTOCOL}127.0.0.1:4200/ws`,
|
||||
];
|
||||
|
||||
const GATEWAY_URL_STORAGE_KEY = 'zclaw_gateway_url';
|
||||
const GATEWAY_TOKEN_STORAGE_KEY = 'zclaw_gateway_token';
|
||||
|
||||
// === URL Normalization ===
|
||||
|
||||
/**
|
||||
* Normalize a gateway URL to ensure correct protocol and path.
|
||||
* - Ensures ws:// or wss:// protocol based on configuration
|
||||
* - Ensures /ws path suffix
|
||||
* - Handles both localhost and IP addresses
|
||||
*/
|
||||
export function normalizeGatewayUrl(url: string): string {
|
||||
let normalized = url.trim();
|
||||
|
||||
// Remove trailing slashes except for protocol
|
||||
normalized = normalized.replace(/\/+$/, '');
|
||||
|
||||
// Ensure protocol
|
||||
if (!normalized.startsWith('ws://') && !normalized.startsWith('wss://')) {
|
||||
normalized = USE_WSS ? `wss://${normalized}` : `ws://${normalized}`;
|
||||
}
|
||||
|
||||
// Ensure /ws path
|
||||
if (!normalized.endsWith('/ws')) {
|
||||
normalized = `${normalized}/ws`;
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
// === LocalStorage Helpers ===
|
||||
|
||||
export function getStoredGatewayUrl(): string {
|
||||
try {
|
||||
const stored = localStorage.getItem(GATEWAY_URL_STORAGE_KEY);
|
||||
return normalizeGatewayUrl(stored || DEFAULT_GATEWAY_URL);
|
||||
} catch {
|
||||
return DEFAULT_GATEWAY_URL;
|
||||
}
|
||||
}
|
||||
|
||||
export function setStoredGatewayUrl(url: string): string {
|
||||
const normalized = normalizeGatewayUrl(url || DEFAULT_GATEWAY_URL);
|
||||
try {
|
||||
localStorage.setItem(GATEWAY_URL_STORAGE_KEY, normalized);
|
||||
} catch { /* ignore localStorage failures */ }
|
||||
return normalized;
|
||||
}
|
||||
|
||||
export function getStoredGatewayToken(): string {
|
||||
try {
|
||||
return localStorage.getItem(GATEWAY_TOKEN_STORAGE_KEY) || '';
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
export function setStoredGatewayToken(token: string): string {
|
||||
const normalized = token.trim();
|
||||
try {
|
||||
if (normalized) {
|
||||
localStorage.setItem(GATEWAY_TOKEN_STORAGE_KEY, normalized);
|
||||
} else {
|
||||
localStorage.removeItem(GATEWAY_TOKEN_STORAGE_KEY);
|
||||
}
|
||||
} catch {
|
||||
/* ignore localStorage failures */
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
Reference in New Issue
Block a user