1export const WEBSITE_SESSION_STORAGE_KEY = "smartguard.extension-handoff.website-session.v1"; 2 3export async function redeemWebsiteSession({ 4 storage = window.sessionStorage, 5 fetchImpl = fetch, 6 signIn, 7 consume, 8 timeoutMs = 10_000, 9} = {}) { 10 let handle; 11 try { handle = storage.getItem(WEBSITE_SESSION_STORAGE_KEY); } catch (error) { return { status: "failed", error }; } 12 if (!handle) return { status: "absent" }; 13 const controller = new AbortController(); 14 let timeout; 15 try { 16 const timeoutPromise = new Promise((_, reject) => { 17 timeout = setTimeout(() => { controller.abort(); reject(new Error("Website session redemption timed out")); }, timeoutMs); 18 }); 19 const response = await Promise.race([ 20 fetchImpl("/oauth/extension-handoff/website-session/redeem", { 21 method: "POST", 22 headers: { "Content-Type": "application/json", Accept: "application/json" }, 23 body: JSON.stringify({ handle }), 24 cache: "no-store", 25 signal: controller.signal, 26 }), 27 timeoutPromise, 28 ]); 29 const body = await Promise.race([ 30 response.json().catch(() => ({})), 31 timeoutPromise, 32 ]); 33 if (!response.ok || typeof body.customToken !== "string") throw new Error("Website session redemption failed"); 34 const user = await Promise.race([ 35 Promise.resolve(signIn(body.customToken)), 36 timeoutPromise, 37 ]); 38 storage.removeItem(WEBSITE_SESSION_STORAGE_KEY); 39 if (consume) { 40 try { await consume(handle, user); } catch (error) { console.warn("[Account] Website session consume failed", error); } 41 } 42 return { status: "redeemed", user }; 43 } catch (error) { 44 return { status: "failed", error }; 45 } finally { 46 if (timeout) clearTimeout(timeout); 47 } 48}
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.