diff --git a/public/sse.js b/public/sse.js new file mode 100644 index 0000000..ebc113b --- /dev/null +++ b/public/sse.js @@ -0,0 +1,33 @@ +// 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) }); + } + } +}