Add timeout helper and resilient signOut flow
cgen-fdb46d24a4f0439b905b3bcf956dbe68
This commit is contained in:
parent
7688f923c1
commit
14ee8b7db4
1 changed files with 69 additions and 13 deletions
|
|
@ -101,6 +101,30 @@ const missingProviderFallback: AuthContextType = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const SIGN_OUT_TIMEOUT_MS = 4000;
|
||||||
|
|
||||||
|
function withTimeout<T>(
|
||||||
|
promise: Promise<T>,
|
||||||
|
timeoutMs: number,
|
||||||
|
timeoutMessage = "Operation timed out",
|
||||||
|
): Promise<T> {
|
||||||
|
return new Promise<T>((resolve, reject) => {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
reject(new Error(timeoutMessage));
|
||||||
|
}, timeoutMs);
|
||||||
|
|
||||||
|
promise
|
||||||
|
.then((value) => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
resolve(value);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export const useAuth = () => {
|
export const useAuth = () => {
|
||||||
const context = useContext(AuthContext);
|
const context = useContext(AuthContext);
|
||||||
if (context === undefined) {
|
if (context === undefined) {
|
||||||
|
|
@ -436,25 +460,57 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({
|
||||||
|
|
||||||
const signOut = async () => {
|
const signOut = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
const issues: string[] = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { error } = await supabase.auth.signOut();
|
const { error: localError } = await supabase.auth.signOut({ scope: "local" });
|
||||||
if (error) throw error;
|
if (localError?.message && !/session/i.test(localError.message)) {
|
||||||
|
issues.push(localError.message);
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
const message = error?.message ?? "Unable to clear local session.";
|
||||||
|
if (!/session/i.test(message)) {
|
||||||
|
issues.push(message);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
clearClientAuthState();
|
clearClientAuthState();
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { error: globalError } = await withTimeout(
|
||||||
|
supabase.auth.signOut({ scope: "global" }),
|
||||||
|
SIGN_OUT_TIMEOUT_MS,
|
||||||
|
"Supabase sign out timed out",
|
||||||
|
);
|
||||||
|
if (globalError) {
|
||||||
|
const status = (globalError as any)?.status;
|
||||||
|
if (status !== 401) {
|
||||||
|
issues.push(globalError.message ?? "Unable to reach authentication service.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
const message = error?.message ?? "Unable to reach authentication service.";
|
||||||
|
issues.push(message);
|
||||||
|
console.warn("Supabase global sign-out issue:", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uniqueIssues = Array.from(new Set(issues)).filter(Boolean);
|
||||||
|
if (uniqueIssues.length) {
|
||||||
|
const hasTimeout = uniqueIssues.some((msg) =>
|
||||||
|
msg.toLowerCase().includes("timed out"),
|
||||||
|
);
|
||||||
|
aethexToast.error({
|
||||||
|
title: "Sign out issue",
|
||||||
|
description: hasTimeout
|
||||||
|
? "We couldn't reach Supabase to finish signing out, but your local session was cleared."
|
||||||
|
: uniqueIssues[0],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
aethexToast.info({
|
aethexToast.info({
|
||||||
title: "Signed out",
|
title: "Signed out",
|
||||||
description: "You have been signed out successfully.",
|
description: "You have been signed out successfully.",
|
||||||
});
|
});
|
||||||
} catch (error: any) {
|
|
||||||
console.warn("Supabase signOut failed, forcing local cleanup:", error);
|
|
||||||
clearClientAuthState();
|
|
||||||
aethexToast.error({
|
|
||||||
title: "Sign out issue",
|
|
||||||
description:
|
|
||||||
error?.message ||
|
|
||||||
"We had trouble contacting the auth service, but local data was cleared.",
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue