diff --git a/.changeset/cuddly-guests-hug.md b/.changeset/cuddly-guests-hug.md
new file mode 100644
index 00000000..ea4be080
--- /dev/null
+++ b/.changeset/cuddly-guests-hug.md
@@ -0,0 +1,7 @@
+---
+"@graphprotocol/hypergraph-react": patch
+"create-hypergraph": patch
+---
+
+improve processConnectAuthSuccess behaviour
+
\ No newline at end of file
diff --git a/apps/events/src/routes/authenticate-success.tsx b/apps/events/src/routes/authenticate-success.tsx
index b546efec..dc21be2b 100644
--- a/apps/events/src/routes/authenticate-success.tsx
+++ b/apps/events/src/routes/authenticate-success.tsx
@@ -1,6 +1,6 @@
import { useHypergraphApp } from '@graphprotocol/hypergraph-react';
import { createFileRoute, useNavigate } from '@tanstack/react-router';
-import { useEffect } from 'react';
+import { useEffect, useRef } from 'react';
export const Route = createFileRoute('/authenticate-success')({
component: RouteComponent,
@@ -16,11 +16,17 @@ function RouteComponent() {
const { ciphertext, nonce } = Route.useSearch();
const { processConnectAuthSuccess } = useHypergraphApp();
const navigate = useNavigate();
+ const isProcessingRef = useRef(false);
useEffect(() => {
- processConnectAuthSuccess({ storage: localStorage, ciphertext, nonce });
- console.log('redirecting to /');
- navigate({ to: '/', replace: true });
+ if (isProcessingRef.current) return; // prevent multiple calls from useEffect double calling in StrictMode
+ const result = processConnectAuthSuccess({ storage: localStorage, ciphertext, nonce });
+ if (result.success) {
+ isProcessingRef.current = true;
+ navigate({ to: '/', replace: true });
+ } else {
+ alert(result.error);
+ }
}, [ciphertext, nonce, processConnectAuthSuccess, navigate]);
return
Authenticating …
;
diff --git a/apps/privy-login-example/src/routes/authenticate-success.tsx b/apps/privy-login-example/src/routes/authenticate-success.tsx
index b546efec..dc21be2b 100644
--- a/apps/privy-login-example/src/routes/authenticate-success.tsx
+++ b/apps/privy-login-example/src/routes/authenticate-success.tsx
@@ -1,6 +1,6 @@
import { useHypergraphApp } from '@graphprotocol/hypergraph-react';
import { createFileRoute, useNavigate } from '@tanstack/react-router';
-import { useEffect } from 'react';
+import { useEffect, useRef } from 'react';
export const Route = createFileRoute('/authenticate-success')({
component: RouteComponent,
@@ -16,11 +16,17 @@ function RouteComponent() {
const { ciphertext, nonce } = Route.useSearch();
const { processConnectAuthSuccess } = useHypergraphApp();
const navigate = useNavigate();
+ const isProcessingRef = useRef(false);
useEffect(() => {
- processConnectAuthSuccess({ storage: localStorage, ciphertext, nonce });
- console.log('redirecting to /');
- navigate({ to: '/', replace: true });
+ if (isProcessingRef.current) return; // prevent multiple calls from useEffect double calling in StrictMode
+ const result = processConnectAuthSuccess({ storage: localStorage, ciphertext, nonce });
+ if (result.success) {
+ isProcessingRef.current = true;
+ navigate({ to: '/', replace: true });
+ } else {
+ alert(result.error);
+ }
}, [ciphertext, nonce, processConnectAuthSuccess, navigate]);
return Authenticating …
;
diff --git a/apps/template-nextjs/Components/Login/AuthCallback.tsx b/apps/template-nextjs/Components/Login/AuthCallback.tsx
index adde8ec4..a76c2e41 100644
--- a/apps/template-nextjs/Components/Login/AuthCallback.tsx
+++ b/apps/template-nextjs/Components/Login/AuthCallback.tsx
@@ -2,7 +2,7 @@
import { useHypergraphApp } from '@graphprotocol/hypergraph-react';
import { useRouter } from 'next/navigation';
-import { useEffect } from 'react';
+import { useEffect, useRef } from 'react';
export type AuthCallbackProps = {
ciphertext: string;
@@ -11,10 +11,17 @@ export type AuthCallbackProps = {
export function AuthCallback({ ciphertext, nonce }: Readonly) {
const router = useRouter();
const { processConnectAuthSuccess } = useHypergraphApp();
+ const isProcessingRef = useRef(false);
useEffect(() => {
- processConnectAuthSuccess({ storage: localStorage, ciphertext, nonce });
- router.replace('/');
+ if (isProcessingRef.current) return; // prevent multiple calls from useEffect double calling in StrictMode
+ const result = processConnectAuthSuccess({ storage: localStorage, ciphertext, nonce });
+ if (result.success) {
+ isProcessingRef.current = true;
+ router.replace('/');
+ } else {
+ alert(result.error);
+ }
}, [ciphertext, nonce, processConnectAuthSuccess, router]);
return Authenticating …
;
diff --git a/apps/template-vite-react/src/routes/authenticate-success.tsx b/apps/template-vite-react/src/routes/authenticate-success.tsx
index b546efec..dc21be2b 100644
--- a/apps/template-vite-react/src/routes/authenticate-success.tsx
+++ b/apps/template-vite-react/src/routes/authenticate-success.tsx
@@ -1,6 +1,6 @@
import { useHypergraphApp } from '@graphprotocol/hypergraph-react';
import { createFileRoute, useNavigate } from '@tanstack/react-router';
-import { useEffect } from 'react';
+import { useEffect, useRef } from 'react';
export const Route = createFileRoute('/authenticate-success')({
component: RouteComponent,
@@ -16,11 +16,17 @@ function RouteComponent() {
const { ciphertext, nonce } = Route.useSearch();
const { processConnectAuthSuccess } = useHypergraphApp();
const navigate = useNavigate();
+ const isProcessingRef = useRef(false);
useEffect(() => {
- processConnectAuthSuccess({ storage: localStorage, ciphertext, nonce });
- console.log('redirecting to /');
- navigate({ to: '/', replace: true });
+ if (isProcessingRef.current) return; // prevent multiple calls from useEffect double calling in StrictMode
+ const result = processConnectAuthSuccess({ storage: localStorage, ciphertext, nonce });
+ if (result.success) {
+ isProcessingRef.current = true;
+ navigate({ to: '/', replace: true });
+ } else {
+ alert(result.error);
+ }
}, [ciphertext, nonce, processConnectAuthSuccess, navigate]);
return Authenticating …
;
diff --git a/docs/docs/authentication.md b/docs/docs/authentication.md
index d31beece..a48212f7 100644
--- a/docs/docs/authentication.md
+++ b/docs/docs/authentication.md
@@ -126,11 +126,17 @@ function RouteComponent() {
const { ciphertext, nonce } = Route.useSearch(); // get the ciphertext and nonce from the URL
const { processConnectAuthSuccess } = useHypergraphApp();
const navigate = useNavigate();
+ const isProcessingRef = useRef(false);
useEffect(() => {
- processConnectAuthSuccess({ storage: localStorage, ciphertext, nonce });
- console.log("redirecting to /");
- navigate({ to: "/", replace: true });
+ if (isProcessingRef.current) return; // prevent multiple calls from useEffect double calling in StrictMode
+ const result = processConnectAuthSuccess({ storage: localStorage, ciphertext, nonce });
+ if (result.success) {
+ isProcessingRef.current = true;
+ navigate({ to: '/', replace: true });
+ } else {
+ alert(result.error);
+ }
}, [ciphertext, nonce, processConnectAuthSuccess, navigate]);
return Authenticating …
;
diff --git a/packages/hypergraph-react/src/HypergraphAppContext.tsx b/packages/hypergraph-react/src/HypergraphAppContext.tsx
index cfd5161a..e50eb65e 100644
--- a/packages/hypergraph-react/src/HypergraphAppContext.tsx
+++ b/packages/hypergraph-react/src/HypergraphAppContext.tsx
@@ -115,7 +115,15 @@ export type HypergraphAppCtx = {
connectUrl: string;
redirectFn: (url: URL) => void;
}): void;
- processConnectAuthSuccess(params: { storage: Identity.Storage; ciphertext: string; nonce: string }): void;
+ processConnectAuthSuccess(params: { storage: Identity.Storage; ciphertext: string; nonce: string }):
+ | {
+ success: true;
+ identity: Connect.PrivateAppIdentity;
+ }
+ | {
+ success: false;
+ error: string;
+ };
syncServerUri: string;
};
@@ -250,9 +258,6 @@ export function HypergraphAppProvider({
const identity = useSelectorStore(store, (state) => state.context.identity);
const privyIdentity = useSelectorStore(store, (state) => state.context.privyIdentity);
- console.log('identity', identity);
- console.log('privyIdentity', privyIdentity);
-
const logout = useCallback(() => {
websocketConnection?.close();
setWebsocketConnection(undefined);
@@ -1464,15 +1469,26 @@ export function HypergraphAppProvider({
);
const processConnectAuthSuccessForContext = useCallback(
- (params: { storage: Identity.Storage; ciphertext: string; nonce: string }) => {
+ (params: {
+ storage: Identity.Storage;
+ ciphertext: string;
+ nonce: string;
+ }):
+ | {
+ success: true;
+ identity: Connect.PrivateAppIdentity;
+ }
+ | {
+ success: false;
+ error: string;
+ } => {
const { storage, ciphertext, nonce } = params;
const storedNonce = storage.getItem('geo-connect-auth-nonce');
const storedExpiry = Number.parseInt(storage.getItem('geo-connect-auth-expiry') ?? '0', 10);
const storedSecretKey = storage.getItem('geo-connect-auth-secret-key');
const storedPublicKey = storage.getItem('geo-connect-auth-public-key');
if (!storedNonce || !storedExpiry || !storedSecretKey || !storedPublicKey) {
- alert('Failed to authenticate due missing data in the local storage');
- return;
+ return { success: false, error: 'Failed to authenticate due missing data in the local storage' };
}
try {
@@ -1487,7 +1503,7 @@ export function HypergraphAppProvider({
}),
);
- setIdentity({
+ const identity: Connect.PrivateAppIdentity = {
address: parsedAuthParams.appIdentityAddress,
addressPrivateKey: parsedAuthParams.appIdentityAddressPrivateKey,
accountAddress: parsedAuthParams.accountAddress,
@@ -1498,14 +1514,17 @@ export function HypergraphAppProvider({
encryptionPrivateKey: parsedAuthParams.encryptionPrivateKey,
sessionToken: parsedAuthParams.sessionToken,
sessionTokenExpires: parsedAuthParams.sessionTokenExpires,
- });
+ };
+
+ setIdentity(identity);
storage.removeItem('geo-connect-auth-nonce');
storage.removeItem('geo-connect-auth-expiry');
storage.removeItem('geo-connect-auth-secret-key');
storage.removeItem('geo-connect-auth-public-key');
+ return { success: true, identity };
} catch (error) {
console.error(error);
- alert('Failed to authenticate due to invalid callback');
+ return { success: false, error: 'Failed to authenticate due to invalid callback' };
}
},
[setIdentity],