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:
@@ -45,6 +45,14 @@ interface ChannelInfo {
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface PluginStatus {
|
||||
id: string;
|
||||
name?: string;
|
||||
status: 'active' | 'inactive' | 'error' | 'loading';
|
||||
version?: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
interface ScheduledTask {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -95,6 +103,96 @@ interface WorkspaceInfo {
|
||||
totalSize: number;
|
||||
}
|
||||
|
||||
// === Raw API Response Types (for mapping) ===
|
||||
|
||||
interface RawHandRequirement {
|
||||
description?: string;
|
||||
name?: string;
|
||||
met?: boolean;
|
||||
satisfied?: boolean;
|
||||
details?: string;
|
||||
hint?: string;
|
||||
}
|
||||
|
||||
interface RawHandRun {
|
||||
runId?: string;
|
||||
run_id?: string;
|
||||
id?: string;
|
||||
status?: string;
|
||||
startedAt?: string;
|
||||
started_at?: string;
|
||||
created_at?: string;
|
||||
completedAt?: string;
|
||||
completed_at?: string;
|
||||
finished_at?: string;
|
||||
result?: unknown;
|
||||
output?: unknown;
|
||||
error?: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
interface RawApproval {
|
||||
id?: string;
|
||||
approvalId?: string;
|
||||
approval_id?: string;
|
||||
type?: string;
|
||||
request_type?: string;
|
||||
handId?: string;
|
||||
hand_id?: string;
|
||||
requester?: string;
|
||||
requested_by?: string;
|
||||
status?: string;
|
||||
createdAt?: string;
|
||||
created_at?: string;
|
||||
details?: Record<string, unknown>;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
interface RawSession {
|
||||
id?: string;
|
||||
sessionId?: string;
|
||||
session_id?: string;
|
||||
agentId?: string;
|
||||
agent_id?: string;
|
||||
model?: string;
|
||||
status?: string;
|
||||
createdAt?: string;
|
||||
created_at?: string;
|
||||
updatedAt?: string;
|
||||
updated_at?: string;
|
||||
messageCount?: number;
|
||||
message_count?: number;
|
||||
}
|
||||
|
||||
interface RawSessionMessage {
|
||||
id?: string;
|
||||
messageId?: string;
|
||||
message_id?: string;
|
||||
role?: string;
|
||||
content?: string;
|
||||
createdAt?: string;
|
||||
created_at?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
interface RawWorkflowRun {
|
||||
runId?: string;
|
||||
run_id?: string;
|
||||
id?: string;
|
||||
workflowId?: string;
|
||||
workflow_id?: string;
|
||||
status?: string;
|
||||
startedAt?: string;
|
||||
started_at?: string;
|
||||
completedAt?: string;
|
||||
completed_at?: string;
|
||||
currentStep?: number;
|
||||
current_step?: number;
|
||||
totalSteps?: number;
|
||||
total_steps?: number;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
// === OpenFang Types ===
|
||||
|
||||
export interface HandRequirement {
|
||||
@@ -308,7 +406,7 @@ interface GatewayStore {
|
||||
// Data
|
||||
clones: Clone[];
|
||||
usageStats: UsageStats | null;
|
||||
pluginStatus: any[];
|
||||
pluginStatus: PluginStatus[];
|
||||
channels: ChannelInfo[];
|
||||
scheduledTasks: ScheduledTask[];
|
||||
skillsCatalog: SkillInfo[];
|
||||
@@ -630,8 +728,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
get().loadSecurityStatus(),
|
||||
]);
|
||||
await get().loadChannels();
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
@@ -657,7 +755,7 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
const client = get().client;
|
||||
const currentDefault = client.getDefaultAgentId();
|
||||
// Only set if the default doesn't exist in the list
|
||||
const defaultExists = clones.some((c: any) => c.id === currentDefault);
|
||||
const defaultExists = clones.some((c) => c.id === currentDefault);
|
||||
if (!defaultExists) {
|
||||
client.setDefaultAgentId(clones[0].id);
|
||||
}
|
||||
@@ -670,8 +768,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
const result = await get().client.createClone(opts);
|
||||
await get().loadClones();
|
||||
return result?.clone;
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
@@ -681,8 +779,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
const result = await get().client.updateClone(id, updates);
|
||||
await get().loadClones();
|
||||
return result?.clone;
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
@@ -691,8 +789,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
try {
|
||||
await get().client.deleteClone(id);
|
||||
await get().loadClones();
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
}
|
||||
},
|
||||
|
||||
@@ -737,7 +835,7 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
|
||||
// QQ channel (check if qqbot plugin is loaded)
|
||||
const plugins = get().pluginStatus;
|
||||
const qqPlugin = plugins.find((p: any) => (p.name || p.id || '').toLowerCase().includes('qqbot'));
|
||||
const qqPlugin = plugins.find((p) => (p.name || p.id || '').toLowerCase().includes('qqbot'));
|
||||
if (qqPlugin) {
|
||||
channels.push({
|
||||
id: 'qqbot',
|
||||
@@ -765,8 +863,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
return result.channel as ChannelInfo;
|
||||
}
|
||||
return undefined;
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
@@ -781,8 +879,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
return result.channel as ChannelInfo;
|
||||
}
|
||||
return undefined;
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
@@ -800,8 +898,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
return result.channel as ChannelInfo;
|
||||
}
|
||||
return undefined;
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
@@ -812,8 +910,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
// Remove the channel from local state
|
||||
const currentChannels = get().channels;
|
||||
set({ channels: currentChannels.filter(c => c.id !== id) });
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
}
|
||||
},
|
||||
|
||||
@@ -927,8 +1025,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
}
|
||||
const result = await get().client.saveQuickConfig(nextConfig);
|
||||
set({ quickConfig: result?.quickConfig || nextConfig });
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
}
|
||||
},
|
||||
|
||||
@@ -951,7 +1049,7 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
const status = await getLocalGatewayStatus();
|
||||
set({ localGateway: status, localGatewayBusy: false });
|
||||
return status;
|
||||
} catch (err: any) {
|
||||
} catch (err: unknown) {
|
||||
const message = err?.message || '读取本地 Gateway 状态失败';
|
||||
const nextStatus = {
|
||||
...get().localGateway,
|
||||
@@ -975,7 +1073,7 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
const status = await startLocalGatewayCommand();
|
||||
set({ localGateway: status, localGatewayBusy: false });
|
||||
return status;
|
||||
} catch (err: any) {
|
||||
} catch (err: unknown) {
|
||||
const message = err?.message || '启动本地 Gateway 失败';
|
||||
const nextStatus = {
|
||||
...get().localGateway,
|
||||
@@ -999,7 +1097,7 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
const status = await stopLocalGatewayCommand();
|
||||
set({ localGateway: status, localGatewayBusy: false });
|
||||
return status;
|
||||
} catch (err: any) {
|
||||
} catch (err: unknown) {
|
||||
const message = err?.message || '停止本地 Gateway 失败';
|
||||
const nextStatus = {
|
||||
...get().localGateway,
|
||||
@@ -1023,7 +1121,7 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
const status = await restartLocalGatewayCommand();
|
||||
set({ localGateway: status, localGatewayBusy: false });
|
||||
return status;
|
||||
} catch (err: any) {
|
||||
} catch (err: unknown) {
|
||||
const message = err?.message || '重启本地 Gateway 失败';
|
||||
const nextStatus = {
|
||||
...get().localGateway,
|
||||
@@ -1097,7 +1195,7 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
icon: result.icon,
|
||||
provider: result.provider || getStringFromConfig('provider'),
|
||||
model: result.model || getStringFromConfig('model'),
|
||||
requirements: result.requirements?.map((r: any) => ({
|
||||
requirements: result.requirements?.map((r: RawHandRequirement) => ({
|
||||
description: r.description || r.name || String(r),
|
||||
met: r.met ?? r.satisfied ?? true,
|
||||
details: r.details || r.hint,
|
||||
@@ -1122,7 +1220,7 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
loadHandRuns: async (name: string, opts?: { limit?: number; offset?: number }) => {
|
||||
try {
|
||||
const result = await get().client.listHandRuns(name, opts);
|
||||
const runs: HandRun[] = (result?.runs || []).map((r: any) => ({
|
||||
const runs: HandRun[] = (result?.runs || []).map((r: RawHandRun) => ({
|
||||
runId: r.runId || r.run_id || r.id,
|
||||
status: r.status || 'unknown',
|
||||
startedAt: r.startedAt || r.started_at || r.created_at || new Date().toISOString(),
|
||||
@@ -1144,8 +1242,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
try {
|
||||
const result = await get().client.triggerHand(name, params);
|
||||
return result ? { runId: result.runId, status: result.status, startedAt: new Date().toISOString() } : undefined;
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
@@ -1155,8 +1253,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
await get().client.approveHand(name, runId, approved, reason);
|
||||
// Refresh hands to update status
|
||||
await get().loadHands();
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
@@ -1166,8 +1264,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
await get().client.cancelHand(name, runId);
|
||||
// Refresh hands to update status
|
||||
await get().loadHands();
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
@@ -1206,8 +1304,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
return newWorkflow;
|
||||
}
|
||||
return undefined;
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
@@ -1240,8 +1338,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
return get().workflows.find(w => w.id === id);
|
||||
}
|
||||
return undefined;
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
@@ -1252,8 +1350,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
set(state => ({
|
||||
workflows: state.workflows.filter(w => w.id !== id),
|
||||
}));
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
@@ -1262,8 +1360,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
try {
|
||||
const result = await get().client.executeWorkflow(id, input);
|
||||
return result ? { runId: result.runId, status: result.status } : undefined;
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
@@ -1273,8 +1371,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
await get().client.cancelWorkflow(id, runId);
|
||||
// Refresh workflows to update status
|
||||
await get().loadWorkflows();
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
@@ -1295,8 +1393,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
type: result.type,
|
||||
enabled: result.enabled,
|
||||
} as Trigger;
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
@@ -1308,8 +1406,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
// Refresh triggers list after creation
|
||||
await get().loadTriggers();
|
||||
return get().triggers.find(t => t.id === result.id);
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
@@ -1326,8 +1424,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
),
|
||||
}));
|
||||
return get().triggers.find(t => t.id === id);
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
@@ -1338,8 +1436,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
set(state => ({
|
||||
triggers: state.triggers.filter(t => t.id !== id),
|
||||
}));
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
@@ -1376,10 +1474,10 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
securityStatusError: 'API returned no data',
|
||||
});
|
||||
}
|
||||
} catch (err: any) {
|
||||
} catch (err: unknown) {
|
||||
set({
|
||||
securityStatusLoading: false,
|
||||
securityStatusError: err.message || 'Security API not available',
|
||||
securityStatusError: (err instanceof Error ? err.message : String(err)) || 'Security API not available',
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -1387,7 +1485,7 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
loadApprovals: async (status?: ApprovalStatus) => {
|
||||
try {
|
||||
const result = await get().client.listApprovals(status);
|
||||
const approvals: Approval[] = (result?.approvals || []).map((a: any) => ({
|
||||
const approvals: Approval[] = (result?.approvals || []).map((a: RawApproval) => ({
|
||||
id: a.id || a.approval_id,
|
||||
handName: a.hand_name || a.handName,
|
||||
runId: a.run_id || a.runId,
|
||||
@@ -1410,8 +1508,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
await get().client.respondToApproval(approvalId, approved, reason);
|
||||
// Refresh approvals after response
|
||||
await get().loadApprovals();
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
@@ -1421,7 +1519,7 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
loadSessions: async (opts?: { limit?: number; offset?: number }) => {
|
||||
try {
|
||||
const result = await get().client.listSessions(opts);
|
||||
const sessions: Session[] = (result?.sessions || []).map((s: any) => ({
|
||||
const sessions: Session[] = (result?.sessions || []).map((s: RawSession) => ({
|
||||
id: s.id,
|
||||
agentId: s.agent_id,
|
||||
createdAt: s.created_at,
|
||||
@@ -1474,8 +1572,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
};
|
||||
set(state => ({ sessions: [...state.sessions, session] }));
|
||||
return session;
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
@@ -1489,8 +1587,8 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
Object.entries(state.sessionMessages).filter(([id]) => id !== sessionId)
|
||||
),
|
||||
}));
|
||||
} catch (err: any) {
|
||||
set({ error: err.message });
|
||||
} catch (err: unknown) {
|
||||
set({ error: err instanceof Error ? err.message : String(err) });
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
@@ -1498,7 +1596,7 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
loadSessionMessages: async (sessionId: string, opts?: { limit?: number; offset?: number }) => {
|
||||
try {
|
||||
const result = await get().client.getSessionMessages(sessionId, opts);
|
||||
const messages: SessionMessage[] = (result?.messages || []).map((m: any) => ({
|
||||
const messages: SessionMessage[] = (result?.messages || []).map((m: RawSessionMessage) => ({
|
||||
id: m.id,
|
||||
role: m.role,
|
||||
content: m.content,
|
||||
@@ -1535,7 +1633,7 @@ export const useGatewayStore = create<GatewayStore>((set, get) => {
|
||||
loadWorkflowRuns: async (workflowId: string, opts?: { limit?: number; offset?: number }) => {
|
||||
try {
|
||||
const result = await get().client.listWorkflowRuns(workflowId, opts);
|
||||
const runs: WorkflowRun[] = (result?.runs || []).map((r: any) => ({
|
||||
const runs: WorkflowRun[] = (result?.runs || []).map((r: RawWorkflowRun) => ({
|
||||
runId: r.runId || r.run_id,
|
||||
status: r.status,
|
||||
startedAt: r.startedAt || r.started_at,
|
||||
|
||||
Reference in New Issue
Block a user