From 36c7261f9274d1d9aec56b4ddb480589007e8956 Mon Sep 17 00:00:00 2001 From: Nezumi-2711 Date: Sat, 15 Aug 2026 12:26:15 +0700 Subject: [PATCH] fix: CORS issues --- src/services/modelService.test.ts | 50 +++++++++++++++++++++++++++++++ src/services/modelService.ts | 49 ++++++++++++++++++++++++------ 2 files changed, 90 insertions(+), 9 deletions(-) create mode 100644 src/services/modelService.test.ts diff --git a/src/services/modelService.test.ts b/src/services/modelService.test.ts new file mode 100644 index 0000000..287dbbb --- /dev/null +++ b/src/services/modelService.test.ts @@ -0,0 +1,50 @@ +import { describe, it, expect, mock } from 'bun:test' +import { fetchRemoteModels } from './modelService' + +describe('fetchRemoteModels', () => { + it('fetches models using Authorization header when supported', async () => { + const mockFetch = mock(() => { + return Promise.resolve(new Response(JSON.stringify({ + data: [{ id: 'cx/gpt-5.6-sol', owned_by: 'cx' }] + }), { status: 200 })) + }) + globalThis.fetch = mockFetch as unknown as typeof fetch + + const models = await fetchRemoteModels({ + baseUrl: 'https://gateway.example.com/v1', + apiKey: 'sk-test-key' + }) + + expect(models.length).toBe(1) + expect(models[0].id).toBe('cx/gpt-5.6-sol') + expect(models[0].provider).toBe('Codex / OpenAI') + }) + + it('falls back to key query param when preflight / Authorization header fails with CORS', async () => { + let callCount = 0 + const mockFetch = mock((url: string | URL | Request) => { + callCount++ + const urlStr = url.toString() + if (callCount === 1) { + // First attempt with Authorization header throws network/CORS TypeError + return Promise.reject(new TypeError('Failed to fetch')) + } + if (urlStr.includes('key=sk-test-key')) { + return Promise.resolve(new Response(JSON.stringify({ + data: [{ id: 'cx/gpt-5.6-sol', owned_by: 'cx' }] + }), { status: 200 })) + } + return Promise.reject(new Error('Unexpected call')) + }) + globalThis.fetch = mockFetch as unknown as typeof fetch + + const models = await fetchRemoteModels({ + baseUrl: 'https://gateway.example.com/v1', + apiKey: 'sk-test-key' + }) + + expect(models.length).toBe(1) + expect(models[0].id).toBe('cx/gpt-5.6-sol') + expect(callCount).toBe(2) + }) +}) diff --git a/src/services/modelService.ts b/src/services/modelService.ts index 9f8a6b0..93925e8 100644 --- a/src/services/modelService.ts +++ b/src/services/modelService.ts @@ -61,13 +61,15 @@ export async function fetchRemoteModels(connection: ConnectionConfig): Promise = { Accept: 'application/json', } - if (connection.apiKey?.trim()) { - headers['Authorization'] = `Bearer ${connection.apiKey.trim()}` + if (apiKey) { + headers['Authorization'] = `Bearer ${apiKey}` } const directRes = await fetch(`${trimmedBase}/models`, { @@ -79,12 +81,41 @@ export async function fetchRemoteModels(connection: ConnectionConfig): Promise