File size: 1,697 Bytes
ec8acdf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
function safeDecodeCookieValue(value: string): string {
  try {
    return decodeURIComponent(value);
  } catch {
    return value;
  }
}

function decodeJwtExp(token: string): number | null {
  const parts = token.split('.');
  if (parts.length !== 3) return null;
  try {
    const b64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');
    const padded = b64 + '='.repeat((4 - (b64.length % 4)) % 4);
    const payload = JSON.parse(atob(padded)) as { exp?: unknown };
    return typeof payload.exp === 'number' ? payload.exp : null;
  } catch {
    return null;
  }
}

/**
 * Strong "is this visitor signed in right now" signal for the public welcome
 * page: true only when a live Clerk `__session` token (a JWT) is present AND
 * not expired. Deliberately ignores `__client_uat` — a longer-lived "last
 * auth" timestamp that can outlive the session — so a stale cookie cannot
 * divert an anonymous visitor away from the landing page.
 *
 * This lets the welcome page redirect a returning, actively-signed-in visitor
 * to /dashboard WITHOUT loading the ~3MB Clerk SDK on the critical path
 * (issue #4428). Idle signed-in users (expired `__session`) simply stay on the
 * landing page and use the Launch CTA — the destination still validates auth.
 */
export function hasLiveSessionJwt(cookieHeader: string): boolean {
  const match = cookieHeader.match(/(?:^|;\s*)__session=([^;]+)/);
  if (!match) return false;
  const exp = decodeJwtExp(safeDecodeCookieValue(match[1]).trim());
  return exp !== null && exp * 1000 > Date.now();
}

export function hasLiveClientSession(): boolean {
  if (typeof document === 'undefined') return false;
  return hasLiveSessionJwt(document.cookie);
}