fix(core): parse event-stream retry and id fields per the SSE spec - #114
Conversation
The decoder now accepts any all-ASCII-digit retry (so `retry: 010` is 10, matching browsers, undici and eventsource-parser) and ignores an id that contains U+0000 NULL, keeping the previous id. Values that parse to Infinity are ignored so withEventMeta never rejects decoded output. The encoder, withEventMeta and the peer validator now also reject ids containing NULL: every spec-compliant client drops such ids, and a NULL in a Last-Event-ID header makes fetch throw.
@standard-server/aws-lambda
@standard-server/core
@standard-server/fastify
@standard-server/fetch
@standard-server/node
@standard-server/peer
@standard-server/shared
commit: |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Merging this PR will not alter performance
Comparing Footnotes
|
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
retrydecoding (decoder.ts) —Number.parseIntis now gated by/^\d+$/andisEventStreamMessageRetry, so leading zeros parse (retry: 010→10) and 400-digit values that becomeInfinityare ignored instead of producing a valuewithEventMetarejects.iddecoding (decoder.ts) — an id containing U+0000 NULL is ignored and the prior id is retained, matching WHATWG §9.2.6.idencoding/validation (encoder.ts,types.ts,peer/src/validators.ts) —isEventStreamMessageIdnow rejects\r,\n, and\0; error text and peer validation updated accordingly, with comments still permitting NULL.- Tests — decoder, encoder,
withEventMeta, and peer validator cases added; each fails against the pre-PR code.
Verified against the WHATWG HTML spec §9.2.6: retry must consist of only ASCII digits (and /^\d+$/ is ASCII-only in JS), and an id containing U+0000 NULL must be ignored while the Last-Event-ID value space excludes NUL/LF/CR. The implementation and its tests line up with both. The only tradeoff, already documented in the PR description, is precision loss for astronomically large finite retry values — not a practical concern.
DeepSeek Flash (default — pick a model for stronger reviews) | 𝕏

The event-stream decoder now follows the WHATWG SSE rules for
retryandid, matching browsers, undici's EventSource and eventsource-parser.retry: 010is now read as 10 instead of being dropped, and anidcontaining U+0000 NULL is ignored (the previous id is kept) instead of being surfaced as event meta that fetch can't send back asLast-Event-ID.Fixes
retryvalues made only of ASCII digits are accepted, including leading zeros; signs, decimals, exponents, hex, non-ASCII digits and extra spaces are still ignored.retrytoo large to parse to a finite number (309+ digits) is ignored instead of producingInfinity, so a decoded message never makeswithEventMetathrow and end the stream.idfields containing NULL are ignored by the decoder, and rejected by the encoder,withEventMetaand the peer validator, since every spec-compliant client drops them.Notes for reviewers
isPeerEventStreamMessage, the same way ids with CR/LF already were.retryvalues are kept as parsed and may lose precision pastNumber.MAX_SAFE_INTEGER.Testing
withEventMetaand peer validator cases; each fails against the previous code.tscclean.