Contents

depasqualeorg/swift-sse

Swift SSE is a minimal parser for Server-Sent Events streams.

Installation

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")
]

Usage

Parse a buffered response body

import SSE

let events = Parser.parse(data)

for event in events {
    print(event.eventType)
    print(event.data)
}

Choosing an API

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\n
  • retry: 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-ID changes even when no event was dispatched
  • retry: updates even when no event was dispatched

Parse state-aware SSE blocks

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)
    }
}

Parse incrementally

import SSE

var parser = Parser()

for byte in bytes {
    parser.consume(byte)

    while let event = parser.nextEvent() {
        print(event.data)
    }
}

parser.finish()

Parse an async byte stream

import SSE

for try await event in byteStream.events {
    print(event.eventType)
    print(event.data)
}

Parse an async byte stream with control updates

import SSE

for try await block in byteStream.sseBlocks {
    if let retry = block.retry {
        updateRetryDelay(milliseconds: retry)
    }

    if let event = block.dispatchedEvent {
        handleEvent(event)
    }
}

API Overview

ServerSentEvent

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:

  • id is event-local
  • lastEventId is stream-level committed state
  • id == "" is valid and means the stream ID was reset

ServerSentEventBlock

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 == nil means no event was dispatched
  • data == "" means an event was dispatched with an empty payload

ServerSentEventsParser

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:

Async parsing

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
  • .events filters out state-only blocks

Short aliases

The package also exposes these shorthand aliases:

  • Event for ServerSentEvent
  • Block for ServerSentEventBlock
  • Parser for ServerSentEventsParser

Scope

This package is intentionally parser-only.

Out of scope:

  • opening HTTP connections
  • reconnect scheduling
  • readyState or DOM-style event handlers
  • a full EventSource client abstraction

Those concerns should stay in the consuming transport/client library.

Package Metadata

Repository: depasqualeorg/swift-sse

Default branch: main

README: README.md