import { Client, ok, simpleFetchHandler } from '@atcute/client'; import { AppBskyActorDefs } from '@atcute/bluesky'; import { configureOAuth, createAuthorizationUrl, finalizeAuthorization, getSession, listStoredSessions, OAuthUserAgent, type Session } from '@atcute/oauth-browser-client'; import { CompositeDidDocumentResolver, LocalActorResolver, PlcDidDocumentResolver, WebDidDocumentResolver, XrpcHandleResolver } from '@atcute/identity-resolver'; configureOAuth({ metadata: { client_id: import.meta.env.VITE_OAUTH_CLIENT_ID, redirect_uri: import.meta.env.VITE_OAUTH_REDIRECT_URI }, identityResolver: new LocalActorResolver({ handleResolver: new XrpcHandleResolver({ serviceUrl: 'https://public.api.bsky.app' }), didDocumentResolver: new CompositeDidDocumentResolver({ methods: { plc: new PlcDidDocumentResolver(), web: new WebDidDocumentResolver() } }) }) }); /** Public (unauthenticated) RPC client — always available */ export const publicClient = new Client({ handler: simpleFetchHandler({ service: 'https://public.api.bsky.app' }) }); /** Authenticated RPC client — set after login, null otherwise */ export let rpc: Client | null = null; /** Current OAuth session */ let currentSession: Session | null = null; export async function getClient(): Promise { if (rpc === null) { await resumeSession(); } return rpc ?? publicClient; } /** Try to resume an existing session from localStorage */ export async function resumeSession(): Promise { const dids = listStoredSessions(); if (dids.length === 0) return false; try { const session = await getSession(dids[0], { allowStale: true }); setSession(session); return true; } catch { return false; } } /** Handle the OAuth callback — call this from the callback route */ export async function handleCallback(params: URLSearchParams): Promise { const { session } = await finalizeAuthorization(params); setSession(session); } /** Start the login flow */ export async function login(handle: string): Promise { const authUrl = await createAuthorizationUrl({ target: { type: 'account', identifier: handle }, scope: import.meta.env.VITE_OAUTH_SCOPE }); await new Promise((r) => setTimeout(r, 200)); window.location.assign(authUrl); } /** Check if a session is active */ export function isLoggedIn(): boolean { return rpc !== null; } /** Fetch the logged-in user's profile */ export async function getProfile(): Promise { if (!rpc || !currentSession) return null; const data = await ok(rpc.get('app.bsky.actor.getProfile', { params: { actor: currentSession.info.sub } })); return data; } function setSession(session: Session): void { currentSession = session; const agent = new OAuthUserAgent(session); rpc = new Client({ handler: agent }); }