mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-23 20:26:28 +00:00
refactor(ui): route behavior-preserving networking calls through apiClient (#29806)
* refactor(ui): route callbacks/nudges calls through apiClient * refactor(ui): route alerting + key/user/team delete calls through apiClient * fix(ui): late-bind fetch in apiClient so global.fetch swaps take effect createApiClient captured fetch at construction time, so reassigning global.fetch (as tests do) had no effect and a real network call leaked. Resolve fetch per request instead; harmless in production where fetch is never swapped, and required for apiClient-based calls to be testable. * refactor(ui): route behavior-preserving networking calls through apiClient Collapse ~61 hand-rolled fetch() calls whose semantics already match the shared apiClient (auth header, JSON body, json-error + deriveErrorMessage + handleError) into apiClient.get/post/etc. Query-string builders and the divergent error-handling functions (no-check, custom messages, text-error) are intentionally left for a follow-up normalization pass, since converting them changes wire encoding or error behavior. Prunes the now-stale no-restricted-syntax suppressions for the removed fetch calls. * refactor(ui): convert remaining admin/guardrail GETs, guard late-bind fetch Routes adminspendByProvider, adminGlobalActivity, and the three guardrail submission calls (list/approve/reject) through apiClient so they match their already-converted siblings instead of staying on raw fetch. Adds a client.test.ts case that swaps globalThis.fetch after createApiClient() and asserts the swap takes effect, which fails on the pre-fix captured-fetch line and locks in the per-call resolution
This commit is contained in:
@@ -1504,7 +1504,7 @@
|
||||
"count": 23
|
||||
},
|
||||
"no-restricted-syntax": {
|
||||
"count": 241
|
||||
"count": 175
|
||||
}
|
||||
},
|
||||
"src/components/object_permissions_view.tsx": {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -85,4 +85,19 @@ describe("createApiClient", () => {
|
||||
const [, init] = fetchImpl.mock.calls[0];
|
||||
expect(init.headers).toEqual({ "Content-Type": "application/json" });
|
||||
});
|
||||
|
||||
it("resolves the global fetch per call, so a swap after construction takes effect", async () => {
|
||||
const client = createApiClient({ getBaseUrl: () => "" });
|
||||
|
||||
const original = globalThis.fetch;
|
||||
const swapped = vi.fn(async () => okResponse({ swapped: true }));
|
||||
globalThis.fetch = swapped as unknown as typeof fetch;
|
||||
try {
|
||||
const result = await client.get("/ping", { accessToken: "sk" });
|
||||
expect(result).toEqual({ swapped: true });
|
||||
expect(swapped).toHaveBeenCalledTimes(1);
|
||||
} finally {
|
||||
globalThis.fetch = original;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -98,7 +98,7 @@ const appendQuery = (url: string, query: QueryParams | undefined): string => {
|
||||
|
||||
export function createApiClient(config: ApiClientConfig): ApiClient {
|
||||
const { getBaseUrl, getAuthHeaderName, onError, fetchImpl } = config;
|
||||
const doFetch = fetchImpl ?? fetch;
|
||||
const doFetch: typeof fetch = (input, init) => (fetchImpl ?? fetch)(input, init);
|
||||
|
||||
async function request<T = any>(method: HttpMethod, path: string, options: RequestOptions = {}): Promise<T> {
|
||||
const { accessToken, body, rawBody, query, headers: extraHeaders, signal } = options;
|
||||
|
||||
Reference in New Issue
Block a user