Creating a Client
The @zocket/client package provides createClient — a fully typed WebSocket client that infers its API from your app definition.
Basic Usage
Section titled “Basic Usage”import { createClient } from "@zocket/client";import type { app } from "./server";
const client = createClient<typeof app>({ url: "ws://localhost:3000",});The generic <typeof app> is the only type annotation you need. Everything else — actor names, method signatures, event payloads, state shapes — is inferred.
Options
Section titled “Options”interface ClientOptions { url: string; rpcTimeout?: number; // ms — reject pending RPCs after this duration}RPC Timeout
Section titled “RPC Timeout”If set, any RPC that doesn’t receive a response within the timeout is automatically rejected:
const client = createClient<typeof app>({ url: "ws://localhost:3000", rpcTimeout: 5000, // 5 seconds});Getting Actor Handles
Section titled “Getting Actor Handles”Access actors by name, then pass an instance ID:
const room = client.chat("general");const game = client.game("match-42");Each call returns a typed ActorHandle — see Actor Handles for the full API.
Connection Lifecycle
Section titled “Connection Lifecycle”$ready
Section titled “$ready”A promise that resolves when the WebSocket connection is open:
await client.$ready;console.log("Connected!");$close()
Section titled “$close()”Gracefully close the connection and dispose all handles:
client.$close();This:
- Clears all pending dispose timers
- Disposes all active actor handles (unsubscribes from events/state, rejects pending RPCs)
- Closes the WebSocket
Message Queueing
Section titled “Message Queueing”Messages sent before the WebSocket is open are queued and flushed once the connection is established. You don’t need to await $ready before calling methods:
const client = createClient<typeof app>({ url: "ws://localhost:3000" });
// These are queued if the connection isn't open yetconst room = client.chat("general");await room.sendMessage({ text: "hello" }); // waits for connection + responseError Handling
Section titled “Error Handling”If the WebSocket closes or errors, all pending RPCs on all handles are rejected:
try { await room.sendMessage({ text: "hello" });} catch (err) { console.error(err.message); // "WebSocket closed" or "WebSocket error"}How It Works
Section titled “How It Works”createClient returns a Proxy object. When you access client.chat, it returns a function. Calling that function (client.chat("room-1")) creates or retrieves a shared ActorHandleImpl for that (actorName, actorId) pair.
Handles are reference-counted — multiple consumers can share the same handle. When the ref count drops to zero, disposal is deferred by one tick to support React StrictMode’s unmount/remount cycle.