frontend client for gemstone. decentralised workplace app
1import { 2 oAuthClient, 3 type TypedExpoOAuthClientInstance, 4} from "@/lib/utils/atproto/oauth"; 5import { isDevMode } from "@/lib/utils/env"; 6import { Agent } from "@atproto/api"; 7import type { OAuthSession } from "@atproto/oauth-client"; 8import type { Dispatch, ReactNode, SetStateAction } from "react"; 9import { createContext, useContext, useEffect, useState } from "react"; 10 11export interface OAuthContextValue { 12 session?: OAuthSession; 13 agent?: Agent; 14 client: TypedExpoOAuthClientInstance; 15 isLoading: boolean; 16} 17 18const OAuthContext = createContext< 19 [OAuthContextValue, Dispatch<SetStateAction<OAuthContextValue>>] | null 20>(null); 21 22export const useOAuthValue = () => { 23 const value = useContext(OAuthContext); 24 if (!value) 25 throw new Error( 26 "OAuth provider failed to initialise. Did you access this out of tree somehow? Tried to access OAuth value before it was initialised.", 27 ); 28 return value[0]; 29}; 30 31export const useOAuthSetter = () => { 32 const value = useContext(OAuthContext); 33 if (!value) 34 throw new Error( 35 "OAuth provider failed to initialise. Did you access this out of tree somehow? Tried to access OAuth value before it was initialised.", 36 ); 37 return value[1]; 38}; 39 40export const useOAuthSession = () => { 41 const { session } = useOAuthValue(); 42 return session; 43}; 44 45export const useOAuthAgent = () => { 46 const { agent } = useOAuthValue(); 47 return agent; 48}; 49 50export const useOAuthAgentGuaranteed = () => { 51 const { agent } = useOAuthValue(); 52 if (!agent) 53 throw new Error( 54 "Tried to access OAuth agent before it was created. Ensure that you are calling useOAuthAgentGuaranteed *after* you have a valid OAuth session.", 55 ); 56 return agent; 57}; 58 59export const useOAuthClient = () => { 60 const { client } = useOAuthValue(); 61 return client; 62}; 63 64export const useOAuthSessionGuaranteed = () => { 65 const { session } = useOAuthValue(); 66 if (!session) 67 throw new Error( 68 "Tried to access OAuth session before it was created. Ensure that you are calling useOAuthSessionGuaranteed *after* you have a valid OAuth session.", 69 ); 70 return session; 71}; 72 73export const OAuthProvider = ({ children }: { children: ReactNode }) => { 74 const providedOAuthClient = oAuthClient; 75 const [oAuth, setOAuth] = useState<OAuthContextValue>({ 76 client: providedOAuthClient, 77 isLoading: true, 78 }); 79 80 useEffect(() => { 81 const initOAuth = async () => { 82 try { 83 const result = await providedOAuthClient.init(); 84 if (result) { 85 const { session, state } = result; 86 87 if (isDevMode) { 88 console.log("session state:", state); 89 if (state != null) { 90 console.log( 91 `${session.sub} was successfully authenticated (state: ${state})`, 92 ); 93 } else { 94 console.log( 95 `${session.sub} was restored (last active session), token_endpoint: ${session.serverMetadata.token_endpoint}`, 96 ); 97 } 98 } 99 const agent = new Agent(session); 100 setOAuth({ 101 session, 102 agent, 103 client: providedOAuthClient, 104 isLoading: false, 105 }); 106 return; 107 } 108 setOAuth((o) => ({ 109 ...o, 110 isLoading: false, 111 })); 112 return; 113 } catch (err: unknown) { 114 console.error( 115 "something went wrong when trying to init the oauth client.", 116 ); 117 console.error(err); 118 } 119 }; 120 121 console.log("initOAuth start"); 122 123 initOAuth() 124 .then(() => { 125 console.log("initOAuth end"); 126 }) 127 .catch((err: unknown) => { 128 console.error( 129 "something went wrong when trying to init the oauth client.", 130 ); 131 console.error(err); 132 }); 133 134 if (isDevMode) { 135 console.log("finished initialising oauth client"); 136 } 137 }, [providedOAuthClient]); 138 139 return <OAuthContext value={[oAuth, setOAuth]}>{children}</OAuthContext>; 140};