A quick vibe-coded site to test response times of PLC.directory mirrors (over 3 attempts)
1import { useState } from "react"; 2import { Button } from "@/components/ui/button"; 3import { Input } from "@/components/ui/input"; 4import { BenchmarkTable } from "@/components/BenchmarkTable"; 5import { mirrors } from "@/config/mirrors"; 6import { benchmarkAllMirrors } from "@/utils/benchmark"; 7import { BenchmarkResult } from "@/types/benchmark"; 8import { toast } from "sonner"; 9import { Activity, Zap } from "lucide-react"; 10 11const Index = () => { 12 const [did, setDid] = useState(""); 13 const [loading, setLoading] = useState(false); 14 const [results, setResults] = useState<BenchmarkResult[]>([]); 15 16 const resolveHandle = async (handle: string): Promise<string | null> => { 17 try { 18 const response = await fetch( 19 `https://quickdid.smokesignal.tools/xrpc/com.atproto.identity.resolveHandle?handle=${encodeURIComponent(handle)}` 20 ); 21 const data = await response.json(); 22 23 if (data.error) { 24 toast.error(`Unable to resolve handle: ${data.message || "Invalid handle"}`); 25 return null; 26 } 27 28 return data.did; 29 } catch (error) { 30 toast.error("Failed to resolve handle"); 31 console.error(error); 32 return null; 33 } 34 }; 35 36 const handleBenchmark = async () => { 37 if (!did.trim()) { 38 toast.error("Please enter a DID or handle"); 39 return; 40 } 41 42 setLoading(true); 43 setResults([]); 44 45 try { 46 let resolvedDid = did.trim(); 47 48 // If input doesn't start with "did:plc", treat it as a handle 49 if (!resolvedDid.startsWith("did:plc")) { 50 const resolved = await resolveHandle(resolvedDid); 51 if (!resolved) { 52 setLoading(false); 53 return; 54 } 55 resolvedDid = resolved; 56 toast.success(`Resolved to ${resolvedDid}`); 57 } 58 59 const benchmarkResults = await benchmarkAllMirrors(mirrors, resolvedDid); 60 setResults(benchmarkResults); 61 62 const successCount = benchmarkResults.filter(r => r.status === "success").length; 63 toast.success(`Benchmark complete! ${successCount}/${benchmarkResults.length} mirrors responded`); 64 } catch (error) { 65 toast.error("Failed to run benchmark"); 66 console.error(error); 67 } finally { 68 setLoading(false); 69 } 70 }; 71 72 const handleKeyPress = (e: React.KeyboardEvent) => { 73 if (e.key === "Enter" && !loading) { 74 handleBenchmark(); 75 } 76 }; 77 78 return ( 79 <div className="min-h-screen bg-background py-8 px-4"> 80 <div className="max-w-6xl mx-auto space-y-8"> 81 {/* Header */} 82 <header className="text-center space-y-3"> 83 <div className="flex items-center justify-center gap-2 text-primary"> 84 <Activity className="w-8 h-8" /> 85 <h1 className="text-4xl font-bold">PLC Mirror Benchmark</h1> 86 </div> 87 <p className="text-muted-foreground text-lg max-w-2xl mx-auto"> 88 Test and compare response times across different PLC.directory mirrors 89 </p> 90 </header> 91 92 {/* Input Section */} 93 <div className="bg-card border border-border rounded-lg p-6 shadow-sm"> 94 <div className="space-y-4"> 95 <div> 96 <label htmlFor="did-input" className="block text-sm font-medium mb-2"> 97 ATProto DID or Handle 98 </label> 99 <div className="flex gap-3"> 100 <Input 101 id="did-input" 102 type="text" 103 placeholder="did:plc:example123... or handle.bsky.social" 104 value={did} 105 onChange={(e) => setDid(e.target.value)} 106 onKeyPress={handleKeyPress} 107 className="flex-1 font-mono" 108 disabled={loading} 109 /> 110 <Button 111 onClick={handleBenchmark} 112 disabled={loading || !did.trim()} 113 className="gap-2" 114 > 115 <Zap className="w-4 h-4" /> 116 {loading ? "Benchmarking..." : "Run Benchmark"} 117 </Button> 118 </div> 119 </div> 120 <div className="text-sm text-muted-foreground"> 121 Testing {mirrors.length} mirrors with 3 attempts each 122 </div> 123 </div> 124 </div> 125 126 {/* Results Section */} 127 {(results.length > 0 || loading) && ( 128 <div className="space-y-4"> 129 <h2 className="text-2xl font-semibold">Results</h2> 130 {loading ? ( 131 <div className="bg-card border border-border rounded-lg p-12 text-center"> 132 <div className="inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-primary mb-4"></div> 133 <p className="text-muted-foreground">Benchmarking mirrors...</p> 134 </div> 135 ) : ( 136 <BenchmarkTable results={results} /> 137 )} 138 </div> 139 )} 140 141 {/* Info Section */} 142 {results.length === 0 && !loading && ( 143 <div className="bg-muted/30 border border-border rounded-lg p-6"> 144 <h3 className="font-semibold mb-2">How to use:</h3> 145 <ol className="list-decimal list-inside space-y-1 text-sm text-muted-foreground"> 146 <li>Enter an ATProto DID or handle (e.g., did:plc:z72i7hdynmk6r22z27h6tvur or handle.bsky.social)</li> 147 <li>Click "Run Benchmark" or press Enter</li> 148 <li>View response times and status for each mirror</li> 149 </ol> 150 <div className="mt-4 pt-4 border-t border-border"> 151 <p className="text-sm text-muted-foreground"> 152 Mirrors can be configured in <code className="bg-background px-2 py-1 rounded text-mono">src/config/mirrors.ts</code> 153 </p> 154 </div> 155 </div> 156 )} 157 </div> 158 </div> 159 ); 160}; 161 162export default Index;