From 259a6e4f2b39afd8efc11dc6a1f33e4b70a884d8 Mon Sep 17 00:00:00 2001 From: Isabel Wu <231155141+wuisabel-gif@users.noreply.github.com> Date: Thu, 9 Jul 2026 19:04:58 -0700 Subject: [PATCH] fix(core): honor config requestOptions in ContinueServerClient Config-sync and index-cache requests used global fetch(), ignoring config.yaml requestOptions (proxy, verifySsl, caBundlePath). Route them through fetchwithRequestOptions like the LLM path already does. Fixes #12956 --- core/continueServer/stubs/client.ts | 68 +++++++++++++--------- core/continueServer/stubs/client.vitest.ts | 55 +++++++++++++++++ core/indexing/CodebaseIndexer.ts | 1 + 3 files changed, 98 insertions(+), 26 deletions(-) create mode 100644 core/continueServer/stubs/client.vitest.ts diff --git a/core/continueServer/stubs/client.ts b/core/continueServer/stubs/client.ts index febed8bbd48..904bfad6ae5 100644 --- a/core/continueServer/stubs/client.ts +++ b/core/continueServer/stubs/client.ts @@ -1,3 +1,6 @@ +import { fetchwithRequestOptions } from "@continuedev/fetch"; + +import type { RequestOptions } from "../../index.js"; import type { ArtifactType, EmbeddingsCacheResponse, @@ -10,6 +13,7 @@ export class ContinueServerClient implements IContinueServerClient { constructor( serverUrl: string | undefined, private readonly userToken: string | undefined, + private readonly requestOptions?: RequestOptions, ) { try { this.url = @@ -32,18 +36,22 @@ export class ContinueServerClient implements IContinueServerClient { public async getConfig(): Promise<{ configJson: string }> { const userToken = await this.userToken; - const response = await fetch(new URL("sync", this.url).href, { - method: "GET", - headers: { - Authorization: `Bearer ${userToken}`, + const response = await fetchwithRequestOptions( + new URL("sync", this.url), + { + method: "GET", + headers: { + Authorization: `Bearer ${userToken}`, + }, }, - }); + this.requestOptions, + ); if (!response.ok) { throw new Error( `Failed to sync remote config (HTTP ${response.status}): ${response.statusText}`, ); } - const data = await response.json(); + const data = (await response.json()) as { configJson: string }; return data; } @@ -66,17 +74,21 @@ export class ContinueServerClient implements IContinueServerClient { const url = new URL("indexing/cache", this.url); try { - const response = await fetch(url, { - method: "POST", - headers: { - Authorization: `Bearer ${await this.userToken}`, + const response = await fetchwithRequestOptions( + url, + { + method: "POST", + headers: { + Authorization: `Bearer ${await this.userToken}`, + }, + body: JSON.stringify({ + keys, + artifactId, + repo: repoName ?? "NONE", + }), }, - body: JSON.stringify({ - keys, - artifactId, - repo: repoName ?? "NONE", - }), - }); + this.requestOptions, + ); if (!response.ok) { const text = await response.text(); @@ -88,7 +100,7 @@ export class ContinueServerClient implements IContinueServerClient { }; } - const data = await response.json(); + const data = (await response.json()) as EmbeddingsCacheResponse; return data; } catch (e) { console.warn("Failed to retrieve from remote cache", e); @@ -105,15 +117,19 @@ export class ContinueServerClient implements IContinueServerClient { const url = new URL("feedback", this.url); - const response = await fetch(url, { - method: "POST", - headers: { - Authorization: `Bearer ${await this.userToken}`, + const response = await fetchwithRequestOptions( + url, + { + method: "POST", + headers: { + Authorization: `Bearer ${await this.userToken}`, + }, + body: JSON.stringify({ + feedback, + data, + }), }, - body: JSON.stringify({ - feedback, - data, - }), - }); + this.requestOptions, + ); } } diff --git a/core/continueServer/stubs/client.vitest.ts b/core/continueServer/stubs/client.vitest.ts new file mode 100644 index 00000000000..87f74537785 --- /dev/null +++ b/core/continueServer/stubs/client.vitest.ts @@ -0,0 +1,55 @@ +import { fetchwithRequestOptions } from "@continuedev/fetch"; +import { beforeEach, expect, test, vi } from "vitest"; +import type { RequestOptions } from "../../index.js"; +import { ContinueServerClient } from "./client.js"; + +vi.mock("@continuedev/fetch"); + +const requestOptions: RequestOptions = { + proxy: "http://proxy.example.com:8080", + verifySsl: false, +}; + +beforeEach(() => { + vi.mocked(fetchwithRequestOptions).mockResolvedValue({ + ok: true, + json: async () => ({ configJson: "{}" }), + } as any); +}); + +test("getConfig forwards requestOptions to the fetch layer", async () => { + const client = new ContinueServerClient( + "https://server.example.com", + "token", + requestOptions, + ); + + await client.getConfig(); + + expect(fetchwithRequestOptions).toHaveBeenCalledWith( + expect.any(URL), + expect.objectContaining({ method: "GET" }), + requestOptions, + ); +}); + +test("getFromIndexCache forwards requestOptions to the fetch layer", async () => { + vi.mocked(fetchwithRequestOptions).mockResolvedValue({ + ok: true, + json: async () => ({ files: {} }), + } as any); + + const client = new ContinueServerClient( + "https://server.example.com", + "token", + requestOptions, + ); + + await client.getFromIndexCache(["key"], "embeddings" as any, "repo"); + + expect(fetchwithRequestOptions).toHaveBeenCalledWith( + expect.any(URL), + expect.objectContaining({ method: "POST" }), + requestOptions, + ); +}); diff --git a/core/indexing/CodebaseIndexer.ts b/core/indexing/CodebaseIndexer.ts index c37992f98cd..8abab6c3d87 100644 --- a/core/indexing/CodebaseIndexer.ts +++ b/core/indexing/CodebaseIndexer.ts @@ -161,6 +161,7 @@ export class CodebaseIndexer { const continueServerClient = new ContinueServerClient( ideSettings.remoteConfigServerUrl, ideSettings.userToken, + config.requestOptions, ); if (!continueServerClient) { return [];