import "server-only"; import { Client } from "@atproto/lex"; import { IdResolver } from "@atproto/identity"; import { TokenRefreshError } from "@atproto/oauth-client"; import { refresh } from "next/cache"; import { getSession } from "@/auth/session"; import { getOAuthClient } from "@/auth/client"; const idResolver = new IdResolver(); export class AuthRequiredError extends Error { constructor(message = "Authentication required") { super(message); this.name = "AuthRequiredError"; } } /** * Get an unauthenticated lex Client for reading from a user's PDS. * Resolves the DID to find the PDS endpoint, then creates a client that hits it directly. * Use this for read-only operations to avoid OAuth client's CachedGetter issues with "use cache". */ export async function getPublicLexClient(did: string): Promise { const atprotoData = await idResolver.did.resolveAtprotoData(did); const pdsUrl = atprotoData.pds; return new Client(pdsUrl); } /** * Get an authenticated lex Client for the current user. * Throws AuthRequiredError if not authenticated. * If the OAuth session is invalid/deleted, clears the cookie and throws AuthRequiredError. */ export async function getLexClient(): Promise { const session = await getSession(); if (!session.did) { throw new AuthRequiredError(); } const oauthClient = await getOAuthClient(); let oauthSession; try { oauthSession = await oauthClient.restore(session.did); } catch (err) { if (err instanceof TokenRefreshError) { const cause = err.cause instanceof Error ? err.cause.message : err.cause; console.log(`[auth] TokenRefreshError ${session.did}: ${err.message} (cause: ${cause})`); session.destroy(); refresh(); } else { const msg = err instanceof Error ? err.message : err; console.log(`[auth] restore failed ${session.did}: ${msg}`); } throw err; } if (!oauthSession) { throw new AuthRequiredError(); } // Create lex Client directly from OAuth session (idiomatic usage) return new Client(oauthSession); }