Swift SSE is a minimal parser for Server-Sent Events streams.
It implements the SSE wire-format parsing rules from the WHATWG HTML spec and is intended as a low-level building block. It does not implement a browser-style EventSource networking client.
Add the package dependency:
dependencies: [
.package(url: "https://github.com/DePasqualeOrg/swift-sse.git", from: "0.1.0")
]Then add the product to your target:
dependencies: [
.product(name: "SSE", package: "swift-sse")
]import SSE
let events = Parser.parse(data)
for event in events {
print(event.eventType)
print(event.data)
}Use the event-only APIs when you only care about dispatched SSE events:
Parser.parse(_:)parser.nextEvent()byteStream.events
These surfaces filter out terminated SSE blocks that only update parser state, such as:
id\n\nretry: 3000\n\n
Use the block-aware APIs when you need to observe those state-only updates:
Parser.parseBlocks(_:)parser.nextBlock()byteStream.sseBlocks
This matters for clients that need to react to:
Last-Event-IDchanges even when no event was dispatchedretry:updates even when no event was dispatched
import SSE
for block in Parser.parseBlocks(data) {
if let event = block.dispatchedEvent {
print(event.data)
} else if let retry = block.retry {
print("retry:", retry)
} else if let id = block.id {
print("last-event-id:", block.lastEventId)
print("raw id field:", id)
}
}import SSE
var parser = Parser()
for byte in bytes {
parser.consume(byte)
while let event = parser.nextEvent() {
print(event.data)
}
}
parser.finish()import SSE
for try await event in byteStream.events {
print(event.eventType)
print(event.data)
}import SSE
for try await block in byteStream.sseBlocks {
if let retry = block.retry {
updateRetryDelay(milliseconds: retry)
}
if let event = block.dispatchedEvent {
handleEvent(event)
}
}Represents a dispatched SSE event.
| Property | Meaning |
|---|---|
id |
The raw id: field from this event block, or nil if the block omitted id: |
event |
The raw custom event type from event:, or nil when the default "message" type applies |
eventType |
The effective event type, defaulting to "message" |
data |
The dispatched payload. This is always present on ServerSentEvent |
retry |
The valid retry: value from this same block, if present |
lastEventId |
The committed stream-level Last-Event-ID value after this event was processed |
Important distinctions:
idis event-locallastEventIdis stream-level committed stateid == ""is valid and means the stream ID was reset
Represents the observable result of a terminated SSE block, including blocks that did not dispatch an event.
| Property | Meaning |
|---|---|
id |
The raw id: field from this block, if present |
event |
The raw custom event type from this block, if present |
data |
The dispatched payload, or nil if this block did not dispatch an event |
retry |
The valid retry: value from this block, if present |
lastEventId |
The committed stream-level Last-Event-ID value after this block was processed |
reconnectionTime |
The current stream-level reconnection time after this block was processed |
dispatchedEvent |
A ServerSentEvent view of this block when data is non-nil |
Important distinctions:
data == nilmeans no event was dispatcheddata == ""means an event was dispatched with an empty payload
Incremental parser state.
| API | Meaning |
|---|---|
consume(_:) |
Feed one byte into the parser |
consume(_ bytes:) |
Feed a sequence of bytes into the parser |
finish() |
Signal end-of-stream; incomplete trailing events are discarded per the SSE spec |
nextBlock() |
Pop the next parsed ServerSentEventBlock |
nextEvent() |
Pop the next dispatched ServerSentEvent, filtering out state-only blocks |
parseBlocks(_:) |
Parse a complete buffered byte sequence into blocks |
parse(_:) |
Parse a complete buffered byte sequence into dispatched events only |
lastEventId |
Current committed stream-level Last-Event-ID |
reconnectionTime |
Current stream-level reconnection time from retry: |
| API | Meaning |
|---|---|
byteStream.sseBlocks |
Async block-aware parsing surface |
byteStream.events |
Async event-only parsing surface |
Behavior notes:
- upstream async sequence failures are rethrown
- EOF does not dispatch an incomplete trailing event
.eventsfilters out state-only blocks
The package also exposes these shorthand aliases:
EventforServerSentEventBlockforServerSentEventBlockParserforServerSentEventsParser
This package is intentionally parser-only.
Out of scope:
- opening HTTP connections
- reconnect scheduling
readyStateor DOM-style event handlers- a full
EventSourceclient abstraction
Those concerns should stay in the consuming transport/client library.