[READ-ONLY] Mirror of https://github.com/flo-bit/atmo-tools. atmo.tools
0

Configure Feed

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

atmo-tools / src / lib / atproto / server / session.ts
2.2 kB 73 lines
1import type { Cookies } from '@sveltejs/kit'; 2import { Client } from '@atcute/client'; 3import type { Did } from '@atcute/lexicons'; 4import { 5 type OAuthSession, 6 TokenInvalidError, 7 TokenRefreshError, 8 TokenRevokedError, 9 AuthMethodUnsatisfiableError 10} from '@atcute/oauth-node-client'; 11import { createOAuthClient } from './oauth'; 12import { getSignedCookie } from './signed-cookie'; 13import { scopes } from '../settings'; 14 15export type SessionLocals = { 16 session: OAuthSession | null; 17 client: Client | null; 18 did: Did | null; 19}; 20 21/** 22 * Restores an OAuth session from the signed `did` cookie. 23 * Returns session locals to be assigned to `event.locals`. 24 * Deletes the cookie only if the session is genuinely unrecoverable. 25 * Transient failures (network, KV) preserve the cookie for retry. 26 */ 27export async function restoreSession( 28 cookies: Cookies, 29 env?: App.Platform['env'] 30): Promise<SessionLocals> { 31 const did = getSignedCookie(cookies, 'did') as Did | null; 32 33 if (!did) { 34 return { session: null, client: null, did: null }; 35 } 36 37 // If permissions changed since login, invalidate the session 38 const savedScope = getSignedCookie(cookies, 'scope'); 39 if (savedScope !== null && savedScope !== scopes.join(' ')) { 40 cookies.delete('did', { path: '/' }); 41 cookies.delete('scope', { path: '/' }); 42 return { session: null, client: null, did: null }; 43 } 44 45 try { 46 const oauth = createOAuthClient(env); 47 const session = await oauth.restore(did); 48 49 return { 50 session, 51 client: new Client({ handler: session }), 52 did 53 }; 54 } catch (e) { 55 console.error('Failed to restore session:', e); 56 57 // Only delete cookies when the session is genuinely unrecoverable. 58 // Transient errors (network issues, KV hiccups) should preserve the 59 // cookie so the next request can retry without forcing a full re-login. 60 const isSessionGone = 61 e instanceof TokenInvalidError || 62 e instanceof TokenRevokedError || 63 e instanceof TokenRefreshError || 64 e instanceof AuthMethodUnsatisfiableError; 65 66 if (isSessionGone) { 67 cookies.delete('did', { path: '/' }); 68 cookies.delete('scope', { path: '/' }); 69 } 70 71 return { session: null, client: null, did: null }; 72 } 73}