fix: finish review-driven single-source cleanup
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
|
||||
class TestStandardApiProviderAdapter extends StandardApiProviderAdapterBase {
|
||||
readonly platformName = 'test-standard';
|
||||
fetchJsonImpl = async () => ({ data: [] as Array<{ id: string }> });
|
||||
|
||||
async detect(_url: string): Promise<boolean> {
|
||||
return false;
|
||||
@@ -15,6 +16,14 @@ class TestStandardApiProviderAdapter extends StandardApiProviderAdapterBase {
|
||||
async getModels(_baseUrl: string, _token: string): Promise<string[]> {
|
||||
return [];
|
||||
}
|
||||
|
||||
protected override async fetchJson<T>(url: string, options?: Parameters<StandardApiProviderAdapterBase['fetchJson']>[1]): Promise<T> {
|
||||
return this.fetchJsonImpl(url, options) as Promise<T>;
|
||||
}
|
||||
|
||||
async fetchModelsForTest(options: Parameters<StandardApiProviderAdapterBase['fetchModelsFromStandardEndpoint']>[0]) {
|
||||
return this.fetchModelsFromStandardEndpoint(options);
|
||||
}
|
||||
}
|
||||
|
||||
describe('standardApiProvider helpers', () => {
|
||||
@@ -43,4 +52,33 @@ describe('standardApiProvider helpers', () => {
|
||||
quota: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it('does not swallow mapper bugs while still returning empty lists for network failures', async () => {
|
||||
const adapter = new TestStandardApiProviderAdapter();
|
||||
adapter.fetchJsonImpl = async () => ({ data: [{ id: 'gpt-5' }] });
|
||||
|
||||
await expect(adapter.fetchModelsForTest({
|
||||
baseUrl: 'https://api.example.com',
|
||||
mapResponse: () => {
|
||||
throw new Error('mapper exploded');
|
||||
},
|
||||
})).rejects.toThrow('mapper exploded');
|
||||
|
||||
adapter.fetchJsonImpl = async () => {
|
||||
throw new Error('network failed');
|
||||
};
|
||||
|
||||
await expect(adapter.fetchModelsForTest({
|
||||
baseUrl: 'https://api.example.com',
|
||||
})).resolves.toEqual([]);
|
||||
});
|
||||
|
||||
it('rejects invalid payload shapes instead of silently treating them as no models', async () => {
|
||||
const adapter = new TestStandardApiProviderAdapter();
|
||||
adapter.fetchJsonImpl = async () => ({ data: 'not-an-array' });
|
||||
|
||||
await expect(adapter.fetchModelsForTest({
|
||||
baseUrl: 'https://api.example.com',
|
||||
})).rejects.toThrow('invalid standard models payload');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -60,18 +60,27 @@ export abstract class StandardApiProviderAdapterBase extends BasePlatformAdapter
|
||||
? options.resolveUrl(normalizedBaseUrl)
|
||||
: resolveVersionedModelsUrl(normalizedBaseUrl);
|
||||
|
||||
let payload: any;
|
||||
try {
|
||||
const payload = await this.fetchJson<any>(url, {
|
||||
payload = await this.fetchJson<any>(url, {
|
||||
headers: options.headers,
|
||||
});
|
||||
const rows = options.mapResponse
|
||||
? options.mapResponse(payload)
|
||||
: (payload?.data || []).map((item: any) => item?.id);
|
||||
return rows
|
||||
.map((item) => (typeof item === 'string' ? item.trim() : ''))
|
||||
.filter((item) => item.length > 0);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
|
||||
const rows = options.mapResponse
|
||||
? options.mapResponse(payload)
|
||||
: Array.isArray(payload?.data)
|
||||
? payload.data.map((item: any) => item?.id)
|
||||
: null;
|
||||
|
||||
if (!Array.isArray(rows)) {
|
||||
throw new Error('invalid standard models payload');
|
||||
}
|
||||
|
||||
return rows
|
||||
.map((item) => (typeof item === 'string' ? item.trim() : ''))
|
||||
.filter((item) => item.length > 0);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user