@sky-mavis/tanto-widget
Version:
Tanto Widget
105 lines • 3.73 kB
JavaScript
import {jsx}from'@emotion/react/jsx-runtime';import {useMutation}from'@tanstack/react-query';import {useState,useRef,useCallback,useMemo}from'react';import {v4}from'uuid';import {useAccount,useSignMessage,useDisconnect}from'wagmi';import {useAccountSwitch}from'../../hooks/useAccountSwitch.mjs';import {authEventEmitter}from'../../hooks/useAuthEffect.mjs';import {mutation}from'../../services/queries.mjs';import {delay}from'../../utils/common.mjs';import {TantoWidgetError,TantoWidgetErrorCodes}from'../../utils/errors.mjs';import {generateSiweMessage}from'../../utils/siwe.mjs';import {isWCConnector,isWaypointConnector}from'../../utils/walletDetection.mjs';import {useTantoConfig}from'../tanto/useTantoConfig.mjs';import {AuthContext}from'./AuthContext.mjs';import {useWaypointMessageHandler}from'./useWaypointMessageHandler.mjs';function AuthProvider({
children
}) {
const {
createAccountOnConnect: enableAuth = false,
clientId,
__internal_baseUrl
} = useTantoConfig();
const {
address,
chainId,
connector
} = useAccount();
const {
signMessageAsync
} = useSignMessage();
const {
disconnect
} = useDisconnect();
const [isSigningIn, setIsSigningIn] = useState(false);
const [error, setError] = useState(null);
const currentSignInRef = useRef(null);
const {
mutateAsync: generateNonce
} = useMutation(mutation.generateNonce());
const {
mutateAsync: createAccount
} = useMutation(mutation.createAccount());
const reset = useCallback(() => {
setIsSigningIn(false);
setError(null);
currentSignInRef.current = null;
}, []);
const signIn = useCallback(async () => {
if (!enableAuth || !address || !chainId || isSigningIn) return;
const sessionId = v4();
currentSignInRef.current = sessionId;
setIsSigningIn(true);
setError(null);
try {
// Wait for WC (in case of connect to metamask) switch chain
if (isWCConnector(connector?.id)) await delay(1_000);
if (isWaypointConnector(connector?.id)) return;
const {
nonce,
expirationTime,
issuedAt,
notBefore
} = await generateNonce({
baseUrl: __internal_baseUrl,
address,
clientId
});
const message = generateSiweMessage({
address,
chainId,
nonce,
expirationTime,
issuedAt,
notBefore
});
const signature = await signMessageAsync({
message
});
if (currentSignInRef.current !== sessionId) return;
const {
idToken
} = await createAccount({
baseUrl: __internal_baseUrl,
message,
signature,
clientId
});
authEventEmitter.emit('success', {
address,
chainId,
token: idToken
});
} catch (error) {
if (currentSignInRef.current !== sessionId) return;
const authError = error instanceof Error ? error : new TantoWidgetError(TantoWidgetErrorCodes.CREATE_ACCOUNT_FAILED, 'Failed to create account');
console.debug('Auth error:', authError);
setError(authError);
authEventEmitter.emit('failed', {
error: authError
});
disconnect();
} finally {
setIsSigningIn(false);
}
}, [enableAuth, address, chainId, isSigningIn, connector?.id, generateNonce, signMessageAsync, createAccount, clientId, disconnect]);
useAccountSwitch(signIn);
useWaypointMessageHandler(enableAuth);
const contextValue = useMemo(() => ({
enable: enableAuth,
error,
isSigningIn,
signIn,
reset
}), [enableAuth, error, isSigningIn, signIn, reset]);
return jsx(AuthContext.Provider, {
value: contextValue,
children: children
});
}export{AuthProvider};