Dstar.SSE (dstar v0.1.0-alpha.1)

Copy Markdown View Source

Server-Sent Event (SSE) connection helpers.

Sets up a Plug conn for chunked SSE streaming and provides functions to send events over it.

Example

conn
|> Dstar.SSE.start()
|> Dstar.SSE.send_event!("my-event", ["data line 1", "data line 2"])

Summary

Functions

Checks if an SSE connection is still open by sending a comment line.

Formats a single SSE event as a string (no connection needed).

Sends an SSE event to the client.

Sends an SSE event, raising on error. Returns the updated conn.

Starts an SSE connection from a Plug conn.

Functions

check_connection(conn)

@spec check_connection(Plug.Conn.t()) ::
  {:ok, Plug.Conn.t()} | {:error, Plug.Conn.t()}

Checks if an SSE connection is still open by sending a comment line.

SSE comments (lines starting with :) are ignored by clients but will fail if the connection has been closed. Useful for detecting disconnections in streaming loops.

Returns {:ok, conn} if the connection is open, {:error, conn} if closed or not yet started.

Example

case Dstar.SSE.check_connection(conn) do
  {:ok, conn} ->
    # Continue streaming
    stream_loop(conn)

  {:error, _conn} ->
    # Connection closed, clean up
    :ok
end

format_event(event_type, data_lines)

@spec format_event(String.t(), [String.t()]) :: String.t()

Formats a single SSE event as a string (no connection needed).

Useful for building SSE response bodies without chunked streaming.

Example

Dstar.SSE.format_event("datastar-patch-signals", ["signals {\"count\":42}"])
# => "event: datastar-patch-signals\ndata: signals {\"count\":42}\n\n"

send_event(conn, event_type, data_lines, opts \\ [])

@spec send_event(Plug.Conn.t(), String.t(), [String.t()] | String.t(), keyword()) ::
  {:ok, Plug.Conn.t()} | {:error, term()}

Sends an SSE event to the client.

Returns {:ok, conn} on success, {:error, reason} on failure.

Options

  • :event_id — Event ID for client tracking
  • :retry — Retry duration in milliseconds

Example

{:ok, conn} = Dstar.SSE.send_event(conn, "my-event", ["line1", "line2"])

send_event!(conn, event_type, data_lines, opts \\ [])

@spec send_event!(Plug.Conn.t(), String.t(), [String.t()] | String.t(), keyword()) ::
  Plug.Conn.t()

Sends an SSE event, raising on error. Returns the updated conn.

Useful for pipelines:

conn
|> send_event!("event-a", "data a")
|> send_event!("event-b", "data b")

start(conn)

@spec start(Plug.Conn.t()) :: Plug.Conn.t()

Starts an SSE connection from a Plug conn.

Sets the required SSE response headers (Content-Type: text/event-stream, Cache-Control: no-cache) and sends a chunked 200 response.

The Connection header is intentionally NOT set — it is forbidden in HTTP/2 (RFC 9113 §8.2.2) and browsers/curl reject the entire response body when they see it. Connection: keep-alive is an HTTP/1.1-only header and is already the default there.

Example

conn = Dstar.SSE.start(conn)