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