diff --git a/packages/common/gotrue.ts b/packages/common/gotrue.ts index 6ab6fb2ec72..caf25993d00 100644 --- a/packages/common/gotrue.ts +++ b/packages/common/gotrue.ts @@ -175,13 +175,27 @@ async function debuggableNavigatorLock( } } +// Wrap fetch with 30-second timeout to prevent indefinite hangs +const fetchWithTimeout: typeof fetch = async (input, init) => { + const timeoutSignal = AbortSignal.timeout(30000); // 30 seconds + const existingSignal = init?.signal; + const combinedSignal = existingSignal + ? AbortSignal.any([existingSignal, timeoutSignal]) + : timeoutSignal; + + return fetch(input, { + ...init, + signal: combinedSignal, + }); +}; + export const gotrueClient = new AuthClient({ url: process.env.NEXT_PUBLIC_GOTRUE_URL, storageKey: STORAGE_KEY, detectSessionInUrl: shouldDetectSessionInUrl, debug: debug ? (persistedDebug ? logIndexedDB : true) : false, lock: navigatorLockEnabled ? debuggableNavigatorLock : undefined, - + fetch: fetchWithTimeout, ...('localStorage' in globalThis ? { storage: globalThis.localStorage, userStorage: globalThis.localStorage } : null),