📄 src/auth.ts
/**
 * Borrowed authentication, straight from the page — the extension never
 * handles credentials itself.
 *
 * - The session token lives in localStorage (key below) as a plain string,
 *   set by the reader app after login. A cookie with the same key is used as
 *   fallback when localStorage is unavailable.
 * - The client token is public and static per application; it is embedded in
 *   the page HTML as `PrenlyData.client = { "authToken": "…" }`. We re-parse
 *   it from the live page so it keeps working if the site rotates it.
 */

const SESSION_STORAGE_KEY = 'prenlyreadersessiontoken';

/** Last-resort fallback (current public token) if the page parse fails. */
const FALLBACK_CLIENT_TOKEN =
  'YjNjODI3YzlmYmMwODY4OXw2MDEzOWVmNmM1ZDY4YzgxYzUzMDI3YWM4Yjc1NzI4YWU2MmUyN2JhYzYxOTc1Y2FjNjhhY2FkNjZkMjIyMDZk';

export function getSessionToken(): string | null {
  try {
    const value = window.localStorage.getItem(SESSION_STORAGE_KEY);
    if (value) return value;
  } catch {
    // localStorage unavailable — fall through to the cookie fallback.
  }
  const match = document.cookie.match(`(?:^|;)\\s*${SESSION_STORAGE_KEY}\\s*=\\s*([^;]+)`);
  return match?.[1] ?? null;
}

export function getClientToken(): string {
  for (const script of Array.from(document.querySelectorAll('script'))) {
    const token = parseClientToken(script.textContent ?? '');
    if (token) return token;
  }
  return FALLBACK_CLIENT_TOKEN;
}

function parseClientToken(scriptText: string): string | null {
  const markerIndex = scriptText.indexOf('PrenlyData.client');
  if (markerIndex === -1) return null;
  const rest = scriptText.slice(markerIndex);
  const start = rest.indexOf('{');
  const end = rest.lastIndexOf('}');
  if (start === -1 || end <= start) return null;
  try {
    const parsed = JSON.parse(rest.slice(start, end + 1)) as { authToken?: unknown };
    if (typeof parsed.authToken === 'string' && parsed.authToken.length > 0) {
      return parsed.authToken;
    }
  } catch {
    // Not the script we're looking for.
  }
  return null;
}