Skip to main content
GET /api/chat/stream is a long-lived text/event-stream. It carries everything that reaches the conversation without a request from this device:
  • Scheduled messages that Lala planned earlier.
  • The daily check-in after a silence.
  • Messages and reactions from the student’s other devices.
Open it when the chat screen opens. Keep it open while the application is in the foreground.

Events

StreamMessageEvent
A message reached the conversation.
StreamReactionEvent
The reactions on this message changed. The payload is the whole message.
object
A keep-alive, about every 25 seconds. Ignore the payload.
The message payload is a full ChatMessage, in the same shape as the history. It needs no extra fetch.

Rules for the client

  1. Merge each message into the local list by id.
  2. The stream repeats messages this device produced through POST /api/chat/send. De-duplicate by id. Do not render the same message twice.
  3. On reaction, replace the reactions of that message.
  4. If no ping arrives for 60 seconds, treat the stream as dead and reconnect.
  5. After a reconnect, read GET /api/chat/messages?after=<cursor of your newest message> to fill the gap.
Do not use the browser EventSource API. EventSource cannot set the Authorization header. Use fetch with a stream reader.

Push and the stream

Push notifications and this stream cover different states. Push reaches a closed application. The stream reaches an open one. The server does both for every proactive message, so an open application can receive a push it does not need. Read Push notifications.

Delivery

The stream is best effort. A message always reaches the database first, and the stream announces it after. A dropped event costs you the live update, not the message. The after parameter recovers it.