Skip to content

8. Going live with SSE

So far every update has been a reaction to your own events. The last step makes a page update when state changes from anywhere — another tab, another visitor, a background process — using server-sent events. We’ll add a tiny “stock remaining” indicator that everyone watching sees tick down in real time.

Most pages need nothing beyond what you’ve already built. When you POST an event, the response patches your view — that covers the overwhelming majority of interactivity, and it works with zero extra moving parts. Reach for live updates only when a page must reflect changes it didn’t initiate.

A route opts into live updates with a single pragma in its frontmatter. Add // @stator live to the catalog route:

---
// @stator live
import ProductsMachine from '../machines/products.ts'
import CartMachine from '../machines/cart.ts'
import CustomerLayout from '../templates/customer-layout.stator'
import ProductList from '../templates/product-list.stator'
const [products, cart] = Stator.reads([ProductsMachine, CartMachine])
---
<CustomerLayout cart={cart}>
<h1>Goods for the desk and home</h1>
<ProductList products={products} cart={cart} />
</CustomerLayout>

That flag tells Stator to inject a small live marker into the page; the client opens one EventSource back to the server for that route. No client code to write — the connection and patch application are handled for you.

Here’s the payoff. When any session triggers a change to a machine this route reads, the server recomputes the affected bindings and pushes the patches to every open connection watching that route — not just the session that caused the change.

Picture an inventory app-machine with a remaining count, displayed via read(inventory, i => i.remaining). When one shopper checks out and decrements stock, every other shopper with the catalog open sees the number drop — in the same patch shape you’ve seen all along, just delivered over SSE instead of in a POST response. The render model doesn’t change; only the transport does.

Be precise about what you’re getting:

  • Opt-in only. A route is static request/response until you add // @stator live.
  • Reconnect means reload. If the connection drops, the client re-establishes and re-renders; there’s no missed-event replay.
  • Single-replica fan-out. The fan-out is in-process — every connection lives on the same server instance.

Desksmith renders, reacts, persists, and broadcasts — but it still can’t take money. The final chapter adds checkout with a real async call, and with it the one pattern behind all I/O in Stator: async effects.