/** Encode a token pack for the fragment. */ export declare function encodeSessionHandoff(pack: SessionHandoffPack): string; /** * Decode a fragment payload. * * Returns null rather than throwing for anything malformed. This runs on a * value an attacker can put in a URL, and a thrown error on page load would * be a denial of service on the destination page. */ export declare function decodeSessionHandoff(value: string | null | undefined): SessionHandoffPack | null; /** * Append the handoff to a redirect target. * * Any fragment already on `redirectTo` is preserved ahead of the handoff, so * `/account#billing` still lands on the billing section. */ export declare function buildSessionHandoffUrl(redirectTo: string, pack: SessionHandoffPack): string; /** Pull the handoff out of a `location.hash`-shaped string. */ export declare function readSessionHandoff(hash: string | null | undefined): SessionHandoffPack | null; /** * The same hash with the handoff removed, ready for `history.replaceState`. * * Returns '' when nothing else was in it, so the caller can drop the `#` * entirely rather than leaving a bare one in the address bar. */ export declare function stripSessionHandoff(hash: string | null | undefined): string; /** * Moving a server-minted session into the browser (stacksjs/stacks#2236). * * `@stacksjs/socials` covers the OAuth exchange and `@stacksjs/auth` covers * `loginUsingId()` server-side. Nothing bridged the two for a browser, so an * app finishing a redirect flow had to hand-serialize a token pack into the * framework's own storage keys — from a server action, inside an HTML * response: * * localStorage.setItem('token', JSON.stringify(JSON.stringify(token))) * * That double stringify is not a typo: the session persists through * `useStorage`, which JSON-stringifies on write, so the string that belongs IN * localStorage under `token` is `"abc"` — quotes included. One app got it * wrong for `user` and stored the literal `[object Object]`, so every social * sign-in produced a broken session. The same inline script also needed * hand-written escaping, because a display name containing a closing script * tag would terminate the block early. * * None of that is application logic. This module is the format, owned once. * * The pack travels in the URL **fragment**, which is never sent to a server: * it stays out of access logs, out of `Referer`, and out of any proxy in * between — all of which an HTML body carrying the same tokens was exposed to. * It does land in browser history, so the client strips it the moment it is * read. A single-use code exchanged over POST would keep the tokens out of the * URL entirely and is the stronger design; it needs server-side state with a * short TTL, which this deliberately does not. */ /** The fragment key the handoff travels under. */ export declare const SESSION_HANDOFF_KEY: 'stx_auth'; export declare interface SessionHandoffPack { token: string refreshToken?: string user?: unknown expiresIn?: number }