refactor(phase-10): complete type safety enhancement
- Add types/api-responses.ts with ApiResponse<T>, PaginatedResponse<T> - Add types/errors.ts with comprehensive error type hierarchy - Replace all any usage (53 → 0, 100% reduction) - Add RawAPI response interfaces for type-safe mapping - Update catch blocks to use unknown with type narrowing - Add getState mock to chatStore tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -54,21 +54,27 @@ export interface GatewayRequest {
|
||||
type: 'req';
|
||||
id: string;
|
||||
method: string;
|
||||
params?: Record<string, any>;
|
||||
params?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface GatewayError {
|
||||
code?: string;
|
||||
message?: string;
|
||||
details?: unknown;
|
||||
}
|
||||
|
||||
export interface GatewayResponse {
|
||||
type: 'res';
|
||||
id: string;
|
||||
ok: boolean;
|
||||
payload?: any;
|
||||
error?: any;
|
||||
payload?: unknown;
|
||||
error?: GatewayError;
|
||||
}
|
||||
|
||||
export interface GatewayEvent {
|
||||
type: 'event';
|
||||
event: string;
|
||||
payload?: any;
|
||||
payload?: unknown;
|
||||
seq?: number;
|
||||
}
|
||||
|
||||
@@ -102,9 +108,30 @@ export interface AgentStreamDelta {
|
||||
workflowResult?: unknown;
|
||||
}
|
||||
|
||||
/** OpenFang WebSocket stream event types */
|
||||
export interface OpenFangStreamEvent {
|
||||
type: 'text_delta' | 'phase' | 'response' | 'typing' | 'tool_call' | 'tool_result' | 'hand' | 'workflow' | 'error';
|
||||
content?: string;
|
||||
phase?: 'streaming' | 'done';
|
||||
state?: 'start' | 'stop';
|
||||
tool?: string;
|
||||
input?: unknown;
|
||||
output?: string;
|
||||
result?: unknown;
|
||||
hand_name?: string;
|
||||
hand_status?: string;
|
||||
hand_result?: unknown;
|
||||
workflow_id?: string;
|
||||
workflow_step?: string;
|
||||
workflow_status?: string;
|
||||
workflow_result?: unknown;
|
||||
message?: string;
|
||||
code?: string;
|
||||
}
|
||||
|
||||
export type ConnectionState = 'disconnected' | 'connecting' | 'handshaking' | 'connected' | 'reconnecting';
|
||||
|
||||
type EventCallback = (payload: any) => void;
|
||||
type EventCallback = (payload: unknown) => void;
|
||||
|
||||
export function getStoredGatewayUrl(): string {
|
||||
try {
|
||||
@@ -329,8 +356,8 @@ export class GatewayClient {
|
||||
private state: ConnectionState = 'disconnected';
|
||||
private requestId = 0;
|
||||
private pendingRequests = new Map<string, {
|
||||
resolve: (value: any) => void;
|
||||
reject: (reason: any) => void;
|
||||
resolve: (value: unknown) => void;
|
||||
reject: (reason: unknown) => void;
|
||||
timer: number;
|
||||
}>();
|
||||
private eventListeners = new Map<string, Set<EventCallback>>();
|
||||
@@ -417,9 +444,10 @@ export class GatewayClient {
|
||||
} else {
|
||||
throw new Error('Health check failed');
|
||||
}
|
||||
} catch (err: any) {
|
||||
} catch (err: unknown) {
|
||||
this.setState('disconnected');
|
||||
throw new Error(`Failed to connect to OpenFang: ${err.message}`);
|
||||
const errorMessage = err instanceof Error ? err.message : String(err);
|
||||
throw new Error(`Failed to connect to OpenFang: ${errorMessage}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,8 +499,9 @@ export class GatewayClient {
|
||||
clearTimeout(handshakeTimer);
|
||||
settleReject(error);
|
||||
});
|
||||
} catch (err: any) {
|
||||
this.log('error', `Parse error: ${err.message}`);
|
||||
} catch (err: unknown) {
|
||||
const errorMessage = err instanceof Error ? err.message : String(err);
|
||||
this.log('error', `Parse error: ${errorMessage}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -519,7 +548,7 @@ export class GatewayClient {
|
||||
|
||||
// === Request/Response ===
|
||||
|
||||
async request(method: string, params?: Record<string, any>): Promise<any> {
|
||||
async request(method: string, params?: Record<string, unknown>): Promise<unknown> {
|
||||
if (this.state !== 'connected') {
|
||||
throw new Error(`Not connected (state: ${this.state})`);
|
||||
}
|
||||
@@ -650,8 +679,9 @@ export class GatewayClient {
|
||||
try {
|
||||
const data = JSON.parse(event.data);
|
||||
this.handleOpenFangStreamEvent(runId, data, sessionId);
|
||||
} catch (err: any) {
|
||||
this.log('error', `Failed to parse stream event: ${err.message}`);
|
||||
} catch (err: unknown) {
|
||||
const errorMessage = err instanceof Error ? err.message : String(err);
|
||||
this.log('error', `Failed to parse stream event: ${errorMessage}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -673,18 +703,19 @@ export class GatewayClient {
|
||||
this.streamCallbacks.delete(runId);
|
||||
this.openfangWs = null;
|
||||
};
|
||||
} catch (err: any) {
|
||||
this.log('error', `Failed to create WebSocket: ${err.message}`);
|
||||
} catch (err: unknown) {
|
||||
const errorMessage = err instanceof Error ? err.message : String(err);
|
||||
this.log('error', `Failed to create WebSocket: ${errorMessage}`);
|
||||
const callbacks = this.streamCallbacks.get(runId);
|
||||
if (callbacks) {
|
||||
callbacks.onError(err.message);
|
||||
callbacks.onError(errorMessage);
|
||||
this.streamCallbacks.delete(runId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle OpenFang stream events */
|
||||
private handleOpenFangStreamEvent(runId: string, data: any, sessionId: string): void {
|
||||
private handleOpenFangStreamEvent(runId: string, data: OpenFangStreamEvent, sessionId: string): void {
|
||||
const callbacks = this.streamCallbacks.get(runId);
|
||||
if (!callbacks) return;
|
||||
|
||||
@@ -736,18 +767,18 @@ export class GatewayClient {
|
||||
|
||||
case 'tool_result':
|
||||
if (callbacks.onTool && data.tool) {
|
||||
callbacks.onTool(data.tool, '', data.result || data.output || '');
|
||||
callbacks.onTool(data.tool, '', String(data.result || data.output || ''));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'hand':
|
||||
if (callbacks.onHand && data.hand_name) {
|
||||
callbacks.onHand(data.hand_name, data.status || 'triggered', data.result);
|
||||
callbacks.onHand(data.hand_name, data.hand_status || 'triggered', data.hand_result);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
callbacks.onError(data.message || data.error || data.content || 'Unknown error');
|
||||
callbacks.onError(data.message || data.code || data.content || 'Unknown error');
|
||||
this.streamCallbacks.delete(runId);
|
||||
if (this.openfangWs) {
|
||||
this.openfangWs.close(1011, 'Error');
|
||||
@@ -1487,7 +1518,7 @@ export class GatewayClient {
|
||||
};
|
||||
|
||||
this.send(connectReq);
|
||||
} catch (err: any) {
|
||||
} catch (err: unknown) {
|
||||
const error = err instanceof Error ? err : new Error(String(err));
|
||||
this.log('error', error.message);
|
||||
this.cleanup();
|
||||
@@ -1514,7 +1545,7 @@ export class GatewayClient {
|
||||
}
|
||||
}
|
||||
|
||||
private emitEvent(event: string, payload: any) {
|
||||
private emitEvent(event: string, payload: unknown) {
|
||||
const listeners = this.eventListeners.get(event);
|
||||
if (listeners) {
|
||||
for (const cb of listeners) {
|
||||
|
||||
Reference in New Issue
Block a user