Skip to content

Stream

Lune includes a WebSocket-backed IPC stream for ordered, low-latency data delivery between Crystal and JavaScript. Use it when you need high-frequency or continuous streams — price ticks, log lines, LLM token output, sensor data — where firing a new evaluateJavaScript call per message would saturate the event loop.

For the full API reference see Stream plugin.


Crystal → JavaScript

Call app.stream.send from any fiber:

crystal
app.stream.send("tick", { "price" => 45123.50 })
app.stream.send("log-line", "build finished in 4.2s")

Listen in JavaScript with lune.Stream.on:

js
import { lune } from "../lunejs/runtime/runtime.js";

lune.Stream.on("tick", ({ price }) => renderTicker(price));
lune.Stream.once("ready", () => showReadyState());

JavaScript → Crystal

Fire-and-forget with lune.Stream.send — no await needed:

js
lune.Stream.send("stream-start");
lune.Stream.send("order", { symbol: "BTC", qty: 1 });

Listen in Crystal with app.stream.on:

crystal
app.stream.on("order") do |data|
  place_order(data["symbol"].as_s, data["qty"].as_i)
end

Event vs Stream

Use Event for discrete, low-frequency signals; use Stream for sustained data flows.

EventStream
TransportevaluateJavaScript per callWebSocket frames
JS → Crystalawait Event.emit(...)lune.Stream.send(...) (no await)
ThroughputLow–mediumHigh (batched WS frames)
OrderingBest-effortGuaranteed per-connection
Best forUI signals, one-off notificationsTickers, log tails, token streams

See Stream plugin for the full API reference including common patterns and listener management.

Released under the MIT License.