Your state lives in one place: the host. Every client that attaches gets a live copy. A browser tab, a phone and a Python script all see the same thing at the same time, with no sync code of your own.
A client gets a snapshot when it attaches, then each change as a small patch. A streaming reply sends only the characters it adds. A client that drops and comes back starts from a fresh snapshot, so it shows what happened while it was away.
The host
State is plain data: objects, arrays, strings, numbers, booleans and dates. Change it like any object. Statewire records each write and sends it out.
The client
One hook in React. The same client attaches to JavaScript and Python hosts.
import { StatewireHttp, useStatewire } from "statewire";
const { state, commands, connection } = useStatewire<
{ messages: string[] } | undefined,
{ say(text: string): void }
>({
transport: StatewireHttp({ url: "/rooms/lobby" }),
});state re-renders on every patch. connection.status says whether the copy is live.
What travels
A patch is a list of add, replace and remove operations on paths. From {"score":0,"players":["Ada"],"text":"Hi"}:
[
{"op":"replace","path":["score"],"value":1},
{"op":"add","path":["players",1],"value":"Lin"},
{"op":"add","path":["text",2],"value":"!"}
]The last one appends ! to text. That is how a streaming reply costs a few bytes per token. The format is Statepatch; the values are a Statewire Document.