import {useSyncExternalStore} from "react"; // The bearer token of the current dataset. It lives in sessionStorage - per tab, gone when the tab // closes - because it is a per-dataset secret the next /start replaces, not a credential to keep. const KEY = 'jfjoch_token'; export const getToken = (): string | undefined => { try { return sessionStorage.getItem(KEY) ?? undefined; } catch { return undefined; } }; export const setToken = (token: string) => { try { if (token) sessionStorage.setItem(KEY, token); else sessionStorage.removeItem(KEY); } catch { // sessionStorage unavailable (private window, CSP): the token is simply not kept } }; // For the few raw fetch() calls that bypass the generated client. export const authHeaders = (): HeadersInit => getToken() ? {Authorization: 'Bearer ' + getToken()} : {}; // Whether the broker last answered 401 - i.e. the dataset is protected and the token we hold (or // its absence) does not open it. Set from the response interceptor, read by the UI. let tokenRequired = false; const listeners = new Set<() => void>(); export const noteResponse = (response: Response) => { const required = response.status === 401; if (required !== tokenRequired) { tokenRequired = required; listeners.forEach(l => l()); } }; export const useTokenRequired = () => useSyncExternalStore( (l) => { listeners.add(l); return () => { listeners.delete(l); }; }, () => tokenRequired);