mirror of
https://github.com/neynarxyz/create-farcaster-mini-app.git
synced 2025-11-16 08:08:56 -05:00
Revert "fix: SIWN dependencies"
This reverts commit 4ba948083278067334670b0573b8029755f4f7e3.
This commit is contained in:
parent
0d43b35c28
commit
5fd0e21532
@ -482,12 +482,6 @@ export async function init(projectName = null, autoAcceptDefaults = false, apiKe
|
|||||||
siwe: '^3.0.0',
|
siwe: '^3.0.0',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add auth-kit and next-auth dependencies if useSponsoredSigner is true
|
|
||||||
if (answers.useSponsoredSigner) {
|
|
||||||
packageJson.dependencies['@farcaster/auth-kit'] = '>=0.6.0 <1.0.0';
|
|
||||||
packageJson.dependencies['next-auth'] = '^4.24.11';
|
|
||||||
}
|
|
||||||
|
|
||||||
packageJson.devDependencies = {
|
packageJson.devDependencies = {
|
||||||
"@types/inquirer": "^9.0.8",
|
"@types/inquirer": "^9.0.8",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
@ -655,9 +649,6 @@ export async function init(projectName = null, autoAcceptDefaults = false, apiKe
|
|||||||
fs.appendFileSync(envPath, `\nSEED_PHRASE="${answers.seedPhrase}"`);
|
fs.appendFileSync(envPath, `\nSEED_PHRASE="${answers.seedPhrase}"`);
|
||||||
}
|
}
|
||||||
fs.appendFileSync(envPath, `\nUSE_TUNNEL="${answers.useTunnel}"`);
|
fs.appendFileSync(envPath, `\nUSE_TUNNEL="${answers.useTunnel}"`);
|
||||||
if (answers.useSponsoredSigner) {
|
|
||||||
fs.appendFileSync(envPath, `\nSPONSOR_SIGNER="${answers.useSponsoredSigner}"`);
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.unlinkSync(envExamplePath);
|
fs.unlinkSync(envExamplePath);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@neynar/create-farcaster-mini-app",
|
"name": "@neynar/create-farcaster-mini-app",
|
||||||
"version": "1.7.4",
|
"version": "1.7.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": false,
|
"private": false,
|
||||||
"access": "public",
|
"access": "public",
|
||||||
|
|||||||
@ -1,19 +1,17 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import '@farcaster/auth-kit/styles.css';
|
||||||
|
import { useSignIn, UseSignInData } from '@farcaster/auth-kit';
|
||||||
import { useCallback, useEffect, useState, useRef } from 'react';
|
import { useCallback, useEffect, useState, useRef } from 'react';
|
||||||
import sdk, { SignIn as SignInCore } from '@farcaster/frame-sdk';
|
import { cn } from '~/lib/utils';
|
||||||
import { useMiniApp } from '@neynar/react';
|
|
||||||
import { Button } from '~/components/ui/Button';
|
import { Button } from '~/components/ui/Button';
|
||||||
import { AuthDialog } from '~/components/ui/NeynarAuthButton/AuthDialog';
|
import { AuthDialog } from '~/components/ui/NeynarAuthButton/AuthDialog';
|
||||||
import { ProfileButton } from '~/components/ui/NeynarAuthButton/ProfileButton';
|
import { ProfileButton } from '~/components/ui/NeynarAuthButton/ProfileButton';
|
||||||
|
import { AuthDialog } from '~/components/ui/NeynarAuthButton/AuthDialog';
|
||||||
import { getItem, removeItem, setItem } from '~/lib/localStorage';
|
import { getItem, removeItem, setItem } from '~/lib/localStorage';
|
||||||
import { useMiniApp } from '@neynar/react';
|
import { useMiniApp } from '@neynar/react';
|
||||||
import {
|
import sdk, { SignIn as SignInCore } from '@farcaster/frame-sdk';
|
||||||
signIn as backendSignIn,
|
import { useQuickAuth } from '~/hooks/useQuickAuth';
|
||||||
signOut as backendSignOut,
|
|
||||||
useSession,
|
|
||||||
} from 'next-auth/react';
|
|
||||||
import sdk, { SignIn as SignInCore } from '@farcaster/miniapp-sdk';
|
|
||||||
|
|
||||||
type User = {
|
type User = {
|
||||||
fid: number;
|
fid: number;
|
||||||
@ -116,8 +114,69 @@ export function NeynarAuthButton() {
|
|||||||
const [backendUserProfile, setBackendUserProfile] = useState<{ username?: string; pfpUrl?: string }>({});
|
const [backendUserProfile, setBackendUserProfile] = useState<{ username?: string; pfpUrl?: string }>({});
|
||||||
|
|
||||||
// Determine which flow to use based on context
|
// Determine which flow to use based on context
|
||||||
|
// - Farcaster clients (when context is not undefined): Use QuickAuth (backend flow)
|
||||||
|
// - Browsers (when context is undefined): Use auth-kit (frontend flow)
|
||||||
const useBackendFlow = context !== undefined;
|
const useBackendFlow = context !== undefined;
|
||||||
|
|
||||||
|
// Helper function to fetch user data from Neynar API
|
||||||
|
const fetchUserData = useCallback(
|
||||||
|
async (fid: number): Promise<User | null> => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/users?fids=${fid}`);
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
return data.users?.[0] || null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching user data:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Auth Kit integration for browser-based authentication (only when not in Farcaster client)
|
||||||
|
const signInState = useSignIn({
|
||||||
|
nonce: !useBackendFlow ? (nonce || undefined) : undefined,
|
||||||
|
onSuccess: useCallback(
|
||||||
|
async (res: UseSignInData) => {
|
||||||
|
if (!useBackendFlow) {
|
||||||
|
// Only handle localStorage for frontend flow
|
||||||
|
const existingAuth = getItem<StoredAuthState>(STORAGE_KEY);
|
||||||
|
const user = res.fid ? await fetchUserData(res.fid) : null;
|
||||||
|
const authState: StoredAuthState = {
|
||||||
|
...existingAuth,
|
||||||
|
isAuthenticated: true,
|
||||||
|
user: user as StoredAuthState['user'],
|
||||||
|
signers: existingAuth?.signers || [], // Preserve existing signers
|
||||||
|
};
|
||||||
|
setItem<StoredAuthState>(STORAGE_KEY, authState);
|
||||||
|
setStoredAuth(authState);
|
||||||
|
}
|
||||||
|
// For backend flow, the session will be handled by QuickAuth
|
||||||
|
},
|
||||||
|
[useBackendFlow, fetchUserData]
|
||||||
|
),
|
||||||
|
onError: useCallback((error?: Error | null) => {
|
||||||
|
console.error('❌ Sign in error:', error);
|
||||||
|
}, []),
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
signIn: frontendSignIn,
|
||||||
|
signOut: frontendSignOut,
|
||||||
|
connect,
|
||||||
|
reconnect,
|
||||||
|
isSuccess,
|
||||||
|
isError,
|
||||||
|
error,
|
||||||
|
channelToken,
|
||||||
|
url,
|
||||||
|
data,
|
||||||
|
validSignature,
|
||||||
|
} = signInState;
|
||||||
|
|
||||||
// Helper function to create a signer
|
// Helper function to create a signer
|
||||||
const createSigner = useCallback(async () => {
|
const createSigner = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
@ -405,18 +464,25 @@ export function NeynarAuthButton() {
|
|||||||
console.error('❌ Backend sign-in error:', e);
|
console.error('❌ Backend sign-in error:', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [nonce, quickAuthSignIn, quickAuthUser, fetchUserData]);
|
}, [useBackendFlow]);
|
||||||
|
|
||||||
// Fetch user profile when quickAuthUser.fid changes (for backend flow)
|
// Auth Kit data synchronization (only for browser flow)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (useBackendFlow && quickAuthUser?.fid) {
|
if (!useBackendFlow) {
|
||||||
(async () => {
|
setMessage(data?.message || null);
|
||||||
const user = await fetchUserData(quickAuthUser.fid);
|
setSignature(data?.signature || null);
|
||||||
setBackendUserProfile({
|
|
||||||
username: user?.username || '',
|
// Reset the signer flow flag when message/signature change
|
||||||
pfpUrl: user?.pfp_url || '',
|
if (data?.message && data?.signature) {
|
||||||
});
|
signerFlowStartedRef.current = false;
|
||||||
})();
|
}
|
||||||
|
}
|
||||||
|
}, [useBackendFlow, data?.message, data?.signature]);
|
||||||
|
|
||||||
|
// Connect for frontend flow when nonce is available (only for browser flow)
|
||||||
|
useEffect(() => {
|
||||||
|
if (!useBackendFlow && nonce && !channelToken) {
|
||||||
|
connect();
|
||||||
}
|
}
|
||||||
}, [useBackendFlow, quickAuthUser?.fid, fetchUserData]);
|
}, [useBackendFlow, quickAuthUser?.fid, fetchUserData]);
|
||||||
|
|
||||||
@ -475,6 +541,97 @@ export function NeynarAuthButton() {
|
|||||||
}
|
}
|
||||||
}, [useBackendFlow, pollingInterval, quickAuthSignOut]);
|
}, [useBackendFlow, pollingInterval, quickAuthSignOut]);
|
||||||
|
|
||||||
|
// Backend flow using QuickAuth
|
||||||
|
const handleBackendSignIn = useCallback(async () => {
|
||||||
|
if (!nonce) {
|
||||||
|
console.error('❌ No nonce available for backend sign-in');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
setSignersLoading(true);
|
||||||
|
const result = await sdk.actions.signIn({ nonce });
|
||||||
|
|
||||||
|
setMessage(result.message);
|
||||||
|
setSignature(result.signature);
|
||||||
|
// Use QuickAuth to sign in
|
||||||
|
const signInResult = await quickAuthSignIn();
|
||||||
|
// Fetch user profile after sign in
|
||||||
|
if (quickAuthUser?.fid) {
|
||||||
|
const user = await fetchUserData(quickAuthUser.fid);
|
||||||
|
setBackendUserProfile({
|
||||||
|
username: user?.username || '',
|
||||||
|
pfpUrl: user?.pfp_url || '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof SignInCore.RejectedByUser) {
|
||||||
|
console.log('ℹ️ Sign-in rejected by user');
|
||||||
|
} else {
|
||||||
|
console.error('❌ Backend sign-in error:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [nonce, quickAuthSignIn, quickAuthUser, fetchUserData]);
|
||||||
|
|
||||||
|
// Fetch user profile when quickAuthUser.fid changes (for backend flow)
|
||||||
|
useEffect(() => {
|
||||||
|
if (useBackendFlow && quickAuthUser?.fid) {
|
||||||
|
(async () => {
|
||||||
|
const user = await fetchUserData(quickAuthUser.fid);
|
||||||
|
setBackendUserProfile({
|
||||||
|
username: user?.username || '',
|
||||||
|
pfpUrl: user?.pfp_url || '',
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}, [useBackendFlow, quickAuthUser?.fid, fetchUserData]);
|
||||||
|
|
||||||
|
const handleFrontEndSignIn = useCallback(() => {
|
||||||
|
if (isError) {
|
||||||
|
reconnect();
|
||||||
|
}
|
||||||
|
setDialogStep('signin');
|
||||||
|
setShowDialog(true);
|
||||||
|
frontendSignIn();
|
||||||
|
}, [isError, reconnect, frontendSignIn]);
|
||||||
|
|
||||||
|
const handleSignOut = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
setSignersLoading(true);
|
||||||
|
|
||||||
|
if (useBackendFlow) {
|
||||||
|
// Use QuickAuth sign out
|
||||||
|
await quickAuthSignOut();
|
||||||
|
} else {
|
||||||
|
// Frontend flow sign out
|
||||||
|
frontendSignOut();
|
||||||
|
removeItem(STORAGE_KEY);
|
||||||
|
setStoredAuth(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common cleanup for both flows
|
||||||
|
setShowDialog(false);
|
||||||
|
setDialogStep('signin');
|
||||||
|
setSignerApprovalUrl(null);
|
||||||
|
setMessage(null);
|
||||||
|
setSignature(null);
|
||||||
|
|
||||||
|
// Reset polling interval
|
||||||
|
if (pollingInterval) {
|
||||||
|
clearInterval(pollingInterval);
|
||||||
|
setPollingInterval(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset signer flow flag
|
||||||
|
signerFlowStartedRef.current = false;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Error during sign out:', error);
|
||||||
|
// Optionally handle error state
|
||||||
|
} finally {
|
||||||
|
setSignersLoading(false);
|
||||||
|
}
|
||||||
|
}, [useBackendFlow, frontendSignOut, pollingInterval, quickAuthSignOut]);
|
||||||
|
|
||||||
// Handle fetching signers after successful authentication
|
// Handle fetching signers after successful authentication
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (message && signature && !isSignerFlowRunning && !signerFlowStartedRef.current) {
|
if (message && signature && !isSignerFlowRunning && !signerFlowStartedRef.current) {
|
||||||
@ -551,10 +708,13 @@ export function NeynarAuthButton() {
|
|||||||
}
|
}
|
||||||
}, [message, signature]); // Simplified dependencies
|
}, [message, signature]); // Simplified dependencies
|
||||||
|
|
||||||
|
// Authentication check based on flow type
|
||||||
const authenticated = useBackendFlow
|
const authenticated = useBackendFlow
|
||||||
? !!quickAuthUser?.fid
|
? !!quickAuthUser?.fid // QuickAuth flow: check if user is authenticated via QuickAuth
|
||||||
: storedAuth?.isAuthenticated && !!(storedAuth?.signers && storedAuth.signers.length > 0);
|
: ((isSuccess && validSignature) || storedAuth?.isAuthenticated) && // Auth-kit flow: check auth-kit success or stored auth
|
||||||
|
!!(storedAuth?.signers && storedAuth.signers.length > 0); // Both flows: ensure signers exist
|
||||||
|
|
||||||
|
// User data based on flow type
|
||||||
const userData = useBackendFlow
|
const userData = useBackendFlow
|
||||||
? {
|
? {
|
||||||
fid: quickAuthUser?.fid,
|
fid: quickAuthUser?.fid,
|
||||||
@ -588,7 +748,7 @@ export function NeynarAuthButton() {
|
|||||||
) : (
|
) : (
|
||||||
<Button
|
<Button
|
||||||
onClick={useBackendFlow ? handleBackendSignIn : handleFrontEndSignIn}
|
onClick={useBackendFlow ? handleBackendSignIn : handleFrontEndSignIn}
|
||||||
disabled={signersLoading}
|
disabled={!useBackendFlow && !url} // Disable button in browser flow if auth-kit URL is not ready
|
||||||
className={cn(
|
className={cn(
|
||||||
'btn btn-primary flex items-center gap-3',
|
'btn btn-primary flex items-center gap-3',
|
||||||
'disabled:opacity-50 disabled:cursor-not-allowed',
|
'disabled:opacity-50 disabled:cursor-not-allowed',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user