Client State
Client state is part of the Client.Service(...) definition. When a client
connects, the actor runtime sends an initial state value during audition. After
that, client-side reducers fold incoming events into the current state.
There is no separate state service. The client itself exposes the state stream, event stream, call surface, and typed reducer helper.
Define state on the client
import { as } from "effect"
import { } from "liminal"
export const = .(["X", "O"])
export const = .([0, 1, 2])
export const = .([, ])
export class extends .<>()(
"examples/TicTacToeClient",
{
: {
: .,
: ,
},
: {
: {},
: {
: ,
: ,
},
: {
: .(),
},
},
: {
: {
: .({ : }),
: .,
: .,
},
},
},
) {}The state record is Effect Schema struct fields. The actor runtime must
hydrate a value matching that shape for every new connection.
Hydrate on connect
In a Workerd actor runtime, hydrate returns the initial state for the
connecting client.
export default .(function* () {
const { } = yield*
if (. === 1) {
return {
: true,
: "X" as ,
}
}
yield* ..("GameStarted", {})
return {
: false,
: "O" as ,
}
}).(.)Hydration is the snapshot. Events sent after hydration are deltas that reducers apply locally.
Reduce events
Reducers live next to the client runtime. Client.reducer(...) narrows the
event tag and returns the reducer unchanged at runtime.
export const = .(
"GameStarted",
() =>
({ }) =>
.({ , : false }),
)
export const = .(
"MoveMade",
() => () => .(),
)
export const = .(
"GameEnded",
() => () => .(),
)Each reducer receives the event first and the current state second. Return the
next state to publish an update, or return void to leave the current state
unchanged.
Provide reducers
Pass the reducer table to Client.layerSocket(...).
export const = .(
.({
: ,
: "/play",
: { : "startup" },
,
}).(.(.)),
)Consume state
TicTacToeClient.state is a stream of hydrated and reduced state values.
export const = .(.)Read Snapshot and Delta Events for event design guidance.