Appearance
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)
endEvent vs Stream
Use Event for discrete, low-frequency signals; use Stream for sustained data flows.
| Event | Stream | |
|---|---|---|
| Transport | evaluateJavaScript per call | WebSocket frames |
| JS → Crystal | await Event.emit(...) | lune.Stream.send(...) (no await) |
| Throughput | Low–medium | High (batched WS frames) |
| Ordering | Best-effort | Guaranteed per-connection |
| Best for | UI signals, one-off notifications | Tickers, log tails, token streams |
See Stream plugin for the full API reference including common patterns and listener management.