From 3f21cb8a2f34dc2d11c8ca450bdb72d4cdaa155d Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Wed, 24 Apr 2024 13:01:23 -0400 Subject: [PATCH] fix: update API code to use Axios instances (#13029) * fix: update API code to use Axios instance * docs: fix typo * fix: update all global axios imports to use Coder instance * fix: remove needless import * fix: update import order * refactor: rename coderAxiosInstance to axiosInstance * docs: update variable reference in FE contributing docs --- docs/contributing/frontend.md | 2 +- site/e2e/helpers.ts | 4 +- site/e2e/reporter.ts | 5 +- site/src/api/api.test.ts | 22 +- site/src/api/api.ts | 386 +++++++++++++++---------- site/src/api/errors.ts | 4 +- site/src/contexts/auth/RequireAuth.tsx | 9 +- site/src/contexts/useProxyLatency.ts | 4 +- 8 files changed, 259 insertions(+), 177 deletions(-) diff --git a/docs/contributing/frontend.md b/docs/contributing/frontend.md index e24fadf8f5..2644c22193 100644 --- a/docs/contributing/frontend.md +++ b/docs/contributing/frontend.md @@ -152,7 +152,7 @@ example below: export const getAgentListeningPorts = async ( agentID: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/workspaceagents/${agentID}/listening-ports`, ); return response.data; diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index 26e416cad7..1c5349fbf5 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -1,5 +1,4 @@ import { type BrowserContext, expect, type Page, test } from "@playwright/test"; -import axios from "axios"; import { type ChildProcess, exec, spawn } from "child_process"; import { randomUUID } from "crypto"; import express from "express"; @@ -7,6 +6,7 @@ import capitalize from "lodash/capitalize"; import path from "path"; import * as ssh from "ssh2"; import { Duplex } from "stream"; +import { axiosInstance } from "api/api"; import type { WorkspaceBuildParameter, UpdateTemplateMeta, @@ -398,7 +398,7 @@ export const waitUntilUrlIsNotResponding = async (url: string) => { while (retries < maxRetries) { try { - await axios.get(url); + await axiosInstance.get(url); } catch (error) { return; } diff --git a/site/e2e/reporter.ts b/site/e2e/reporter.ts index fe214d8aed..f981dede78 100644 --- a/site/e2e/reporter.ts +++ b/site/e2e/reporter.ts @@ -8,9 +8,9 @@ import type { Reporter, TestError, } from "@playwright/test/reporter"; -import axios from "axios"; import * as fs from "fs/promises"; import type { Writable } from "stream"; +import { axiosInstance } from "api/api"; import { coderdPProfPort, enterpriseLicense } from "./constants"; class CoderReporter implements Reporter { @@ -136,9 +136,10 @@ class CoderReporter implements Reporter { const logLines = (chunk: string): string[] => chunk.trimEnd().split("\n"); const exportDebugPprof = async (outputFile: string) => { - const response = await axios.get( + const response = await axiosInstance.get( `http://127.0.0.1:${coderdPProfPort}/debug/pprof/goroutine?debug=1`, ); + if (response.status !== 200) { throw new Error(`Error: Received status code ${response.status}`); } diff --git a/site/src/api/api.test.ts b/site/src/api/api.test.ts index e755d241cb..1861530668 100644 --- a/site/src/api/api.test.ts +++ b/site/src/api/api.test.ts @@ -1,4 +1,3 @@ -import axios from "axios"; import { MockTemplate, MockTemplateVersionParameter1, @@ -8,6 +7,7 @@ import { MockWorkspaceBuildParameter1, } from "testHelpers/entities"; import * as api from "./api"; +import { axiosInstance } from "./api"; import type * as TypesGen from "./typesGenerated"; describe("api.ts", () => { @@ -17,13 +17,16 @@ describe("api.ts", () => { const loginResponse: TypesGen.LoginWithPasswordResponse = { session_token: "abc_123_test", }; - jest.spyOn(axios, "post").mockResolvedValueOnce({ data: loginResponse }); + + jest + .spyOn(axiosInstance, "post") + .mockResolvedValueOnce({ data: loginResponse }); // when const result = await api.login("test", "123"); // then - expect(axios.post).toHaveBeenCalled(); + expect(axiosInstance.post).toHaveBeenCalled(); expect(result).toStrictEqual(loginResponse); }); @@ -38,7 +41,7 @@ describe("api.ts", () => { const axiosMockPost = jest.fn().mockImplementationOnce(() => { return Promise.reject(expectedError); }); - axios.post = axiosMockPost; + axiosInstance.post = axiosMockPost; try { await api.login("test", "123"); @@ -54,7 +57,7 @@ describe("api.ts", () => { const axiosMockPost = jest.fn().mockImplementationOnce(() => { return Promise.resolve(); }); - axios.post = axiosMockPost; + axiosInstance.post = axiosMockPost; // when await api.logout(); @@ -73,7 +76,8 @@ describe("api.ts", () => { const axiosMockPost = jest.fn().mockImplementationOnce(() => { return Promise.reject(expectedError); }); - axios.post = axiosMockPost; + + axiosInstance.post = axiosMockPost; try { await api.logout(); @@ -92,7 +96,8 @@ describe("api.ts", () => { const axiosMockPost = jest.fn().mockImplementationOnce(() => { return Promise.resolve({ data: apiKeyResponse }); }); - axios.post = axiosMockPost; + + axiosInstance.post = axiosMockPost; // when const result = await api.getApiKey(); @@ -112,7 +117,8 @@ describe("api.ts", () => { const axiosMockPost = jest.fn().mockImplementationOnce(() => { return Promise.reject(expectedError); }); - axios.post = axiosMockPost; + + axiosInstance.post = axiosMockPost; try { await api.getApiKey(); diff --git a/site/src/api/api.ts b/site/src/api/api.ts index a243123a31..6b4102073b 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -1,20 +1,36 @@ /** - * @fileoverview This file is imported externally by things like vscode-coder so - * it must not import anything using aliases otherwise it will break when being - * imported by those external consumers. For example, `utils/delay` must be - * imported using `../utils/delay` instead. + * @file Coder is starting to import the Coder API file into more and more + * external projects, as a "pseudo-SDK". We are not at a stage where we are + * ready to commit to maintaining a public SDK, but we need equivalent + * functionality in other places. + * + * Message somebody from Team Blueberry if you need more context, but so far, + * these projects are importing the file: + * + * - The Coder VS Code extension + * @see {@link https://github.com/coder/vscode-coder} + * - The Coder Backstage plugin + * @see {@link https://github.com/coder/backstage-plugins} + * + * It is important that this file not do any aliased imports, or else the other + * consumers could break (particularly for platforms that limit how much you can + * touch their configuration files, like Backstage). Relative imports are still + * safe, though. + * + * For example, `utils/delay` must be imported using `../utils/delay` instead. */ - -import axios, { isAxiosError } from "axios"; +import globalAxios, { isAxiosError } from "axios"; import type dayjs from "dayjs"; import userAgentParser from "ua-parser-js"; import { delay } from "../utils/delay"; import * as TypesGen from "./typesGenerated"; +export const axiosInstance = globalAxios.create(); + // Adds 304 for the default axios validateStatus function // https://github.com/axios/axios#handling-errors Check status here // https://httpstatusdogs.com/ -axios.defaults.validateStatus = (status) => { +axiosInstance.defaults.validateStatus = (status) => { return (status >= 200 && status < 300) || status === 304; }; @@ -27,7 +43,7 @@ export const hardCodedCSRFCookie = (): string => { // "JXm9hOUdZctWt0ZZGAy9xiS/gxMKYOThdxjjMnMUyn4=" const csrfToken = "KNKvagCBEHZK7ihe2t7fj6VeJ0UyTDco1yVUJE8N06oNqxLu5Zx1vRxZbgfC0mJJgeGkVjgs08mgPbcWPBkZ1A=="; - axios.defaults.headers.common["X-CSRF-TOKEN"] = csrfToken; + axiosInstance.defaults.headers.common["X-CSRF-TOKEN"] = csrfToken; return csrfToken; }; @@ -59,10 +75,11 @@ const token = if (token !== null && token.getAttribute("content") !== null) { if (process.env.NODE_ENV === "development") { // Development mode uses a hard-coded CSRF token - axios.defaults.headers.common["X-CSRF-TOKEN"] = hardCodedCSRFCookie(); + axiosInstance.defaults.headers.common["X-CSRF-TOKEN"] = + hardCodedCSRFCookie(); token.setAttribute("content", hardCodedCSRFCookie()); } else { - axios.defaults.headers.common["X-CSRF-TOKEN"] = + axiosInstance.defaults.headers.common["X-CSRF-TOKEN"] = token.getAttribute("content") ?? ""; } } else { @@ -73,11 +90,11 @@ if (token !== null && token.getAttribute("content") !== null) { } export const setSessionToken = (token: string) => { - axios.defaults.headers.common["Coder-Session-Token"] = token; + axiosInstance.defaults.headers.common["Coder-Session-Token"] = token; }; export const setHost = (host?: string) => { - axios.defaults.baseURL = host; + axiosInstance.defaults.baseURL = host; }; const CONTENT_TYPE_JSON = { @@ -114,7 +131,7 @@ export const login = async ( password, }); - const response = await axios.post( + const response = await axiosInstance.post( "/api/v2/users/login", payload, { @@ -126,7 +143,7 @@ export const login = async ( }; export const convertToOAUTH = async (request: TypesGen.ConvertLoginRequest) => { - const response = await axios.post( + const response = await axiosInstance.post( "/api/v2/users/me/convert-login", request, ); @@ -134,30 +151,30 @@ export const convertToOAUTH = async (request: TypesGen.ConvertLoginRequest) => { }; export const logout = async (): Promise => { - await axios.post("/api/v2/users/logout"); + await axiosInstance.post("/api/v2/users/logout"); }; export const getAuthenticatedUser = async () => { - const response = await axios.get("/api/v2/users/me"); + const response = await axiosInstance.get("/api/v2/users/me"); return response.data; }; export const getUserParameters = async (templateID: string) => { - const response = await axios.get( + const response = await axiosInstance.get( "/api/v2/users/me/autofill-parameters?template_id=" + templateID, ); return response.data; }; export const getAuthMethods = async (): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( "/api/v2/users/authmethods", ); return response.data; }; export const getUserLoginType = async (): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( "/api/v2/users/me/login-type", ); return response.data; @@ -166,7 +183,7 @@ export const getUserLoginType = async (): Promise => { export const checkAuthorization = async ( params: TypesGen.AuthorizationRequest, ): Promise => { - const response = await axios.post( + const response = await axiosInstance.post( `/api/v2/authcheck`, params, ); @@ -174,7 +191,7 @@ export const checkAuthorization = async ( }; export const getApiKey = async (): Promise => { - const response = await axios.post( + const response = await axiosInstance.post( "/api/v2/users/me/keys", ); return response.data; @@ -183,7 +200,7 @@ export const getApiKey = async (): Promise => { export const getTokens = async ( params: TypesGen.TokensFilter, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/users/me/keys/tokens`, { params, @@ -193,18 +210,23 @@ export const getTokens = async ( }; export const deleteToken = async (keyId: string): Promise => { - await axios.delete("/api/v2/users/me/keys/" + keyId); + await axiosInstance.delete("/api/v2/users/me/keys/" + keyId); }; export const createToken = async ( params: TypesGen.CreateTokenRequest, ): Promise => { - const response = await axios.post(`/api/v2/users/me/keys/tokens`, params); + const response = await axiosInstance.post( + `/api/v2/users/me/keys/tokens`, + params, + ); return response.data; }; export const getTokenConfig = async (): Promise => { - const response = await axios.get("/api/v2/users/me/keys/tokens/tokenconfig"); + const response = await axiosInstance.get( + "/api/v2/users/me/keys/tokens/tokenconfig", + ); return response.data; }; @@ -213,23 +235,26 @@ export const getUsers = async ( signal?: AbortSignal, ): Promise => { const url = getURLWithSearchParams("/api/v2/users", options); - const response = await axios.get(url.toString(), { - signal, - }); + const response = await axiosInstance.get( + url.toString(), + { + signal, + }, + ); return response.data; }; export const getOrganization = async ( organizationId: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/organizations/${organizationId}`, ); return response.data; }; export const getOrganizations = async (): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( "/api/v2/users/me/organizations", ); return response.data; @@ -238,7 +263,7 @@ export const getOrganizations = async (): Promise => { export const getTemplate = async ( templateId: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/templates/${templateId}`, ); return response.data; @@ -260,7 +285,7 @@ export const getTemplates = async ( params["deprecated"] = String(options.deprecated); } - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/organizations/${organizationId}/templates`, { params, @@ -273,7 +298,7 @@ export const getTemplateByName = async ( organizationId: string, name: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/organizations/${organizationId}/templates/${name}`, ); return response.data; @@ -282,7 +307,7 @@ export const getTemplateByName = async ( export const getTemplateVersion = async ( versionId: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/templateversions/${versionId}`, ); return response.data; @@ -291,7 +316,7 @@ export const getTemplateVersion = async ( export const getTemplateVersionResources = async ( versionId: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/templateversions/${versionId}/resources`, ); return response.data; @@ -300,7 +325,7 @@ export const getTemplateVersionResources = async ( export const getTemplateVersionVariables = async ( versionId: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/templateversions/${versionId}/variables`, ); return response.data; @@ -309,7 +334,7 @@ export const getTemplateVersionVariables = async ( export const getTemplateVersions = async ( templateId: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/templates/${templateId}/versions`, ); return response.data; @@ -320,7 +345,7 @@ export const getTemplateVersionByName = async ( templateName: string, versionName: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/organizations/${organizationId}/templates/${templateName}/versions/${versionName}`, ); return response.data; @@ -336,7 +361,7 @@ export const getPreviousTemplateVersionByName = async ( versionName: string, ) => { try { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/organizations/${organizationId}/templates/${templateName}/versions/${versionName}/previous`, ); return response.data; @@ -344,7 +369,7 @@ export const getPreviousTemplateVersionByName = async ( // When there is no previous version, like the first version of a template, // the API returns 404 so in this case we can safely return undefined if ( - axios.isAxiosError(error) && + isAxiosError(error) && error.response && error.response.status === 404 ) { @@ -359,7 +384,7 @@ export const createTemplateVersion = async ( organizationId: string, data: TypesGen.CreateTemplateVersionRequest, ): Promise => { - const response = await axios.post( + const response = await axiosInstance.post( `/api/v2/organizations/${organizationId}/templateversions`, data, ); @@ -369,7 +394,7 @@ export const createTemplateVersion = async ( export const getTemplateVersionExternalAuth = async ( versionId: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/templateversions/${versionId}/external-auth`, ); return response.data; @@ -378,7 +403,7 @@ export const getTemplateVersionExternalAuth = async ( export const getTemplateVersionRichParameters = async ( versionId: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/templateversions/${versionId}/rich-parameters`, ); return response.data; @@ -388,7 +413,7 @@ export const createTemplate = async ( organizationId: string, data: TypesGen.CreateTemplateRequest, ): Promise => { - const response = await axios.post( + const response = await axiosInstance.post( `/api/v2/organizations/${organizationId}/templates`, data, ); @@ -399,7 +424,7 @@ export const updateActiveTemplateVersion = async ( templateId: string, data: TypesGen.UpdateActiveTemplateVersion, ) => { - const response = await axios.patch( + const response = await axiosInstance.patch( `/api/v2/templates/${templateId}/versions`, data, ); @@ -410,7 +435,7 @@ export const patchTemplateVersion = async ( templateVersionId: string, data: TypesGen.PatchTemplateVersionRequest, ) => { - const response = await axios.patch( + const response = await axiosInstance.patch( `/api/v2/templateversions/${templateVersionId}`, data, ); @@ -418,14 +443,14 @@ export const patchTemplateVersion = async ( }; export const archiveTemplateVersion = async (templateVersionId: string) => { - const response = await axios.post( + const response = await axiosInstance.post( `/api/v2/templateversions/${templateVersionId}/archive`, ); return response.data; }; export const unarchiveTemplateVersion = async (templateVersionId: string) => { - const response = await axios.post( + const response = await axiosInstance.post( `/api/v2/templateversions/${templateVersionId}/unarchive`, ); return response.data; @@ -435,7 +460,7 @@ export const updateTemplateMeta = async ( templateId: string, data: TypesGen.UpdateTemplateMeta, ): Promise => { - const response = await axios.patch( + const response = await axiosInstance.patch( `/api/v2/templates/${templateId}`, data, ); @@ -450,7 +475,7 @@ export const updateTemplateMeta = async ( export const deleteTemplate = async ( templateId: string, ): Promise => { - const response = await axios.delete( + const response = await axiosInstance.delete( `/api/v2/templates/${templateId}`, ); return response.data; @@ -460,7 +485,7 @@ export const getWorkspace = async ( workspaceId: string, params?: TypesGen.WorkspaceOptions, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/workspaces/${workspaceId}`, { params, @@ -509,7 +534,7 @@ export const getWorkspaces = async ( options: TypesGen.WorkspacesRequest, ): Promise => { const url = getURLWithSearchParams("/api/v2/workspaces", options); - const response = await axios.get(url); + const response = await axiosInstance.get(url); return response.data; }; @@ -518,7 +543,7 @@ export const getWorkspaceByOwnerAndName = async ( workspaceName: string, params?: TypesGen.WorkspaceOptions, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/users/${username}/workspace/${workspaceName}`, { params, @@ -560,7 +585,7 @@ export const postWorkspaceBuild = async ( workspaceId: string, data: TypesGen.CreateWorkspaceBuildRequest, ): Promise => { - const response = await axios.post( + const response = await axiosInstance.post( `/api/v2/workspaces/${workspaceId}/builds`, data, ); @@ -605,7 +630,7 @@ export const deleteWorkspace = ( export const cancelWorkspaceBuild = async ( workspaceBuildId: TypesGen.WorkspaceBuild["id"], ): Promise => { - const response = await axios.patch( + const response = await axiosInstance.patch( `/api/v2/workspacebuilds/${workspaceBuildId}/cancel`, ); return response.data; @@ -619,7 +644,7 @@ export const updateWorkspaceDormancy = async ( dormant: dormant, }; - const response = await axios.put( + const response = await axiosInstance.put( `/api/v2/workspaces/${workspaceId}/dormant`, data, ); @@ -634,7 +659,7 @@ export const updateWorkspaceAutomaticUpdates = async ( automatic_updates: automaticUpdates, }; - const response = await axios.put( + const response = await axiosInstance.put( `/api/v2/workspaces/${workspaceId}/autoupdates`, req, ); @@ -668,7 +693,7 @@ export const restartWorkspace = async ({ export const cancelTemplateVersionBuild = async ( templateVersionId: TypesGen.TemplateVersion["id"], ): Promise => { - const response = await axios.patch( + const response = await axiosInstance.patch( `/api/v2/templateversions/${templateVersionId}/cancel`, ); return response.data; @@ -677,7 +702,10 @@ export const cancelTemplateVersionBuild = async ( export const createUser = async ( user: TypesGen.CreateUserRequest, ): Promise => { - const response = await axios.post("/api/v2/users", user); + const response = await axiosInstance.post( + "/api/v2/users", + user, + ); return response.data; }; @@ -686,7 +714,7 @@ export const createWorkspace = async ( userId = "me", workspace: TypesGen.CreateWorkspaceRequest, ): Promise => { - const response = await axios.post( + const response = await axiosInstance.post( `/api/v2/organizations/${organizationId}/members/${userId}/workspaces`, workspace, ); @@ -697,17 +725,17 @@ export const patchWorkspace = async ( workspaceId: string, data: TypesGen.UpdateWorkspaceRequest, ) => { - await axios.patch(`/api/v2/workspaces/${workspaceId}`, data); + await axiosInstance.patch(`/api/v2/workspaces/${workspaceId}`, data); }; export const getBuildInfo = async (): Promise => { - const response = await axios.get("/api/v2/buildinfo"); + const response = await axiosInstance.get("/api/v2/buildinfo"); return response.data; }; export const getUpdateCheck = async (): Promise => { - const response = await axios.get("/api/v2/updatecheck"); + const response = await axiosInstance.get("/api/v2/updatecheck"); return response.data; }; @@ -716,9 +744,13 @@ export const putWorkspaceAutostart = async ( autostart: TypesGen.UpdateWorkspaceAutostartRequest, ): Promise => { const payload = JSON.stringify(autostart); - await axios.put(`/api/v2/workspaces/${workspaceID}/autostart`, payload, { - headers: { ...CONTENT_TYPE_JSON }, - }); + await axiosInstance.put( + `/api/v2/workspaces/${workspaceID}/autostart`, + payload, + { + headers: { ...CONTENT_TYPE_JSON }, + }, + ); }; export const putWorkspaceAutostop = async ( @@ -726,7 +758,7 @@ export const putWorkspaceAutostop = async ( ttl: TypesGen.UpdateWorkspaceTTLRequest, ): Promise => { const payload = JSON.stringify(ttl); - await axios.put(`/api/v2/workspaces/${workspaceID}/ttl`, payload, { + await axiosInstance.put(`/api/v2/workspaces/${workspaceID}/ttl`, payload, { headers: { ...CONTENT_TYPE_JSON }, }); }; @@ -735,7 +767,10 @@ export const updateProfile = async ( userId: string, data: TypesGen.UpdateUserProfileRequest, ): Promise => { - const response = await axios.put(`/api/v2/users/${userId}/profile`, data); + const response = await axiosInstance.put( + `/api/v2/users/${userId}/profile`, + data, + ); return response.data; }; @@ -743,14 +778,19 @@ export const updateAppearanceSettings = async ( userId: string, data: TypesGen.UpdateUserAppearanceSettingsRequest, ): Promise => { - const response = await axios.put(`/api/v2/users/${userId}/appearance`, data); + const response = await axiosInstance.put( + `/api/v2/users/${userId}/appearance`, + data, + ); return response.data; }; export const getUserQuietHoursSchedule = async ( userId: TypesGen.User["id"], ): Promise => { - const response = await axios.get(`/api/v2/users/${userId}/quiet-hours`); + const response = await axiosInstance.get( + `/api/v2/users/${userId}/quiet-hours`, + ); return response.data; }; @@ -758,14 +798,17 @@ export const updateUserQuietHoursSchedule = async ( userId: TypesGen.User["id"], data: TypesGen.UpdateUserQuietHoursScheduleRequest, ): Promise => { - const response = await axios.put(`/api/v2/users/${userId}/quiet-hours`, data); + const response = await axiosInstance.put( + `/api/v2/users/${userId}/quiet-hours`, + data, + ); return response.data; }; export const activateUser = async ( userId: TypesGen.User["id"], ): Promise => { - const response = await axios.put( + const response = await axiosInstance.put( `/api/v2/users/${userId}/status/activate`, ); return response.data; @@ -774,7 +817,7 @@ export const activateUser = async ( export const suspendUser = async ( userId: TypesGen.User["id"], ): Promise => { - const response = await axios.put( + const response = await axiosInstance.put( `/api/v2/users/${userId}/status/suspend`, ); return response.data; @@ -783,7 +826,7 @@ export const suspendUser = async ( export const deleteUser = async ( userId: TypesGen.User["id"], ): Promise => { - return await axios.delete(`/api/v2/users/${userId}`); + return await axiosInstance.delete(`/api/v2/users/${userId}`); }; // API definition: @@ -791,11 +834,11 @@ export const deleteUser = async ( export const hasFirstUser = async (): Promise => { try { // If it is success, it is true - await axios.get("/api/v2/users/first"); + await axiosInstance.get("/api/v2/users/first"); return true; } catch (error) { // If it returns a 404, it is false - if (axios.isAxiosError(error) && error.response?.status === 404) { + if (isAxiosError(error) && error.response?.status === 404) { return false; } @@ -806,7 +849,7 @@ export const hasFirstUser = async (): Promise => { export const createFirstUser = async ( req: TypesGen.CreateFirstUserRequest, ): Promise => { - const response = await axios.post(`/api/v2/users/first`, req); + const response = await axiosInstance.post(`/api/v2/users/first`, req); return response.data; }; @@ -814,11 +857,13 @@ export const updateUserPassword = async ( userId: TypesGen.User["id"], updatePassword: TypesGen.UpdateUserPasswordRequest, ): Promise => - axios.put(`/api/v2/users/${userId}/password`, updatePassword); + axiosInstance.put(`/api/v2/users/${userId}/password`, updatePassword); export const getRoles = async (): Promise> => { const response = - await axios.get>(`/api/v2/users/roles`); + await axiosInstance.get>( + `/api/v2/users/roles`, + ); return response.data; }; @@ -826,7 +871,7 @@ export const updateUserRoles = async ( roles: TypesGen.Role["name"][], userId: TypesGen.User["id"], ): Promise => { - const response = await axios.put( + const response = await axiosInstance.put( `/api/v2/users/${userId}/roles`, { roles }, ); @@ -836,7 +881,7 @@ export const updateUserRoles = async ( export const getUserSSHKey = async ( userId = "me", ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/users/${userId}/gitsshkey`, ); return response.data; @@ -845,7 +890,7 @@ export const getUserSSHKey = async ( export const regenerateUserSSHKey = async ( userId = "me", ): Promise => { - const response = await axios.put( + const response = await axiosInstance.put( `/api/v2/users/${userId}/gitsshkey`, ); return response.data; @@ -855,7 +900,7 @@ export const getWorkspaceBuilds = async ( workspaceId: string, req?: TypesGen.WorkspaceBuildsRequest, ) => { - const response = await axios.get( + const response = await axiosInstance.get( getURLWithSearchParams(`/api/v2/workspaces/${workspaceId}/builds`, req), ); return response.data; @@ -866,7 +911,7 @@ export const getWorkspaceBuildByNumber = async ( workspaceName: string, buildNumber: number, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/users/${username}/workspace/${workspaceName}/builds/${buildNumber}`, ); return response.data; @@ -876,7 +921,7 @@ export const getWorkspaceBuildLogs = async ( buildId: string, before: Date, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/workspacebuilds/${buildId}/logs?before=${before.getTime()}`, ); return response.data; @@ -885,7 +930,7 @@ export const getWorkspaceBuildLogs = async ( export const getWorkspaceAgentLogs = async ( agentID: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/workspaceagents/${agentID}/logs`, ); return response.data; @@ -895,21 +940,21 @@ export const putWorkspaceExtension = async ( workspaceId: string, newDeadline: dayjs.Dayjs, ): Promise => { - await axios.put(`/api/v2/workspaces/${workspaceId}/extend`, { + await axiosInstance.put(`/api/v2/workspaces/${workspaceId}/extend`, { deadline: newDeadline, }); }; export const refreshEntitlements = async (): Promise => { - await axios.post("/api/v2/licenses/refresh-entitlements"); + await axiosInstance.post("/api/v2/licenses/refresh-entitlements"); }; export const getEntitlements = async (): Promise => { try { - const response = await axios.get("/api/v2/entitlements"); + const response = await axiosInstance.get("/api/v2/entitlements"); return response.data; } catch (ex) { - if (axios.isAxiosError(ex) && ex.response?.status === 404) { + if (isAxiosError(ex) && ex.response?.status === 404) { return { errors: [], features: withDefaultFeatures({}), @@ -926,10 +971,10 @@ export const getEntitlements = async (): Promise => { export const getExperiments = async (): Promise => { try { - const response = await axios.get("/api/v2/experiments"); + const response = await axiosInstance.get("/api/v2/experiments"); return response.data; } catch (error) { - if (axios.isAxiosError(error) && error.response?.status === 404) { + if (isAxiosError(error) && error.response?.status === 404) { return []; } throw error; @@ -939,10 +984,10 @@ export const getExperiments = async (): Promise => { export const getAvailableExperiments = async (): Promise => { try { - const response = await axios.get("/api/v2/experiments/available"); + const response = await axiosInstance.get("/api/v2/experiments/available"); return response.data; } catch (error) { - if (axios.isAxiosError(error) && error.response?.status === 404) { + if (isAxiosError(error) && error.response?.status === 404) { return { safe: [] }; } throw error; @@ -952,14 +997,16 @@ export const getAvailableExperiments = export const getExternalAuthProvider = async ( provider: string, ): Promise => { - const resp = await axios.get(`/api/v2/external-auth/${provider}`); + const resp = await axiosInstance.get(`/api/v2/external-auth/${provider}`); return resp.data; }; export const getExternalAuthDevice = async ( provider: string, ): Promise => { - const resp = await axios.get(`/api/v2/external-auth/${provider}/device`); + const resp = await axiosInstance.get( + `/api/v2/external-auth/${provider}/device`, + ); return resp.data; }; @@ -967,7 +1014,7 @@ export const exchangeExternalAuthDevice = async ( provider: string, req: TypesGen.ExternalAuthDeviceExchange, ): Promise => { - const resp = await axios.post( + const resp = await axiosInstance.post( `/api/v2/external-auth/${provider}/device`, req, ); @@ -976,14 +1023,14 @@ export const exchangeExternalAuthDevice = async ( export const getUserExternalAuthProviders = async (): Promise => { - const resp = await axios.get(`/api/v2/external-auth`); + const resp = await axiosInstance.get(`/api/v2/external-auth`); return resp.data; }; export const unlinkExternalAuthProvider = async ( provider: string, ): Promise => { - const resp = await axios.delete(`/api/v2/external-auth/${provider}`); + const resp = await axiosInstance.delete(`/api/v2/external-auth/${provider}`); return resp.data; }; @@ -993,21 +1040,26 @@ export const getOAuth2ProviderApps = async ( const params = filter?.user_id ? new URLSearchParams({ user_id: filter.user_id }) : ""; - const resp = await axios.get(`/api/v2/oauth2-provider/apps?${params}`); + const resp = await axiosInstance.get( + `/api/v2/oauth2-provider/apps?${params}`, + ); return resp.data; }; export const getOAuth2ProviderApp = async ( id: string, ): Promise => { - const resp = await axios.get(`/api/v2/oauth2-provider/apps/${id}`); + const resp = await axiosInstance.get(`/api/v2/oauth2-provider/apps/${id}`); return resp.data; }; export const postOAuth2ProviderApp = async ( data: TypesGen.PostOAuth2ProviderAppRequest, ): Promise => { - const response = await axios.post(`/api/v2/oauth2-provider/apps`, data); + const response = await axiosInstance.post( + `/api/v2/oauth2-provider/apps`, + data, + ); return response.data; }; @@ -1015,25 +1067,32 @@ export const putOAuth2ProviderApp = async ( id: string, data: TypesGen.PutOAuth2ProviderAppRequest, ): Promise => { - const response = await axios.put(`/api/v2/oauth2-provider/apps/${id}`, data); + const response = await axiosInstance.put( + `/api/v2/oauth2-provider/apps/${id}`, + data, + ); return response.data; }; export const deleteOAuth2ProviderApp = async (id: string): Promise => { - await axios.delete(`/api/v2/oauth2-provider/apps/${id}`); + await axiosInstance.delete(`/api/v2/oauth2-provider/apps/${id}`); }; export const getOAuth2ProviderAppSecrets = async ( id: string, ): Promise => { - const resp = await axios.get(`/api/v2/oauth2-provider/apps/${id}/secrets`); + const resp = await axiosInstance.get( + `/api/v2/oauth2-provider/apps/${id}/secrets`, + ); return resp.data; }; export const postOAuth2ProviderAppSecret = async ( id: string, ): Promise => { - const resp = await axios.post(`/api/v2/oauth2-provider/apps/${id}/secrets`); + const resp = await axiosInstance.post( + `/api/v2/oauth2-provider/apps/${id}/secrets`, + ); return resp.data; }; @@ -1041,27 +1100,29 @@ export const deleteOAuth2ProviderAppSecret = async ( appId: string, secretId: string, ): Promise => { - await axios.delete( + await axiosInstance.delete( `/api/v2/oauth2-provider/apps/${appId}/secrets/${secretId}`, ); }; export const revokeOAuth2ProviderApp = async (appId: string): Promise => { - await axios.delete(`/oauth2/tokens?client_id=${appId}`); + await axiosInstance.delete(`/oauth2/tokens?client_id=${appId}`); }; export const getAuditLogs = async ( options: TypesGen.AuditLogsRequest, ): Promise => { const url = getURLWithSearchParams("/api/v2/audit", options); - const response = await axios.get(url); + const response = await axiosInstance.get(url); return response.data; }; export const getTemplateDAUs = async ( templateId: string, ): Promise => { - const response = await axios.get(`/api/v2/templates/${templateId}/daus`); + const response = await axiosInstance.get( + `/api/v2/templates/${templateId}/daus`, + ); return response.data; }; @@ -1071,7 +1132,9 @@ export const getDeploymentDAUs = async ( // we truncate the tz offset down to the closest hour. offset = Math.trunc(new Date().getTimezoneOffset() / 60), ): Promise => { - const response = await axios.get(`/api/v2/insights/daus?tz_offset=${offset}`); + const response = await axiosInstance.get( + `/api/v2/insights/daus?tz_offset=${offset}`, + ); return response.data; }; @@ -1083,14 +1146,16 @@ export const getTemplateACLAvailable = async ( `/api/v2/templates/${templateId}/acl/available`, options, ); - const response = await axios.get(url.toString()); + const response = await axiosInstance.get(url.toString()); return response.data; }; export const getTemplateACL = async ( templateId: string, ): Promise => { - const response = await axios.get(`/api/v2/templates/${templateId}/acl`); + const response = await axiosInstance.get( + `/api/v2/templates/${templateId}/acl`, + ); return response.data; }; @@ -1098,7 +1163,7 @@ export const updateTemplateACL = async ( templateId: string, data: TypesGen.UpdateTemplateACL, ): Promise<{ message: string }> => { - const response = await axios.patch( + const response = await axiosInstance.patch( `/api/v2/templates/${templateId}/acl`, data, ); @@ -1107,14 +1172,14 @@ export const updateTemplateACL = async ( export const getApplicationsHost = async (): Promise => { - const response = await axios.get(`/api/v2/applications/host`); + const response = await axiosInstance.get(`/api/v2/applications/host`); return response.data; }; export const getGroups = async ( organizationId: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/organizations/${organizationId}/groups`, ); return response.data; @@ -1124,7 +1189,7 @@ export const createGroup = async ( organizationId: string, data: TypesGen.CreateGroupRequest, ): Promise => { - const response = await axios.post( + const response = await axiosInstance.post( `/api/v2/organizations/${organizationId}/groups`, data, ); @@ -1132,7 +1197,7 @@ export const createGroup = async ( }; export const getGroup = async (groupId: string): Promise => { - const response = await axios.get(`/api/v2/groups/${groupId}`); + const response = await axiosInstance.get(`/api/v2/groups/${groupId}`); return response.data; }; @@ -1140,7 +1205,7 @@ export const patchGroup = async ( groupId: string, data: TypesGen.PatchGroupRequest, ): Promise => { - const response = await axios.patch(`/api/v2/groups/${groupId}`, data); + const response = await axiosInstance.patch(`/api/v2/groups/${groupId}`, data); return response.data; }; @@ -1162,13 +1227,13 @@ export const removeMember = async (groupId: string, userId: string) => { }; export const deleteGroup = async (groupId: string): Promise => { - await axios.delete(`/api/v2/groups/${groupId}`); + await axiosInstance.delete(`/api/v2/groups/${groupId}`); }; export const getWorkspaceQuota = async ( username: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/workspace-quota/${encodeURIComponent(username)}`, ); return response.data; @@ -1177,7 +1242,7 @@ export const getWorkspaceQuota = async ( export const getAgentListeningPorts = async ( agentID: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/workspaceagents/${agentID}/listening-ports`, ); return response.data; @@ -1186,7 +1251,7 @@ export const getAgentListeningPorts = async ( export const getWorkspaceAgentSharedPorts = async ( workspaceID: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/workspaces/${workspaceID}/port-share`, ); return response.data; @@ -1196,7 +1261,7 @@ export const upsertWorkspaceAgentSharedPort = async ( workspaceID: string, req: TypesGen.UpsertWorkspaceAgentPortShareRequest, ): Promise => { - const response = await axios.post( + const response = await axiosInstance.post( `/api/v2/workspaces/${workspaceID}/port-share`, req, ); @@ -1207,7 +1272,7 @@ export const deleteWorkspaceAgentSharedPort = async ( workspaceID: string, req: TypesGen.DeleteWorkspaceAgentPortShareRequest, ): Promise => { - const response = await axios.delete( + const response = await axiosInstance.delete( `/api/v2/workspaces/${workspaceID}/port-share`, { data: req, @@ -1219,7 +1284,7 @@ export const deleteWorkspaceAgentSharedPort = async ( // getDeploymentSSHConfig is used by the VSCode-Extension. export const getDeploymentSSHConfig = async (): Promise => { - const response = await axios.get(`/api/v2/deployment/ssh`); + const response = await axiosInstance.get(`/api/v2/deployment/ssh`); return response.data; }; @@ -1229,25 +1294,28 @@ export type DeploymentConfig = { }; export const getDeploymentConfig = async (): Promise => { - const response = await axios.get(`/api/v2/deployment/config`); + const response = await axiosInstance.get(`/api/v2/deployment/config`); return response.data; }; export const getDeploymentStats = async (): Promise => { - const response = await axios.get(`/api/v2/deployment/stats`); + const response = await axiosInstance.get(`/api/v2/deployment/stats`); return response.data; }; export const getReplicas = async (): Promise => { - const response = await axios.get(`/api/v2/replicas`); + const response = await axiosInstance.get(`/api/v2/replicas`); return response.data; }; export const getFile = async (fileId: string): Promise => { - const response = await axios.get(`/api/v2/files/${fileId}`, { - responseType: "arraybuffer", - }); + const response = await axiosInstance.get( + `/api/v2/files/${fileId}`, + { + responseType: "arraybuffer", + }, + ); return response.data; }; @@ -1255,7 +1323,7 @@ export const getWorkspaceProxyRegions = async (): Promise< TypesGen.RegionsResponse > => { const response = - await axios.get>( + await axiosInstance.get>( `/api/v2/regions`, ); return response.data; @@ -1264,7 +1332,7 @@ export const getWorkspaceProxyRegions = async (): Promise< export const getWorkspaceProxies = async (): Promise< TypesGen.RegionsResponse > => { - const response = await axios.get< + const response = await axiosInstance.get< TypesGen.RegionsResponse >(`/api/v2/workspaceproxies`); return response.data; @@ -1273,16 +1341,16 @@ export const getWorkspaceProxies = async (): Promise< export const createWorkspaceProxy = async ( b: TypesGen.CreateWorkspaceProxyRequest, ): Promise => { - const response = await axios.post(`/api/v2/workspaceproxies`, b); + const response = await axiosInstance.post(`/api/v2/workspaceproxies`, b); return response.data; }; export const getAppearance = async (): Promise => { try { - const response = await axios.get(`/api/v2/appearance`); + const response = await axiosInstance.get(`/api/v2/appearance`); return response.data || {}; } catch (ex) { - if (axios.isAxiosError(ex) && ex.response?.status === 404) { + if (isAxiosError(ex) && ex.response?.status === 404) { return { application_name: "", logo_url: "", @@ -1298,14 +1366,14 @@ export const getAppearance = async (): Promise => { export const updateAppearance = async ( b: TypesGen.AppearanceConfig, ): Promise => { - const response = await axios.put(`/api/v2/appearance`, b); + const response = await axiosInstance.put(`/api/v2/appearance`, b); return response.data; }; export const getTemplateExamples = async ( organizationId: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/organizations/${organizationId}/templates/examples`, ); return response.data; @@ -1314,7 +1382,7 @@ export const getTemplateExamples = async ( export const uploadFile = async ( file: File, ): Promise => { - const response = await axios.post("/api/v2/files", file, { + const response = await axiosInstance.post("/api/v2/files", file, { headers: { "Content-Type": "application/x-tar", }, @@ -1325,7 +1393,7 @@ export const uploadFile = async ( export const getTemplateVersionLogs = async ( versionId: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/templateversions/${versionId}/logs`, ); return response.data; @@ -1341,7 +1409,7 @@ export const updateWorkspaceVersion = async ( export const getWorkspaceBuildParameters = async ( workspaceBuildId: TypesGen.WorkspaceBuild["id"], ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/workspacebuilds/${workspaceBuildId}/parameters`, ); return response.data; @@ -1363,19 +1431,19 @@ export type GetLicensesResponse = Omit & { }; export const getLicenses = async (): Promise => { - const response = await axios.get(`/api/v2/licenses`); + const response = await axiosInstance.get(`/api/v2/licenses`); return response.data; }; export const createLicense = async ( data: TypesGen.AddLicenseRequest, ): Promise => { - const response = await axios.post(`/api/v2/licenses`, data); + const response = await axiosInstance.post(`/api/v2/licenses`, data); return response.data; }; export const removeLicense = async (licenseId: number): Promise => { - await axios.delete(`/api/v2/licenses/${licenseId}`); + await axiosInstance.delete(`/api/v2/licenses/${licenseId}`); }; export class MissingBuildParameters extends Error { @@ -1467,7 +1535,7 @@ export const updateWorkspace = async ( export const getWorkspaceResolveAutostart = async ( workspaceId: string, ): Promise => { - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/workspaces/${workspaceId}/resolve-autostart`, ); return response.data; @@ -1677,7 +1745,7 @@ export const watchBuildLogsByBuildId = ( export const issueReconnectingPTYSignedToken = async ( params: TypesGen.IssueReconnectingPTYSignedTokenRequest, ): Promise => { - const response = await axios.post( + const response = await axiosInstance.post( "/api/v2/applications/reconnecting-pty-signed-token", params, ); @@ -1706,7 +1774,9 @@ export const getInsightsUserLatency = async ( filters: InsightsParams, ): Promise => { const params = new URLSearchParams(filters); - const response = await axios.get(`/api/v2/insights/user-latency?${params}`); + const response = await axiosInstance.get( + `/api/v2/insights/user-latency?${params}`, + ); return response.data; }; @@ -1714,7 +1784,9 @@ export const getInsightsUserActivity = async ( filters: InsightsParams, ): Promise => { const params = new URLSearchParams(filters); - const response = await axios.get(`/api/v2/insights/user-activity?${params}`); + const response = await axiosInstance.get( + `/api/v2/insights/user-activity?${params}`, + ); return response.data; }; @@ -1726,7 +1798,7 @@ export const getInsightsTemplate = async ( params: InsightsTemplateParams, ): Promise => { const searchParams = new URLSearchParams(params); - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/insights/templates?${searchParams}`, ); return response.data; @@ -1734,7 +1806,7 @@ export const getInsightsTemplate = async ( export const getHealth = async (force: boolean = false) => { const params = new URLSearchParams({ force: force.toString() }); - const response = await axios.get( + const response = await axiosInstance.get( `/api/v2/debug/health?${params}`, ); return response.data; @@ -1742,14 +1814,16 @@ export const getHealth = async (force: boolean = false) => { export const getHealthSettings = async () => { return ( - await axios.get(`/api/v2/debug/health/settings`) + await axiosInstance.get( + `/api/v2/debug/health/settings`, + ) ).data; }; export const updateHealthSettings = async ( data: TypesGen.UpdateHealthSettings, ) => { - const response = await axios.put( + const response = await axiosInstance.put( `/api/v2/debug/health/settings`, data, ); @@ -1757,11 +1831,11 @@ export const updateHealthSettings = async ( }; export const putFavoriteWorkspace = async (workspaceID: string) => { - await axios.put(`/api/v2/workspaces/${workspaceID}/favorite`); + await axiosInstance.put(`/api/v2/workspaces/${workspaceID}/favorite`); }; export const deleteFavoriteWorkspace = async (workspaceID: string) => { - await axios.delete(`/api/v2/workspaces/${workspaceID}/favorite`); + await axiosInstance.delete(`/api/v2/workspaces/${workspaceID}/favorite`); }; export type GetJFrogXRayScanParams = { @@ -1776,7 +1850,7 @@ export const getJFrogXRayScan = async (options: GetJFrogXRayScanParams) => { }); try { - const res = await axios.get( + const res = await axiosInstance.get( `/api/v2/integrations/jfrog/xray-scan?${searchParams}`, ); return res.data; diff --git a/site/src/api/errors.ts b/site/src/api/errors.ts index 0d1a3dc203..ada591d754 100644 --- a/site/src/api/errors.ts +++ b/site/src/api/errors.ts @@ -1,4 +1,4 @@ -import axios, { type AxiosError, type AxiosResponse } from "axios"; +import { type AxiosError, type AxiosResponse, isAxiosError } from "axios"; const Language = { errorsByCode: { @@ -25,7 +25,7 @@ export type ApiError = AxiosError & { export const isApiError = (err: unknown): err is ApiError => { return ( - axios.isAxiosError(err) && + isAxiosError(err) && err.response !== undefined && isApiErrorResponse(err.response.data) ); diff --git a/site/src/contexts/auth/RequireAuth.tsx b/site/src/contexts/auth/RequireAuth.tsx index 4ec918eed1..d8db9071cc 100644 --- a/site/src/contexts/auth/RequireAuth.tsx +++ b/site/src/contexts/auth/RequireAuth.tsx @@ -1,6 +1,6 @@ -import axios from "axios"; import { type FC, useEffect } from "react"; import { Outlet, Navigate, useLocation } from "react-router-dom"; +import { axiosInstance } from "api/api"; import { isApiError } from "api/errors"; import { Loader } from "components/Loader/Loader"; import { ProxyProvider } from "contexts/ProxyContext"; @@ -22,7 +22,7 @@ export const RequireAuth: FC = () => { return; } - const interceptorHandle = axios.interceptors.response.use( + const interceptorHandle = axiosInstance.interceptors.response.use( (okResponse) => okResponse, (error: unknown) => { // 401 Unauthorized @@ -32,13 +32,14 @@ export const RequireAuth: FC = () => { signOut(); } - // Otherwise, pass the response through so that it can be displayed in the UI + // Otherwise, pass the response through so that it can be displayed in + // the UI return Promise.reject(error); }, ); return () => { - axios.interceptors.response.eject(interceptorHandle); + axiosInstance.interceptors.response.eject(interceptorHandle); }; }, [isLoading, isSigningOut, isSignedIn, signOut]); diff --git a/site/src/contexts/useProxyLatency.ts b/site/src/contexts/useProxyLatency.ts index 9d28830b7d..497cd457ed 100644 --- a/site/src/contexts/useProxyLatency.ts +++ b/site/src/contexts/useProxyLatency.ts @@ -1,6 +1,6 @@ import PerformanceObserver from "@fastly/performance-observer-polyfill"; -import axios from "axios"; import { useEffect, useReducer, useState } from "react"; +import { axiosInstance } from "api/api"; import type { Region } from "api/typesGenerated"; import { generateRandomString } from "utils/random"; @@ -198,7 +198,7 @@ export const useProxyLatency = ( observer.observe({ entryTypes: ["resource"] }); const proxyRequests = Object.keys(proxyChecks).map((latencyURL) => { - return axios.get(latencyURL, { + return axiosInstance.get(latencyURL, { withCredentials: false, // Must add a custom header to make the request not a "simple request". // We want to force a preflight request.