atproto pds in zig pds.zat.dev
pds atproto
25

Configure Feed

Select the types of activity you want to include in your feed.

Clarify session active status labels

zzstoatzz (Jun 9, 2026, 11:27 AM -0500) 04d2b26f 67b2e8c6

+9 -7
+9 -7
src/internal/passkeys.zig
··· 206 206 \\<button class="choice" type="button" data-kind="sessions" aria-pressed="false"><span>direct API tokens</span><strong id="session-count">0</strong></button> 207 207 \\</div> 208 208 \\<div class="filters" id="filters" hidden> 209 - \\<button class="filter" type="button" data-filter="usable" aria-pressed="true">usable token</button> 210 - \\<button class="filter" type="button" data-filter="ended" aria-pressed="false">expired/revoked</button> 211 - \\<button class="filter" type="button" data-filter="all" aria-pressed="false">all</button> 209 + \\<button class="filter" type="button" data-filter="usable" aria-pressed="true" title="Show rows that can currently authenticate requests. For OAuth rows: not expired and not revoked. For direct API token families: not revoked and either access or refresh token is still unexpired.">active</button> 210 + \\<button class="filter" type="button" data-filter="ended" aria-pressed="false" title="Show rows that cannot currently authenticate requests because they are expired or revoked.">inactive</button> 211 + \\<button class="filter" type="button" data-filter="all" aria-pressed="false" title="Show active and inactive rows together.">all</button> 212 212 \\</div> 213 213 \\<section class="section"> 214 214 \\<div class="section-head"><div><h2 id="list-title">OAuth app sessions</h2> ··· 639 639 \\const time=(value)=>{if(!value)return{short:'never',full:'never'};const d=new Date(value);return{short:d.toLocaleString([], {month:'short',day:'numeric',hour:'2-digit',minute:'2-digit'}),full:d.toLocaleString([], {dateStyle:'full',timeStyle:'long'})}}; 640 640 \\const methodLabel=(s)=>{if(s.appPasswordName)return`app password: ${s.appPasswordName}`;if(s.authMethod==='password')return'account password token';if(s.authMethod==='app_password')return'app password token';if(s.authMethod==='app_password_privileged')return'privileged app password token';return s.authMethod}; 641 641 \\const shownItems=()=>{const source=kind==='grants'?grants:sessions;if(filter==='all')return source;if(filter==='usable')return source.filter(item=>item.active);return source.filter(item=>!item.active)}; 642 - \\const pill=(usable)=>{const span=document.createElement('span');span.className=`pill ${usable?'usable':'ended'}`;span.textContent=usable?'usable token':'expired/revoked';span.title=usable?'Not revoked and not expired.':'Expired or revoked.';return span}; 642 + \\const activeTitle=(isGrant)=>isGrant?'OAuth token row is active when it has not expired and has not been revoked.':'Direct API token family is active when it has not been revoked and either its access token or refresh token is still unexpired.'; 643 + \\const inactiveTitle=(isGrant)=>isGrant?'OAuth token row is inactive when it is expired or revoked.':'Direct API token family is inactive when it is revoked or both access and refresh tokens are expired.'; 644 + \\const pill=(active,isGrant)=>{const span=document.createElement('span');span.className=`pill ${active?'usable':'ended'}`;span.textContent=active?'active':'inactive';span.title=active?activeTitle(isGrant):inactiveTitle(isGrant);return span}; 643 645 \\const stamp=(label,value)=>{const div=document.createElement('div');div.className='stamp';const span=document.createElement('span');span.textContent=label;const t=time(value);const body=document.createElement('time');body.textContent=t.short;body.title=t.full;body.dateTime=value||'';div.append(span,body);return div}; 644 646 \\const oauthAuthMethod=(g)=>g.authMethod==='passkey'?'passkey':g.authMethod==='password'?'password':'unknown method'; 645 - \\const card=(item)=>{const isGrant=kind==='grants';const el=document.createElement('article');el.className=`session-card ${item.active?'usable':'ended'}`;const top=document.createElement('div');top.className='card-top';const main=document.createElement('div');const who=document.createElement('div');who.className='who';who.textContent=item.handle||item.did||'unknown account';const sub=document.createElement('span');sub.className='did';sub.textContent=item.did||'';main.append(who,sub);top.append(main,pill(item.active));const what=document.createElement('div');what.className='what';what.textContent=isGrant?item.clientId:methodLabel(item);const scope=document.createElement('span');scope.className='scope';scope.textContent=isGrant?`${oauthAuthMethod(item)} authorization · ${item.scope}`:(item.controllerDid?`controller ${item.controllerDid}`:'com.atproto.server.createSession token family');what.append(scope);const grid=document.createElement('div');grid.className='card-grid';if(isGrant){grid.append(stamp('authorized',item.createdAt),stamp('token row expires',item.expiresAt),stamp('revoked',item.revokedAt))}else{grid.append(stamp('created',item.createdAt),stamp('last used',item.lastUsedAt),stamp('refresh token expires',item.refreshExpiresAt))}el.append(top,what,grid);return el}; 647 + \\const card=(item)=>{const isGrant=kind==='grants';const el=document.createElement('article');el.className=`session-card ${item.active?'usable':'ended'}`;const top=document.createElement('div');top.className='card-top';const main=document.createElement('div');const who=document.createElement('div');who.className='who';who.textContent=item.handle||item.did||'unknown account';const sub=document.createElement('span');sub.className='did';sub.textContent=item.did||'';main.append(who,sub);top.append(main,pill(item.active,isGrant));const what=document.createElement('div');what.className='what';what.textContent=isGrant?item.clientId:methodLabel(item);const scope=document.createElement('span');scope.className='scope';scope.textContent=isGrant?`${oauthAuthMethod(item)} authorization · ${item.scope}`:(item.controllerDid?`controller ${item.controllerDid}`:'com.atproto.server.createSession token family');what.append(scope);const grid=document.createElement('div');grid.className='card-grid';if(isGrant){grid.append(stamp('authorized',item.createdAt),stamp('token row expires',item.expiresAt),stamp('revoked',item.revokedAt))}else{grid.append(stamp('created',item.createdAt),stamp('last used',item.lastUsedAt),stamp('refresh token expires',item.refreshExpiresAt))}el.append(top,what,grid);return el}; 646 648 \\const renderPager=(total)=>{pagerRoot.textContent='';if(total<=pageSize)return;const pages=Math.ceil(total/pageSize);const prev=document.createElement('button');prev.type='button';prev.textContent='prev';prev.disabled=page===0;prev.onclick=()=>{page--;render()};const label=document.createElement('span');label.textContent=`${page+1}/${pages}`;const next=document.createElement('button');next.type='button';next.textContent='next';next.disabled=page>=pages-1;next.onclick=()=>{page++;render()};pagerRoot.append(prev,label,next)}; 647 - \\const renderControls=()=>{grantCount.textContent=`${grants.filter(g=>g.active).length} usable / ${grants.length} total`;sessionCount.textContent=`${sessions.filter(s=>s.active).length} usable / ${sessions.length} total`;for(const b of chooser.querySelectorAll('button'))b.setAttribute('aria-pressed',String(b.dataset.kind===kind));for(const b of filters.querySelectorAll('button'))b.setAttribute('aria-pressed',String(b.dataset.filter===filter))}; 648 - \\const render=()=>{renderControls();const isGrant=kind==='grants';title.textContent=isGrant?'OAuth app sessions':'direct API tokens';hint.textContent=isGrant?'App sign-ins issued by the OAuth flow. New rows show passkey or password authorization; older rows may show unknown method.':'Token families from com.atproto.server.createSession. These are separate from OAuth passkey sign-ins.';const items=shownItems();if(!items.length)return empty(filter==='usable'?'No usable token rows.':filter==='ended'?'No expired or revoked rows.':'No entries.');const maxPage=Math.max(0,Math.ceil(items.length/pageSize)-1);if(page>maxPage)page=maxPage;itemsRoot.textContent='';const list=document.createElement('div');list.className='list';for(const item of items.slice(page*pageSize,page*pageSize+pageSize))list.append(card(item));itemsRoot.append(list);renderPager(items.length)}; 649 + \\const renderControls=()=>{grantCount.textContent=`${grants.filter(g=>g.active).length} active / ${grants.length} total`;grantCount.title='OAuth active means the token row has not expired and has not been revoked.';sessionCount.textContent=`${sessions.filter(s=>s.active).length} active / ${sessions.length} total`;sessionCount.title='Direct API active means the token family has not been revoked and either access or refresh token is still unexpired.';for(const b of chooser.querySelectorAll('button'))b.setAttribute('aria-pressed',String(b.dataset.kind===kind));for(const b of filters.querySelectorAll('button'))b.setAttribute('aria-pressed',String(b.dataset.filter===filter))}; 650 + \\const render=()=>{renderControls();const isGrant=kind==='grants';title.textContent=isGrant?'OAuth app sessions':'direct API tokens';hint.textContent=isGrant?'App sign-ins issued by the OAuth flow. Active means the token row has not expired or been revoked. New rows show passkey or password authorization; older rows may show unknown method.':'Token families from com.atproto.server.createSession. Active means the family has not been revoked and still has an unexpired access or refresh token. These are separate from OAuth app sign-ins.';const items=shownItems();if(!items.length)return empty(filter==='usable'?'No active rows.':filter==='ended'?'No inactive rows.':'No entries.');const maxPage=Math.max(0,Math.ceil(items.length/pageSize)-1);if(page>maxPage)page=maxPage;itemsRoot.textContent='';const list=document.createElement('div');list.className='list';for(const item of items.slice(page*pageSize,page*pageSize+pageSize))list.append(card(item));itemsRoot.append(list);renderPager(items.length)}; 649 651 \\chooser.addEventListener('click',(e)=>{const b=e.target.closest('button[data-kind]');if(!b)return;kind=b.dataset.kind;page=0;render()}); 650 652 \\filters.addEventListener('click',(e)=>{const b=e.target.closest('button[data-filter]');if(!b)return;filter=b.dataset.filter;page=0;render()}); 651 653 \\form.addEventListener('submit',async(e)=>{e.preventDefault();status.className='status';try{status.textContent='loading token rows...';const token=form.token.value.trim();const data=await fail(await fetch('/xrpc/dev.zat.admin.listSessions?active=false&limit=500',{headers:{authorization:`Bearer ${token}`}}),'failed to load token rows');sessions=data.sessions||[];grants=data.oauthGrants||[];chooser.hidden=false;filters.hidden=false;kind='grants';filter=grants.some(g=>g.active)?'usable':grants.length?'ended':'all';page=0;render();status.textContent=''}catch(err){status.className='status error';status.textContent=err.message||String(err)}});