Files
wehub-resource-sync e30e75b5d4
Changesets / Create Version PR (push) Has been cancelled
Deploy Shadcn Registry / Deploy Production (push) Has been cancelled
Template Metrics / LOC + Bundle Size (push) Has been cancelled
Code Quality / Oxlint + Oxfmt (push) Has been cancelled
Code Quality / Template Sync (push) Has been cancelled
Code Quality / Build Changed Packages (push) Has been cancelled
Code Quality / Test Changed Packages (push) Has been cancelled
Deploy Expo Example / Deploy Production (push) Has been cancelled
Deploy Ink Example / Deploy Production (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.12) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.12) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:40:13 +08:00

98 lines
2.2 KiB
Plaintext

---
title: Quickstart
description: Install gorp and wire up your first client/server replica.
---
## Installation
```sh
npm install @assistant-ui/gorp
```
## Define your state and commands
A gorp app has two types: the shape of the synced **state**, and the
**commands** the client can send. Both live in shared code so client and
server stay in lockstep.
```ts
type State = {
count: number;
};
type Command =
| { type: "inc" }
| { type: "set"; value: number };
```
## Define a mutator
The mutator responds to commands by writing to state. Its signature is
the same for `GorpClient` and `GorpServer`, so a single function can run
on both sides.
```ts
const initialState: State = { count: 0 };
const mutator = (state: State, cmd: Command) => {
switch (cmd.type) {
case "inc":
state.count += 1;
break;
case "set":
state.count = cmd.value;
break;
}
};
```
It must be deterministic in `(state, command, seq)` — `GorpClient` re-runs
it on every replay to rebuild the optimistic view.
## Set up the server
`GorpServer` owns the authoritative state. Writes inside the mutator are
batched per microtask and emitted as deep-patch ops to every subscriber.
```ts
import { GorpServer, GorpSessions } from "@assistant-ui/gorp";
const server = new GorpServer<State, Command>({
initialState,
mutator,
});
const sessions = new GorpSessions(server);
```
## Set up the client
`GorpClient` is a replica plus an optimistic view layered on top of the
last server-confirmed state. The config also takes a `send` callback —
gorp invokes it whenever a command needs to go over the wire.
```ts
import { GorpClient } from "@assistant-ui/gorp";
const transport = createTransport();
const client = new GorpClient<State, Command>({
initialState,
mutator,
send: (cmd) => transport.send(cmd),
});
transport.onMessage((msg) => client.apply(msg));
```
## Use it
```ts
client.send({ type: "inc" });
client.state.count; // 1, immediately (optimistic)
```
The server's first envelope is always a full snapshot, so a fresh client
catches up without an explicit handshake. After that, only patches flow.
On reconnect, call `client.resync()` to re-emit pending commands via the
new connection. `GorpSessions` dedups them against the session high-water.