# `@openclaw/gateway-client`

Reference WebSocket client for the OpenClaw Gateway protocol. It provides the
connection state machine used by OpenClaw's own Node and browser clients:
challenge-based authentication, typed protocol frames, request correlation,
timeouts, reconnect backoff, device-token handling, and event delivery.

The current wire protocol is version 4. General clients must advertise exactly v4 with
`minProtocol: 4` and `maxProtocol: 4`. See the
[Gateway protocol specification](https://docs.openclaw.ai/gateway/protocol) for
the complete handshake, authentication, role, scope, and method contracts.
Exact node identities (`role: "node"` plus `mode: "node"`) and probe clients
can use v3. The built-in node host starts with an exact v4 envelope, then retries
an exact v3 envelope after a v3 Gateway rejects v4. If that legacy probe reaches
an upgraded v4 Gateway, the client reconnects with the full v4 envelope before
reporting readiness. Other exact node identities default to `[3, 4]`. Explicit
bounds override these defaults; `[3, 4]` on the built-in node host selects the
same bounded negotiation.

## Versioning

Package versions follow the OpenClaw calendar release train: `YYYY.M.PATCH`,
including the OpenClaw prerelease suffix when applicable. The package version is
separate from the Gateway's current wire protocol number reported in `hello-ok`.

## Install

```bash
npm install @openclaw/gateway-client @openclaw/gateway-protocol
```

Node consumers use the `ws` transport included as a runtime dependency. Browser
consumers provide their platform WebSocket through the browser-safe protocol
client surface.

## Entry points

- `@openclaw/gateway-client` exports the Node `GatewayClient`, device-auth
  helpers, readiness helpers, and timeout utilities.
- `@openclaw/gateway-client/browser` exports the browser-safe protocol client,
  browser device-auth lifecycle, reconnect policy, and lightweight protocol
  constants. Its module graph does not import Node built-ins or `ws`.
- `@openclaw/gateway-client/readiness` exports helpers that delay client startup
  until the event loop can process Gateway IO.
- `@openclaw/gateway-client/timeouts` exports timeout constants and safe timer
  resolution helpers.
- `@openclaw/gateway-client/websocket-data` converts every Node `ws` raw-data
  shape to UTF-8 text.

## Node quickstart

```ts
import { GatewayClient } from "@openclaw/gateway-client";
import { PROTOCOL_VERSION } from "@openclaw/gateway-protocol/version";

const connected = Promise.withResolvers<void>();
const client = new GatewayClient({
  url: "ws://127.0.0.1:18789",
  token: process.env.OPENCLAW_GATEWAY_TOKEN,
  minProtocol: PROTOCOL_VERSION, // v4
  maxProtocol: PROTOCOL_VERSION, // v4
  onHelloOk: () => connected.resolve(),
  onConnectError: (error) => connected.reject(error),
  onEvent: (event) => {
    console.log(event.event, event.payload);
  },
});

client.start();
await connected.promise;

const status = await client.request("status", {});
console.log(status);

client.stop();
```

The client waits for the Gateway's `connect.challenge` event before sending its
`connect` request. It includes the challenge nonce in device authentication and
does not fall back to a pre-challenge handshake. `onHelloOk` fires only after the
Gateway accepts a compatible connection, so requests should wait for that callback.

For remote connections, use `wss://`. Plaintext `ws://` is allowed by default
only for loopback addresses. Authentication material and Gateway traffic must
not cross an untrusted network without transport security.

## Browser clients

Import `@openclaw/gateway-client/browser` when the host owns the WebSocket
adapter and device-key storage. The browser entry includes
`GatewayProtocolClient` and `GatewayBrowserDeviceAuthLifecycle`; it deliberately
omits the Node transport, TLS fingerprint handling, and private-network address
policy.

The host is responsible for:

- creating a `GatewayProtocolSocket` adapter around the browser WebSocket;
- loading and storing browser device identity and issued device tokens;
- signing the challenge-bound device payload;
- using the Gateway challenge `ts` as the device proof's `signedAt` value;
- supplying the client identity, role, scopes, and authentication selection;
- choosing close and reconnect behavior for product-specific errors.

The shared protocol client still owns frame parsing, request correlation,
challenge ordering, timeout cleanup, sequence-gap detection, and reconnect
scheduling.

## Defaults and reconnect behavior

The Node client starts with a 30 second request timeout, a 15 second
connect-challenge timeout, and exponential reconnect delays from 1 second to 30
seconds with a multiplier of 2. Server-provided startup retry hints may override
the next delay.

The canonical defaults table and the server policy fields that can replace
pre-handshake values are documented in the
[Gateway protocol specification](https://docs.openclaw.ai/gateway/protocol#client-constants).

Use the `./timeouts` entry point when a host must align readiness or watchdog
budgets with these defaults. Use the `./readiness` entry point when startup must
wait for an event-loop probe before opening the socket.

## Bundled internals

The retry supervisor and the small `@openclaw/net-policy/ip` implementation are
inlined into the published JavaScript and declarations. They are implementation
details, not public exports or supported API surfaces. `ipaddr.js` remains an
external dependency because the inlined IP helpers use its public runtime and
types.

`ws`, `@openclaw/gateway-protocol`, and `ipaddr.js` remain external in the
published distribution. Consumers should import protocol types and constants
from `@openclaw/gateway-protocol`, not from bundled implementation paths.

## Contract notes

- The client is inert at module import and construction time. `start()` opens
  the socket; `stop()` closes it and rejects pending requests.
- A request uses `request(method, params)` after `hello-ok`. Passing
  `timeoutMs: null` creates an intentionally unbounded request.
- Finite request deadlines reject with `GatewayProtocolRequestTimeoutError`,
  whose `CLIENT_TIMEOUT` code, method, deadline, and send-boundary flag remain
  distinct from authoritative Gateway response errors.
- Device identity persistence, signing, proxy routing, TLS formatting, and
  logging stay host-owned through `GatewayClientHostDeps`.
- Protocol changes are additive first. Incompatible changes require an explicit
  wire-version decision and coordinated server/client follow-through.
