A quick vibe-coded site to test response times of PLC.directory mirrors (over 3 attempts)

Add multi-attempt benchmarking

Extend benchmarks to query each mirror 3 times, record per-attempt timings, and compute per-mirror and overall averages. Refactor config to only store mirror URLs (derive names from URLs), update types to support multiple attempts, and adjust table to display all attempts plus averages.

X-Lovable-Edit-ID: edt-04f07964-c2a1-49ca-91cd-632202b89962

Changed files
+140 -102
src
components
config
pages
types
utils
+93 -70
src/components/BenchmarkTable.tsx
···
}
export const BenchmarkTable = ({ results }: BenchmarkTableProps) => {
-
// Sort by response time (fastest first)
+
// Sort by average response time (fastest first)
const sortedResults = [...results].sort((a, b) => {
if (a.status === "error" && b.status === "success") return 1;
if (a.status === "success" && b.status === "error") return -1;
-
return a.responseTime - b.responseTime;
+
return a.avgResponseTime - b.avgResponseTime;
});
+
// Calculate overall average across all successful attempts
+
const allSuccessfulAttempts = sortedResults.flatMap((r) =>
+
r.attempts.filter((a) => a.status === "success")
+
);
+
const overallAvg =
+
allSuccessfulAttempts.length > 0
+
? allSuccessfulAttempts.reduce((sum, a) => sum + a.responseTime, 0) /
+
allSuccessfulAttempts.length
+
: 0;
+
return (
-
<div className="rounded-lg border border-border bg-card overflow-hidden">
-
<Table>
-
<TableHeader>
-
<TableRow className="bg-muted/50">
-
<TableHead className="font-semibold">Mirror</TableHead>
-
<TableHead className="font-semibold">URL</TableHead>
-
<TableHead className="font-semibold text-right">Response Time</TableHead>
-
<TableHead className="font-semibold">Status</TableHead>
-
<TableHead className="font-semibold">HTTP Code</TableHead>
-
</TableRow>
-
</TableHeader>
-
<TableBody>
-
{sortedResults.map((result, index) => (
-
<TableRow key={index} className="hover:bg-muted/30 transition-colors">
-
<TableCell className="font-medium">{result.mirrorName}</TableCell>
-
<TableCell className="font-mono text-sm text-muted-foreground">
-
{result.mirrorUrl}
-
</TableCell>
-
<TableCell className="text-right font-mono text-sm">
-
{result.status === "success" ? (
-
<span className="text-foreground font-medium">
-
{result.responseTime.toFixed(0)}ms
-
</span>
-
) : (
-
<span className="text-muted-foreground">—</span>
-
)}
-
</TableCell>
-
<TableCell>
-
{result.status === "success" ? (
-
<Badge
-
variant="outline"
-
className="bg-success/10 text-success border-success/20 gap-1"
-
>
-
<CheckCircle2 className="w-3 h-3" />
-
Success
-
</Badge>
-
) : (
-
<Badge
-
variant="outline"
-
className="bg-destructive/10 text-destructive border-destructive/20 gap-1"
-
>
-
<XCircle className="w-3 h-3" />
-
Error
-
</Badge>
-
)}
-
</TableCell>
-
<TableCell className="font-mono text-sm">
-
{result.statusCode ? (
-
<span
-
className={
-
result.statusCode >= 200 && result.statusCode < 300
-
? "text-success"
-
: "text-destructive"
-
}
-
>
-
{result.statusCode}
-
</span>
-
) : (
-
<span className="text-muted-foreground">—</span>
-
)}
-
</TableCell>
-
</TableRow>
-
))}
-
</TableBody>
-
</Table>
-
{sortedResults.length === 0 && (
-
<div className="text-center py-12 text-muted-foreground">
-
No results yet. Enter a DID and run the benchmark.
+
<div className="space-y-4">
+
{/* Overall Average */}
+
{overallAvg > 0 && (
+
<div className="bg-primary/5 border border-primary/20 rounded-lg p-4 flex items-center justify-between">
+
<span className="font-semibold text-foreground">
+
Overall Average Response Time
+
</span>
+
<span className="text-2xl font-bold font-mono text-primary">
+
{overallAvg.toFixed(0)}ms
+
</span>
</div>
)}
+
+
{/* Results Table */}
+
<div className="rounded-lg border border-border bg-card overflow-hidden">
+
<Table>
+
<TableHeader>
+
<TableRow className="bg-muted/50">
+
<TableHead className="font-semibold">Implementation</TableHead>
+
<TableHead className="font-semibold text-center">Attempt 1</TableHead>
+
<TableHead className="font-semibold text-center">Attempt 2</TableHead>
+
<TableHead className="font-semibold text-center">Attempt 3</TableHead>
+
<TableHead className="font-semibold text-center">Average</TableHead>
+
<TableHead className="font-semibold">Status</TableHead>
+
</TableRow>
+
</TableHeader>
+
<TableBody>
+
{sortedResults.map((result, index) => (
+
<TableRow key={index} className="hover:bg-muted/30 transition-colors">
+
<TableCell className="font-mono text-sm font-medium">
+
{result.mirrorUrl}
+
</TableCell>
+
{result.attempts.map((attempt, attemptIndex) => (
+
<TableCell key={attemptIndex} className="text-center font-mono text-sm">
+
{attempt.status === "success" ? (
+
<span className="text-foreground">
+
{attempt.responseTime.toFixed(0)}ms
+
</span>
+
) : (
+
<span className="text-destructive">
+
<XCircle className="w-4 h-4 inline" />
+
</span>
+
)}
+
</TableCell>
+
))}
+
<TableCell className="text-center font-mono text-sm">
+
{result.status === "success" ? (
+
<span className="font-bold text-primary text-base">
+
{result.avgResponseTime.toFixed(0)}ms
+
</span>
+
) : (
+
<span className="text-muted-foreground">—</span>
+
)}
+
</TableCell>
+
<TableCell>
+
{result.status === "success" ? (
+
<Badge
+
variant="outline"
+
className="bg-success/10 text-success border-success/20 gap-1"
+
>
+
<CheckCircle2 className="w-3 h-3" />
+
Success
+
</Badge>
+
) : (
+
<Badge
+
variant="outline"
+
className="bg-destructive/10 text-destructive border-destructive/20 gap-1"
+
>
+
<XCircle className="w-3 h-3" />
+
Error
+
</Badge>
+
)}
+
</TableCell>
+
</TableRow>
+
))}
+
</TableBody>
+
</Table>
+
{sortedResults.length === 0 && (
+
<div className="text-center py-12 text-muted-foreground">
+
No results yet. Enter a DID and run the benchmark.
+
</div>
+
)}
+
</div>
</div>
);
};
+3 -13
src/config/mirrors.ts
···
export interface Mirror {
-
name: string;
url: string;
}
export const mirrors: Mirror[] = [
-
{
-
name: "plc.directory",
-
url: "https://plc.directory",
-
},
-
{
-
name: "plc.bsky-mirror.dev",
-
url: "https://plc.bsky-mirror.dev",
-
},
-
{
-
name: "plc.us-east.host.bsky.network",
-
url: "https://plc.us-east.host.bsky.network",
-
},
+
{ url: "https://plc.directory" },
+
{ url: "https://plc.bsky-mirror.dev" },
+
{ url: "https://plc.us-east.host.bsky.network" },
];
+1 -1
src/pages/Index.tsx
···
</div>
</div>
<div className="text-sm text-muted-foreground">
-
Testing {mirrors.length} mirrors: {mirrors.map(m => m.name).join(", ")}
+
Testing {mirrors.length} mirrors with 3 attempts each
</div>
</div>
</div>
+8 -4
src/types/benchmark.ts
···
-
export interface BenchmarkResult {
-
mirrorName: string;
-
mirrorUrl: string;
+
export interface BenchmarkAttempt {
responseTime: number;
status: "success" | "error";
statusCode?: number;
error?: string;
-
data?: any;
+
}
+
+
export interface BenchmarkResult {
+
mirrorUrl: string;
+
attempts: BenchmarkAttempt[];
+
avgResponseTime: number;
+
status: "success" | "error";
}
+35 -14
src/utils/benchmark.ts
···
import { Mirror } from "@/config/mirrors";
-
import { BenchmarkResult } from "@/types/benchmark";
+
import { BenchmarkResult, BenchmarkAttempt } from "@/types/benchmark";
+
+
const ATTEMPTS_PER_MIRROR = 3;
-
export const benchmarkMirror = async (
-
mirror: Mirror,
+
const singleAttempt = async (
+
url: string,
did: string
-
): Promise<BenchmarkResult> => {
-
const url = `${mirror.url}/${did}`;
+
): Promise<BenchmarkAttempt> => {
+
const fullUrl = `${url}/${did}`;
const startTime = performance.now();
try {
-
const response = await fetch(url);
+
const response = await fetch(fullUrl);
const endTime = performance.now();
const responseTime = endTime - startTime;
if (!response.ok) {
return {
-
mirrorName: mirror.name,
-
mirrorUrl: mirror.url,
responseTime,
status: "error",
statusCode: response.status,
···
};
}
-
const data = await response.json();
+
await response.json(); // Consume the response
return {
-
mirrorName: mirror.name,
-
mirrorUrl: mirror.url,
responseTime,
status: "success",
statusCode: response.status,
-
data,
};
} catch (error) {
const endTime = performance.now();
return {
-
mirrorName: mirror.name,
-
mirrorUrl: mirror.url,
responseTime: endTime - startTime,
status: "error",
error: error instanceof Error ? error.message : "Unknown error",
};
}
+
};
+
+
export const benchmarkMirror = async (
+
mirror: Mirror,
+
did: string
+
): Promise<BenchmarkResult> => {
+
const attempts: BenchmarkAttempt[] = [];
+
+
for (let i = 0; i < ATTEMPTS_PER_MIRROR; i++) {
+
const attempt = await singleAttempt(mirror.url, did);
+
attempts.push(attempt);
+
}
+
+
const successfulAttempts = attempts.filter((a) => a.status === "success");
+
const avgResponseTime =
+
successfulAttempts.length > 0
+
? successfulAttempts.reduce((sum, a) => sum + a.responseTime, 0) /
+
successfulAttempts.length
+
: 0;
+
+
return {
+
mirrorUrl: mirror.url,
+
attempts,
+
avgResponseTime,
+
status: successfulAttempts.length > 0 ? "success" : "error",
+
};
};
export const benchmarkAllMirrors = async (