fix: SSE via fetch for auth headers, remove query param auth, add heartbeat every 10s

This commit is contained in:
M1
2026-03-16 16:17:33 +04:00
parent 6d48a83560
commit 31d1fa7b04
3 changed files with 44 additions and 17 deletions
+34 -11
View File
@@ -94,20 +94,43 @@ function escapeHtml(str) {
return div.innerHTML;
}
// Subscribe to live ping updates for a monitor via SSE
// onPing(ping) called with each new ping object
// Subscribe to live ping updates for a monitor via SSE (fetch-based for auth header support)
// Returns an AbortController — call .abort() to close
function watchMonitor(monitorId, onPing) {
const key = localStorage.getItem('pingql_key');
if (!key) return null;
const url = `/monitors/${monitorId}/stream`;
const es = new EventSource(url + `?auth=${encodeURIComponent(key)}`);
const ac = new AbortController();
es.onmessage = (e) => {
try { onPing(JSON.parse(e.data)); } catch {}
};
es.onerror = () => {
// Reconnect is automatic with EventSource
};
return es;
async function connect() {
try {
const res = await fetch(`/monitors/${monitorId}/stream`, {
headers: { Authorization: `Bearer ${key}` },
signal: ac.signal,
});
if (!res.ok || !res.body) return;
const reader = res.body.getReader();
const dec = new TextDecoder();
let buf = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buf += dec.decode(value, { stream: true });
const lines = buf.split('\n');
buf = lines.pop() ?? '';
for (const line of lines) {
if (line.startsWith('data: ')) {
try { onPing(JSON.parse(line.slice(6))); } catch {}
}
}
}
} catch (e) {
if (e.name === 'AbortError') return;
// Reconnect after a short delay on unexpected disconnect
setTimeout(connect, 3000);
}
}
connect();
return ac;
}