# zidane/ipc/remote

> The client side of remote zidane hosts, over WebSocket with saved servers and settings sync.

Import: `import { … } from 'zidane/ipc/remote'`. Source: [src/ipc/remote.ts](https://github.com/Tahul/zidane/blob/main/src/ipc/remote.ts).

Use `zidane/ipc/remote` to connect to a zidane-server from Node 22 or later, or Bun. `connectWsClient` returns the same typed client as the unix-socket path, and the saved-hosts helpers keep a registry of the servers you connect to. It sits outside `zidane/ipc`, so an app loads none of it until remote hosts are on. [Server clients](https://zidane.si/docs/server-clients.md#node-client) covers errors, reconnection and settings sync.

```ts
import { connectWsClient } from 'zidane/ipc/remote'

const client = await connectWsClient({
  url: 'wss://zidane.example.com/',
  token: process.env.ZIDANE_HOST_TOKEN,
})
const sessions = await client.request('sessions.list', {})
console.log(sessions.length)
client.close()
```

## Functions

### `classifyWsFailure`

Function.

A refused token stays refused until the user changes something: no retry
loop. Another protocol version stays until one side is upgraded: a slow re-check.

```ts
function classifyWsFailure(err: unknown): HostFailureKind
```

**Parameters**

- `err` (`unknown`): The error a connect attempt failed with.

**Returns** `HostFailureKind`: `auth` for a refused token, `identity` for another host answering, `protocol` for a version mismatch, `retry` otherwise.

Source: [src/ipc/hosts/ws.ts:21](https://github.com/Tahul/zidane/blob/main/src/ipc/hosts/ws.ts#L21)

### `connectWsClient`

Function.

Connects to a remote zidane server over WebSocket and completes the `ipc.hello` handshake.
A refused upgrade rejects with [`HostAuthError`](https://zidane.si/docs/reference/ipc-remote.md#HostAuthError) for a 401 or 403, and [`HostBusyError`](https://zidane.si/docs/reference/ipc-remote.md#HostBusyError) for a 429. A hello from another host than `expectHostId` rejects with `HostIdentityError`. A version mismatch rejects with `IpcVersionMismatchError` and leaves the server running.

```ts
function connectWsClient(options: WsClientOptions): Promise<IpcClient>
```

**Parameters**

- `options` (`WsClientOptions`): Server URL, token and connection settings.

**Returns** `Promise<IpcClient>`: A typed client.

**Example**

```ts
import { connectWsClient } from 'zidane/ipc/remote'

const client = await connectWsClient({
  url: 'wss://zidane.example.com/',
  token: process.env.ZIDANE_HOST_TOKEN,
})
const sessions = await client.request('sessions.list', {})
console.log(sessions.length)
client.close()
```

Source: [src/ipc/transports/ws-client.ts:251](https://github.com/Tahul/zidane/blob/main/src/ipc/transports/ws-client.ts#L251)

### `createSyncEngine`

Function.

Creates a sync engine for this computer. Starts file watchers once a server is set to keep in sync.

```ts
function createSyncEngine(options: SyncEngineOptions): SyncEngine
```

**Parameters**

- `options` (`SyncEngineOptions`): Paths, providers and timing for the engine.

**Returns** `SyncEngine`

Source: [src/chat/sync/engine.ts:139](https://github.com/Tahul/zidane/blob/main/src/chat/sync/engine.ts#L139)

### `createWsHostRegistry`

Function.

The registry in `dataDir`, connecting over WebSocket.

```ts
function createWsHostRegistry(options: { dataDir: string }): HostRegistry
```

**Parameters**

- `options` (`{ dataDir: string }`): Where the registry keeps its data.

**Returns** `HostRegistry`: The host registry.

Source: [src/ipc/hosts/probe.ts:97](https://github.com/Tahul/zidane/blob/main/src/ipc/hosts/probe.ts#L97)

### `hostCaBundle`

Function.

The runtime's roots, the OS store's and `NODE_EXTRA_CA_CERTS`'s, read once.
`null` when the OS store adds nothing (or can't be read): the runtime's
default then applies as it is.

```ts
function hostCaBundle(): string[] | null
```

**Returns** `string[] | null`

Source: [src/ipc/transports/tls-trust.ts:39](https://github.com/Tahul/zidane/blob/main/src/ipc/transports/tls-trust.ts#L39)

### `keepHostConnected`

Function.

Connects a host and keeps it connected: reconnects with backoff when the connection drops, unless the failure is classified as final.

```ts
function keepHostConnected(options: HostConnectionLoopOptions): HostConnectionLoop
```

**Parameters**

- `options` (`HostConnectionLoopOptions`): How to connect, where to report, and the callbacks.

**Returns** `HostConnectionLoop`: A handle to stop the loop or retry now.

Source: [src/ipc/hosts/connection-loop.ts:97](https://github.com/Tahul/zidane/blob/main/src/ipc/hosts/connection-loop.ts#L97)

### `probeUnsavedWsHost`

Function.

The add form's "test": the registry's own checks and probe over WebSocket, saving nothing.

```ts
function probeUnsavedWsHost(
  target: { token: string; url: string },
): Promise<HostProbeResult>
```

**Parameters**

- `target` (`{ token: string; url: string }`): URL and token to try.

**Returns** `Promise<HostProbeResult>`: The probe result.

Source: [src/ipc/hosts/ws.ts:34](https://github.com/Tahul/zidane/blob/main/src/ipc/hosts/ws.ts#L34)

### `probeWsHost`

Function.

Connect, read the host's identity and `daemon.info`, disconnect. Never throws.

```ts
function probeWsHost(
  target: { timeoutMs?: number; token: string; url: string },
): Promise<HostProbeResult>
```

**Parameters**

- `target` (`{ timeoutMs?: number; token: string; url: string }`): URL, token and an optional timeout in milliseconds. The timeout defaults to [`HOST_PROBE_TIMEOUT_MS`](https://zidane.si/docs/reference/ipc-remote.md#HOST_PROBE_TIMEOUT_MS).

**Returns** `Promise<HostProbeResult>`: Who answered and how fast, or a classified failure.

Source: [src/ipc/hosts/probe.ts:59](https://github.com/Tahul/zidane/blob/main/src/ipc/hosts/probe.ts#L59)

### `startSavedHosts`

Function.

Starts the connections of a client's saved servers and keeps the directory in step with the registry.
Each saved server gets a directory entry and a connection loop. A connection whose host id differs from the saved one is closed and reported as `identity`.

```ts
function startSavedHosts(options: SavedHostsOptions): SavedHostsController
```

**Parameters**

- `options` (`SavedHostsOptions`): Registry, directory and how to dial.

**Returns** `SavedHostsController`: A controller over the saved servers.

Source: [src/ipc/hosts/saved-hosts.ts:108](https://github.com/Tahul/zidane/blob/main/src/ipc/hosts/saved-hosts.ts#L108)

### `startWsSavedHosts`

Function.

Keeps the saved servers of a client connected over WebSocket.
Uses the registry in `dataDir` unless `registry` is given, and dials with [`connectWsClient`](https://zidane.si/docs/reference/ipc-remote.md#connectWsClient) unless `connect` is given.

```ts
function startWsSavedHosts(options: WsSavedHostsOptions): SavedHostsController
```

**Parameters**

- `options` (`WsSavedHostsOptions`): Data directory, host directory and callbacks.

**Returns** `SavedHostsController`: A controller to list, add, remove, test and retry hosts, and to stop them all.

Source: [src/ipc/hosts/ws.ts:57](https://github.com/Tahul/zidane/blob/main/src/ipc/hosts/ws.ts#L57)

### `trustSystemCertificates`

Function.

Node: every TLS client of this process trusts [`hostCaBundle`](https://zidane.si/docs/reference/ipc-remote.md#hostCaBundle) from now
on (the desktop app's main process). Whether it applied.

```ts
function trustSystemCertificates(): boolean
```

**Returns** `boolean`

Source: [src/ipc/transports/tls-trust.ts:51](https://github.com/Tahul/zidane/blob/main/src/ipc/transports/tls-trust.ts#L51)

## Classes

### `HostAuthError`

Class.

The server refused this client's credential: 401 (no valid token) or 403
(not allowed here). `reason` only when the server sent a code clients know.

```ts
class HostAuthError extends Error
```

**Constructor**

```ts
new HostAuthError(
  url: string,
  status: 401 | 403,
  reason?: 'origin' | 'insecure-transport' | 'untrusted-proxy' | 'scope',
)
```

**Parameters**

- `url` (`string`): The server URL.
- `status` (`401 | 403`): HTTP status of the refusal.
- `reason?` (`'origin' | 'insecure-transport' | 'untrusted-proxy' | 'scope'`): Refusal code the server sent, when any.

**Returns** `HostAuthError`

**Properties**

- `reason?` (`'origin' | 'insecure-transport' | 'untrusted-proxy' | 'scope'`, readonly): Refusal code the server sent, when any.
- `status` (`401 | 403`, readonly): HTTP status of the refusal.
- `url` (`string`, readonly): The server URL, scheme, host and path only.

Source: [src/ipc/transports/ws-client.ts:99](https://github.com/Tahul/zidane/blob/main/src/ipc/transports/ws-client.ts#L99)

### `HostBusyError`

Class.

The server turned the upgrade down with a 429: too many open connections (per token, per address) or upgrades (per address). Transient.

```ts
class HostBusyError extends Error
```

**Constructor**

```ts
new HostBusyError(url: string)
```

**Parameters**

- `url` (`string`): The server URL.

**Returns** `HostBusyError`

Source: [src/ipc/transports/ws-client.ts:118](https://github.com/Tahul/zidane/blob/main/src/ipc/transports/ws-client.ts#L118)

### `MissingHostTokenError`

Class.

No token is saved for this server (removed by hand, or another window removed it).

```ts
class MissingHostTokenError extends Error
```

**Constructor**

```ts
new MissingHostTokenError()
```

**Returns** `MissingHostTokenError`

Source: [src/ipc/hosts/saved-hosts.ts:41](https://github.com/Tahul/zidane/blob/main/src/ipc/hosts/saved-hosts.ts#L41)

## Constants

### `HOST_PROBE_TIMEOUT_MS`

Constant.

Bound on one probe: the upgrade, the handshake and `daemon.info`.

```ts
const HOST_PROBE_TIMEOUT_MS = 10_000
```

Source: [src/ipc/hosts/probe.ts:13](https://github.com/Tahul/zidane/blob/main/src/ipc/hosts/probe.ts#L13)

## Interfaces

### `HostConnectionLoop`

Interface.

Handle returned by [`keepHostConnected`](https://zidane.si/docs/reference/ipc-remote.md#keepHostConnected) to stop the loop or retry at once.

```ts
interface HostConnectionLoop
```

**Properties**

- `retry` (`() => void`): Try now (a manual retry, or after an auth fix).
- `stop` (`() => void`): Stops the loop, aborts a pending connect and closes the live client.

Source: [src/ipc/hosts/connection-loop.ts:81](https://github.com/Tahul/zidane/blob/main/src/ipc/hosts/connection-loop.ts#L81)

### `HostConnectionLoopOptions`

Interface.

Options for [`keepHostConnected`](https://zidane.si/docs/reference/ipc-remote.md#keepHostConnected): how to connect, where status goes, and the backoff bounds.

```ts
interface HostConnectionLoopOptions
```

**Properties**

- `classify?` (`(err: unknown) => HostFailureKind`): `auth`: the token was refused; `identity`: another host answered. Both
  are for good (no retry until `retry()`). `protocol`: another protocol
  version, re-checked every `recheckMs`. Default: every failure retries.
- `connect` (`(options: { onClose: () => void; signal: AbortSignal }) => Promise<IpcClient>`): One connect attempt. `onClose` fires when that connection drops (not on `close()`).
- `maxDelayMs?` (`number`, default `30000`): Upper backoff bound in milliseconds.
- `minDelayMs?` (`number`, default `1000`): Lower backoff bound in milliseconds (tests shrink it).
- `onConnected?` (`(client: IpcClient) => void`): Connected (also after a reconnect).
- `onDisconnected?` (`() => void`): The live connection dropped (a reconnect is scheduled).
- `onSignal?` (`(signal: HostSignal) => void`): Every signal of the live connection.
- `recheckMs?` (`number`, default `PROTOCOL_RECHECK_MS`): Re-check interval for a `protocol` failure, in milliseconds (tests shrink it).
- `update` (`(patch: HostConnectionPatch) => void`): Receives each status change of the host.

Source: [src/ipc/hosts/connection-loop.ts:46](https://github.com/Tahul/zidane/blob/main/src/ipc/hosts/connection-loop.ts#L46)

### `HostConnectionPatch`

Interface.

What the loop says about its host, applied by the owner to its directory entry.

```ts
interface HostConnectionPatch
```

**Properties**

- `client?` (`IpcClient | null`): The live client, or `null` when there is none.
- `error?` (`string`): Why the last connect failed; `undefined` once connected.
- `serverName?` (`string`): The host's own name, from its `ipc.hello`.
- `status?` (`HostConnectionStatus`): Connection status to show.

Source: [src/ipc/hosts/connection-loop.ts:34](https://github.com/Tahul/zidane/blob/main/src/ipc/hosts/connection-loop.ts#L34)

### `SavedHostsController`

Interface.

Handle returned by [`startSavedHosts`](https://zidane.si/docs/reference/ipc-remote.md#startSavedHosts) to list, add, remove, rename, test and retry saved servers.

```ts
interface SavedHostsController
```

**Properties**

- `add` (`(input: { name?: string; token: string; url: string }) => Promise<HostEntry>`): Verify, save, connect (in place when already saved). Throws a `HostRegistryError`.
- `list` (`() => HostEntry[]`): The saved hosts, read fresh (other windows share the file).
- `remove` (`(id: string) => boolean`): Removes a server from the registry and its entry from the directory. Returns whether it existed.
- `rename` (`(id: string, name: string) => HostEntry`): Renames a saved server and returns the updated entry.
- `retry` (`(id: string) => void`): Reconnect now (after an outage or a token fix).
- `retryAll` (`() => void`): Reconnect every saved server that is not connected now, its backoff reset (the computer woke up).
- `setUrl` (`(id: string, url: string) => Promise<HostEntry>`): Move a saved server to a new URL (its saved token; the same server must answer), then reconnect it in place. Throws a `HostRegistryError`.
- `stop` (`() => void`): Disconnects every saved server and removes their directory entries. The registry is not changed.
- `test` (`(target: string | { id: string } | { token: string; url: string }) => Promise<HostProbeResult>`): A saved server (by id), or an unsaved URL + token (the add form's test).

Source: [src/ipc/hosts/saved-hosts.ts:81](https://github.com/Tahul/zidane/blob/main/src/ipc/hosts/saved-hosts.ts#L81)

### `SavedHostsDirectory`

Interface.

The client's host directory, as the saved servers see it. Keys are host ids.

```ts
interface SavedHostsDirectory
```

**Properties**

- `remove` (`(key: string) => void`): The server left the registry, or the saved servers stopped.
- `saved` (`() => { key: string; url: string }[]`): The saved servers it holds now, with their URL (a `--host` server excluded).
- `update` (`(key: string, patch: HostConnectionPatch & { name?: string; serverVersion?: string }) => void`): Applies a connection patch, a new name or a server version to the entry.
- `upsert` (`(entry: HostEntry, token: string | undefined) => void`): Add the entry, or reconfigure the one under its key in place (status `connecting`).

Source: [src/ipc/hosts/saved-hosts.ts:29](https://github.com/Tahul/zidane/blob/main/src/ipc/hosts/saved-hosts.ts#L29)

### `SavedHostsOptions`

Interface.

Options for [`startSavedHosts`](https://zidane.si/docs/reference/ipc-remote.md#startSavedHosts): the registry, the host directory, the connect function and callbacks.

```ts
interface SavedHostsOptions
```

**Properties**

- `classify?` (`(err: unknown) => HostFailureKind`): `auth`: refused for good. A missing token is always `auth`, another host answering always `identity`.
- `connect` (`(entry: HostEntry, token: string, options: { onClose: () => void; signal: AbortSignal }) => Promise<IpcClient>`): One connect attempt to a saved server, with its token read fresh.
- `directory` (`SavedHostsDirectory`): The client's host directory the entries are kept in.
- `maxDelayMs?` (`number`, default `30000`): Upper backoff bound in milliseconds.
- `minDelayMs?` (`number`, default `1000`): Lower backoff bound in milliseconds.
- `onConnected?` (`(key: string, client: IpcClient) => void`): Called when a saved server connects, also after a reconnect.
- `onDisconnected?` (`(key: string) => void`): Called when a saved server's connection drops.
- `onSignal?` (`(key: string, signal: HostSignal) => void`): Called with every signal of a connected saved server.
- `probeUnsaved?` (`(target: { token: string; url: string }) => Promise<HostProbeResult>`): The add form's test of an unsaved URL + token (`probeUnsavedHost`).
- `registry` (`HostRegistry`): The registry of saved servers.
- `skip?` (`(entry: HostEntry) => boolean`): Saved entries the directory already reaches another way (the TUI's `--host` server).

Source: [src/ipc/hosts/saved-hosts.ts:49](https://github.com/Tahul/zidane/blob/main/src/ipc/hosts/saved-hosts.ts#L49)

### `ServerSyncConfig`

Interface.

Saved sync settings for one server, kept in `hosts-sync.json`.

```ts
interface ServerSyncConfig
```

**Properties**

- `categories` (`SyncCategory[]`): Categories sent to the server.
- `keys` (`string[]`): Providers whose stored API key goes to this server.
- `lastError?` (`string`): Message of the last failed push.
- `lastSyncAt?` (`number`): Time of the last successful push in epoch ms.
- `mode` (`SyncMode`): Whether and how this computer syncs to the server.
- `pending` (`SyncCategory[]`): Categories changed here and not pushed yet (offline queue).
- `results` (`Partial<Record<SyncCategory, SyncPushResult>>`): What the last push of each category did there.
- `sent` (`Partial<Record<SyncCategory, string>>`): Per category, a hash of what was last pushed (a restart finds what changed meanwhile).

Source: [src/chat/sync/local.ts:26](https://github.com/Tahul/zidane/blob/main/src/chat/sync/local.ts#L26)

### `SyncClient`

Interface.

The part of a host connection sync uses (an `IpcClient` is one).

```ts
interface SyncClient
```

**Properties**

- `hello` (`{ sync?: boolean; syncCategories?: SyncCategory[] }`): What the server announced when it connected. `sync` is set when it supports settings sync.
- `request` (`((method: 'sync.status', params: Record<string, never>) => Promise<SyncStatus>) & ((method: 'sync.claim', params: { categories?: SyncCategory[]; deviceId: string; deviceName: string; keys?: string[]; takeover?: boolean }) => Promise<SyncClaimResult>) & ((method: 'sync.push', params: { category: SyncCategory; deviceId: string; payload: SyncPayload }) => Promise<SyncPushResult>) & ((method: 'sync.reset', params: { field: string }) => Promise<{ reset: boolean }>) & ((method: 'sync.release', params: { deviceId: string }) => Promise<{ released: boolean }>)`): Sends a sync RPC to the server and resolves with its reply.

Source: [src/chat/sync/engine.ts:29](https://github.com/Tahul/zidane/blob/main/src/chat/sync/engine.ts#L29)

### `SyncEngine`

Interface.

Pushes this computer's settings to saved servers and tracks the state each one reports. Servers are identified by key.

```ts
interface SyncEngine
```

**Properties**

- `configure` (`(key: string, patch: Partial<Pick<ServerSyncConfig, 'mode' | 'categories' | 'keys'>>) => Promise<void>`): Change the mode, categories or opted-in keys; pushes what that calls for.
- `connected` (`(key: string, client: SyncClient) => void`): Reports that a connection to the server opened. Reads its record and pushes what its mode calls for.
- `device` (`DeviceIdentity`): Identity of this computer.
- `disconnected` (`(key: string) => void`): Reports that the connection to the server closed.
- `localInfo` (`() => SyncLocalInfo`): What this computer has that the UIs mention: API keys to opt in, extensions that can't sync, stdio MCP servers.
- `notifyLocalChange` (`(category?: SyncCategory) => void`): This computer changed something (the app's settings stream): check, push if it differs.
- `pushAll` (`(key: string) => Promise<void>`): Push every selected category now (whatever the mode, but off).
- `refresh` (`(key: string) => Promise<void>`): Read the server's record again.
- `removed` (`(key: string) => void`): The server was removed here: forget its sync config (the server keeps what it has).
- `reset` (`(key: string, field: string) => Promise<void>`): Drop an override on the server (the next push writes the field again).
- `serverChanged` (`(key: string) => void`): A server's `sync:changed` signal.
- `stop` (`() => void`): Stops the file watchers and pending pushes.
- `subscribe` (`(listener: () => void) => () => void`): Calls `listener` when any view changes. Returns a function that removes it.
- `takeOver` (`(key: string) => Promise<void>`): Become the source of a server another device syncs to, then push.
- `view` (`(key: string) => SyncView`): Returns what a UI shows for the server.
- `watching` (`() => boolean`): File watchers are running (some server keeps in sync).

Source: [src/chat/sync/engine.ts:77](https://github.com/Tahul/zidane/blob/main/src/chat/sync/engine.ts#L77)

### `SyncEngineOptions`

Interface.

Options for [`createSyncEngine`](https://zidane.si/docs/reference/ipc-remote.md#createSyncEngine).

```ts
interface SyncEngineOptions
```

**Properties**

- `dataDir` (`string`): Directory holding the sync state files and the device identity.
- `debounceMs?` (`number`): Wait after a change before checking (a save is often several writes). Default 500 ms.
- `deviceName?` (`string`): Default: this computer's host name.
- `home` (`string`): User home directory, where user-scope files and skills are read from.
- `prefix` (`string`): Storage prefix, such as `.zidane`.
- `providers` (`() => Readonly<Record<string, ProviderDescriptor>>`): Returns the provider descriptors used to list API keys that can be opted in.
- `statePath` (`string`): Path of the file holding the app's saved settings.
- `watch?` (`boolean`): File watchers (default on); off, only `notifyLocalChange` finds changes.

Source: [src/chat/sync/engine.ts:41](https://github.com/Tahul/zidane/blob/main/src/chat/sync/engine.ts#L41)

### `SyncLocalInfo`

Interface.

What this computer has that sync UIs mention.

```ts
interface SyncLocalInfo
```

**Properties**

- `accounts` (`LocalProviderAccounts[]`): Every provider with an API key or a sign-in here (the GUI's accounts list).
- `keyProviders` (`{ key: string; label: string }[]`): Providers with an API key that can be opted in, with display labels.
- `localExtensions` (`string[]`): Names of extensions that cannot sync because they are not installed from npm or GitHub.
- `stdioMcps` (`string[]`): Names of stdio MCP servers, whose commands may be missing on the server.

Source: [src/chat/sync/engine.ts:113](https://github.com/Tahul/zidane/blob/main/src/chat/sync/engine.ts#L113)

### `SyncView`

Interface.

What a UI shows for one server.

```ts
interface SyncView
```

**Properties**

- `busy` (`boolean`): A push or refresh is running.
- `config` (`ServerSyncConfig`): Saved sync settings for the server.
- `conflict` (`string | null`): Another device syncs to this server: its name.
- `connected` (`boolean`): Whether a connection to the server is open.
- `status` (`SyncStatus | null`): The server's record, when read.
- `supported` (`boolean`): The server takes sync (`ipc.hello.sync`); false for an older server.

Source: [src/chat/sync/engine.ts:61](https://github.com/Tahul/zidane/blob/main/src/chat/sync/engine.ts#L61)

### `WsClientOptions`

Interface.

Options for [`connectWsClient`](https://zidane.si/docs/reference/ipc-remote.md#connectWsClient).

```ts
interface WsClientOptions
```

**Properties**

- `appVersion?` (`string`): Client zidane version, surfaced in the host's diagnostics.
- `ca?` (`readonly string[]`): Certificate authorities (PEM) a `wss://` server's certificate may chain
  to. Default: the runtime's roots and the OS store (`hostCaBundle`). Bun
  only: under Node the process default applies.
- `expectHostId?` (`string`): The host id a saved host answered with when it was added: a hello with
  any other id closes the connection and rejects with a
  [`HostIdentityError`](https://zidane.si/docs/reference/chat-pure.md#HostIdentityError) (nothing is read from that host).
- `heartbeatMs?` (`number`): `$/ping` interval (`./client-core`). Default `WS_HEARTBEAT_MS`; `0` disables.
- `onClose?` (`() => void`): The connection dropped (server exit, network error, a missed deadline or heartbeat). Not called for `close()`.
- `openTimeoutMs?` (`number`): Bound on the upgrade (not the handshake, which has its own). Default `WS_OPEN_TIMEOUT_MS`.
- `serve?` (`{ notification?: (method: string, params: unknown) => void; request: (method: string, params: unknown) => Promise<unknown> }`): Answer the host's requests and notifications on this connection: a
  machine serving its host (`docs/MACHINES.md`). A throw becomes a
  JSON-RPC error (its `code` when it carries one). Default: a client
  refuses requests and reads only `ipc.signal`.
- `signal?` (`AbortSignal`): Abandon the connect (upgrade and handshake): it rejects with the signal's reason.
- `token?` (`string`): Bearer token for the server, see `./ws-auth`.
- `tokenCarrier?` (`WsTokenCarrier`): How the token travels. Default: the `Authorization` header where the
  runtime's WebSocket can set one (Bun), else the subprotocol fallback.
- `url` (`string`): `ws://` or `wss://` URL of the server.

Source: [src/ipc/transports/ws-client.ts:39](https://github.com/Tahul/zidane/blob/main/src/ipc/transports/ws-client.ts#L39)

## Types

### `WsSavedHostsOptions`

Type.

Options for [`startWsSavedHosts`](https://zidane.si/docs/reference/ipc-remote.md#startWsSavedHosts): [`SavedHostsOptions`](https://zidane.si/docs/reference/ipc-remote.md#SavedHostsOptions) with the registry, dialer and classifier filled in.
`dataDir` holds the saved-hosts registry file.

```ts
type WsSavedHostsOptions = Omit<SavedHostsOptions, 'registry' | 'connect' | 'classify' | 'probeUnsaved'> & { appVersion?: string; connect?: SavedHostsOptions['connect']; dataDir: string; registry?: SavedHostsOptions['registry'] }
```

Source: [src/ipc/hosts/ws.ts:42](https://github.com/Tahul/zidane/blob/main/src/ipc/hosts/ws.ts#L42)
