The page's side of accounts (worker/src/auth.ts): who is signed in, and the passkey ceremonies, with @simplewebauthn/browser turning the Worker's options into navigator.credentials calls and the answers back into JSON. The session is an HttpOnly cookie the page never sees; it only asks the Worker who it is (GET /jev/auth/me).
Signed in, the listener's Jev calls are charged to their own daily budget
instead of the address's per-minute share alone; the relay says how much
is used on each answer it charged (Jev-Budget: used/limit, read by
ask.mjs into noteBudget), so the header's count stays current.
14export const AUTH = '/jev/auth';
{ ready, user: { id, displayName } | null, budget: { used, limit, resetsAt } | null }
Who is signed in is asked for once per page, by the first reader to subscribe: every reader (the jev pane's budget, the you tab, profiles, ⏭'s history) then sees the real account, whichever of them mounts first. It was asked for only by the account control, and once that moved into a panel tab, the page read as signed out until the tab was opened (2026-09-27).
43export const passkeysSupported = () => typeof window !== 'undefined' && browserSupportsWebAuthn(); 44 45async function call(path, body) { 46 const res = await fetch(`${AUTH}/${path}`, { 47 method: body === undefined ? 'GET' : 'POST', 48 headers: body === undefined ? {} : { 'Content-Type': 'application/json' }, 49 body: body === undefined ? undefined : JSON.stringify(body), 50 credentials: 'same-origin', 51 }); 52 const text = await res.text(); 53 let parsed = null; 54 try { 55 parsed = text ? JSON.parse(text) : null; 56 } catch { 57 // a proxy's or the platform's own error page 58 } 59 if (!res.ok) throw new Error(parsed?.error ?? `the site answered ${res.status}`); 60 return parsed; 61}
Who is signed in, asked again; the page calls it once on load.
A browser's own refusal (the listener closed the prompt) reads as plain words.
A new account called displayName, with a passkey made on this device.
Sign in with any passkey this site has; the browser lists them.
Signed in: another passkey for the same account (another device, or a key).
The AI apps this listener connected through the hosted MCP (/ai/, worker/src/oauth.ts): [{ id, app, redirectHost, published, scope, createdAt }]. Disconnecting one ends its access at once.
112export async function listApps() { 113 const res = await fetch('/jev/me/apps', { credentials: 'same-origin' }); 114 if (!res.ok) throw new Error(`the site answered ${res.status}`); 115 return (await res.json()).apps; 116} 117export async function disconnectApp(id) { 118 const res = await fetch(`/jev/me/apps/${encodeURIComponent(id)}`, { method: 'DELETE', credentials: 'same-origin' }); 119 if (!res.ok && res.status !== 404) throw new Error(`the site answered ${res.status}`); 120}
The relay's Jev-Budget header on an answer: used/limit, or spent.
128export function noteBudget(value) { 129 if (!value || !state.user) return; 130 if (value === 'spent') { 131 if (state.budget) set({ budget: { ...state.budget, used: state.budget.limit } }); 132 return; 133 } 134 const m = /^(\d+)\/(\d+)$/.exec(value); 135 if (m) set({ budget: { ...(state.budget ?? {}), used: Number(m[1]), limit: Number(m[2]) } }); 136} 137onBudget(noteBudget);