Title

Diagnostics: add “Ping Domains Provider” (latency + status)

What to build

Server endpoint: GET /api/domain/ping

Returns { ok, provider: "OpenSRS", configured, mode, latencyMs, sample, raw? }

If creds missing, return { ok:false, configured:false } (no external call)

If creds present, do a lightweight lookup (e.g., example.com) and time it

Diagnostics page: add a Ping Domains Provider button that calls this endpoint and shows the result (status + latency)

A) Server: new ping endpoint

File: server/index.ts (or your main Express file where routes live)

 // ...existing imports
 import fetch from "node-fetch";
+import { performance } from "perf_hooks";

 // ...existing app setup

+app.get("/api/domain/ping", async (req, res) => {
+  const user = process.env.OPENSRS_USER;
+  const key = process.env.OPENSRS_KEY;
+  const mode = process.env.OPENSRS_MODE || "ote";
+  const configured = !!user && !!key;
+
+  if (!configured) {
+    return res.json({
+      ok: false,
+      provider: "OpenSRS",
+      configured: false,
+      mode,
+      message: "OpenSRS not configured",
+    });
+  }
+
+  const t0 = performance.now();
+  try {
+    // Lightweight sample: use your existing provider call or a tiny lookup
+    // Example assumes you already have a function to check availability.
+    const sampleDomain = "example.com";
+    const url = `${process.env.DOMAIN_PROVIDER_PING_URL || ""}`; // optional override
+    // If you already have a lookup util, use it here instead of raw fetch.
+    // For illustration, we call your own API route to reuse provider code:
+    const resp = await fetch(`${req.protocol}://${req.get("host")}/api/domain/search?name=${encodeURIComponent(sampleDomain)}`);
+    const txt = await resp.text();
+    const latencyMs = Math.round(performance.now() - t0);
+    return res.status(200).json({
+      ok: resp.ok,
+      provider: "OpenSRS",
+      configured: true,
+      mode,
+      latencyMs,
+      sample: sampleDomain,
+      raw: resp.ok ? undefined : txt?.slice(0, 300),
+    });
+  } catch (err:any) {
+    const latencyMs = Math.round(performance.now() - t0);
+    console.error("[domain.ping] error", err?.message);
+    return res.status(200).json({
+      ok: false,
+      provider: "OpenSRS",
+      configured: true,
+      mode,
+      latencyMs,
+      sample: "example.com",
+      message: err?.message || "Ping failed",
+    });
+  }
+});


If you already have a provider abstraction, feel free to call that directly instead of hitting your own /api/domain/search.

B) Client: add button + result to Diagnostics page

File: client/src/pages/dev/DiagnosticsPage.tsx

@@
 export default function DiagnosticsPage() {
   const [health, setHealth] = React.useState<Health | null>(null);
   const [events, setEvents] = React.useState<Telemetry[]>([]);
   const [loading, setLoading] = React.useState(false);
+  const [pingLoading, setPingLoading] = React.useState(false);
+  const [ping, setPing] = React.useState<{ ok:boolean; configured:boolean; latencyMs?:number; mode?:string; sample?:string; message?:string }|null>(null);
@@
   React.useEffect(() => { load(); }, []);
@@
   return (
     <div className="mx-auto max-w-5xl p-6">
@@
-      <div className="grid md:grid-cols-2 gap-4">
+      <div className="grid md:grid-cols-2 gap-4">
         <div className="rounded-xl border p-4">
           <h2 className="font-semibold mb-2">Server Health</h2>
           {!health ? <div>Loading…</div> : (
             <ul className="text-sm space-y-1">
               <li><b>Status:</b> {health.ok ? "OK" : "Down"}</li>
               <li><b>Env:</b> {health.env}</li>
               <li><b>Host:</b> {health.hostname}</li>
               <li><b>Uptime:</b> {health.uptimeSec}s</li>
               <li><b>OpenSRS:</b> {health.opensrsConfigured ? `configured (${health.opensrsMode || "?"})` : "missing"}</li>
               <li><b>CORS Origins:</b> {health.corsOrigins?.length ? health.corsOrigins.join(", ") : "none"}</li>
               <li><b>Domain URL:</b> {health.domainUrl || "not set"}</li>
               <li><b>Time:</b> {new Date(health.time).toLocaleString()}</li>
             </ul>
           )}
+          <div className="mt-3 flex items-center gap-2">
+            <button
+              className="btn btn-outline btn-sm"
+              onClick={async () => {
+                setPingLoading(true);
+                try {
+                  const res = await fetch("/api/domain/ping");
+                  const data = await res.json();
+                  setPing(data);
+                } finally {
+                  setPingLoading(false);
+                }
+              }}
+              disabled={pingLoading}
+            >
+              {pingLoading ? "Pinging…" : "Ping Domains Provider"}
+            </button>
+            {ping && (
+              <span className={`text-xs ${ping.ok ? "text-emerald-700" : "text-red-600"}`}>
+                {ping.configured ? (ping.ok ? `OK ${ping.latencyMs}ms` : `Failed ${ping.latencyMs ?? "-"}ms`) : "Not configured"}
+                {ping.mode ? ` • ${ping.mode}` : ""}
+                {ping.sample ? ` • ${ping.sample}` : ""}
+                {ping.message ? ` • ${ping.message}` : ""}
+              </span>
+            )}
+          </div>
         </div>
@@
       <div className="mt-4">
         <button className="btn btn-primary" onClick={load} disabled={loading}>
           {loading ? "Refreshing…" : "Reload Data"}
         </button>
       </div>
     </div>
   );
 }

Acceptance

On /__qa/diag (dev-only), click Ping Domains Provider:

If OpenSRS creds missing → shows Not configured

If configured and reachable → shows OK 123ms • ote • example.com

If configured but failing → shows Failed 800ms • [message]

Server logs any unexpected errors under [domain.ping].