Skip to content

sse

stable

Parse and format Server-Sent Events (SSE) streams according to the W3C specification, including event formatting, stream parsing, keepalives, and HTTP header generation.

use plugin sse::{parse_event, format_event, parse_stream, …}
12 functions Networking
/ filter jk navigate Esc clear
Functions (12)
  1. parse_event Parse a single SSE event block into a table
  2. format_event Format data as an SSE event string
  3. parse_stream Parse a full SSE stream into a table of events
  4. format_comment Format a comment line for an SSE stream
  5. format_retry Format a retry directive in milliseconds
  6. format_keepalive Return the SSE keepalive ping string
  7. format_data_only Format data-only lines without an event type
  8. validate_event_type Check whether an event type string is valid
  9. extract_last_event_id Extract the last event ID from a raw stream
  10. build_headers Build HTTP request headers for SSE connections
  11. event_count Count the number of events in a raw stream
  12. content_type Return the SSE content-type string

Overview

sse is a stateless toolkit for the wire format behind Server-Sent Events: the plain-text protocol where a server streams field: value lines and clients listen over a long-lived HTTP connection. Every function is a pure transform on strings — there is no socket, connection object, or hidden state to manage. You either parse raw stream text into ordinary tables (parse_event, parse_stream, extract_last_event_id, event_count) or build spec-compliant output to write to a response (format_event, format_comment, format_retry, format_keepalive, format_data_only).

The mental model is two halves that mirror each other: a parsing half that turns the text/event-stream wire format into Zolo values, and a formatting half that turns Zolo values back into bytes. Reach for it on the server when emitting a stream (set the content_type, format each event, send format_keepalive periodically), and on the client when consuming one (build request headers with build_headers, then parse incoming chunks and resume from extract_last_event_id after a drop).

Common patterns

Emit a stream: set the content type, then format each event before writing it:

use plugin sse::{content_type, format_event}

print("Content-Type: {content_type()}")
print(format_event("system online", "status", "1"))
print(format_event("user joined", "presence", "2"))

Consume a stream: parse every event, then remember where to resume after a drop:

use plugin sse::{parse_stream, extract_last_event_id}

let raw = "event: tick\ndata: 1\nid: 1\n\nevent: tick\ndata: 2\nid: 2\n\n"
let events = parse_stream(raw)
for _, evt in events {
  print("{evt["event"]}: {evt["data"]}")
}
print("resume after: {extract_last_event_id(raw)}")

Open a client connection that resumes from the last seen id, then keep it warm:

use plugin sse::{build_headers, format_keepalive}

let headers = build_headers("42")
for key, val in headers {
  print("{key}: {val}")
}
print("keepalive: {format_keepalive()}")

Parse a single SSE event block into a table

Parses a single SSE event block (multiple field: value lines) and returns a table with event, data, id, and retry. The event field defaults to "message" if not specified.

use plugin sse::{parse_event}

let raw = "event: update\ndata: hello world\nid: 42\n"
let evt = parse_event(raw)
print("type={evt["event"]} data={evt["data"]} id={evt["id"]}")

A retry: line is parsed into an integer, and a missing event defaults to "message":

use plugin sse::{parse_event}

let evt = parse_event("data: keepalive\nretry: 3000\n")
print("event={evt["event"]} retry={evt["retry"]}")

Format data as an SSE event string

Formats an SSE event string ready to write to an HTTP response. event_type and id are optional. The default event type ("message") is omitted from the output per spec.

use plugin sse::{format_event}

let msg = format_event("hello world", "update", "1")
print(msg)

let simple = format_event("ping", nil, nil)
print(simple)

Multi-line data is split into one data: line per source line, which the client reassembles into a single payload joined by newlines:

use plugin sse::{format_event}

let block = format_event("first line\nsecond line", "log", "7")
print(block)

Parse a full SSE stream into a table of events

Parses a complete SSE stream (multiple events separated by blank lines) and returns a table of event tables, each with event, data, id, and retry.

use plugin sse::{parse_stream}

let stream = "data: first\n\ndata: second\nid: 2\n\n"
let events = parse_stream(stream)
for _, evt in events {
  print(evt["data"])
}

Pair it with event_count to size a stream before walking it:

use plugin sse::{parse_stream, event_count}

let raw = "data: a\n\ndata: b\n\ndata: c\n\n"
print("parsing {event_count(raw)} events")
let events = parse_stream(raw)
print("got {#events} tables")

Format a comment line for an SSE stream

Formats one or more lines as SSE comments (prefixed with :). Comments are ignored by clients but keep the connection alive.

use plugin sse::{format_comment}

let c = format_comment("server time: 12:00")
print(c)

Format a retry directive in milliseconds

Formats a retry: directive telling the client to wait ms milliseconds before reconnecting after a dropped connection.

use plugin sse::{format_retry}

let directive = format_retry(5000)
print(directive)

Return the SSE keepalive ping string

Returns the SSE keepalive string (":\n\n"). Send this periodically to prevent proxies and clients from closing an idle connection.

use plugin sse::{format_keepalive}

let ping = format_keepalive()
print(ping)

Format data-only lines without an event type

Formats multi-line data as SSE data: lines without setting an event type. Each line of data becomes a separate data: field.

use plugin sse::{format_data_only}

let msg = format_data_only("line one\nline two")
print(msg)

Check whether an event type string is valid

Returns true if event_type is a valid SSE event type name (non-empty, no newlines or colons).

use plugin sse::{validate_event_type}

print(validate_event_type("update"))
print(validate_event_type("bad:type"))
print(validate_event_type(""))

Extract the last event ID from a raw stream

Scans a raw SSE stream and returns the value of the last id: field found (a string), or nil if none. Use this to resume a stream from where it left off.

use plugin sse::{extract_last_event_id}

let stream = "id: 1\ndata: a\n\nid: 2\ndata: b\n\n"
let last_id = extract_last_event_id(stream)
print("resume from id: {last_id}")

Build HTTP request headers for SSE connections

Returns a table of HTTP request headers appropriate for opening an SSE connection: Accept, Cache-Control, and Connection. If last_event_id is non-empty, a Last-Event-ID header is also included for stream resumption.

use plugin sse::{build_headers}

let headers = build_headers("42")
for key, val in headers {
  print("{key}: {val}")
}

On a fresh connection with no prior id, pass nil to omit Last-Event-ID:

use plugin sse::{build_headers}

let headers = build_headers(nil)
for key, val in headers {
  print("{key}: {val}")
}

Count the number of events in a raw stream

Counts the number of events in a raw SSE stream by counting non-comment data blocks separated by blank lines.

use plugin sse::{event_count}

let stream = "data: one\n\ndata: two\n\ndata: three\n\n"
print("events: {event_count(stream)}")

Return the SSE content-type string

Returns the correct MIME type string for SSE responses: "text/event-stream".

use plugin sse::{content_type}

print(content_type())
enespt-br