const STORAGE_KEY = "hfviewer:space-native-oauth:v2"; const START_URL = "https://hfviewer.com/api/hf_space_oauth/start"; const CONSUME_URL = "https://hfviewer.com/api/hf_space_oauth/consume"; const DESTINATION_URL = "https://hfviewer.com/api/hf_space_oauth/destination"; const POLL_INTERVAL_MS = 800; const FLOW_TIMEOUT_MS = 5 * 60 * 1000; const PREPARE_REFRESH_MS = 4 * 60 * 1000; const PREPARE_RETRY_DELAYS_MS = [0, 450, 1400]; // Recovery after a failed preparation backs off and then stops: a page load // never loops on an unreachable start endpoint (a copied Space once emitted // ~15 failures per visitor that way). The next sign-in intent starts over. const PREPARE_RECOVERY_DELAYS_MS = [2000, 8000, 30000, 60000]; // Hard ceiling on consecutive failed start requests that were not // user-initiated; a successful preparation resets it. const PREPARE_MAX_BACKGROUND_ATTEMPTS = 6; // A user may retry by clicking, but a page reports at most this many // user-initiated preparation failures. const PREPARE_MAX_USER_FAILURE_REPORTS = 3; const OFFICIAL_SPACE_URL = "https://huggingface.co/spaces/embedl/hfviewer"; const REQUEST_TIMEOUT_MS = 12 * 1000; const AUTH_CHANGED_EVENT = "hfviewer-space-auth-changed"; const OFFICIAL_SPACE_HOSTS = new Set([ "embedl-hfviewer.static.hf.space", "hfvwr-hfviewer-private-qa.static.hf.space", ]); // The Space shell intercepts canonical hfviewer.com links during capture and // treats every root-path URL as "return to the Space landing page", even when // its query opens an account view. Use the canonicalizing www host so these // remain ordinary external links; its 301 preserves the full query string. const ACCOUNT_DESTINATION_ORIGIN = "https://www.hfviewer.com"; const authHost = document.getElementById("hfnx-auth"); const compactAuthHost = document.getElementById("sx-auth"); let oauthResult = readStoredResult(); let rendering = false; let activeFlow = null; let preparedFlow = null; let preparePromise = null; let prepareFailureCount = 0; let prepareRecoveryTimer = null; let prepareFailureEpisodeActive = false; let prepareSuccessReported = false; let preparePromiseTrigger = ""; let prepareIntentEscalated = false; let backgroundPrepareAttempts = 0; let backgroundPrepareFailureReported = false; let userPrepareFailureReports = 0; let preparedFlowExpiryTimer = null; let loginContinueRequested = false; let accountDestinationLinks = []; let lastAnnouncedAuthIdentity = null; let nativeLoginPopover = null; function currentSpaceDeployment() { const host = String(window.location.hostname || "").trim().toLowerCase(); if (host === "embedl-hfviewer.static.hf.space") return "production"; if (host === "hfvwr-hfviewer-private-qa.static.hf.space") return "qa"; if (host.endsWith(".hf.space")) return "clone"; return "local"; } // OAuth only works on the two official Space origins (the backend trusts // them for the handoff). A duplicated Space can copy our space_repo value, // but it can never sign in, so it must not prepare OAuth or report failures. function isCloneDeployment() { return currentSpaceDeployment() === "clone"; } function preparedFlowIsFresh() { return !!preparedFlow && Date.now() - preparedFlow.preparedAt < PREPARE_REFRESH_MS; } function readStoredResult() { try { const value = localStorage.getItem(STORAGE_KEY); const result = value ? JSON.parse(value) : null; const expiresAt = Number(result?.spaceSession?.expiresAt || 0) * 1000; if (!result || !expiresAt || expiresAt <= Date.now()) { localStorage.removeItem(STORAGE_KEY); return null; } return result; } catch { return null; } } function writeStoredResult(value) { try { if (value) localStorage.setItem(STORAGE_KEY, JSON.stringify(value)); else localStorage.removeItem(STORAGE_KEY); } catch { // Keep the current-tab session even when durable storage is unavailable. } } function randomFlowValue() { const bytes = new Uint8Array(32); crypto.getRandomValues(bytes); return Array.from(bytes, (value) => value.toString(16).padStart(2, "0")).join(""); } function userFromResult(result) { const raw = result?.userInfo || result?.userinfo || result?.user_info || result?.user || {}; const username = String( raw.preferred_username || raw.preferredUsername || raw.username || raw.name || "" ).trim(); if (!username) return null; return { username, name: String(raw.name || username).trim(), picture: String(raw.picture || raw.avatar_url || raw.avatarUrl || "").trim(), profile: String(raw.profile || `https://huggingface.co/${encodeURIComponent(username)}`).trim(), subject: String(raw.sub || raw.id || "").trim(), email: String(raw.email || "").trim().toLowerCase(), }; } function trackAuthEvent(eventName, properties = {}) { try { const productContext = window.HFVIEWER_PRODUCT_CONTEXT && typeof window.HFVIEWER_PRODUCT_CONTEXT === "object" ? window.HFVIEWER_PRODUCT_CONTEXT : {}; window.hfviewerAnalyticsBridge?.capture?.(eventName, { product_surface: "hf_space", space_repo: String(productContext.space_repo || "unknown"), space_revision: String(productContext.space_revision || "unknown"), space_host: String(window.location.hostname || "unknown").toLowerCase(), space_deployment: currentSpaceDeployment(), auth_provider: "hugging_face", ...properties, }); } catch { // Authentication must remain independent of analytics availability. } } function identifyAuthenticatedUser(user, source) { if (!user?.username) return; try { window.hfviewerAnalyticsBridge?.identifyHfSession?.( { authenticated: true, email: user.email || "", user: { id: user.subject || "", username: user.username, name: user.name || user.username, email: user.email || "", }, }, source || "hf_space_native_oauth" ); } catch { // Consent-gated identity is best effort only. } } function keepReleasePills() { if (!authHost) return []; return Array.from(authHost.children).filter((element) => element.classList.contains("hfnx-auth__pill") ); } function makeAvatar(user) { if (user.picture) { const image = document.createElement("img"); image.className = "hfnx-auth__avatar"; image.src = user.picture; image.alt = ""; image.referrerPolicy = "no-referrer"; return image; } const letter = document.createElement("span"); letter.className = "hfnx-auth__avatar hfnx-auth__avatar--letter"; letter.textContent = user.username.charAt(0).toUpperCase(); return letter; } function makeHfviewerAccountLink(label, path, target) { const link = document.createElement("a"); link.className = "hfnx-auth__item"; link.href = new URL(path, ACCOUNT_DESTINATION_ORIGIN).href; link.target = "_blank"; link.rel = "noopener"; link.textContent = label; link.setAttribute("role", "menuitem"); link.dataset.accountDestination = target; link.dataset.accountDestinationReady = "0"; accountDestinationLinks.push(link); link.addEventListener("click", () => { trackAuthEvent("space_hfviewer_account_destination_opened", { target }); // The clicked handoff is single-use. Mint its replacement after the // browser has captured this anchor's current href for native navigation. link.dataset.accountDestinationReady = "0"; window.setTimeout(() => { void prepareAccountDestination(link); }, 0); }); return link; } function liveSpaceSession() { const session = oauthResult?.spaceSession; const expiresAt = Number(session?.expiresAt || 0) * 1000; if (!session?.id || !session?.secret || !expiresAt || expiresAt <= Date.now()) { return null; } return session; } function invalidAuthResponse(code) { const error = new Error("Sign-in is temporarily unavailable. Please try again."); error.name = "AuthResponseError"; error.code = code; return error; } function validatedLoginUrl(result, destination = false) { if (!result || typeof result.login_url !== "string" || !result.login_url.trim()) { throw invalidAuthResponse("missing_login_url"); } let url; try { url = new URL(result.login_url); } catch { throw invalidAuthResponse("invalid_login_url"); } const allowed = destination ? ["https://hfviewer.com", "https://www.hfviewer.com"].includes(url.origin) && url.pathname === "/api/hf_space_oauth/enter" : url.origin === "https://huggingface.co" && url.pathname === "/oauth/authorize"; if (!allowed || url.username || url.password) throw invalidAuthResponse("invalid_login_url"); return url; } function authFailureCategory(error) { if (error?.name === "AuthResponseError") return "invalid_response"; if (error?.name === "AbortError" || error?.name === "TimeoutError") return "timeout"; if (Number(error?.status)) return "http"; if (error?.name === "TypeError") return "network"; return "unknown"; } async function prepareAccountDestination(link) { const session = liveSpaceSession(); const destination = String(link?.dataset?.accountDestination || ""); if (!session || !destination || link.dataset.accountDestinationPreparing === "1") return; link.dataset.accountDestinationPreparing = "1"; try { const result = await postJson(DESTINATION_URL, { link_session_id: session.id, link_session_secret: session.secret, destination, }); const loginUrl = validatedLoginUrl(result, true); link.href = loginUrl.toString(); link.dataset.accountDestinationReady = "1"; } catch (error) { console.warn("Hugging Face Space account handoff preparation failed", error); link.dataset.accountDestinationReady = "0"; trackAuthEvent("space_hf_account_destination_preparation_failed", { user_initiated: false, failure_category: authFailureCategory(error), error_code: error?.code, component: "space_account_destination", failure_stage: "destination_prepare", destination, error_name: String(error?.name || "Error").slice(0, 80), }); } finally { link.dataset.accountDestinationPreparing = "0"; } } function prepareAccountDestinations() { if (!liveSpaceSession()) { if (oauthResult) { oauthResult = null; writeStoredResult(null); renderAuth(); void prepareLogin("background_session_expired"); } return; } for (const link of accountDestinationLinks) void prepareAccountDestination(link); } function makeOfficialSpaceLink() { const link = document.createElement("a"); link.dataset.spaceNativeAuth = "official-space"; // Reuse the login control's class: the Space stylesheet hides every other // child of #hfnx-auth. link.className = "space-native-auth-login space-native-auth-official"; link.href = OFFICIAL_SPACE_URL; link.target = "_blank"; link.rel = "noopener"; link.textContent = "Open the official hfviewer Space"; link.title = "Sign-in is available in the official hfviewer Space"; link.style.fontSize = "12px"; link.style.opacity = "0.8"; link.style.whiteSpace = "nowrap"; link.addEventListener("click", () => { trackAuthEvent("space_clone_official_space_opened", { component: "space_nav" }); }); return link; } // Sign-in intent (hover, keyboard focus, press) re-prepares a missing or // stale OAuth URL so a failed background preparation recovers before the click. function bindLoginIntentPreparation(element) { const prepareOnIntent = (event) => { void prepareLogin(`intent_${event.type}`); }; for (const type of ["pointerenter", "focus", "pointerdown", "touchstart"]) { element.addEventListener(type, prepareOnIntent, type === "touchstart" ? { passive: true } : undefined); } } function makeLoggedOutControl() { if (isCloneDeployment()) return makeOfficialSpaceLink(); const link = document.createElement("a"); link.dataset.spaceNativeAuth = "login"; link.className = "space-native-auth-login"; const ready = !activeFlow && preparedFlowIsFresh(); link.textContent = activeFlow ? "Signing in…" : "Log in"; // A click that had to prepare first needs a second click to open the // native target=_blank navigation; say so instead of looking unchanged. if (ready && loginContinueRequested) link.textContent = "Continue to Hugging Face"; link.title = activeFlow ? "Cancel this sign-in and try again" : "Sign in with Hugging Face"; link.href = (ready && preparedFlow?.loginUrl) || "#"; link.target = "_blank"; link.rel = "noopener"; link.setAttribute("aria-disabled", ready || activeFlow ? "false" : "true"); bindLoginIntentPreparation(link); link.addEventListener("click", (event) => { if (activeFlow) { event.preventDefault(); failLogin(new Error("Sign-in cancelled"), "handoff_cancelled"); return; } if (!preparedFlowIsFresh()) { event.preventDefault(); loginContinueRequested = true; void prepareLogin("user_nav_click"); return; } startLogin(preparedFlow, link); }); return link; } function closeNativeLoginPopover() { const popover = nativeLoginPopover; nativeLoginPopover = null; if (!popover) return; window.removeEventListener("resize", popover.reposition); window.removeEventListener("scroll", popover.reposition, true); document.removeEventListener("pointerdown", popover.onPointerDown, true); document.removeEventListener("keydown", popover.onKeyDown, true); popover.element.remove(); } function positionNativeLoginPopover() { const popover = nativeLoginPopover; if (!popover?.anchor?.isConnected) { closeNativeLoginPopover(); return; } const rect = popover.anchor.getBoundingClientRect(); const width = popover.element.offsetWidth || 320; const margin = 12; const left = Math.max( margin, Math.min(rect.left + rect.width / 2 - width / 2, window.innerWidth - width - margin) ); popover.element.style.left = `${Math.round(left + window.scrollX)}px`; popover.element.style.top = `${Math.round(rect.bottom + window.scrollY + 10)}px`; } function requestNativeLogin( anchor, { title = "Sign in with Hugging Face", description = "Continue to use this feature in the Space.", intent = "protected_action", } = {} ) { if (userFromResult(oauthResult) && liveSpaceSession()) return false; if (!anchor?.isConnected) return false; closeNativeLoginPopover(); const element = document.createElement("div"); element.className = "hf-watch-popover hf-login-popover space-native-login-popover"; element.setAttribute("role", "dialog"); element.setAttribute("aria-label", title); const close = document.createElement("button"); close.type = "button"; close.className = "hf-watch-popover__close"; close.setAttribute("aria-label", "Close"); close.textContent = "×"; const titleElement = document.createElement("p"); titleElement.className = "hf-watch-popover__title"; titleElement.textContent = title; const descriptionElement = document.createElement("p"); descriptionElement.className = "hf-watch-popover__sub"; descriptionElement.textContent = description; const continueLink = document.createElement("a"); continueLink.className = "hf-login-popover__btn"; continueLink.target = "_blank"; continueLink.rel = "noopener"; continueLink.setAttribute("aria-disabled", "true"); continueLink.innerHTML = '' + 'Preparing sign in…'; element.append(close, titleElement, descriptionElement, continueLink); const clone = isCloneDeployment(); if (clone) { descriptionElement.textContent = "Sign-in is only available in the official hfviewer Space."; continueLink.href = OFFICIAL_SPACE_URL; continueLink.setAttribute("aria-disabled", "false"); const label = continueLink.querySelector("span"); if (label) label.textContent = "Open the official hfviewer Space"; } else { bindLoginIntentPreparation(continueLink); } document.body.appendChild(element); const popover = { element, anchor, intent, continueLink, reposition: () => positionNativeLoginPopover(), onPointerDown: (event) => { if (!element.contains(event.target) && !anchor.contains(event.target)) { closeNativeLoginPopover(); } }, onKeyDown: (event) => { if (event.key === "Escape") closeNativeLoginPopover(); }, }; nativeLoginPopover = popover; close.addEventListener("click", closeNativeLoginPopover); continueLink.addEventListener("click", (event) => { if (clone) { trackAuthEvent("space_clone_official_space_opened", { component: "space_native_login_popover", login_intent: intent, }); return; } if (!preparedFlowIsFresh() || activeFlow) { event.preventDefault(); if (!activeFlow) void prepareLogin("user_continue_click").then(() => refreshNativeLoginPopover()); return; } trackAuthEvent("space_hf_login_continue_clicked", { component: "space_native_login_popover", login_intent: intent, }); startLogin(preparedFlow, continueLink); }); window.addEventListener("resize", popover.reposition); window.addEventListener("scroll", popover.reposition, true); document.addEventListener("pointerdown", popover.onPointerDown, true); document.addEventListener("keydown", popover.onKeyDown, true); positionNativeLoginPopover(); trackAuthEvent("space_hf_login_preflight_shown", { component: "space_native_login_popover", login_intent: intent, }); if (!clone) void prepareLogin("user_preflight").then(() => refreshNativeLoginPopover()); return true; } function refreshNativeLoginPopover() { const popover = nativeLoginPopover; if (!popover) return; if (isCloneDeployment()) { positionNativeLoginPopover(); return; } if (preparedFlowIsFresh() && preparedFlow.loginUrl && !activeFlow) { popover.continueLink.href = preparedFlow.loginUrl; popover.continueLink.setAttribute("aria-disabled", "false"); const label = popover.continueLink.querySelector("span"); if (label) label.textContent = "Continue with Hugging Face"; } positionNativeLoginPopover(); } function makeLoggedInControl(user, { compact = false } = {}) { const wrap = document.createElement("div"); wrap.dataset.spaceNativeAuth = "profile"; wrap.className = "space-native-auth-wrap"; if (compact) wrap.classList.add("space-native-auth-wrap--compact"); const chip = document.createElement("button"); chip.type = "button"; chip.className = "hfnx-auth__chip"; chip.setAttribute("aria-haspopup", "menu"); chip.setAttribute("aria-expanded", "false"); chip.appendChild(makeAvatar(user)); const label = document.createElement("span"); label.textContent = user.username; chip.appendChild(label); const menu = document.createElement("div"); menu.className = "hfnx-auth__menu space-native-auth-menu"; menu.setAttribute("role", "menu"); const myModels = makeHfviewerAccountLink( "My models", "/?my_models=1&blogs_with_graphs=1&next_landing=1", "my_models" ); const bookmarks = makeHfviewerAccountLink( "Bookmarks", "/?bookmarks=1&blogs_with_graphs=1&next_landing=1", "bookmarks" ); const releaseWatchlist = makeHfviewerAccountLink( "Release watchlist", "/?release_watchlist=1&blogs_with_graphs=1&next_landing=1", "release_watchlist" ); const writeArticle = makeHfviewerAccountLink( "Write article", "/?article_picker=1&login_intent=interactive_articles&blogs_with_graphs=1&next_landing=1", "write_article" ); const logout = document.createElement("button"); logout.type = "button"; logout.className = "hfnx-auth__item"; logout.textContent = "Log out"; logout.setAttribute("role", "menuitem"); logout.addEventListener("click", () => { trackAuthEvent("space_hf_logout"); oauthResult = null; writeStoredResult(null); renderAuth(); // Logged-in page loads intentionally do not prepare an OAuth flow. Once // the profile is cleared, prepare one immediately so the replacement Log // in control is a real link on the first click. void prepareLogin("background_post_logout"); }); const setOpen = (open) => { menu.classList.toggle("is-open", open); chip.setAttribute("aria-expanded", open ? "true" : "false"); }; chip.addEventListener("click", (event) => { event.stopPropagation(); setOpen(!menu.classList.contains("is-open")); }); document.addEventListener("click", () => setOpen(false)); menu.append(myModels, bookmarks, releaseWatchlist, writeArticle, logout); wrap.append(chip, menu); return wrap; } function renderAuth() { if ((!authHost && !compactAuthHost) || rendering) return; rendering = true; accountDestinationLinks = []; const pills = keepReleasePills(); const user = userFromResult(oauthResult); if (authHost) { authHost.replaceChildren(...pills, user ? makeLoggedInControl(user) : makeLoggedOutControl()); } if (compactAuthHost) { compactAuthHost.replaceChildren(); compactAuthHost.hidden = !user; if (user) compactAuthHost.appendChild(makeLoggedInControl(user, { compact: true })); } queueMicrotask(() => { rendering = false; prepareAccountDestinations(); announceAuthState(); }); } function applyOauthResult(callbackResult, source) { oauthResult = callbackResult; writeStoredResult(callbackResult); activeFlow = null; renderAuth(); closeNativeLoginPopover(); const user = userFromResult(callbackResult); identifyAuthenticatedUser(user, source); trackAuthEvent("space_hf_login_completed", { component: "space_nav", username_present: !!user?.username, subject_present: !!user?.subject, email_present: !!user?.email, }); } function failLogin(error, failureStage) { console.warn("Hugging Face Space login failed", error); activeFlow = null; renderAuth(); trackAuthEvent(failureStage === "handoff_cancelled" ? "space_hf_login_cancelled" : "space_hf_login_failed", { user_initiated: true, failure_category: authFailureCategory(error), component: "space_nav", failure_stage: failureStage, error_name: String(error?.name || "Error").slice(0, 80), error_message: String(error?.message || "Unknown error").slice(0, 240), request_status: Number(error?.status || 0) || undefined, }); void prepareLogin("background_after_login_failure"); } function delay(milliseconds) { return new Promise((resolve) => window.setTimeout(resolve, milliseconds)); } function isUserPreparationTrigger(trigger) { return String(trigger || "").startsWith("user_"); } function schedulePrepareRecovery(trigger) { if (prepareRecoveryTimer || oauthResult || activeFlow) return; // Bounded backoff: once the schedule is exhausted this page stops trying // until the next sign-in intent. if (prepareFailureCount >= PREPARE_RECOVERY_DELAYS_MS.length) return; const recoveryDelay = PREPARE_RECOVERY_DELAYS_MS[prepareFailureCount]; prepareFailureCount += 1; prepareRecoveryTimer = window.setTimeout(() => { prepareRecoveryTimer = null; void prepareLogin( isUserPreparationTrigger(trigger) ? "user_recovery" : "background_recovery" ); }, recoveryDelay); } function retryableRequestError(error) { return ( error?.name === "AuthResponseError" || error?.name === "TypeError" || error?.name === "AbortError" || [408, 425, 429, 500, 502, 503, 504].includes(Number(error?.status || 0)) ); } async function postJson(url, body, { retryDelays = [0], validate = null } = {}) { let lastError = null; for (let attempt = 0; attempt < retryDelays.length; attempt += 1) { if (retryDelays[attempt] > 0) await delay(retryDelays[attempt]); const controller = new AbortController(); const timer = window.setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS); try { const response = await fetch(url, { method: "POST", mode: "cors", credentials: "omit", headers: { "content-type": "application/json" }, body: JSON.stringify(body), signal: controller.signal, }); let payload; try { payload = await response.json(); } catch { const error = invalidAuthResponse("invalid_json"); if (!response.ok) error.status = response.status; throw error; } if (!response.ok && response.status !== 202) { const error = new Error(payload?.error || `Request failed (${response.status})`); error.status = response.status; throw error; } if (!payload || typeof payload !== "object" || Array.isArray(payload)) throw invalidAuthResponse("invalid_payload"); validate?.(payload); return payload; } catch (error) { error.retryCount = attempt; lastError = error; if (!retryableRequestError(error) || attempt === retryDelays.length - 1) throw error; } finally { window.clearTimeout(timer); } } throw lastError || new Error("Request failed"); } function announceAuthState() { const user = userFromResult(oauthResult); const session = liveSpaceSession(); const identity = user && session ? `${user.subject || user.username}:${session.id}` : ""; if (identity === lastAnnouncedAuthIdentity) return; lastAnnouncedAuthIdentity = identity; window.dispatchEvent( new CustomEvent(AUTH_CHANGED_EVENT, { detail: { authenticated: !!identity, username: user?.username || "", }, }) ); } async function postAuthenticatedSpaceJson(url, payload) { const session = liveSpaceSession(); if (!session) throw new Error("The Space login expired. Please sign in again."); try { return await postJson(url, { ...(payload || {}), link_session_id: session.id, link_session_secret: session.secret, }); } catch (error) { if (/login expired|session expired|invalid|unauthorized/i.test(String(error?.message || ""))) { oauthResult = null; writeStoredResult(null); renderAuth(); void prepareLogin("background_session_expired"); } throw error; } } window.hfviewerSpaceAuth = Object.freeze({ isAuthenticated: () => !!userFromResult(oauthResult) && !!liveSpaceSession(), postJson: postAuthenticatedSpaceJson, requestLogin: requestNativeLogin, }); async function pollForCompletion(flow) { while (activeFlow === flow && Date.now() - flow.startedAt < FLOW_TIMEOUT_MS) { try { const result = await postJson(CONSUME_URL, { flow_id: flow.id, flow_secret: flow.secret, }); if (result?.status === "complete" && userFromResult(result)) { applyOauthResult( { userInfo: result.userInfo, spaceSession: result.spaceSession }, "hf_space_native_oauth_handoff" ); return; } } catch (error) { failLogin(error, "handoff_consume"); return; } await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS)); } if (activeFlow === flow) failLogin(new Error("OAuth flow timed out"), "handoff_timeout"); } function schedulePreparedFlowExpiry(flow) { if (preparedFlowExpiryTimer) window.clearTimeout(preparedFlowExpiryTimer); // A prepared URL is only valid for a few minutes. Replace it as it expires // so the Log in control stays a real link: the sign-in must open from the // user's first click (native target=_blank), which an async fetch cannot do. preparedFlowExpiryTimer = window.setTimeout(() => { preparedFlowExpiryTimer = null; if (preparedFlow !== flow || activeFlow) return; preparedFlow = null; renderAuth(); void prepareLogin("background_scheduled").then(() => refreshNativeLoginPopover()); }, PREPARE_REFRESH_MS); } function startLogin(flow, link) { flow.startedAt = Date.now(); activeFlow = flow; preparedFlow = null; loginContinueRequested = false; // Keep the clicked anchor alive until the browser has performed its native // target=_blank navigation. Replacing it synchronously can cancel the popup. link.textContent = "Signing in…"; link.title = "Cancel this sign-in and try again"; link.setAttribute("aria-disabled", "false"); trackAuthEvent("space_hf_login_clicked", { component: "space_nav" }); void pollForCompletion(flow); } async function prepareLogin(trigger = "background_initial") { if (oauthResult || activeFlow) return; // Authentication is intentionally available only in the two official // deployments. A fork can copy our declared space_repo value, but it cannot // claim an official browser origin and must never generate misleading auth // failures or receive a trusted handoff. if ( window.location.hostname.endsWith(".hf.space") && !OFFICIAL_SPACE_HOSTS.has(window.location.hostname.toLowerCase()) ) return; if (preparedFlowIsFresh()) return; if (preparePromise) { if (isUserPreparationTrigger(trigger)) prepareIntentEscalated = true; return preparePromise; } if (!isUserPreparationTrigger(trigger)) { if (backgroundPrepareAttempts >= PREPARE_MAX_BACKGROUND_ATTEMPTS) return; backgroundPrepareAttempts += 1; } const prepareStartedAt = performance.now(); preparePromiseTrigger = String(trigger || "background_initial"); prepareIntentEscalated = isUserPreparationTrigger(preparePromiseTrigger); const flow = { id: randomFlowValue(), secret: randomFlowValue(), preparedAt: Date.now(), startedAt: 0, loginUrl: "", }; preparePromise = postJson( START_URL, { flow_id: flow.id, flow_secret: flow.secret }, { retryDelays: PREPARE_RETRY_DELAYS_MS, validate: validatedLoginUrl } ).then((result) => { const loginUrl = validatedLoginUrl(result); flow.loginUrl = loginUrl.toString(); preparedFlow = flow; const recoveredFailureCount = prepareFailureCount; const recoveredFromFailure = prepareFailureEpisodeActive; if (!prepareSuccessReported || recoveredFromFailure || prepareIntentEscalated) { trackAuthEvent("space_hf_login_prepared", { component: "space_nav", preparation_trigger: preparePromiseTrigger, user_initiated: prepareIntentEscalated, duration_ms: Math.max(0, Math.round(performance.now() - prepareStartedAt)), recovered_from_failure: recoveredFromFailure, recovery_count: recoveredFailureCount, }); } prepareSuccessReported = true; prepareFailureEpisodeActive = false; prepareFailureCount = 0; backgroundPrepareAttempts = 0; if (prepareRecoveryTimer) window.clearTimeout(prepareRecoveryTimer); prepareRecoveryTimer = null; schedulePreparedFlowExpiry(flow); if (!activeFlow) renderAuth(); refreshNativeLoginPopover(); }).catch((error) => { console.warn("Hugging Face Space login preparation failed", error); // Background/intent preparation is operational prewarm telemetry, not a // failed login attempt: report it at most once per page load. A user who // explicitly asked to sign in is reported per failure, up to a small cap. const reportFailure = prepareIntentEscalated ? userPrepareFailureReports < PREPARE_MAX_USER_FAILURE_REPORTS : !backgroundPrepareFailureReported && !prepareFailureEpisodeActive; if (reportFailure) { if (prepareIntentEscalated) userPrepareFailureReports += 1; else backgroundPrepareFailureReported = true; trackAuthEvent("space_hf_login_preparation_failed", { component: "space_nav", failure_stage: "login_prepare", preparation_trigger: preparePromiseTrigger, user_initiated: prepareIntentEscalated, error_name: String(error?.name || "Error").slice(0, 80), error_message: String(error?.message || "Unknown error").slice(0, 240), request_status: Number(error?.status || 0) || undefined, failure_category: authFailureCategory(error), error_code: error?.code, retry_count: error?.retryCount || 0, recovery_count: prepareFailureCount, }); } prepareFailureEpisodeActive = true; schedulePrepareRecovery(preparePromiseTrigger); }).finally(() => { preparePromise = null; preparePromiseTrigger = ""; prepareIntentEscalated = false; }); return preparePromise; } async function initializeApp() { renderAuth(); identifyAuthenticatedUser(userFromResult(oauthResult), "hf_space_native_oauth_restored"); await prepareLogin("background_initial"); } if (authHost) { const observer = new MutationObserver(() => { if (!rendering && !authHost.querySelector("[data-space-native-auth]")) renderAuth(); }); observer.observe(authHost, { childList: true }); } window.addEventListener("storage", (event) => { if (event.key !== STORAGE_KEY) return; oauthResult = readStoredResult(); renderAuth(); }); window.setInterval(() => { void prepareLogin("background_scheduled"); prepareAccountDestinations(); }, PREPARE_REFRESH_MS); void initializeApp();