diff --git a/src/cliproxy/quota-fetcher-gemini-cli.ts b/src/cliproxy/quota-fetcher-gemini-cli.ts index 33aaec41..0ec6afef 100644 --- a/src/cliproxy/quota-fetcher-gemini-cli.ts +++ b/src/cliproxy/quota-fetcher-gemini-cli.ts @@ -639,6 +639,11 @@ async function fetchWithAuthData( const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 5000); + const supplementaryPromise = fetchGeminiCliSupplementary( + authData.accessToken, + authData.projectId, + verbose + ); try { const response = await fetch(GEMINI_CLI_QUOTA_URL, { @@ -668,11 +673,7 @@ async function fetchWithAuthData( const data = (await response.json()) as GeminiCliQuotaResponse; const rawBuckets = data.buckets || []; const buckets = buildGeminiCliBuckets(rawBuckets); - const supplementary = await fetchGeminiCliSupplementary( - authData.accessToken, - authData.projectId, - verbose - ); + const supplementary = await supplementaryPromise; if (verbose) console.error(`[i] Gemini CLI buckets found: ${buckets.length}`); diff --git a/tests/unit/cliproxy/quota-fetcher-gemini-cli.test.ts b/tests/unit/cliproxy/quota-fetcher-gemini-cli.test.ts index 10574df0..8c2d1b18 100644 --- a/tests/unit/cliproxy/quota-fetcher-gemini-cli.test.ts +++ b/tests/unit/cliproxy/quota-fetcher-gemini-cli.test.ts @@ -448,6 +448,43 @@ describe('Gemini CLI Quota Fetcher', () => { expect(result.creditBalance).toBeNull(); expect(result.buckets[0].remainingPercent).toBe(75); }); + + it('keeps base quota success when supplementary metadata throws a network error', async () => { + writeActiveGeminiAccount('supplementary-network@example.com'); + + mockFetch([ + { + url: GEMINI_QUOTA_URL, + method: 'POST', + status: 200, + response: { + buckets: [{ model_id: 'gemini-3-flash-preview', remaining_fraction: 0.75 }], + }, + }, + ]); + + const mockedFetch = globalThis.fetch; + globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => { + const url = + typeof input === 'string' ? input : input instanceof URL ? input.href : input.url; + if (url === GEMINI_CODE_ASSIST_URL) { + throw new TypeError('supplementary network down'); + } + return mockedFetch(input, init); + }) as typeof fetch; + + try { + const result = await fetchGeminiCliQuota('supplementary-network@example.com'); + + expect(result.success).toBe(true); + expect(result.tierLabel).toBeNull(); + expect(result.tierId).toBeNull(); + expect(result.creditBalance).toBeNull(); + expect(result.buckets[0].remainingPercent).toBe(75); + } finally { + globalThis.fetch = mockedFetch; + } + }); }); describe('fetchGeminiCliQuota failure metadata', () => {