Skip to content
Plugins (190)

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
12 functions Networking
Runs with the native Zolo host

Plugin snippets can be edited in the Playground, but native capabilities are executed locally with the Zolo CLI.

/ 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

From import to result

  1. 01Import only what you use
  2. 02Copy the smallest example
  3. 03Run it with the Zolo CLI

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 {len(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())

Global index

Find your way through Zolo

Try an idea

Start here

9 results

9 results

en