parse method
Decodes bytes (a text/event-stream byte stream) into the typed
AgUiEvents it carries, in wire order.
Framing is RFC 8895 / WHATWG event-stream: lines terminate on \r\n,
\r, or \n (a \r straddling a chunk boundary is resolved against the
next chunk); a leading : marks a comment; field:value strips one
optional leading space; a blank line dispatches the accumulated frame;
data lines are joined with \n and the single trailing \n is dropped
at dispatch. The event/id/retry fields are recognized SSE fields and
are kept out of the data payload; their retention (Last-Event-ID,
reconnect retry) lands with reconnect support in Story 4.4.
A frame with no data line (comment-only or event:-only) dispatches
nothing. A final frame whose data is not closed by a blank line is still
flushed when bytes completes. Source stream errors propagate unchanged;
corrupt data JSON surfaces as ProtocolError(protocolMalformed) (see
the class contract).
Implementation
Stream<AgUiEvent> parse(Stream<List<int>> bytes) async* {
final data = StringBuffer();
await for (final line in _lines(bytes)) {
final event = _consume(line, data);
if (event != null) yield event;
}
// EOF: flush a final frame whose data was never closed by a blank line.
final tail = _consume('', data);
if (tail != null) yield tail;
}