/** * The one way this app calls `continuum-backend`. * * Auth is Supabase throughout: the backend verifies access tokens * asymmetrically against the project's published JWKS and holds no signing * key of its own (`continuum-backend/src/auth/verifier.ts`), and * `requireUser` wants that token in `Authorization: Bearer`. So this attaches * it, and that is the whole of the client's side of authentication. * * What this replaces: `useRequestHeaders(["cookie"])` on each call site. * Forwarding a cookie is what you do when a Nuxt *server* is proxying a * browser's request, and this app sets `ssr: false` so that it can ship the * same static bundle to the browser and to the Tauri shell - there is no * server to forward anything, so the header arrived empty and every call got * a 401. The token was already to hand the whole time; the telemetry store * has been reading it for its socket. * * The token is read inside the fetcher rather than captured when this is * called, because supabase-js refreshes the session in the background about * once an hour. A token captured at setup would work until it quietly * stopped. */ export function useApiFetch() { const config = useRuntimeConfig(); const session = useSupabaseSession(); return (path: string, options: Parameters[1] = {}) => { const token = session.value?.access_token; return $fetch(`${config.public.apiBase}${path}`, { ...options, headers: { // Omitted rather than sent empty when there is no session. An empty // Bearer is a malformed credential the backend rejects with a // message about the header's shape, which reads like a client bug; // no header at all is the honest "not signed in". The Supabase // module's own redirect is what handles getting the user a session. ...(token ? { Authorization: `Bearer ${token}` } : {}), ...options?.headers, }, }); }; }