WarpClient

Version Note

This documentation describes Swim JS packages v4.0.0 or later. Users of earlier package versions may experience differences in behavior.

WarpClient is the class which behaves as the primary mechanism for handling connection management and link routing. WARP clients transparently multiplex all links to Web Agents on a given host over a single WebSocket connection, and automatically manage the network connection to each host, including reconnection and resynchronization after a network failure. Key lifecycle events may also be observed through the registration of callbacks.

Besides managing connections and opening links (from here on called downlinks) to Web Agents, WARP clients do many other things. They can be used to send arbitrary WARP commands, provide authentication credentials for hosts, and create HostRef, NodeRef, and LaneRef scopes to facilitate downlink management. Additionally, when multiple downlinks are opened to the same lane of the same remote Web Agent, WARP clients seamlessly handle multicast event routing.

Instantiating a WarpClient

WarpClient’s constructor requires no arguments.

import { WarpClient } from "@swim/client";

const client = new WarpClient();

A singleton is also available via the .global() getter method.

import { WarpClient } from "@swim/client";

const globalClient = WarpClient.global();

A downlink provides a virtual bidirectional stream over which data can be synchronized between the client and a lane of a remote Web Agent. WARP clients transparently multiplex all links to Web Agents on a given host over a single WebSocket connection. A downlink represents one link in this scenario.

WarpClient includes three methods that open different kinds of downlinks. The downlink method creates an EventDownlink for streaming raw events from any Web Agent lane. The valueDownlink method creates a ValueDownlink for synchronizing state with a Web Agent value lane. A ValueDownlink views its state as a @swim/structure Value by default, which itself may represent any kind of JavaScript value, be it primitive or composite. Values may be coerced into a strongly-typed value by passing a Form to the valueForm option. The mapDownlink method creates a MapDownlink. This type of downlink is useful for synchronizing state with any Web Agent lane backed by a map. In addition to map lanes, this includes join value lanes and join map lanes, which are maps of other value lanes and maps lanes, respectively.

Here is an example of opening an EventDownlink. We will go into further detail on all of the downlink types in subsequent sections.

import { WarpClient } from "@swim/client";

const client = new WarpClient();
const downlink = client
  .downlink({
    hostUri: "warp://example.com",
    nodeUri: "/building/1",
    laneUri: "status"
  })

Observing Lifecycle Events

WarpClient instances can also be used to observe key lifecycle events. The didConnect method registers an observer callback that gets invoked whenever a connection to a WARP host is established. The didDisconnect method registers an observer callback that gets invoked whenever a WARP host disconnects. didAuthenticate registers an observer callback that gets invoked whenever the client successfully authenticates with a WARP host. The didDeauthenticate method gets invoked when a WARP host rejects the client’s authentication credentials. And didFail registers an observer callback that gets invoked when the client encounters an unexpected error.

import { WarpClient } from "@swim/client";

const client = new WarpClient();
client.hostDidConnect = (host) => {
  console.log("connected to", host);
}
client.hostDidDisconnect = (host) => {
  console.log("disconnected from", host);
}
client.hostDidAuthenticate = (session, host) => {
  console.log("authenticated to", host, "with session", session.toLike());
}
client.hostDidDeauthenticate = (reason, host) => {
  console.log("deauthenticated from", host, "because", reason.toLike());
}
client.hostDidFail = (error, host) => {
  console.log("host", host, "failed because", error);
}

Authentication

The authenticate method associates a credentials structure with a particular host URI. The credentials will be sent in a WARP @auth envelope whenever the client connects to the specified host.

import { WarpClient } from "@swim/client";

const client = new WarpClient();
client.authenticate("warps://example.com", {"@openId": jwt});

Distinct WarpClient instances can be used to create isolated connection pools for different security domains.

import { WarpClient } from "@swim/client";

const userClient = new WarpClient();
userClient.authenticate("warps://example.com", {"@openId": userJwt});

const toolClient = new WarpClient();
toolClient.authenticate("warps://example.com", {"@oauth": toolJwt});

Sending Commands

The command method sends a WARP command message to a lane of a remote node. command takes up to four arguments: a host URI, a node URI, a lane URI, and a command payload. The URIs may be ommitted if they are already set on the WarpClient, though a command payload is always required. A URI with more specificity may not be ommitted if a less specific one is included. For example, the first two commands below are valid while the third is not.

import { WarpClient } from "@swim/client";

const client = new WarpClient();
client.command("warp://example.com", "/house/kitchen", "light", "off"); // valid

client.hostUri.set("warp://example.com");
client.command("/house/kitchen", "light", "off"); // valid

client.laneUri.set("light");
client.command("/house/kitchen", "off"); // invalid

Refs

Refs are a useful tool for grouping and organizing downlinks. Still capable of sending commands, providing authentication credentials, and opening downlinks, Refs can be thought of as a particular scope of a WarpClient instance, and where it stores a subset of its links. This analogy of scope is accurate as the Refs are actually instances of a class called WarpScope. Refs must have a portion of their address pre-configured — at minimum the hostUri, and optionally the nodeUri and laneUri. When downlinks are opened from a Ref they are bound to the portion of the address provided.

HostRef

A HostRef only needs a hostUri to be initialized.

import { WarpClient } from "@swim/client";

const hostRef = client.hostRef("warp://example.com");
hostRef.downlink({
  nodeUri: "house/kitchen",
  laneUri: "light"
})
.open();

The HostRef.nodeRef and HostRef.laneRef instance methods can be used to create further resolved WARP scopes.

import { WarpClient } from "@swim/client";

const client = new WarpClient();
const hostRef = client.hostRef("warp://example.com");
const nodeRef = hostRef.nodeRef("/house/kitchen");
const laneRef = nodeRef.laneRef("/house/kitchen", "light");

NodeRef

A NodeRef needs a hostUri and a nodeUri to be initialized.

const nodeRef = client.nodeRef("warp://example.com", "/house/kitchen");
nodeRef.downlink({ laneUri: "light" }).open();

The NodeRef.laneRef instance method can be used to create further resolved WARP scopes.

const nodeRef = client.nodeRef("warp://example.com", "/house/kitchen");
const laneRef = nodeRef.laneRef("light");

LaneRef

A LaneRef needs all three of hostUri, nodeUri, and laneUri to be initialized.

const laneRef = client.laneRef("warp://example.com", "/house/kitchen", "light");
laneRef.downlink().open();

Utility Methods

isOnline

The isOnline method returns true when the the client has access to a network; it can also be used to force a client online or offline. The WarpClient.keepOnline method controls whether or not the client should automatically reopen connections after a network failure. Note that the keepOnline state of the client overrides the keepLinked state of individual downlinks. Setting keepOnline to false can be useful for ephemeral clients, but should typically be left true.

import { WarpClient } from "@swim/client";

const client = new WarpClient();
client.isOnline(); // true most of the time

client.isOnline(false); // force offline
client.isOnline(true); // force online

client.keepOnline(); // defaults to true

client.keepOnline(false); // disable network reconnection