// Authenticated POST -> SSE reader. Calls onEvent({ type, ...data }) per frame. const TOKEN_KEY = 'void_token'; export async function streamTurn(path, body, onEvent) { const res = await fetch(path, { method: 'POST', headers: { 'Authorization': 'Bearer ' + (localStorage.getItem(TOKEN_KEY) || ''), 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); if (!res.ok || !res.body) throw new Error('stream failed: ' + res.status); const reader = res.body.getReader(); const decoder = new TextDecoder(); let buf = ''; for (;;) { const { value, done } = await reader.read(); if (done) break; buf += decoder.decode(value, { stream: true }); const frames = buf.split('\n\n'); buf = frames.pop(); // keep the trailing partial for (const frame of frames) { let event = 'message', data = ''; for (const line of frame.split('\n')) { if (line.startsWith('event:')) event = line.slice(6).trim(); else if (line.startsWith('data:')) data += line.slice(5).trim(); } if (data) onEvent({ type: event, ...JSON.parse(data) }); } } }