-
Notifications
You must be signed in to change notification settings - Fork 0
Next.js API Integration for Universal Deployment #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -350,6 +350,106 @@ async def fetch_all_verifications() -> list[dict]: | |||||
| verifications.sort(key=lambda x: x.get('timestamp', ''), reverse=True) | ||||||
| return verifications | ||||||
|
|
||||||
| # ========= MAIN FETCH FUNCTION (like notify_golem) ========= | ||||||
| def fetch_golem_verification(user_id: str) -> Optional[Dict[str, Any]]: | ||||||
| """ | ||||||
| Main function to fetch verification from Golem DB - similar pattern to notify_golem | ||||||
| This function searches for user_id annotation and returns the latest verification | ||||||
| """ | ||||||
| try: | ||||||
| import threading | ||||||
| import concurrent.futures | ||||||
|
|
||||||
| def run_async_in_thread(): | ||||||
| """Run async function in a separate thread with proper event loop handling""" | ||||||
| # Create a new event loop for this thread | ||||||
| loop = asyncio.new_event_loop() | ||||||
| asyncio.set_event_loop(loop) | ||||||
|
|
||||||
| try: | ||||||
| return loop.run_until_complete(fetch_verification_by_user_id(user_id)) | ||||||
| finally: | ||||||
| loop.close() | ||||||
|
|
||||||
| # Run the async function in a separate thread to avoid signal issues | ||||||
| with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor: | ||||||
| future = executor.submit(run_async_in_thread) | ||||||
| verification_data = future.result(timeout=30) # 30 second timeout | ||||||
|
|
||||||
| if verification_data: | ||||||
| print(f"✅ Verification found for user {user_id}") | ||||||
| return verification_data | ||||||
| else: | ||||||
| print(f"❌ No verification found for user {user_id}") | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use the configured logger instead of print for consistency and observability. Prompt for AI agents
Suggested change
|
||||||
| return None | ||||||
|
|
||||||
| except Exception as e: | ||||||
| print(f"❌ Failed to fetch from Golem DB: {e}") | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use the error logger instead of print to capture exceptions in logs. Prompt for AI agents
Suggested change
|
||||||
| return None | ||||||
|
|
||||||
| async def fetch_verification_by_user_id(user_id: str) -> Optional[Dict[str, Any]]: | ||||||
| """Fetch verification from Golem DB by searching for user_id annotation""" | ||||||
| client = await get_golem_client() | ||||||
|
|
||||||
| # Get account address (our writer address) | ||||||
| writer_address = client.get_account_address() | ||||||
|
|
||||||
| # Get all entities owned by this account | ||||||
| entity_keys = await client.get_entities_of_owner(writer_address) | ||||||
|
|
||||||
| latest_verification = None | ||||||
| latest_timestamp = None | ||||||
|
|
||||||
| # Search through all entities for matching user_id | ||||||
| for entity_key in entity_keys: | ||||||
| try: | ||||||
| # Get metadata to check annotations | ||||||
| metadata = await client.get_entity_metadata(entity_key) | ||||||
|
|
||||||
| # Check if this entity matches our user_id and is a humanity verification | ||||||
| is_target_user = False | ||||||
| is_humanity_verification = False | ||||||
| entity_timestamp = None | ||||||
|
|
||||||
| for annotation in metadata.string_annotations: | ||||||
| if annotation.key == "user_id" and annotation.value == user_id: | ||||||
| is_target_user = True | ||||||
| elif annotation.key == "recordType" and annotation.value == "humanity_verification": | ||||||
| is_humanity_verification = True | ||||||
| elif annotation.key == "timestamp": | ||||||
| entity_timestamp = annotation.value | ||||||
|
|
||||||
| # If this matches our criteria and is newer than current latest | ||||||
| if is_target_user and is_humanity_verification and entity_timestamp: | ||||||
| if not latest_timestamp or entity_timestamp > latest_timestamp: | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comparing timestamp strings can return the wrong latest record; parse to datetime for reliable ordering. Prompt for AI agents
Suggested change
|
||||||
| # Get the full entity data | ||||||
| entity_key_hex = entity_key.as_hex_string() | ||||||
| storage_value = await client.get_storage_value(GenericBytes.from_hex_string(entity_key_hex)) | ||||||
|
|
||||||
| if storage_value: | ||||||
| # Decode the JSON data | ||||||
| entity_data = json.loads(storage_value.decode('utf-8')) | ||||||
|
|
||||||
| # Collect all annotations | ||||||
| annotations = {} | ||||||
| for annotation in metadata.string_annotations: | ||||||
| annotations[annotation.key] = annotation.value | ||||||
|
|
||||||
| # Update latest verification | ||||||
| latest_verification = { | ||||||
| **entity_data, | ||||||
| 'entity_key': entity_key_hex, | ||||||
| 'annotations': annotations, | ||||||
| 'source': 'golem_db_direct' | ||||||
| } | ||||||
| latest_timestamp = entity_timestamp | ||||||
|
|
||||||
| except Exception as error: | ||||||
| logger.warning(f"⚠️ Error processing entity {entity_key.as_hex_string()}: {error}") | ||||||
| continue | ||||||
|
|
||||||
| return latest_verification | ||||||
|
|
||||||
| # ========= SYNCHRONOUS WRAPPER FUNCTIONS ========= | ||||||
| def fetch_latest_verification_sync() -> Optional[dict]: | ||||||
| """ | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -593,6 +593,94 @@ async def get_verification_status(user_id: str): | |
| logger.error(f"❌ Error getting verification status: {e}") | ||
| raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}") | ||
|
|
||
| @app.get("/golem-verification/{user_id}") | ||
| async def get_golem_verification_by_user(user_id: str): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This endpoint re-implements logic that already exists in golem_endpoints.fetch_verification_by_user_id; prefer calling the shared function to avoid duplication and divergence. Prompt for AI agents |
||
| """Get verification data directly from Golem DB by searching for user_id annotation""" | ||
| try: | ||
| from golem_endpoints import get_golem_client | ||
| from golem_base_sdk import GenericBytes | ||
| import json | ||
|
|
||
| logger.info(f"🔍 Searching Golem DB for user: {Fore.GREEN}{user_id}{Style.RESET_ALL}") | ||
|
|
||
| # Connect to Golem DB | ||
| client = await get_golem_client() | ||
| writer_address = client.get_account_address() | ||
| logger.info(f"📝 Writer address: {writer_address}") | ||
|
|
||
| # Get all entities owned by this account | ||
| entity_keys = await client.get_entities_of_owner(writer_address) | ||
| logger.info(f"🔍 Found {len(entity_keys)} entities owned by writer") | ||
|
|
||
| latest_verification = None | ||
| latest_timestamp = None | ||
|
|
||
| # Search through all entities for matching user_id | ||
| for entity_key in entity_keys: | ||
| try: | ||
| # Get metadata to check annotations | ||
| metadata = await client.get_entity_metadata(entity_key) | ||
|
|
||
| # Check if this entity matches our user_id and is a humanity verification | ||
| is_target_user = False | ||
| is_humanity_verification = False | ||
| entity_timestamp = None | ||
|
|
||
| for annotation in metadata.string_annotations: | ||
| if annotation.key == "user_id" and annotation.value == user_id: | ||
| is_target_user = True | ||
| elif annotation.key == "recordType" and annotation.value == "humanity_verification": | ||
| is_humanity_verification = True | ||
| elif annotation.key == "timestamp": | ||
| entity_timestamp = annotation.value | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comparing timestamp strings may select the wrong latest verification; parse to datetime for robust ordering. Prompt for AI agents |
||
|
|
||
| # If this matches our criteria and is newer than current latest | ||
| if is_target_user and is_humanity_verification and entity_timestamp: | ||
| if not latest_timestamp or entity_timestamp > latest_timestamp: | ||
| logger.info(f"📅 Found newer verification: {entity_timestamp}") | ||
|
|
||
| # Get the full entity data | ||
| entity_key_hex = entity_key.as_hex_string() | ||
| storage_value = await client.get_storage_value(GenericBytes.from_hex_string(entity_key_hex)) | ||
|
|
||
| if storage_value: | ||
| # Decode the JSON data | ||
| entity_data = json.loads(storage_value.decode('utf-8')) | ||
|
|
||
| # Collect all annotations | ||
| annotations = {} | ||
| for annotation in metadata.string_annotations: | ||
| annotations[annotation.key] = annotation.value | ||
|
|
||
| # Update latest verification | ||
| latest_verification = { | ||
| **entity_data, | ||
| 'entity_key': entity_key_hex, | ||
| 'annotations': annotations, | ||
| 'source': 'golem_db_direct' | ||
| } | ||
| latest_timestamp = entity_timestamp | ||
|
|
||
| except Exception as error: | ||
| logger.warning(f"⚠️ Error processing entity {entity_key.as_hex_string()}: {error}") | ||
| continue | ||
|
|
||
| if latest_verification: | ||
| logger.info(f"✅ Found latest verification for user {user_id}") | ||
| return { | ||
| "status": "success", | ||
| "verification": latest_verification | ||
| } | ||
| else: | ||
| logger.warning(f"❌ No verification found for user {user_id}") | ||
| raise HTTPException(status_code=404, detail=f"No verification found for user {user_id}") | ||
|
|
||
| except HTTPException: | ||
| raise | ||
| except Exception as e: | ||
| logger.error(f"❌ Error fetching verification from Golem DB for user {user_id}: {e}") | ||
| raise HTTPException(status_code=500, detail=f"Failed to fetch verification for user {user_id}: {str(e)}") | ||
|
|
||
| @app.get("/verification-with-golem/{user_id}") | ||
| async def get_verification_with_golem_db(user_id: str): | ||
| """Get verification data using local biometrics data enhanced with Golem DB annotations""" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,7 +6,6 @@ import { Button } from '@/components/ui/button'; | |
| import { useToast } from "@/hooks/use-toast"; | ||
| import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog'; | ||
| import { useAccount } from 'wagmi'; | ||
| import { GolemBaseClient, GenericBytes } from 'golem-base-sdk'; | ||
|
|
||
| interface VerificationData { | ||
| verification_id: string; | ||
|
|
@@ -36,109 +35,40 @@ export function VerificationHero() { | |
| const [isLoading, setIsLoading] = useState(false); | ||
|
|
||
| const fetchLatestVerification = async () => { | ||
| console.log('🔥 DIRECT GOLEM DB FETCH FUNCTION CALLED - NO API CALLS!'); | ||
| console.log('🔥 FETCHING FROM NEXT.JS API ROUTE - INTEGRATED SOLUTION!'); | ||
| setIsLoading(true); | ||
| try { | ||
| // Use connected wallet address, fallback to hardcoded for testing | ||
| const targetUserId = address || '0x1bc868c8C92B7fD35900f6d687067748ADbd8571'; | ||
|
|
||
| console.log('🔍 Connecting directly to Golem DB for user:', targetUserId); | ||
| console.log('🔍 Calling Next.js API route for user:', targetUserId); | ||
|
|
||
| // Connect directly to Golem DB | ||
| const GOLEM_DB_RPC = "https://ethwarsaw.holesky.golemdb.io/rpc"; | ||
| const GOLEM_DB_WSS = "wss://ethwarsaw.holesky.golemdb.io/rpc/ws"; | ||
| const PRIVATE_KEY = process.env.NEXT_PUBLIC_PRIVATE_KEY || "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d"; // Default for testing | ||
| // Call local Next.js API route - no external dependencies! | ||
| const response = await fetch(`/api/verification-by-user/${targetUserId}`); | ||
|
|
||
| if (!PRIVATE_KEY) { | ||
| throw new Error('Private key not configured for Golem DB connection'); | ||
| if (!response.ok) { | ||
| const errorText = await response.text(); | ||
| throw new Error(`API error: ${response.status} - ${errorText}`); | ||
| } | ||
|
|
||
| // Create Golem DB client | ||
| const client = await GolemBaseClient.create_rw_client( | ||
| GOLEM_DB_RPC, | ||
| GOLEM_DB_WSS, | ||
| PRIVATE_KEY | ||
| ); | ||
| const data = await response.json(); | ||
| console.log('✅ Next.js API response:', data); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unrestricted console logging in production may leak identifiers and clutter logs; gate these logs behind a dev check or remove them. Prompt for AI agents |
||
|
|
||
| console.log('✅ Connected to Golem DB, searching for user_id:', targetUserId); | ||
|
|
||
| // Get account address (our writer address) | ||
| const writerAddress = client.get_account_address(); | ||
| console.log('📝 Writer address:', writerAddress); | ||
|
|
||
| // Get all entities owned by this account | ||
| const entityKeys = await client.get_entities_of_owner(writerAddress); | ||
| console.log(`🔍 Found ${entityKeys.length} entities owned by writer`); | ||
|
|
||
| let latestVerification: any = null; | ||
| let latestTimestamp: string | null = null; | ||
|
|
||
| // Search through all entities for matching user_id | ||
| for (const entityKey of entityKeys) { | ||
| try { | ||
| // Get metadata to check annotations | ||
| const metadata = await client.get_entity_metadata(entityKey); | ||
|
|
||
| // Check if this entity matches our user_id and is a humanity verification | ||
| let isTargetUser = false; | ||
| let isHumanityVerification = false; | ||
| let entityTimestamp: string | null = null; | ||
|
|
||
| for (const annotation of metadata.string_annotations) { | ||
| if (annotation.key === "user_id" && annotation.value === targetUserId) { | ||
| isTargetUser = true; | ||
| } else if (annotation.key === "recordType" && annotation.value === "humanity_verification") { | ||
| isHumanityVerification = true; | ||
| } else if (annotation.key === "timestamp") { | ||
| entityTimestamp = annotation.value; | ||
| } | ||
| } | ||
|
|
||
| // If this matches our criteria and is newer than current latest | ||
| if (isTargetUser && isHumanityVerification && entityTimestamp) { | ||
| if (!latestTimestamp || entityTimestamp > latestTimestamp) { | ||
| console.log(`📅 Found newer verification: ${entityTimestamp}`); | ||
|
|
||
| // Get the full entity data | ||
| const entityKeyHex = entityKey.as_hex_string(); | ||
| const storageValue = await client.get_storage_value(GenericBytes.from_hex_string(entityKeyHex)); | ||
|
|
||
| if (storageValue) { | ||
| // Decode the JSON data | ||
| const entityData = JSON.parse(storageValue.toString()); | ||
|
|
||
| // Collect all annotations | ||
| const annotations: { [key: string]: string } = {}; | ||
| for (const annotation of metadata.string_annotations) { | ||
| annotations[annotation.key] = annotation.value; | ||
| } | ||
|
|
||
| // Update latest verification | ||
| latestVerification = { | ||
| ...entityData, | ||
| entity_key: entityKeyHex, | ||
| annotations: annotations, | ||
| source: 'golem_db_direct' | ||
| }; | ||
| latestTimestamp = entityTimestamp; | ||
| } | ||
| } | ||
| } | ||
| } catch (error) { | ||
| console.warn(`⚠️ Error processing entity ${entityKey.as_hex_string()}:`, error); | ||
| continue; | ||
| } | ||
| } | ||
|
|
||
| if (latestVerification) { | ||
| console.log('✅ Found latest verification:', latestVerification); | ||
| setVerificationData(latestVerification); | ||
| if (data.status === 'success' && data.verification) { | ||
| setVerificationData(data.verification); | ||
| console.log('✅ Successfully loaded verification data from integrated API'); | ||
| console.log('📊 Verification details:'); | ||
| console.log(' Entity Key:', data.verification.entity_key); | ||
| console.log(' User ID:', data.verification.user_id); | ||
| console.log(' Humanity Score:', data.verification.humanity_score); | ||
| console.log(' Timestamp:', data.verification.timestamp); | ||
| console.log(' Source:', data.verification.source); | ||
| } else { | ||
| throw new Error(`No verification found for user ${targetUserId}`); | ||
| throw new Error('Invalid response format from API'); | ||
| } | ||
|
|
||
| } catch (error) { | ||
| console.error('❌ Error fetching verification from Golem DB:', error); | ||
| console.error('❌ Error fetching verification:', error); | ||
| toast({ | ||
| title: "Error", | ||
| description: `Failed to fetch verification data: ${error instanceof Error ? error.message : 'Unknown error'}`, | ||
|
|
@@ -190,14 +120,14 @@ export function VerificationHero() { | |
| <Dialog open={isProofModalOpen} onOpenChange={setProofModalOpen}> | ||
| <DialogContent className="max-w-2xl"> | ||
| <DialogHeader> | ||
| <DialogTitle>🔗 Direct Golem DB Verification</DialogTitle> | ||
| <DialogDescription>Real-time data: Connected directly to Golem DB blockchain, searching by user_id annotation for latest verification with full metadata</DialogDescription> | ||
| <DialogTitle>🔗 Golem DB Verification</DialogTitle> | ||
| <DialogDescription>Real-time data: Fetched directly from Golem DB via integrated Next.js API route, showing latest verification with full blockchain metadata and annotations</DialogDescription> | ||
| </DialogHeader> | ||
| <div className="py-4 space-y-4"> | ||
| {isLoading ? ( | ||
| <div className="flex items-center justify-center py-8"> | ||
| <Loader2 className="h-8 w-8 animate-spin" /> | ||
| <span className="ml-2">Connecting directly to Golem DB blockchain...</span> | ||
| <span className="ml-2">Fetching verification data from Golem DB...</span> | ||
| </div> | ||
| ) : verificationData ? ( | ||
| <> | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the configured logger instead of print for consistency and proper log handling.
Prompt for AI agents