@inkly/client
v0.0.0
Published
The isomorphic inkly client: typed RPC, push events, resumable streams, auto-reconnect.
Readme
@inkly/client
The isomorphic typed client for inkly — actions, events, and server-push streams from one shared contract, with automatic reconnect and resumable replay in browsers, Node 22+, Bun, and Deno.
This package is client-only. It expects an inkly server built with
@inkly/coreand a runtime adapter such as@inkly/node.
Why it exists
@inkly/client gives application code a small, typed surface instead of raw WebSocket frame handling: client.actions.* returns promises, client.on() subscribes to validated events, and client.streams.*() returns cancellable async iterables. Reconnect and resume are transparent, so short network drops do not force every UI or worker to rebuild its own retry, replay, and duplicate-suppression logic.
Install
pnpm add @inkly/client @inkly/protocol zodQuickstart
import { createClient } from "@inkly/client";
import { contract } from "@inkly/protocol";
import { z } from "zod";
const chat = contract({
actions: {
sendMessage: {
input: z.object({ room: z.string(), text: z.string() }),
output: z.object({ id: z.string(), at: z.number() }),
},
},
events: {
message: z.object({ id: z.string(), room: z.string(), text: z.string(), at: z.number() }),
},
streams: {
history: { input: z.object({ room: z.string() }), yields: z.object({ id: z.string(), text: z.string() }) },
},
});
const client = createClient(chat, {
url: "ws://localhost:3000/ws",
params: () => ({ token: localStorage.getItem("token") ?? "" }),
});
client.on("message", (message) => console.log(message.text));
await client.connect();
await client.actions.sendMessage({ room: "general", text: "hello" });
for await (const message of client.streams.history({ room: "general" })) {
console.log(message.text);
}API reference
| API | Purpose |
| --- | --- |
| createClient(contract, options) | Creates a typed client for one contract. |
| options.url | ws:// or wss:// endpoint. |
| options.params | Static object or function resolved fresh for every connect/reconnect. |
| options.reconnect | Backoff options { minDelay?, maxDelay?, jitter? }, or false to disable reconnect. |
| options.resume | Enables session resume by default; set false to reconnect with fresh sessions. |
| options.timeout | Per-action timeout in milliseconds. |
| options.heartbeat | Client ping/pong configuration, or false. |
| options.WebSocket | Injectable WebSocket constructor; defaults to globalThis.WebSocket. |
| options.codec | Wire codec; must match the server. |
| options.autoConnect | Connects immediately by default; set false for manual connect(). |
| client.actions.<name>(input) | Calls a typed server action and returns Promise<output>. |
| client.streams.<name>(input) | Starts a typed stream; the handle is AsyncIterable and has .cancel(). |
| client.on(event, cb) | Subscribes to a typed event and returns an unsubscribe function. |
| client.status | Current status: connecting, open, reconnecting, or closed. |
| client.onStatus(cb) | Subscribes to status changes and returns an unsubscribe function. |
| client.connect() | Resolves on ready; rejects with the server's typed auth error. |
| client.auth(token?, params?) | Refreshes auth on the live connection (no reconnect); resolves when the server accepts, rejects if it refuses (the prior auth stays valid). Requires the server to set reauthorize. |
| client.close() | Intentionally closes and stops reconnecting. |
Docs
- docs/overview.md — client model and lifecycle.
- docs/actions-events-streams.md — the three typed APIs.
- docs/reconnect-and-resume.md — automatic recovery semantics.
Examples
- examples/browser-client.ts — browser usage with actions, events, and a stream.
- examples/node-client.ts — Node 22+ usage with native
globalThis.WebSocket.
License
Dazza Public License 1.0 (LicenseRef-Dazza-1.0).
