CrossRelay stage 0+1: Go gateway with Anthropic<->Chat Completions relay, Tauri shell, bilingual management UI
- Go gateway (stdlib only): /v1/messages non-stream + SSE, /v1/messages/count_tokens, management API /api/* (providers CRUD, apply/restore, settings, backups, logs) - Protocol conversion: Anthropic Messages <-> Chat Completions with a streaming state machine keyed by content block index (text, tool_use, parallel calls) - ~/.claude/settings.json guarded read/write: timestamped backups, managed env keys only, one-click restore - Tauri 2 shell: spawns the gateway sidecar, parses the random port from stdout, stdin pipe watchdog prevents orphans, kills the child on exit - React frontend: Dashboard/Providers/Settings, zh-CN + en-US, TanStack Query - Tests: Go table-driven + httptest integration (all green), vitest + RTL
This commit is contained in:
1 parent
8ee5e98ea3
commit
f8acf31ebc
71 files changed
+15727
-1
No files matched your search
@@ -0,0 +1,76 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { api, type ProviderInput } from "./api";
|
||||
|
||||
export const queryKeys = {
|
||||
status: ["status"] as const,
|
||||
providers: ["providers"] as const,
|
||||
logs: ["logs"] as const,
|
||||
backups: ["backups"] as const,
|
||||
settings: ["settings"] as const,
|
||||
};
|
||||
|
||||
export function useStatus() {
|
||||
return useQuery({ queryKey: queryKeys.status, queryFn: api.getStatus, refetchInterval: 5000 });
|
||||
}
|
||||
|
||||
export function useProviders() {
|
||||
return useQuery({ queryKey: queryKeys.providers, queryFn: api.listProviders });
|
||||
}
|
||||
|
||||
export function useLogs() {
|
||||
return useQuery({ queryKey: queryKeys.logs, queryFn: api.listLogs, refetchInterval: 5000 });
|
||||
}
|
||||
|
||||
export function useBackups() {
|
||||
return useQuery({ queryKey: queryKeys.backups, queryFn: api.listBackups });
|
||||
}
|
||||
|
||||
export function useSettings() {
|
||||
return useQuery({ queryKey: queryKeys.settings, queryFn: api.getSettings });
|
||||
}
|
||||
|
||||
function invalidateAll(queryClient: ReturnType<typeof useQueryClient>) {
|
||||
return Promise.all([
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.providers }),
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.status }),
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.backups }),
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.settings }),
|
||||
]);
|
||||
}
|
||||
|
||||
export function useProviderMutations() {
|
||||
const queryClient = useQueryClient();
|
||||
const create = useMutation({
|
||||
mutationFn: (input: ProviderInput) => api.createProvider(input),
|
||||
onSuccess: () => invalidateAll(queryClient),
|
||||
});
|
||||
const update = useMutation({
|
||||
mutationFn: ({ id, input }: { id: string; input: ProviderInput }) => api.updateProvider(id, input),
|
||||
onSuccess: () => invalidateAll(queryClient),
|
||||
});
|
||||
const remove = useMutation({
|
||||
mutationFn: (id: string) => api.deleteProvider(id),
|
||||
onSuccess: () => invalidateAll(queryClient),
|
||||
});
|
||||
const apply = useMutation({
|
||||
mutationFn: (id: string) => api.applyProvider(id),
|
||||
onSuccess: () => invalidateAll(queryClient),
|
||||
});
|
||||
return { create, update, remove, apply };
|
||||
}
|
||||
|
||||
export function useRestore() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: () => api.restore(),
|
||||
onSuccess: () => invalidateAll(queryClient),
|
||||
});
|
||||
}
|
||||
|
||||
export function useSettingsMutation() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (patch: Parameters<typeof api.updateSettings>[0]) => api.updateSettings(patch),
|
||||
onSuccess: () => invalidateAll(queryClient),
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user