<!doctype html>
/* ---------------- CONFIG ---------------- */
const CONFIG = {
officeSpeedUrl: null, // e.g., 'https://synology.example.com/librespeed/'
statusSources: [
{ name: "WP Engine", url: "https://status.wpengine.com/api/v2/summary.json", type: "statuspage" },
{ name: "Cloudflare", url: "https://www.cloudflarestatus.com/api/v2/summary.json", type: "statuspage" },
{ name: "GitHub", url: "https://www.githubstatus.com/api/v2/summary.json", type: "statuspage" },
{ name: "Zoom", url: "https://status.zoom.us/api/v2/summary.json", type: "statuspage" },
{ name: "Dropbox", url: "https://status.dropbox.com/api/v2/summary.json", type: "statuspage" },
{ name: "Google Workspace", url: "https://www.google.com/appsstatus/dashboard/", type: "link" },
{ name: "Microsoft 365 (Admin)", url: "https://portal.office.com/adminportal/home#/servicehealth", type: "link" }
],
ispMap: [
{match:/verizon|fios/i, name:"Verizon Fios", links:{status:"https://www.verizon.com/support/residential/service-outage", radar:"https://radar.cloudflare.com/AS701"}},
{match:/comcast|xfinity/i, name:"Xfinity (Comcast)", links:{status:"https://www.xfinity.com/support/status/", radar:"https://radar.cloudflare.com/AS7922"}},
{match:/spectrum|charter/i, name:"Spectrum", links:{status:"https://www.spectrum.net/support/internet", radar:"https://radar.cloudflare.com/AS20115"}},
{match:/optimum|altice/i, name:"Optimum (Altice)", links:{status:"https://www.optimum.net/outage-center/", radar:"https://radar.cloudflare.com/AS6128"}},
{match:/rcn|astound/i, name:"Astound/RCN", links:{status:"https://www.astound.com/support/network-status/", radar:"https://radar.cloudflare.com/AS6079"}}
]
};
/* ---------------- UI ---------------- */
const $ = id => document.getElementById(id);
const ui = {
alert: $("alert"), start:$("startBtn"), again:$("againBtn"), copy:$("copyBtn"), office:$("officeBtn"),
progress:$("progress"), phase:$("phase"),
bigDown:$("bigDown"), up:$("up"), rtt:$("rtt"), loss:$("loss"),
loc:$("loc"), server:$("server"), ip:$("ip"), netinfo:$("netinfo"),
diag:$("diagList"), statusGrid:$("statusGrid")
};
function showAlert(msg){ ui.alert.textContent = msg; ui.alert.style.display = "block"; }
function clearAlert(){ ui.alert.style.display = "none"; ui.alert.textContent = ""; }
function setProgress(pct){ ui.progress.style.width = Math.max(0,Math.min(100,pct)) + "%"; }
function phase(text,pct){ ui.phase.textContent = text; if(typeof pct==="number") setProgress(pct); }
const fmt = (n,d=1)=> (n==null || isNaN(n)) ? "—" : Number(n).toFixed(d);
/* ---------------- STATE ---------------- */
const s = { downloadMbps:null, uploadMbps:null, minRttMs:null, lossPct:null,
serverCity:null, serverCountry:null, fqdn:null, clientIP:null,
effectiveType:null, browserRTT:null };
// Network Information (best-effort)
try{
const conn = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
if(conn){
s.effectiveType = conn.effectiveType || null;
s.browserRTT = typeof conn.rtt==="number" ? conn.rtt : null;
conn.addEventListener?.("change", ()=>{
s.effectiveType = conn.effectiveType || null;
s.browserRTT = typeof conn.rtt==="number" ? conn.rtt : null;
paint();
});
}
}catch(_){}
function paint(){
ui.bigDown.textContent = fmt(s.downloadMbps,1);
ui.up.textContent = fmt(s.uploadMbps,1);
ui.rtt.textContent = fmt(s.minRttMs,0);
ui.loss.textContent= s.lossPct==null ? "—" : fmt(s.lossPct,2);
ui.loc.textContent = (s.serverCity && s.serverCountry) ? `${s.serverCity}, ${s.serverCountry}` : "—";
ui.server.textContent = s.fqdn || "—";
ui.ip.textContent = s.clientIP || "—";
const ni=[];
if(s.effectiveType) ni.push(`ECT: ${s.effectiveType}`);
if(s.browserRTT!=null) ni.push(`browser RTT: ${fmt(s.browserRTT,0)} ms`);
ui.netinfo.textContent = ni.length ? ni.join(" · ") : "—";
const L=[], d=s.downloadMbps, u=s.uploadMbps, r=s.minRttMs, loss=s.lossPct;
const add=(cls,msg)=>L.push(`
`);
if(d!=null && u!=null){
if(d>=200 && u>=20 && (r!=null && r
if(d
if(u0 && d/u>8) add("warn","Upload far below download. Typical of cable plans or upstream saturation.");
}
if(r!=null){
if(r>80) add("warn","High latency (>80 ms). Could be ISP routing, bufferbloat, or VPN.");
if(r>150) add("bad","Very high latency (>150 ms). Likely upstream congestion or a routing issue.");
}
if(loss!=null){
if(loss>1) add("bad","Packet loss >1%. Suspects: Wi-Fi interference, failing Ethernet cable, or saturated uplink.");
else if(loss>0.3) add("warn","Some packet loss detected. Check crowded channel/interference sources.");
}
if(!L.length) add("ok","No major issues detected. If problems persist, re-test on Ethernet to isolate Wi-Fi.");
ui.diag.innerHTML = L.join("");
}
/* ---------------- STATUS BOARD ---------------- */
function indicatorToBadge(ind){
if(ind==="none"||ind==="operational") return {class:"b-ok", text:"Operational"};
if(ind==="minor") return {class:"b-warn", text:"Minor"};
if(ind==="major"||ind==="critical") return {class:"b-bad", text: ind==="major"?"Major":"Critical"};
return {class:"", text:"—"};
}
function addStatusCard({name, indicator="unknown", description="—", incidents=[], link=null, extra=[]}){
const badge = indicatorToBadge(indicator);
const el = document.createElement("div");
el.className = "tile";
el.innerHTML = `
${incidents && incidents.length ? `
`).join("")}
` : ""}
`;
ui.statusGrid.appendChild(el);
}
async function fetchStatusSource(src){
if(src.type==="link"){
addStatusCard({name:src.name, indicator:"unknown", description:"Open the official dashboard.", link:src.url});
return;
}
try{
const res = await fetch(src.url, {cache:"no-store"});
if(!res.ok) throw new Error(res.status);
const data = await res.json();
const indicator = data?.status?.indicator || "unknown";
const description = data?.status?.description || "—";
const incidents = (data?.incidents||[]).filter(i => !i.resolved_at).map(i=>({name:i.name, url:i.shortlink || i.url}));
addStatusCard({name:src.name, indicator, description, incidents, link: src.url.replace("/api/v2/summary.json","")});
}catch(_){
addStatusCard({name:src.name, indicator:"unknown", description:"Could not fetch via browser (CORS or blocked). Open status site.", link: src.url.re