PageSourceSearch

https://cardcompass.app/nav-auth.js?v=2

js cardcompass.app collected 2026-09-24 14:30:38 UTC 3,537 bytes, 92 lines download raw bytes

1// nav-auth.js — replaces Log In / Get Started with My Account / Sign Out when signed in.
2// cc_token (bearer session token) is the real auth signal; cc_user is a display cache
3// refreshed from /api/auth/session in the background (stale-while-revalidate).
4(function () {
5  'use strict';
6
7  window.signOut = window.signOut || function () {
8    if (!confirm('Sign out of CardCompass?')) return;
9    var token = localStorage.getItem('cc_token');
10    localStorage.removeItem('cc_token');
11    localStorage.removeItem('cc_user');
12    localStorage.removeItem('cc_session');
13    sessionStorage.removeItem('cc_token');
14    sessionStorage.removeItem('cc_user');
15    sessionStorage.removeItem('cc_session');
16    if (token) {
17      fetch('/api/auth/logout', { method: 'POST', headers: { 'Authorization': 'Bearer ' + token } }).catch(function () {});
18    }
19    location.href = '/';
20  };
21
22  function getToken() {
23    return localStorage.getItem('cc_token') || sessionStorage.getItem('cc_token');
24  }
25  function getUser() {
26    try { return JSON.parse(localStorage.getItem('cc_user') || sessionStorage.getItem('cc_user') || 'null'); }
27    catch (e) { return null; }
28  }
29  function clearAuth() {
30    localStorage.removeItem('cc_token');
31    localStorage.removeItem('cc_user');
32    sessionStorage.removeItem('cc_token');
33    sessionStorage.removeItem('cc_user');
34  }
35
36  // Validates the cached token against the server. Returns the fresh user object,
37  // or null if the session is invalid/expired (and clears local state in that case).
38  // Merges (not replaces) into the cached cc_user — until prefs/wallet also live in
39  // D1 (Milestone 4), those fields only exist client-side and must survive this call.
40  async function requireAuth() {
41    var token = getToken();
42    if (!token) return null;
43    try {
44      const res = await fetch('/api/auth/session', { headers: { 'Authorization': 'Bearer ' + token } });
45      if (!res.ok) { clearAuth(); return null; }
46      const data = await res.json();
47      var merged = Object.assign({}, getUser() || {}, data.user);
48      localStorage.setItem('cc_user', JSON.stringify(merged));
49      return merged;
50    } catch (e) {
51      // Network failure — keep the cached user rather than force a sign-out.
52      return getUser();
53    }
54  }
55
56  window.ccAuth = { getToken, getUser, requireAuth, clearAuth };
57
58  var signedOutMarkup = null;
59
60  function paintSignedIn() {
61    var na = document.querySelector('.nav-actions');
62    if (!na || na.querySelector('.user-btn')) return; // skip if page has its own dropdown
63    if (signedOutMarkup === null) signedOutMarkup = na.innerHTML;
64
65    na.innerHTML =
66      '<a href="/account" class="btn-outline">My Account</a>' +
67      '<button class="btn-primary" style="border:none;cursor:pointer;font-family:inherit;" onclick="signOut()">Sign Out</button>';
68
69    var footerLink = document.getElementById('footer-account-link');
70    if (footerLink) footerLink.style.display = '';
71  }
72
73  function paintSignedOut() {
74    var na = document.querySelector('.nav-actions');
75    if (!na || na.querySelector('.user-btn') || signedOutMarkup === null) return;
76    na.innerHTML = signedOutMarkup;
77  }
78
79  function init() {
80    if (getToken() && getUser()) paintSignedIn(); // optimistic paint from cache, avoids a flash of signed-out UI
81    requireAuth().then(function (user) {
82      if (user) paintSignedIn();
83      else paintSignedOut();
84    });
85  }
86
87  if (document.readyState === 'loading') {
88    document.addEventListener('DOMContentLoaded', init);
89  } else {
90    init();
91  }
92})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.