useRegionPing
neon-ui/use-region-pingFreeHook
Measures browser round-trip latency to per-region endpoints via opaque no-cors requests.
Install it
npx shadcn@latest add https://ui.neon.com/r/use-region-ping.jsonSource
1"use client";23import { useCallback, useEffect, useRef, useState } from "react";45export type RegionPingResult = number | null;67export type RegionPingStatus = "idle" | "measuring" | "done";89export interface UseRegionPingOptions {10 /** Timed requests per region after the warmup; the best time wins. */11 samples?: number;12 /** Set false to defer measuring, then call refresh() when ready. */13 enabled?: boolean;14}1516const DEFAULT_SAMPLES = 3;1718/** One opaque round-trip to the endpoint; null when unreachable. */19const timeRequest = async (url: string): Promise<RegionPingResult> => {20 try {21 const start = performance.now();2223 await fetch(url, {24 cache: "no-store",25 method: "HEAD",26 mode: "no-cors",27 });2829 return Math.round(performance.now() - start);30 } catch {31 return null;32 }33};3435const measureRegion = async (36 url: string,37 samples: number38): Promise<RegionPingResult> => {39 // Warmup request pays DNS + TLS so samples measure the wire.40 await timeRequest(url);4142 let best: RegionPingResult = null;4344 for (let index = 0; index < samples; index += 1) {45 // Sequential on purpose: parallel samples contend for the socket.46 // eslint-disable-next-line no-await-in-loop47 const sample = await timeRequest(url);4849 if (sample !== null && (best === null || sample < best)) {50 best = sample;51 }52 }5354 return best;55};5657/**58 * Measures round-trip latency from the browser to each region59 * endpoint. Endpoints must tolerate opaque no-cors HEAD requests60 * (any reachable URL works; the response is never read).61 */62export const useRegionPing = (63 urls: Record<string, string>,64 { enabled = true, samples = DEFAULT_SAMPLES }: UseRegionPingOptions = {}65) => {66 const [pings, setPings] = useState<Record<string, RegionPingResult>>({});67 const [status, setStatus] = useState<RegionPingStatus>("idle");68 const urlsRef = useRef(urls);6970 useEffect(() => {71 urlsRef.current = urls;72 }, [urls]);7374 const refresh = useCallback(async () => {75 setStatus("measuring");7677 const entries = Object.entries(urlsRef.current);7879 await Promise.all(80 entries.map(async ([id, url]) => {81 const ping = await measureRegion(url, samples);82 setPings((current) => ({ ...current, [id]: ping }));83 })84 );8586 setStatus("done");87 }, [samples]);8889 useEffect(() => {90 if (!enabled) {91 return;92 }9394 // Deferred a frame so the initial "measuring" state doesn't95// … truncated
Files it writes
More from neon-ui
All 77 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| useConsumptionHistoryuse-consumption-history | neon-ui | Hooks | Free | no deps | |
| useGatewayModelsuse-gateway-models | neon-ui | Hooks | Free | no deps |
