Files
cc-switch/src/lib/query/queries.ts
Jason 85334d8dce refine(usage): enhance query robustness and error handling
Backend improvements:
- Add InvalidHttpMethod error enum for better error semantics
- Clamp HTTP timeout to 2-30s to prevent config abuse
- Strict HTTP method validation instead of silent fallback to GET

Frontend improvements:
- Add i18n support for usage query errors (en/zh)
- Improve error handling with type-safe unknown instead of any
- Optimize i18n import (direct import instead of dynamic)
- Disable auto-retry for usage queries to avoid API stampede

Additional changes:
- Apply prettier formatting to affected files

Files changed:
- src-tauri/src/error.rs (+2)
- src-tauri/src/usage_script.rs (+8 -2)
- src/i18n/locales/{en,zh}.json (+4 -1 each)
- src/lib/api/usage.ts (+21 -4)
- src/lib/query/queries.ts (+1)
- style: prettier formatting on 6 other files
2025-11-03 10:24:59 +08:00

100 lines
2.7 KiB
TypeScript

import {
useQuery,
type UseQueryResult,
keepPreviousData,
} from "@tanstack/react-query";
import { providersApi, settingsApi, usageApi, type AppId } from "@/lib/api";
import type { Provider, Settings, UsageResult } from "@/types";
const sortProviders = (
providers: Record<string, Provider>,
): Record<string, Provider> => {
const sortedEntries = Object.values(providers)
.sort((a, b) => {
const indexA = a.sortIndex ?? Number.MAX_SAFE_INTEGER;
const indexB = b.sortIndex ?? Number.MAX_SAFE_INTEGER;
if (indexA !== indexB) {
return indexA - indexB;
}
const timeA = a.createdAt ?? 0;
const timeB = b.createdAt ?? 0;
if (timeA === timeB) {
return a.name.localeCompare(b.name, "zh-CN");
}
return timeA - timeB;
})
.map((provider) => [provider.id, provider] as const);
return Object.fromEntries(sortedEntries);
};
export interface ProvidersQueryData {
providers: Record<string, Provider>;
currentProviderId: string;
}
export const useProvidersQuery = (
appId: AppId,
): UseQueryResult<ProvidersQueryData> => {
return useQuery({
queryKey: ["providers", appId],
placeholderData: keepPreviousData,
queryFn: async () => {
let providers: Record<string, Provider> = {};
let currentProviderId = "";
try {
providers = await providersApi.getAll(appId);
} catch (error) {
console.error("获取供应商列表失败:", error);
}
try {
currentProviderId = await providersApi.getCurrent(appId);
} catch (error) {
console.error("获取当前供应商失败:", error);
}
if (Object.keys(providers).length === 0) {
try {
const success = await providersApi.importDefault(appId);
if (success) {
providers = await providersApi.getAll(appId);
currentProviderId = await providersApi.getCurrent(appId);
}
} catch (error) {
console.error("导入默认配置失败:", error);
}
}
return {
providers: sortProviders(providers),
currentProviderId,
};
},
});
};
export const useSettingsQuery = (): UseQueryResult<Settings> => {
return useQuery({
queryKey: ["settings"],
queryFn: async () => settingsApi.get(),
});
};
export const useUsageQuery = (
providerId: string,
appId: AppId,
enabled: boolean = true,
): UseQueryResult<UsageResult> => {
return useQuery({
queryKey: ["usage", providerId, appId],
queryFn: async () => usageApi.query(providerId, appId),
enabled: enabled && !!providerId,
refetchOnWindowFocus: false,
retry: false,
staleTime: 5 * 60 * 1000, // 5分钟
});
};