fix(auth-files): fix deleting OAuth model mappings providers

This commit is contained in:
LTbinglingfeng
2026-01-19 23:29:11 +08:00
parent d077b5dd26
commit 883059b031

View File

@@ -6,6 +6,14 @@ import { apiClient } from './client';
import type { AuthFilesResponse } from '@/types/authFile'; import type { AuthFilesResponse } from '@/types/authFile';
import type { OAuthModelMappingEntry } from '@/types'; import type { OAuthModelMappingEntry } from '@/types';
type StatusError = { status?: number };
const getStatusCode = (err: unknown): number | undefined => {
if (!err || typeof err !== 'object') return undefined;
if ('status' in err) return (err as StatusError).status;
return undefined;
};
const normalizeOauthExcludedModels = (payload: unknown): Record<string, string[]> => { const normalizeOauthExcludedModels = (payload: unknown): Record<string, string[]> => {
if (!payload || typeof payload !== 'object') return {}; if (!payload || typeof payload !== 'object') return {};
@@ -43,6 +51,55 @@ const normalizeOauthExcludedModels = (payload: unknown): Record<string, string[]
return result; return result;
}; };
const normalizeOauthModelMappings = (payload: unknown): Record<string, OAuthModelMappingEntry[]> => {
if (!payload || typeof payload !== 'object') return {};
const source =
(payload as any)['oauth-model-mappings'] ??
(payload as any)['oauth-model-alias'] ??
(payload as any).items ??
payload;
if (!source || typeof source !== 'object') return {};
const result: Record<string, OAuthModelMappingEntry[]> = {};
Object.entries(source as Record<string, unknown>).forEach(([channel, mappings]) => {
const key = String(channel ?? '')
.trim()
.toLowerCase();
if (!key) return;
if (!Array.isArray(mappings)) return;
const seen = new Set<string>();
const normalized = mappings
.map((item) => {
if (!item || typeof item !== 'object') return null;
const name = String((item as any).name ?? (item as any).id ?? (item as any).model ?? '').trim();
const alias = String((item as any).alias ?? '').trim();
if (!name || !alias) return null;
const fork = (item as any).fork === true;
return fork ? { name, alias, fork } : { name, alias };
})
.filter(Boolean)
.filter((entry) => {
const mapping = entry as OAuthModelMappingEntry;
const dedupeKey = `${mapping.name.toLowerCase()}::${mapping.alias.toLowerCase()}::${mapping.fork ? '1' : '0'}`;
if (seen.has(dedupeKey)) return false;
seen.add(dedupeKey);
return true;
}) as OAuthModelMappingEntry[];
if (normalized.length) {
result[key] = normalized;
}
});
return result;
};
const OAUTH_MODEL_MAPPINGS_ENDPOINT = '/oauth-model-mappings';
const OAUTH_MODEL_MAPPINGS_LEGACY_ENDPOINT = '/oauth-model-alias';
export const authFilesApi = { export const authFilesApi = {
list: () => apiClient.get<AuthFilesResponse>('/auth-files'), list: () => apiClient.get<AuthFilesResponse>('/auth-files'),
@@ -81,34 +138,63 @@ export const authFilesApi = {
// OAuth 模型映射 // OAuth 模型映射
async getOauthModelMappings(): Promise<Record<string, OAuthModelMappingEntry[]>> { async getOauthModelMappings(): Promise<Record<string, OAuthModelMappingEntry[]>> {
const data = await apiClient.get('/oauth-model-alias'); try {
const payload = (data && (data['oauth-model-alias'] ?? data.items ?? data)) as any; const data = await apiClient.get(OAUTH_MODEL_MAPPINGS_ENDPOINT);
if (!payload || typeof payload !== 'object') return {}; return normalizeOauthModelMappings(data);
const result: Record<string, OAuthModelMappingEntry[]> = {}; } catch (err: unknown) {
Object.entries(payload).forEach(([channel, mappings]) => { if (getStatusCode(err) !== 404) throw err;
if (!Array.isArray(mappings)) return; const data = await apiClient.get(OAUTH_MODEL_MAPPINGS_LEGACY_ENDPOINT);
const normalized = mappings return normalizeOauthModelMappings(data);
.map((item) => { }
if (!item || typeof item !== 'object') return null;
const name = String(item.name ?? item.id ?? item.model ?? '').trim();
const alias = String(item.alias ?? '').trim();
if (!name || !alias) return null;
const fork = item.fork === true;
return fork ? { name, alias, fork } : { name, alias };
})
.filter(Boolean) as OAuthModelMappingEntry[];
if (normalized.length) {
result[channel] = normalized;
}
});
return result;
}, },
saveOauthModelMappings: (channel: string, mappings: OAuthModelMappingEntry[]) => saveOauthModelMappings: async (channel: string, mappings: OAuthModelMappingEntry[]) => {
apiClient.patch('/oauth-model-alias', { channel, aliases: mappings }), const normalizedChannel = String(channel ?? '')
.trim()
.toLowerCase();
const normalizedMappings = normalizeOauthModelMappings({ [normalizedChannel]: mappings })[normalizedChannel] ?? [];
deleteOauthModelMappings: (channel: string) => try {
apiClient.delete(`/oauth-model-alias?channel=${encodeURIComponent(channel)}`), await apiClient.patch(OAUTH_MODEL_MAPPINGS_ENDPOINT, { channel: normalizedChannel, mappings: normalizedMappings });
return;
} catch (err: unknown) {
if (getStatusCode(err) !== 404) throw err;
await apiClient.patch(OAUTH_MODEL_MAPPINGS_LEGACY_ENDPOINT, { channel: normalizedChannel, aliases: normalizedMappings });
}
},
deleteOauthModelMappings: async (channel: string) => {
const normalizedChannel = String(channel ?? '')
.trim()
.toLowerCase();
const deleteViaPatch = async () => {
try {
await apiClient.patch(OAUTH_MODEL_MAPPINGS_ENDPOINT, { channel: normalizedChannel, mappings: [] });
return true;
} catch (err: unknown) {
if (getStatusCode(err) !== 404) throw err;
await apiClient.patch(OAUTH_MODEL_MAPPINGS_LEGACY_ENDPOINT, { channel: normalizedChannel, aliases: [] });
return true;
}
};
try {
await deleteViaPatch();
return;
} catch (err: unknown) {
const status = getStatusCode(err);
if (status !== 405) throw err;
}
try {
await apiClient.delete(`${OAUTH_MODEL_MAPPINGS_ENDPOINT}?channel=${encodeURIComponent(normalizedChannel)}`);
return;
} catch (err: unknown) {
if (getStatusCode(err) !== 404) throw err;
await apiClient.delete(`${OAUTH_MODEL_MAPPINGS_LEGACY_ENDPOINT}?channel=${encodeURIComponent(normalizedChannel)}`);
}
},
// 获取认证凭证支持的模型 // 获取认证凭证支持的模型
async getModelsForAuthFile(name: string): Promise<{ id: string; display_name?: string; type?: string; owned_by?: string }[]> { async getModelsForAuthFile(name: string): Promise<{ id: string; display_name?: string; type?: string; owned_by?: string }[]> {