Spaces:
Running
Running
File size: 2,537 Bytes
ce8f04a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | /**
* Shared auth gate so axios 401 handler does not fight Clerk session state.
* ApiInterceptor writes; client interceptor reads.
*/
let clerkLoaded = false;
let clerkSignedIn = false;
let hardRedirectArmed = false;
let lastRedirectAt = 0;
export function setClerkAuthState(opts: { isLoaded: boolean; isSignedIn: boolean }) {
clerkLoaded = opts.isLoaded;
clerkSignedIn = Boolean(opts.isSignedIn);
// Allow a hard redirect only after Clerk finished loading and user is truly out
hardRedirectArmed = clerkLoaded && !clerkSignedIn;
}
export function getClerkAuthState() {
return { clerkLoaded, clerkSignedIn, hardRedirectArmed };
}
/**
* Should a 401 response force navigation to /sign-in?
* - Never while Clerk still loading
* - Never while Clerk says the user IS signed in (token race / backend lag)
* - Throttle hard redirects to avoid bounce loops
*/
export function shouldHardRedirectOn401(): boolean {
if (!clerkLoaded) return false;
if (clerkSignedIn) return false;
if (!hardRedirectArmed) return false;
const now = Date.now();
if (now - lastRedirectAt < 2500) return false;
lastRedirectAt = now;
return true;
}
export function safeSignInRedirectPath(currentPath: string, search = ''): string {
const path = currentPath || '/projects';
if (
path === '/' ||
path.startsWith('/sign-in') ||
path.startsWith('/sign-up') ||
path.startsWith('/pricing') ||
path.startsWith('/cennik') ||
path.startsWith('/regulamin') ||
path.startsWith('/polityka')
) {
return '/sign-in';
}
const returnTo = encodeURIComponent(path + (search || ''));
return `/sign-in?redirect_url=${returnTo}`;
}
/** Resolve post-login landing: query redirect_url → fallback /projects (not /dashboard). */
export function resolvePostAuthRedirect(search: string): string {
try {
const params = new URLSearchParams(search.startsWith('?') ? search.slice(1) : search);
const raw = params.get('redirect_url') || params.get('redirectUrl') || '';
if (raw) {
const decoded = decodeURIComponent(raw);
// Only same-origin relative paths
if (decoded.startsWith('/') && !decoded.startsWith('//') && !decoded.includes('://')) {
// Avoid bounce: /dashboard is an alias of /projects
if (decoded === '/dashboard' || decoded.startsWith('/dashboard?')) {
return '/projects' + (decoded.includes('?') ? decoded.slice(decoded.indexOf('?')) : '');
}
return decoded;
}
}
} catch {
/* ignore */
}
return '/projects';
}
|