@lavedon/sdk
v2.0.0
Published
TypeScript SDK for building Lavedon games and clients.
Downloads
74
Readme
Lavedon SDK
TypeScript SDK for building Lavedon games and clients.
Install
npm install @lavedon/sdkEntry Points
import { LavedonClient, type GameDefinition, type PlayerAction } from "@lavedon/sdk";import { LavedonClient } from "@lavedon/sdk/client";
import type { Context, GameDefinition, PlayerAction, SystemAction } from "@lavedon/sdk/server";@lavedon/sdk exports the client and shared types.
@lavedon/sdk/client exports the WebSocket client only.
@lavedon/sdk/server currently exports the server-side type definitions used to describe a game.
Client
LavedonClient manages a WebSocket connection, tracks the latest state snapshot, applies JSON Patch updates, and notifies subscribers when state changes.
Basic Usage
import { LavedonClient } from "@lavedon/sdk";
type State = {
count: number;
};
type Action = {
type: "INC";
};
const client = new LavedonClient<State, Action>();
const unsubscribe = client.subscribe((state) => {
console.log("state", state);
});
client.connect("ws://localhost:8080");
client.send({ type: "INC" });
// later
unsubscribe();Client Options
const client = new LavedonClient({
autoReconnect: true,
initialBackoff: 1000,
maxBackoff: 30000,
});Available options:
autoReconnect: reconnect automatically after the socket closes. Defaults totrue.initialBackoff: starting reconnect delay in milliseconds. Defaults to1000.maxBackoff: maximum reconnect delay in milliseconds. Defaults to30000.
Supported Server Messages
The client accepts full state payloads and patch payloads:
{
"type": "FULL_STATE",
"state": { "count": 1 },
"version": 3
}{
"type": "PATCH_UPDATE",
"patch": [{ "op": "replace", "path": "/count", "value": 2 }],
"baseVersion": 3,
"version": 4
}Compatibility notes:
- Full snapshots are accepted as
FULL_STATE,STATE, or any payload with astatefield. - Patch payloads are accepted as
PATCH_UPDATEorPATCH. - If a patch arrives with the wrong
baseVersion, the client ignores it and sends{ "type": "FULL_STATE_REQUEST" }. - If the server sends
RELOAD, the client keeps the connection alive and waits for the next state payload.
Game Definition Types
The package also exports types for describing a Lavedon game on the server side.
import type { GameDefinition, PlayerAction, Context } from "@lavedon/sdk/server";
type State = {
count: number;
};
type Action =
| { type: "INC"; payload?: { amount?: number } }
| { type: "DEC"; payload?: { amount?: number } };
export const game: GameDefinition<State, Action> = {
setup: (_ctx: Context) => ({ count: 0 }),
actions: {
INC: (state, payload) => {
state.count += payload?.amount ?? 1;
},
DEC: (state, payload) => {
state.count -= payload?.amount ?? 1;
},
},
afterAction: (state, action, ctx) => {
if (action.type === "INC" && state.count >= 10) {
ctx.chat.announce("Target reached");
}
},
};Context
The setup, actions, and afterAction hooks receive a Context with:
playerIdroomIdtimestamprandom.next()random.chance(p)chat.announce(msg)chat.sendSystem(msg)events.emit(event, payload)
SystemAction
Reserved engine actions are exported as:
type SystemAction =
| { type: "@@INIT" }
| { type: "@@TICK" };Use afterAction if you need to react to these lifecycle events.
onTurnEnd
onTurnEnd is still present for compatibility, but it is deprecated. Prefer afterAction.
Development
bun install
bun test
bun run build