Skip to content

Live events

Instead of polling, subscribe to a context’s real-time events. mero.events(contextIds) opens a Server-Sent-Events stream and emits a ContextEvent for each node emission — new messages, application-version flips, and other context activity — so a screen can react as changes arrive.

events(contextIds) returns a cold Flow<ContextEvent>. Collect it inside a coroutine you can cancel:

val job = scope.launch {
mero.events(contextIds = listOf(contextId)).collect { event ->
when (event.kind) {
"ExecutionEvent" -> reloadMessages()
else -> println("event on ${event.contextId}: ${event.kind}")
}
}
}

Each event is:

data class ContextEvent(
val contextId: String,
val kind: String, // e.g. "ExecutionEvent"
val payload: JsonElement, // raw event JSON
)

For a contract emission (kind == "ExecutionEvent") the encoded contract events are nested under payload’s data.events[].data.

The stream reconnects automatically ~3 seconds after a drop and re-subscribes to your context ids (the node persists the session’s subscriptions). You don’t need to rebuild the flow on a transient network blip — the collector keeps delivering events across reconnects.

The stream lives for as long as its collecting coroutine — cancel that job (or the enclosing scope) to close the SSE connection:

job.cancel() // closes the connection

LaunchedEffect(contextId) ties collection to a composable’s lifetime — it starts when the composable enters composition and is cancelled when contextId changes or it leaves:

@Composable
fun MessagesScreen(mero: Mero, contextId: String) {
var messages by remember { mutableStateOf(emptyList<Message>()) }
LaunchedEffect(contextId) {
mero.events(contextIds = listOf(contextId)).collect {
messages = loadMessages()
}
}
MessageList(messages)
}