const CSS = ` :root { color-scheme: light; --bg: #f3efe4; --ink: #1b1916; --muted: #5c564c; --accent: #0b5d45; --card: #fffdf7; --line: #d9d2c3; } * { box-sizing: border-box; } html, body { margin: 0; padding: 0; } body { font-family: "Iowan Old Style", Palatino, Georgia, serif; background: var(--bg); color: var(--ink); line-height: 1.45; } main { max-width: 36rem; margin: 0 auto; padding: 2.5rem 1.25rem 4rem; } h1 { font-size: 1.75rem; letter-spacing: -0.02em; margin: 0 0 0.5rem; } p { color: var(--muted); margin: 0 0 1rem; } a { color: var(--accent); } button, .btn { appearance: none; border: 0; background: var(--accent); color: #f7fff9; font: 600 0.95rem/1.2 system-ui, sans-serif; padding: 0.7rem 1rem; border-radius: 999px; cursor: pointer; text-decoration: none; display: inline-block; } button.secondary { background: transparent; color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); } button:disabled { opacity: 0.5; cursor: not-allowed; } .wordmark { font-size: 0.8rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent); margin-bottom: 1.25rem; } .list { display: grid; gap: 0.6rem; margin: 1.25rem 0; } .account { text-align: left; width: 100%; border-radius: 14px; background: var(--card); color: var(--ink); box-shadow: inset 0 0 0 1px var(--line); padding: 0.85rem 1rem; font-family: system-ui, sans-serif; } .account strong { display: block; font-size: 1rem; } .account span { color: var(--muted); font-size: 0.8rem; } .empty { font-family: system-ui, sans-serif; color: var(--muted); } .actions { display: flex; gap: 0.6rem; flex-wrap: wrap; margin-top: 1.25rem; } .mono { font-family: ui-monospace, monospace; font-size: 0.8rem; word-break: break-all; } `; /** * JSON literal safe to inline in a `` from closing the element early. */ function jsonForScript(value: unknown): string { return JSON.stringify(value ?? null) .replaceAll("<", "\\u003c") .replaceAll(">", "\\u003e") .replaceAll("\u2028", "\\u2028") .replaceAll("\u2029", "\\u2029"); } function shell(title: string, body: string, extraHead = ""): string { return ` ${escapeHtml(title)} ${extraHead} ${body} `; } export { landingPage } from "./landing"; export function embedPage(): string { const script = ` const parentOrigin = resolveParentOrigin(); function resolveParentOrigin() { if (location.ancestorOrigins && location.ancestorOrigins[0]) return location.ancestorOrigins[0]; if (document.referrer) { try { return new URL(document.referrer).origin; } catch { return ""; } } return ""; } function isHttpOrigin(origin) { try { const url = new URL(origin); if (url.protocol === "https:") return true; return url.protocol === "http:" && (url.hostname === "localhost" || url.hostname === "127.0.0.1"); } catch { return false; } } function hasAccess() { if (window.top === window) return Promise.resolve(true); if (typeof document.hasStorageAccess === "function") return document.hasStorageAccess(); return Promise.resolve(true); } async function tryActivateExistingGrant() { if (window.top === window) return true; if (typeof document.requestStorageAccess !== "function") return false; try { await document.requestStorageAccess(); return true; } catch { return false; } } async function api(method, path, body) { const res = await fetch(path, { method, credentials: "include", headers: body ? { "content-type": "application/json" } : undefined, body: body ? JSON.stringify(body) : undefined, }); const data = await res.json().catch(() => ({})); if (!res.ok) throw new Error(data.message || res.statusText); return data; } function showChoose() { window.parent.postMessage({ type: "needs-access" }, parentOrigin); document.body.innerHTML = ''; document.body.style.margin = "0"; document.body.style.background = "transparent"; const btn = document.getElementById("choose"); btn.style.width = "100%"; btn.addEventListener("click", async () => { // Do not call hasStorageAccess() here — it can consume the user gesture. if (typeof document.requestStorageAccess === "function") { try { await document.requestStorageAccess(); window.location.reload(); return; } catch {} } window.parent.postMessage({ type: "popup" }, parentOrigin); const url = "/choose?parent=" + encodeURIComponent(parentOrigin); window.open(url, "loggedin-choose", "width=440,height=600"); }); } async function bootSilent() { window.addEventListener("message", onMessage); window.parent.postMessage({ type: "ready" }, parentOrigin); const data = await api("GET", "/xrpc/fyi.loggedin.account.list"); window.parent.postMessage({ type: "accounts", accounts: data.accounts }, parentOrigin); } async function boot() { if (!parentOrigin || !isHttpOrigin(parentOrigin)) return; if (await hasAccess()) { await bootSilent(); return; } if (await tryActivateExistingGrant()) { window.location.reload(); return; } showChoose(); } async function onMessage(event) { if (event.data && event.data.type === "picked" && event.data.did && event.source === window) { return; } if (event.data && event.data.type === "picked" && event.data.did && event.origin === location.origin) { window.parent.postMessage({ type: "picked", did: event.data.did }, parentOrigin); return; } if (event.origin !== parentOrigin) return; const type = event.data && event.data.type; const did = event.data && event.data.did; if (type === "heartbeat" && did) { await api("POST", "/xrpc/fyi.loggedin.account.loggedIn", { did, origin: parentOrigin }); const data = await api("GET", "/xrpc/fyi.loggedin.account.list"); window.parent.postMessage({ type: "accounts", accounts: data.accounts }, parentOrigin); } if (type === "logout" && did) { await api("POST", "/xrpc/fyi.loggedin.account.logout", { did, origin: parentOrigin }); const data = await api("GET", "/xrpc/fyi.loggedin.account.list"); window.parent.postMessage({ type: "accounts", accounts: data.accounts }, parentOrigin); } } boot().catch(() => { if (parentOrigin && isHttpOrigin(parentOrigin)) showChoose(); }); `; return shell( "loggedin.fyi embed", "", ``, ); } export function choosePage(parentOrigin: string): string { const script = ` const PARENT = ${JSON.stringify(parentOrigin)}; async function main() { const res = await fetch("/xrpc/fyi.loggedin.account.list", { credentials: "include" }); const data = await res.json(); const root = document.getElementById("list"); if (!data.accounts || data.accounts.length === 0) { root.innerHTML = '

No accounts saved on this device yet.

'; return; } const needed = [...new Set(data.accounts.flatMap((a) => a.origins || []))]; const LABELS = await loadOriginLabels(needed); for (const account of data.accounts) { const btn = document.createElement("button"); btn.className = "account"; btn.type = "button"; const handle = await resolveHandle(account.did); const originNames = account.origins.map((o) => LABELS[o] || o).join(", "); btn.innerHTML = "" + escapeHtml(handle) + "" + escapeHtml(originNames) + ""; btn.addEventListener("click", () => pick(account.did)); root.appendChild(btn); } } async function loadOriginLabels(origins) { const labels = {}; if (!origins.length) return labels; try { const qs = origins.map((o) => "origin=" + encodeURIComponent(o)).join("&"); const res = await fetch("/origins?" + qs); const data = await res.json(); for (const row of data.origins || []) labels[row.origin] = row.name; } catch {} return labels; } function pick(did) { const payload = { type: "picked", did }; if (window.opener) { try { if (window.opener.parent && window.opener.parent !== window.opener) { window.opener.parent.postMessage(payload, PARENT); } else { window.opener.postMessage(payload, PARENT); } } catch { window.opener.postMessage(payload, PARENT); } } window.close(); } async function resolveHandle(did) { try { const res = await fetch("https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=" + encodeURIComponent(did)); if (!res.ok) return did; const profile = await res.json(); return profile.handle ? "@" + profile.handle : did; } catch { return did; } } function escapeHtml(s) { return String(s).replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c])); } main(); `; return shell( "Choose an account — loggedin.fyi", `
loggedin.fyi

Continue with an account you already use

These DIDs were saved on this device by participating AT Proto apps. Picking one sends it back so the app can start a normal login.

`, ); } export function enrollPage(did: string, returnUrl: string): string { const script = ` const DID = ${JSON.stringify(did)}; const RETURN_URL = ${JSON.stringify(returnUrl)}; document.getElementById("save").addEventListener("click", async () => { const btn = document.getElementById("save"); btn.disabled = true; try { const origin = new URL(RETURN_URL).origin; const res = await fetch("/xrpc/fyi.loggedin.account.loggedIn", { method: "POST", credentials: "include", headers: { "content-type": "application/json" }, body: JSON.stringify({ did: DID, origin }), }); if (!res.ok) throw new Error("save failed"); location.href = RETURN_URL; } catch (err) { btn.disabled = false; document.getElementById("err").textContent = String(err.message || err); } }); document.getElementById("skip").addEventListener("click", () => { location.href = RETURN_URL; }); `; return shell( "Save this account — loggedin.fyi", `
loggedin.fyi

Save this account on this device

Other AT Proto apps can then offer it as a login hint. This does not sign you in anywhere.

${escapeHtml(did)}

`, ); } export function savePage(did: string, origin: string): string { const script = ` const DID = ${JSON.stringify(did)}; const ORIGIN = ${JSON.stringify(origin)}; async function run() { const btn = document.getElementById("save"); const err = document.getElementById("err"); try { const res = await fetch("/xrpc/fyi.loggedin.account.loggedIn", { method: "POST", credentials: "include", headers: { "content-type": "application/json" }, body: JSON.stringify({ did: DID, origin: ORIGIN }), }); if (!res.ok) throw new Error("save failed"); if (window.opener) { window.opener.postMessage({ type: "saved", did: DID }, ORIGIN); } window.close(); } catch (e) { btn.disabled = false; btn.style.display = ""; err.textContent = String(e.message || e); } } document.getElementById("save").addEventListener("click", run); run(); `; return shell( "Saving — loggedin.fyi", `
loggedin.fyi

Saving account…

${escapeHtml(did)}

`, ); } export function savePageLogout(did: string, origin: string): string { const script = ` const DID = ${JSON.stringify(did)}; const ORIGIN = ${JSON.stringify(origin)}; async function run() { try { const res = await fetch("/xrpc/fyi.loggedin.account.logout", { method: "POST", credentials: "include", headers: { "content-type": "application/json" }, body: JSON.stringify({ did: DID, origin: ORIGIN }), }); if (!res.ok) throw new Error("logout failed"); if (window.opener) { window.opener.postMessage({ type: "saved", did: DID, action: "logout" }, ORIGIN); } window.close(); } catch (e) { document.getElementById("err").textContent = String(e.message || e); } } run(); `; return shell( "Removing — loggedin.fyi", `
loggedin.fyi

Removing account…

${escapeHtml(did)}

`, ); } export type NativeStartOptions = { appName: string; callback: string; origin: string; state: string | null; token: string; /** Set for the post-login save flow; omitted for the account chooser. */ did?: string; }; /** * First-party page opened by a native SDK through the shared browser cookie * jar (ASWebAuthenticationSession on iOS, a Custom Tab on Android). The cookie * is attached here, so this page — and only this page — can hand the app a * token for the same session. The token travels on the affirmative action * only; "Not now" returns `denied=1`. */ export function nativeStartPage(options: NativeStartOptions): string { const script = ` const CALLBACK = ${jsonForScript(options.callback)}; const ORIGIN = ${jsonForScript(options.origin)}; const STATE = ${jsonForScript(options.state)}; const TOKEN = ${jsonForScript(options.token)}; const SAVE_DID = ${jsonForScript(options.did ?? null)}; function callbackUrl(params) { const url = new URL(CALLBACK); if (STATE !== null) url.searchParams.set("state", STATE); for (const [key, value] of Object.entries(params)) url.searchParams.set(key, value); return url.toString(); } function finish(params) { location.href = callbackUrl(params); } function deny() { finish({ denied: "1" }); } async function api(method, path, body) { const res = await fetch(path, { method, credentials: "include", headers: body ? { "content-type": "application/json" } : undefined, body: body ? JSON.stringify(body) : undefined, }); const data = await res.json().catch(() => ({})); if (!res.ok) throw new Error(data.message || res.statusText); return data; } async function save() { const btn = document.getElementById("primary"); btn.disabled = true; try { await api("POST", "/xrpc/fyi.loggedin.account.loggedIn", { did: SAVE_DID, origin: ORIGIN }); finish({ did: SAVE_DID, token: TOKEN }); } catch (err) { btn.disabled = false; document.getElementById("err").textContent = String(err.message || err); } } async function chooser() { const list = document.getElementById("list"); try { const data = await api("GET", "/xrpc/fyi.loggedin.account.list"); const accounts = data.accounts || []; if (accounts.length === 0) { list.innerHTML = '

No accounts saved on this device yet. Continue to sign in normally.

'; document.getElementById("continue").hidden = false; return; } list.innerHTML = ""; for (const account of accounts) { const btn = document.createElement("button"); btn.type = "button"; btn.className = "account"; btn.innerHTML = "" + escapeHtml(account.did) + "" + "" + escapeHtml((account.origins || []).join(", ")) + ""; btn.addEventListener("click", () => finish({ did: account.did, token: TOKEN })); list.appendChild(btn); } document.getElementById("continue").hidden = false; } catch (err) { list.innerHTML = '

' + escapeHtml(String(err.message || err)) + "

"; document.getElementById("continue").hidden = false; } } function escapeHtml(s) { return String(s).replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c])); } document.getElementById("deny").addEventListener("click", deny); if (SAVE_DID) { document.getElementById("primary").addEventListener("click", save); } else { document.getElementById("continue").addEventListener("click", () => finish({ token: TOKEN })); chooser(); } `; const body = options.did ? `

Remember this account on this device?

${escapeHtml(options.appName)} can let other AT Proto apps on this device offer this account as a login hint. It does not sign you in anywhere else.

${escapeHtml(options.did)}

` : `

Continue with an account you already use

These accounts were saved on this device by participating AT Proto apps. Picking one sends it to ${escapeHtml(options.appName)} so it can start a normal login.

Looking…

`; return shell( "loggedin.fyi", `
loggedin.fyi
${body}

`, ); } export function exampleRendererJs(): string { return `(() => { const BSKY = "https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile"; function ensureAccountStyles() { if (document.getElementById("loggedin-account-styles")) return; const style = document.createElement("style"); style.id = "loggedin-account-styles"; style.textContent = [ ".loggedin-account { display: flex; align-items: center; gap: 0.75rem; text-align: left; width: 100%; box-sizing: border-box; cursor: pointer; }", ".loggedin-account-avatar { width: 2.5rem; height: 2.5rem; border-radius: 999px; object-fit: cover; flex-shrink: 0; background: currentColor; opacity: 0.18; }", "img.loggedin-account-avatar { opacity: 1; background: transparent; }", ".loggedin-account-meta { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }", ".loggedin-account-meta strong, .loggedin-account-meta em, .loggedin-account-meta span { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }", ".loggedin-account-meta em { font-style: normal; opacity: 0.85; }", ".loggedin-account-meta span { opacity: 0.7; font-size: 0.85em; }", ].join("\\n"); document.head.appendChild(style); } async function resolveHandle(did) { try { const res = await fetch(BSKY + "?actor=" + encodeURIComponent(did)); if (!res.ok) return { handle: did, displayName: "", avatar: "" }; const p = await res.json(); return { handle: p.handle ? "@" + p.handle : did, displayName: p.displayName || "", avatar: typeof p.avatar === "string" ? p.avatar : "", }; } catch { return { handle: did, displayName: "", avatar: "" }; } } async function renderAccountList(el, accounts, options) { const onPick = options && options.onPick; const labels = (options && options.originLabels) || {}; ensureAccountStyles(); el.innerHTML = ""; if (!accounts || accounts.length === 0) { el.textContent = "No hinted accounts on this device."; return; } for (const account of accounts) { const profile = await resolveHandle(account.did); const btn = document.createElement("button"); btn.type = "button"; btn.className = "loggedin-account"; const originNames = (account.origins || []).map((o) => labels[o] || o).join(", "); const avatar = profile.avatar ? '' : ''; btn.innerHTML = avatar + '' + "" + escapeHtml(profile.handle) + "" + (profile.displayName ? "" + escapeHtml(profile.displayName) + "" : "") + "" + escapeHtml(originNames) + "" + ""; btn.addEventListener("click", () => onPick && onPick(account.did, profile.handle)); el.appendChild(btn); } } let popupMode = false; function originOf(iframe, fallback) { try { return new URL(iframe.src).origin; } catch { return fallback || ""; } } function prepareEmbed(iframe) { const current = iframe.getAttribute("allow") || ""; const parts = current.split(";").map((part) => part.trim()).filter(Boolean); if (!parts.includes("storage-access")) parts.push("storage-access"); iframe.setAttribute("allow", parts.join("; ")); return iframe; } function listenToEmbed(iframe, handlers) { prepareEmbed(iframe); window.addEventListener("message", (event) => { if (event.source === iframe.contentWindow) { const type = event.data && event.data.type; if (type === "accounts" && handlers.onAccounts) handlers.onAccounts(event.data.accounts || [], event.origin); if (type === "unavailable" && handlers.onUnavailable) handlers.onUnavailable(); if (type === "needs-access" && handlers.onNeedsAccess) handlers.onNeedsAccess(); if (type === "popup") { popupMode = true; if (handlers.onPopup) handlers.onPopup(); else if (handlers.onUnavailable) handlers.onUnavailable(); } if (type === "ready" && handlers.onReady) handlers.onReady(); if (type === "picked" && handlers.onPicked) handlers.onPicked(event.data.did); return; } const loggedinOrigin = originOf(iframe, ""); if (loggedinOrigin && event.origin === loggedinOrigin && event.data && event.data.type === "saved" && event.data.did) { if (handlers.onSaved) handlers.onSaved(event.data.did, event.data.action || "save"); } }); } function mountEmbed(iframe, src, handlers) { prepareEmbed(iframe); listenToEmbed(iframe, handlers); iframe.src = src; } function listenForPicked(loggedinOrigin, onPicked) { window.addEventListener("message", (event) => { if (event.origin !== loggedinOrigin) return; if (event.data && event.data.type === "picked" && event.data.did) onPicked(event.data.did); }); } function saveUrl(loggedinOrigin, did, origin, action) { const url = new URL("/save", loggedinOrigin); url.searchParams.set("did", did); url.searchParams.set("origin", origin); if (action === "logout") url.searchParams.set("action", "logout"); return url.toString(); } function openSavePopup(iframe, did, targetOrigin, action) { const loggedinOrigin = originOf(iframe, targetOrigin); window.open( saveUrl(loggedinOrigin, did, location.origin, action), action === "logout" ? "loggedin-logout" : "loggedin-save", "width=440,height=600" ); } function heartbeat(iframe, did, targetOrigin) { if (popupMode) { openSavePopup(iframe, did, targetOrigin, "save"); return; } iframe.contentWindow.postMessage({ type: "heartbeat", did }, targetOrigin); } function logout(iframe, did, targetOrigin) { if (popupMode) { openSavePopup(iframe, did, targetOrigin, "logout"); return; } iframe.contentWindow.postMessage({ type: "logout", did }, targetOrigin); } function enrollUrl(loggedinOrigin, did, returnUrl) { const url = new URL("/enroll", loggedinOrigin); url.searchParams.set("did", did); url.searchParams.set("return", returnUrl); return url.toString(); } function escapeHtml(s) { return String(s).replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c])); } window.Loggedin = { renderAccountList, prepareEmbed, listenToEmbed, mountEmbed, listenForPicked, heartbeat, logout, enrollUrl, saveUrl, }; })(); `; } function escapeHtml(value: string): string { return value .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """); }