import { splitSSELines } from './SSEByteLineSplitter'; function noop(): void { return undefined; } export interface StreamResponse { statusCode: number; contentType: string | null; lines: AsyncIterable; close: () => void; } export interface StreamLineProvider { open(url: string, headers: Record, signal: AbortSignal): Promise; } async function* readChunks(reader: ReadableStreamDefaultReader): AsyncGenerator { try { while (true) { const result = await reader.read(); if (result.done) return; if (result.value) yield result.value; } } finally { try { reader.releaseLock(); } catch (e) { void e; } } } export class FetchStreamLineProvider implements StreamLineProvider { async open(url: string, headers: Record, signal: AbortSignal): Promise { const response = await fetch(url, { method: 'GET', headers, signal, cache: 'no-store', credentials: 'omit', }); const body = response.body; if (!body) { throw new Error('SSE response has no body'); } const reader = body.getReader(); return { statusCode: response.status, contentType: response.headers.get('content-type'), lines: splitSSELines(readChunks(reader)), close: () => { try { reader.cancel().catch(noop); } catch (e) { void e; } }, }; } }