atproto explorer pdsls.dev
atproto tool
at main 3.2 kB view raw
1import { Client, simpleFetchHandler } from "@atcute/client"; 2import { Did } from "@atcute/lexicons"; 3import { 4 finalizeAuthorization, 5 getSession, 6 OAuthUserAgent, 7 type Session, 8} from "@atcute/oauth-browser-client"; 9import { resolveDidDoc } from "../utils/api"; 10import { Sessions, setAgent, setSessions } from "./state"; 11 12export const saveSessionToStorage = (sessions: Sessions) => { 13 localStorage.setItem("sessions", JSON.stringify(sessions)); 14}; 15 16export const loadSessionsFromStorage = (): Sessions | null => { 17 const localSessions = localStorage.getItem("sessions"); 18 return localSessions ? JSON.parse(localSessions) : null; 19}; 20 21export const getAvatar = async (did: Did): Promise<string | undefined> => { 22 const rpc = new Client({ 23 handler: simpleFetchHandler({ service: "https://public.api.bsky.app" }), 24 }); 25 const res = await rpc.get("app.bsky.actor.getProfile", { params: { actor: did } }); 26 if (res.ok) { 27 return res.data.avatar; 28 } 29 return undefined; 30}; 31 32export const loadHandleForSession = async (did: Did, storedSessions: Sessions) => { 33 const doc = await resolveDidDoc(did); 34 const alias = doc.alsoKnownAs?.find((alias) => alias.startsWith("at://")); 35 if (alias) { 36 setSessions(did, { 37 signedIn: storedSessions[did].signedIn, 38 handle: alias.replace("at://", ""), 39 grantedScopes: storedSessions[did].grantedScopes, 40 }); 41 } 42}; 43 44export const retrieveSession = async (): Promise<void> => { 45 const init = async (): Promise<Session | undefined> => { 46 const params = new URLSearchParams(location.hash.slice(1)); 47 48 if (params.has("state") && (params.has("code") || params.has("error"))) { 49 history.replaceState(null, "", location.pathname + location.search); 50 51 const auth = await finalizeAuthorization(params); 52 const did = auth.session.info.sub; 53 54 localStorage.setItem("lastSignedIn", did); 55 56 const grantedScopes = localStorage.getItem("pendingScopes") || "atproto"; 57 localStorage.removeItem("pendingScopes"); 58 59 const sessions = loadSessionsFromStorage(); 60 const newSessions: Sessions = sessions || {}; 61 newSessions[did] = { signedIn: true, grantedScopes }; 62 saveSessionToStorage(newSessions); 63 return auth.session; 64 } else { 65 const lastSignedIn = localStorage.getItem("lastSignedIn"); 66 67 if (lastSignedIn) { 68 const sessions = loadSessionsFromStorage(); 69 const newSessions: Sessions = sessions || {}; 70 try { 71 const session = await getSession(lastSignedIn as Did); 72 const rpc = new Client({ handler: new OAuthUserAgent(session) }); 73 const res = await rpc.get("com.atproto.server.getSession"); 74 newSessions[lastSignedIn].signedIn = true; 75 saveSessionToStorage(newSessions); 76 if (!res.ok) throw res.data.error; 77 return session; 78 } catch (err) { 79 newSessions[lastSignedIn].signedIn = false; 80 saveSessionToStorage(newSessions); 81 throw err; 82 } 83 } 84 } 85 }; 86 87 const session = await init(); 88 89 if (session) setAgent(new OAuthUserAgent(session)); 90}; 91 92export const resumeSession = async (did: Did): Promise<void> => { 93 localStorage.setItem("lastSignedIn", did); 94 await retrieveSession(); 95};