useGunDBReferents.ts
1 import { useState, useCallback } from 'react' 2 import { litProtocolService } from '../lib/litProtocol' 3 import { useLitSession } from './useLitSession' 4 import { gunDBService } from '../services/database/gundb' 5 import { optimisticCache } from '../services/database/gundb/optimisticCache' 6 import { isPopularSong, getPopularSongData } from '../constants/popularSongs' 7 8 export interface GunDBReferent { 9 id: number 10 fragment: string 11 range?: { start?: number; end?: number } 12 annotation?: { 13 body: string 14 votes_total: number 15 verified: boolean 16 } 17 } 18 19 interface UseGunDBReferentsReturn { 20 fetchReferents: (geniusId: number, page?: number) => Promise<GunDBReferent[]> 21 isFetching: boolean 22 error: string | null 23 hasMore: boolean 24 } 25 26 export interface FetchReferentsResult { 27 referents: GunDBReferent[] 28 hasMore: boolean 29 } 30 31 export function useGunDBReferents(): UseGunDBReferentsReturn { 32 const [isFetching, setIsFetching] = useState(false) 33 const [error, setError] = useState<string | null>(null) 34 const [hasMore, setHasMore] = useState(false) 35 const { sessionSigs, createSession } = useLitSession() 36 37 const fetchReferents = useCallback(async (geniusId: number, page: number = 1): Promise<GunDBReferent[]> => { 38 setIsFetching(true) 39 setError(null) 40 41 try { 42 // Check if this is a popular song with pre-populated data 43 if (isPopularSong(geniusId) && page === 1) { 44 console.log('🌟 Using pre-populated referents for popular song:', geniusId) 45 const popularData = getPopularSongData(geniusId) 46 if (popularData && popularData.referents) { 47 // Transform to match the expected format 48 const referents = popularData.referents.map((ref: any, index) => ({ 49 id: index + 1, 50 fragment: ref.fragment, 51 range: { start: ref.start_index, end: ref.end_index } 52 })) 53 setHasMore(false) // Popular songs have all referents pre-loaded 54 setIsFetching(false) 55 return referents 56 } 57 } 58 59 const cacheKey = `referents:${geniusId}:${page}` 60 61 const result = await optimisticCache.getOrExecute( 62 cacheKey, 63 async () => { 64 // Check GunDB cache 65 console.log(`🔍 Checking GunDB cache for referents: song=${geniusId}, page=${page}`) 66 const cached = await gunDBService.getReferents(geniusId, page) 67 if (cached) { 68 console.log(`📦 Using cached referents for song ${geniusId}`) 69 setHasMore(cached.hasMore) 70 return cached 71 } 72 return null 73 }, 74 async () => { 75 console.log('📡 Cache miss, need to fetch from Genius API...') 76 77 // Create Lit session 78 let currentSessionSigs = sessionSigs 79 if (!currentSessionSigs) { 80 console.log('🔐 Creating new Lit session for referents fetch...') 81 currentSessionSigs = await createSession() 82 if (!currentSessionSigs) { 83 throw new Error('Failed to create Lit session') 84 } 85 } 86 87 console.log('🚀 Executing Genius referents fetcher Lit Action...') 88 89 // Load the Lit Action code 90 const geniusReferentsFetcherCode = await fetch('/lit-actions/genius-referents-fetcher/geniusReferentsFetcher.js').then(r => r.text()) 91 92 const result = await litProtocolService.litNodeClient!.executeJs({ 93 code: geniusReferentsFetcherCode, 94 sessionSigs: currentSessionSigs, 95 jsParams: { 96 songId: geniusId.toString(), 97 page, 98 perPage: 50 99 } 100 }) 101 102 const response = JSON.parse(result.response as string) 103 104 if (!response.success) { 105 throw new Error(response.error || 'Failed to fetch referents') 106 } 107 108 console.log(`✅ Fetched ${response.referents.length} referents from Genius API`) 109 110 // Save to GunDB cache for next time 111 await gunDBService.saveReferents(geniusId, page, response.referents, response.hasMore) 112 113 return { 114 referents: response.referents, 115 hasMore: response.hasMore 116 } 117 } 118 ) 119 120 if (result) { 121 setHasMore(result.hasMore) 122 return result.referents 123 } 124 125 return [] 126 } catch (err) { 127 const errorMessage = err instanceof Error ? err.message : 'Failed to fetch referents' 128 console.error('❌ Fetch referents error:', errorMessage) 129 setError(errorMessage) 130 return [] 131 } finally { 132 setIsFetching(false) 133 } 134 }, [sessionSigs, createSession]) 135 136 return { 137 fetchReferents, 138 isFetching, 139 error, 140 hasMore 141 } 142 }