resolver.ts
1 2 interface RollupInfo { 3 namespace: number; 4 name: string; 5 website: string; 6 scan: string; 7 } 8 import { parseRollupData } from '@/lib/rollup-parser' 9 10 interface RollupMapping { 11 [rollupName: string]: number; 12 } 13 14 let rollupMapping: RollupMapping | null = null; 15 let rollupList: RollupInfo[] = []; 16 let isLoading = false; 17 18 const WEB_WORKER_PROXY_URL = '/api/rollup?raw=true'; 19 20 async function fetchRollupMetadata(): Promise<RollupInfo[]> { 21 try { 22 // Suppress fetch errors from appearing in console (service is optional) 23 const response = await fetch(WEB_WORKER_PROXY_URL, { 24 // Don't throw on HTTP errors 25 cache: 'no-cache' 26 }); 27 28 if (!response.ok) { 29 // Service unavailable - this is expected and OK 30 // App works fine without rollup names 31 return []; 32 } 33 34 const content = await response.text(); 35 const rollupData = parseRollupData(content); 36 37 if (rollupData.length === 0) { 38 return []; 39 } 40 41 return rollupData; 42 } catch (error) { 43 // Silently fail - rollup service is optional 44 return []; 45 } 46 } 47 48 function createRollupMapping(rollups: RollupInfo[]): RollupMapping { 49 const mapping: RollupMapping = {}; 50 51 rollups.forEach(rollup => { 52 53 const normalizedName = rollup.name.toUpperCase().trim(); 54 mapping[normalizedName] = rollup.namespace; 55 56 57 if (normalizedName === 'MOLTEN') { 58 mapping['MOLTEN NETWORK'] = rollup.namespace; 59 } 60 if (normalizedName === 'LOGX') { 61 mapping['LOGX NETWORK'] = rollup.namespace; 62 } 63 }); 64 65 return mapping; 66 } 67 68 export async function initializeRollupResolver(): Promise<void> { 69 if (rollupMapping || isLoading) { 70 return; 71 } 72 73 isLoading = true; 74 75 rollupList = await fetchRollupMetadata(); 76 rollupMapping = createRollupMapping(rollupList); 77 78 isLoading = false; 79 } 80 81 export function resolveRollupName(rollupName: string): number | null { 82 if (!rollupMapping) { 83 return null; 84 } 85 86 const normalizedName = rollupName.toUpperCase().trim(); 87 return rollupMapping[normalizedName] || null; 88 } 89 90 export function getRollupName(namespace: number): string | null { 91 if (!rollupList || rollupList.length === 0) { 92 return null; 93 } 94 95 96 const rollup = rollupList.find(r => r.namespace === namespace); 97 return rollup ? rollup.name : null; 98 } 99 100 101 export async function findRollupByNamespace(targetNamespace: number): Promise<RollupInfo | null> { 102 const response = await fetch(`/api/rollup?namespace=${targetNamespace}`); 103 104 if (!response.ok) { 105 if (response.status === 404) { 106 return null; 107 } 108 return null; 109 } 110 111 const rollupInfo = await response.json(); 112 return rollupInfo; 113 } 114 115 116 export async function universalRollupSearch(query: string): Promise<RollupInfo[]> { 117 const searchTerm = query.trim(); 118 119 if (!searchTerm) { 120 return []; 121 } 122 123 const response = await fetch(`/api/rollup?query=${encodeURIComponent(searchTerm)}`, { 124 method: 'GET', 125 headers: { 'Content-Type': 'application/json' } 126 }); 127 128 if (!response.ok) { 129 if (response.status === 404) { 130 return []; 131 } 132 return []; 133 } 134 135 const result = await response.json(); 136 137 const rollups = Array.isArray(result) ? result : [result]; 138 139 return rollups; 140 } 141 142 export function getAllRollups(): RollupInfo[] { 143 return rollupList || []; 144 } 145 146 export function isRollupResolverReady(): boolean { 147 return rollupMapping !== null; 148 } 149 150