import type { Cookies } from '@sveltejs/kit'; import { Client } from '@atcute/client'; import type { Did } from '@atcute/lexicons'; import { type OAuthSession, TokenInvalidError, TokenRefreshError, TokenRevokedError, AuthMethodUnsatisfiableError } from '@atcute/oauth-node-client'; import { createOAuthClient } from './oauth'; import { getSignedCookie } from './signed-cookie'; import { scopes } from '../settings'; export type SessionLocals = { session: OAuthSession | null; client: Client | null; did: Did | null; }; /** * Restores an OAuth session from the signed `did` cookie. * Returns session locals to be assigned to `event.locals`. * Deletes the cookie only if the session is genuinely unrecoverable. * Transient failures (network, KV) preserve the cookie for retry. */ export async function restoreSession( cookies: Cookies, env?: App.Platform['env'] ): Promise { const did = getSignedCookie(cookies, 'did') as Did | null; if (!did) { return { session: null, client: null, did: null }; } // If permissions changed since login, invalidate the session const savedScope = getSignedCookie(cookies, 'scope'); if (savedScope !== null && savedScope !== scopes.join(' ')) { cookies.delete('did', { path: '/' }); cookies.delete('scope', { path: '/' }); return { session: null, client: null, did: null }; } try { const oauth = createOAuthClient(env); const session = await oauth.restore(did); return { session, client: new Client({ handler: session }), did }; } catch (e) { console.error('Failed to restore session:', e); // Only delete cookies when the session is genuinely unrecoverable. // Transient errors (network issues, KV hiccups) should preserve the // cookie so the next request can retry without forcing a full re-login. const isSessionGone = e instanceof TokenInvalidError || e instanceof TokenRevokedError || e instanceof TokenRefreshError || e instanceof AuthMethodUnsatisfiableError; if (isSessionGone) { cookies.delete('did', { path: '/' }); cookies.delete('scope', { path: '/' }); } return { session: null, client: null, did: null }; } }