fix: session error after retries + refactor on interceptor component (#2803)
* 📝 (API): Add AxiosRequestConfig to import statement in api.tsx for better type checking 🔧 (API): Add useFlowsManagerStore to import statement in api.tsx for managing saveLoading state ♻️ (API): Refactor ApiInterceptor function in api.tsx to improve error handling and flow control 📝 (API): Update comments in api.tsx for better code readability and understanding 🔧 (API): Add setSaveLoading function to FlowsManagerStoreType in flowsManagerStore.ts for managing saveLoading state * 🐛 (frontend): fix potential error when api response is null or undefined by adding optional chaining to data property access * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
57c72d3ea4
commit
011ebc2a5c
4 changed files with 56 additions and 32 deletions
|
|
@ -2,7 +2,8 @@ import {
|
|||
LANGFLOW_ACCESS_TOKEN,
|
||||
LANGFLOW_AUTO_LOGIN_OPTION,
|
||||
} from "@/constants/constants";
|
||||
import axios, { AxiosError, AxiosInstance } from "axios";
|
||||
import useFlowsManagerStore from "@/stores/flowsManagerStore";
|
||||
import axios, { AxiosError, AxiosInstance, AxiosRequestConfig } from "axios";
|
||||
import { useContext, useEffect } from "react";
|
||||
import { Cookies } from "react-cookie";
|
||||
import { renewAccessToken } from ".";
|
||||
|
|
@ -19,9 +20,10 @@ const api: AxiosInstance = axios.create({
|
|||
|
||||
function ApiInterceptor() {
|
||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||
let { accessToken, login, logout, authenticationErrorCount, autoLogin } =
|
||||
let { accessToken, logout, authenticationErrorCount, autoLogin } =
|
||||
useContext(AuthContext);
|
||||
const cookies = new Cookies();
|
||||
const setSaveLoading = useFlowsManagerStore((state) => state.setSaveLoading);
|
||||
|
||||
useEffect(() => {
|
||||
const interceptor = api.interceptors.response.use(
|
||||
|
|
@ -39,7 +41,8 @@ function ApiInterceptor() {
|
|||
if (!stillRefresh) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
const acceptedRequest = await tryToRenewAccessToken(error);
|
||||
|
||||
await tryToRenewAccessToken(error);
|
||||
|
||||
const accessToken = cookies.get(LANGFLOW_ACCESS_TOKEN);
|
||||
|
||||
|
|
@ -47,11 +50,12 @@ function ApiInterceptor() {
|
|||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
return acceptedRequest;
|
||||
await remakeRequest(error);
|
||||
setSaveLoading(false);
|
||||
authenticationErrorCount = 0;
|
||||
}
|
||||
}
|
||||
await clearBuildVerticesState(error);
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -67,7 +71,6 @@ function ApiInterceptor() {
|
|||
|
||||
try {
|
||||
const parsedURL = new URL(url);
|
||||
|
||||
const isDomainAllowed = authorizedDomains.some(
|
||||
(domain) => parsedURL.origin === new URL(domain).origin,
|
||||
);
|
||||
|
|
@ -131,10 +134,7 @@ function ApiInterceptor() {
|
|||
async function tryToRenewAccessToken(error: AxiosError) {
|
||||
try {
|
||||
if (window.location.pathname.includes("/login")) return;
|
||||
const res = await renewAccessToken();
|
||||
if (res?.data?.access_token && res?.data?.refresh_token) {
|
||||
login(res?.data?.access_token, cookies.get(LANGFLOW_AUTO_LOGIN_OPTION));
|
||||
}
|
||||
await renewAccessToken();
|
||||
} catch (error) {
|
||||
clearBuildVerticesState(error);
|
||||
logout();
|
||||
|
|
@ -152,6 +152,28 @@ function ApiInterceptor() {
|
|||
}
|
||||
}
|
||||
|
||||
async function remakeRequest(error: AxiosError) {
|
||||
const originalRequest = error.config as AxiosRequestConfig;
|
||||
|
||||
try {
|
||||
const accessToken = cookies.get(LANGFLOW_ACCESS_TOKEN);
|
||||
if (!accessToken) {
|
||||
throw new Error("Access token not found in cookies");
|
||||
}
|
||||
|
||||
// Modify headers in originalRequest
|
||||
originalRequest.headers = {
|
||||
...(originalRequest.headers as Record<string, string>), // Cast to suppress TypeScript error
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
};
|
||||
|
||||
const response = await axios.request(originalRequest);
|
||||
return response.data; // Or handle the response as needed
|
||||
} catch (err) {
|
||||
throw err; // Throw the error if request fails again
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ const GITHUB_API_URL = "https://api.github.com";
|
|||
export async function getRepoStars(owner: string, repo: string) {
|
||||
try {
|
||||
const response = await api.get(`${GITHUB_API_URL}/repos/${owner}/${repo}`);
|
||||
return response.data.stargazers_count;
|
||||
return response?.data.stargazers_count;
|
||||
} catch (error) {
|
||||
console.error("Error fetching repository data:", error);
|
||||
return null;
|
||||
|
|
@ -101,7 +101,7 @@ export async function getExamples(): Promise<FlowType[]> {
|
|||
"https://api.github.com/repos/langflow-ai/langflow_examples/contents/examples?ref=main";
|
||||
const response = await api.get(url);
|
||||
|
||||
const jsonFiles = response.data.filter((file: any) => {
|
||||
const jsonFiles = response?.data.filter((file: any) => {
|
||||
return file.name.endsWith(".json");
|
||||
});
|
||||
|
||||
|
|
@ -143,7 +143,7 @@ export async function saveFlowToDatabase(newFlow: {
|
|||
if (response?.status !== 201) {
|
||||
throw new Error(`HTTP error! status: ${response?.status}`);
|
||||
}
|
||||
return response.data;
|
||||
return response?.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
|
|
@ -168,10 +168,10 @@ export async function updateFlowInDatabase(
|
|||
endpoint_name: updatedFlow.endpoint_name,
|
||||
});
|
||||
|
||||
if (response?.status !== 200) {
|
||||
if (response && response?.status !== 200) {
|
||||
throw new Error(`HTTP error! status: ${response?.status}`);
|
||||
}
|
||||
return response.data;
|
||||
return response?.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
|
|
@ -187,10 +187,10 @@ export async function updateFlowInDatabase(
|
|||
export async function readFlowsFromDatabase() {
|
||||
try {
|
||||
const response = await api.get(`${BASE_URL_API}flows/`);
|
||||
if (response?.status !== 200) {
|
||||
if (response && response?.status !== 200) {
|
||||
throw new Error(`HTTP error! status: ${response?.status}`);
|
||||
}
|
||||
return response.data;
|
||||
return response?.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
|
|
@ -200,10 +200,10 @@ export async function readFlowsFromDatabase() {
|
|||
export async function downloadFlowsFromDatabase() {
|
||||
try {
|
||||
const response = await api.get(`${BASE_URL_API}flows/download/`);
|
||||
if (response?.status !== 200) {
|
||||
if (response && response?.status !== 200) {
|
||||
throw new Error(`HTTP error! status: ${response?.status}`);
|
||||
}
|
||||
return response.data;
|
||||
return response?.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
|
|
@ -217,7 +217,7 @@ export async function uploadFlowsToDatabase(flows: FormData) {
|
|||
if (response?.status !== 201) {
|
||||
throw new Error(`HTTP error! status: ${response?.status}`);
|
||||
}
|
||||
return response.data;
|
||||
return response?.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
|
|
@ -237,7 +237,7 @@ export async function deleteFlowFromDatabase(flowId: string) {
|
|||
if (response.status !== 200) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return response.data;
|
||||
return response?.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
|
|
@ -254,10 +254,10 @@ export async function deleteFlowFromDatabase(flowId: string) {
|
|||
export async function getFlowFromDatabase(flowId: number) {
|
||||
try {
|
||||
const response = await api.get(`${BASE_URL_API}flows/${flowId}`);
|
||||
if (response?.status !== 200) {
|
||||
if (response && response?.status !== 200) {
|
||||
throw new Error(`HTTP error! status: ${response?.status}`);
|
||||
}
|
||||
return response.data;
|
||||
return response?.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
|
|
@ -276,7 +276,7 @@ export async function getFlowStylesFromDatabase() {
|
|||
if (response.status !== 200) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return response.data;
|
||||
return response?.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
|
|
@ -302,7 +302,7 @@ export async function saveFlowStyleToDatabase(flowStyle: FlowStyleType) {
|
|||
if (response.status !== 201) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return response.data;
|
||||
return response?.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
|
|
@ -316,7 +316,7 @@ export async function saveFlowStyleToDatabase(flowStyle: FlowStyleType) {
|
|||
*/
|
||||
export async function getVersion() {
|
||||
const response = await api.get(`${BASE_URL_API}version`);
|
||||
return response.data;
|
||||
return response?.data;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -416,7 +416,7 @@ export async function onLogin(user: LoginType) {
|
|||
);
|
||||
|
||||
if (response.status === 200) {
|
||||
const data = response.data;
|
||||
const data = response?.data;
|
||||
return data;
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
@ -431,7 +431,7 @@ export async function autoLogin(abortSignal) {
|
|||
});
|
||||
|
||||
if (response.status === 200) {
|
||||
const data = response.data;
|
||||
const data = response?.data;
|
||||
return data;
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
@ -607,7 +607,7 @@ export async function saveFlowStore(
|
|||
if (response.status !== 201) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return response.data;
|
||||
return response?.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
|
|
@ -862,7 +862,7 @@ export async function updateFlowStore(
|
|||
if (response.status !== 201) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return response.data;
|
||||
return response?.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
|
|
@ -872,7 +872,7 @@ export async function updateFlowStore(
|
|||
export async function requestLogout() {
|
||||
try {
|
||||
const response = await api.post(`${BASE_URL_API}logout`);
|
||||
return response.data;
|
||||
return response?.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
|
|
@ -883,7 +883,7 @@ export async function getGlobalVariables(): Promise<{
|
|||
[key: string]: { id: string; type: string; default_fields: string[] };
|
||||
}> {
|
||||
const globalVariables = {};
|
||||
(await api.get(`${BASE_URL_API}variables/`)).data.forEach((element) => {
|
||||
(await api.get(`${BASE_URL_API}variables/`))?.data?.forEach((element) => {
|
||||
globalVariables[element.name] = {
|
||||
id: element.id,
|
||||
type: element.type,
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
|
|||
},
|
||||
currentFlow: undefined,
|
||||
saveLoading: false,
|
||||
setSaveLoading: (saveLoading: boolean) => set({ saveLoading }),
|
||||
isLoading: true,
|
||||
setIsLoading: (isLoading: boolean) => set({ isLoading }),
|
||||
refreshFlows: () => {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export type FlowsManagerStoreType = {
|
|||
currentFlowId: string;
|
||||
setCurrentFlowId: (currentFlowId: string) => void;
|
||||
saveLoading: boolean;
|
||||
setSaveLoading: (saveLoading: boolean) => void;
|
||||
isLoading: boolean;
|
||||
setIsLoading: (isLoading: boolean) => void;
|
||||
refreshFlows: () => Promise<void>;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue