an atproto based link aggregator
at main 61 lines 1.7 kB view raw
1/** 2 * Lex client utilities for ATProto record operations 3 */ 4 5import { Client } from '@atproto/lex'; 6import { IdResolver } from '@atproto/identity'; 7import { TokenRefreshError } from '@atproto/oauth-client-node'; 8import { createOAuthClient, getSession } from './auth'; 9import { localDb } from './db'; 10 11const idResolver = new IdResolver(); 12 13export class AuthRequiredError extends Error { 14 constructor(message = 'Authentication required') { 15 super(message); 16 this.name = 'AuthRequiredError'; 17 } 18} 19 20/** 21 * Get an unauthenticated lex Client for reading from a user's PDS. 22 * Resolves the DID to find the PDS endpoint. 23 */ 24export async function getPublicLexClient(did: string): Promise<Client> { 25 const atprotoData = await idResolver.did.resolveAtprotoData(did); 26 const pdsUrl = atprotoData.pds; 27 return new Client(pdsUrl); 28} 29 30/** 31 * Get an authenticated lex Client for the current user. 32 * Throws AuthRequiredError if not authenticated. 33 */ 34export async function getLexClient(cookies: Parameters<typeof getSession>[0]): Promise<Client> { 35 const session = await getSession(cookies); 36 if (!session.did) { 37 throw new AuthRequiredError(); 38 } 39 40 const oauthClient = await createOAuthClient(localDb); 41 42 let oauthSession; 43 try { 44 oauthSession = await oauthClient.restore(session.did); 45 } catch (err) { 46 if (err instanceof TokenRefreshError) { 47 // Session was deleted or token refresh failed - clear stale cookie 48 console.log(`[auth] Clearing stale session for ${session.did}: ${(err as Error).message}`); 49 session.did = undefined; 50 await session.save(); 51 } 52 throw err; 53 } 54 55 if (!oauthSession) { 56 throw new AuthRequiredError(); 57 } 58 59 // Create lex Client directly from OAuth session 60 return new Client(oauthSession); 61}