@swim/client
TypeScript icon, indicating that this package has built-in type declarations

4.0.0 • Public • Published

Swim Swim Client Library

The Swim Client library implements a streaming API client for linking to lanes of stateful Web Agents using the multiplxed WARP streaming protocol.

Command line tool for linking to Web Agent lanes over the WARP protocol.

Installation

npm install -g swim-client

Command Line

$ swim-client help
Usage: swim-client <command>

Commands:
  link                  stream changes to a lane of a remote node
  sync                  stream the current state and changes to a lane of a remote node
  get                   fetch the current state of a lane of a remote node
  reflect               stream introspection metadata
  help
$ swim-client sync help
Usage: swim-client sync [options] <command>

Options:
  -h, --host <hostUri>  remote host to link
  -n, --node <nodeUri>  remote node to link
  -l, --lane <laneUri>  lane to link
  -f, --format <json|recon> event output format

Commands:
  help
$ swim-client reflect help
Usage: swim-client reflect [options] <command>

Options:
  -e, --edge <edgeUri>  endpoint to introspect
  -m, --mesh <meshUri>? introspect default or specified mesh
  -p, --part <partKey>? introspect default or specified partition
  -h, --host <hostUri>? introspect default or specified host
  -n, --node <nodeUri>  introspect specified node
  -l, --lane <laneUri>  introspect specified lane
  -k, --link            introspect link behavior
  -r, --router          introspect router behavior
      --data            introspect data behavior
      --system          introspect system behavior
      --process         introspect process behavior
  -s, --stats           stream introspection statistics
  -f, --format <json|recon> event output format

Commands:
  log                   stream log events
  help

API

WarpRef

A WarpRef is a handle through which WARP downlinks can be opened. WarpClient implements the WarpRef interface, as does the exported Swim Client module object, and by extension, the global swim namespace object used web browsers and other non-module contexts.

WarpRef instances have four 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. The mapDownlink method creates a MapDownlink for synchronizing state with a Web Agent map lane. And the listDownlink method creates a ListDownlink for synchronizing state with a Web Agent list lane.

swim.downlink()
    .hostUri("warp://traffic.swim.services")
    .nodeUri("swim:meta:mesh")
    .laneUri("linkStats")
    .onEvent((value) => console.log(value.toLike()))
    .open();

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

swim.didConnect((host) => console.log("connected to", host));
swim.didDisconnect((host) => console.log("disconnected from", host));
swim.didAuthenticate((session, host) => console.log("authenticated to", host, "with session", session.toLike()));
swim.didDeauthenticate((reason, host) => console.log("deauthenticated from", host, "because", reason.toLike()));
swim.didFail((error, host) => console.log("host", host, "failed because", error));

WarpClient

The WarpClient class handles connection management and link routing, and implements the WarpRef interface. In addition to opening downlinks, WarpClient instances can be used to send arbitrary WARP commands, to provide authentication credentials for hosts, to control network reconnection behavior, and to create HostRef, NodeRef, and LaneRef scopes to facilitate downlink management.

The WarpClient.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.

swim.authenticate("warps://example.com", {"@openId": jwt});

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

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

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

The WarpClient.command method sends a WARP command message to a lane of a remote node. WarpClient.command takes either three our four arguments. The three argument command overload takes a node URI, a lane URI, and a command payload. The node URI must have an authority component that specifies the host to which the command should be sent. The four argument command overload takes a host URI, a node URI, a lane URI, and a command payload; the node URI is interpreted relative to the host URI.

swim.command("warp://example.com/house/kitchen", "light", "on");
swim.command("warp://example.com", "/house/kitchen", "light", "off");

The WarpClient.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.

swim.isOnline(); // true most of the time

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

swim.keepOnline(); // defaults to true

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

The WarpClient.hostRef method returns a new HostRef bound to the given host URI. The WarpClient.nodeRef method returns a new NodeRef bound to the given host and node URIs. The WarpClient.laneRef method returns a new LaneRef bound to the given host, node, and lane URIs.

HostRef

A HostRef is a WarpRef that automatically provides its bound host URI when opening downlinks, sending commands, and providing authentication credentials. HostRef instances keep track of all the downlinks they directly open. When a HostRef is closed, it automatically closes all of its open downlink views.

const hostRef = swim.hostRef("warp://traffic.swim.services");
hostRef.downlink()
       .nodeUri("swim:meta:mesh")
       .laneUri("linkStats")
       .onEvent((value) => console.log(value.toLike())})
       .open();
// ...
hostRef.close();

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

const hostRef = swim.hostRef("warp://traffic.swim.services");
const nodeRef = hostRef.nodeRef("swim:meta:mesh");
const laneRef = hostRef.laneRef("swim:meta:mesh", "linkStats");

NodeRef

A NodeRef is a WarpRef that automatically provides its bound host and node URIs when opening downlinks and sending commands. NodeRef instances keep track of all the downlinks they directly open. When a NodeRef is closed, it automatically closes all of its open downlink views.

const nodeRef = swim.nodeRef("warp://traffic.swim.services", "swim:meta:mesh");
nodeRef.downlink()
       .laneUri("linkStats")
       .onEvent((value) => console.log(value.toLike())})
       .open();
// ...
nodeRef.close();

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

const nodeRef = swim.nodeRef("warp://traffic.swim.services", "swim:meta:mesh");
const laneRef = nodeRef.laneRef("linkStats");

LaneRef

A LaneRef is a WarpRef that automatically provides its bound host, node, and lane URIs when opening downlinks and sending commands. LaneRef instances keep track of all the downlinks they directly open. When a LaneRef is closed, it automatically closes all of its open downlink views.

const laneRef = swim.laneRef("warp://traffic.swim.services", "swim:meta:mesh", "linkStats");
laneRef.downlink()
       .onEvent((value) => console.log(value.toLike())})
       .open();
// ...
laneRef.close();

Downlink

A Downlink provides a virtual bidirectional stream 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, and automatically manage the network connection to each host, including reconnection and resynchronization after a network failure. WARP clients also seamlessly handle multicast event routing when multiple downlinks are opened to the same lane of the same remote Web Agent.

Downlinks come in several flavors, depending on the WARP subprotocol to which they conform. An EventDownlink observes raw WARP events, and can be used to observe lanes of any kind. A ValueDownlink synchronizes a structured value with a remote value lane. A MapDownlink implements the WARP map subprotocol to synchronize key-value state with a remote map lane. A ListDownlink implements the WARP list subprotocol to to synchronize sequential list state with a remote list lane.

Before opening, a downlink must be addressed with the hostUri, nodeUri, and laneUri to which the link should connect. A downlink may also be configured with a relative priority, a max rate, and an optional body structure that can contain query or other link parameters to be passed to the remote lane.

The keepLinked parameter determines whether or not a downlink should be automatically reopened after a network failure; it defaults to true. The keepSynced parameter determines whether or not a downlink should synchronize with the remote lane when opened; it defaults to true for stateful lanes.

The open method is used to open a downlink after it has been configured. The close method closes a downlink. Closing a downlink does not necessarily close the underlying WARP link. The WARP client will keep a link open so long as at least one downlink to a given node and lane URI remains open. This prevents application components from stepping on each other's toes when they link to the same lanes of the same Web Agents. This can happen, for example, when a UI has a summary view and a detail view both display information derived from the same remote lane. The WARP link should not be closed when a detail view is hidden, if state updates are still required by the summary view. Events should also not be sent twice: once for the summary view, and once for the detail view. Neither the summary view nor the detail view should have to know about each other. And no global event dispatcher should be required, which could introduce consistency problems. WARP clients efficiently, and transparently handle all of these cases on behalf of all downlinks.

The isConnected method returns true if the underlying connection to the remote host is currently open. The isAuthenticated method returns true if the underlying connection to the remote host is currently authenticated. The isLinked method returns true if the logical WARP link is currently open. And the isSynced method returns true if the WARP link is currently synchronized.

All downlinks support registering onEvent, onCommand, willLink, didLink, willSync, didSync, willUnlink, didUnlink, willConnect, didConnect, didDisconnect, didClose, and didFail callbacks.

EventDownlink

An EventDownlink provides a raw view of a WARP link.

swim.downlink()
    .hostUri("warp://example.com")
    .nodeUri("/house")
    .laneUri("power/meter")
    .onEvent((body) => /* ... */)
    .open();

ValueDownlink

A ValueDownlink synchronizes a shared real-time value with a remote value lane. In addition to the standard Downlink callbacks, ValueDownlink supports registering willSet and didSet callbacks to observe all changes to downlinked state—whether remote or local.

A ValueDownlink views its state as an Swim Structure Value by default. Use the valueForm method to create a typed projection of a ValueDownlink that automatically transforms its state using an Swim Structure Form. For example, you can use Form.foString() to create a ValueDownlink that coerces its state to a string; and you can also use Form.forAny() to create a ValueDownlink that coerces its state to a plain old JavaScript value.

const value = swim.downlinkValue()
    .hostUri("warp://example.com")
    .nodeUri("/house/kitchen")
    .laneUri("light")
    .valueForm(swim.Form.forAny())
    .didSet((value) => /* ... */)
    .open();

Use the ValueDownlink.get method to get the current state value. Use the ValueDownlink.set method to set the current state value.

value.get(); // get the current local state of the downlink
value.set(newValue); // update the local and remote state of the downlink

For the most part, client code can treat a ValueDownlink like an ordinary mutable variable; the WARP client will ensure that the downlink is continuously made consistent with the remote lane. Using didSet callbacks, applications can update UI views, and other dependent components, to keep them consistent with the shared state of the remote value lane in network real-time.

swim.downlinkValue()
    .didSet((value) => {
      // update UI view with latest value
      document.getElementById("value").innerText = value;
    })

MapDownlink

A MapDownlink synchronizes a shared real-time key-value map with a remote map lane. In addition to the standard Downlink callbacks, MapDownlink supports registering willUpdate, didUpdate, willRemove, and didRemove callbacks to observe all changes to downlinked map state—whether remote or local.

A MapDownlink views its keys and values as Swim Structure Values by default. Use the keyForm and valueForm methods to create a typed projection of a MapDownlink that automatically transforms its keys and values using Swim Structure Forms.

const map = swim.downlinkMap()
    .hostUri("warp://example.com")
    .nodeUri("/house")
    .laneUri("rooms")
    .keyForm(swim.Form.forString())
    .valueForm(swim.Form.forAny())
    .didUpdate((key, value) => /* ... */)
    .didRemove((key) => /* ... */)
    .open();

MapDownlink implements the standard JavaScript Map interface. Use the MapDownlink.get method to get the value associated with a given key. Use the MapDownlink.set method to update the value associated with a key. And use the MapDownlink.delete method to remove a key and its associated value.

map.get("kitchen"); // get the locally cached value associated with the key
map.set("garage", newRoom); // locally and remotely insert a new entry

For the most part, client code can treat a MapDownlink like an ordinary JavaScript Map; the WARP client will ensure that the downlink is continuously made consistent with the remote lane. Using didUpdate and didRemove callbacks, applications can update UI collection views, and other dependent components, to keep them consistent with the shared state of the remote map lane in network real-time.

swim.downlinkMap()
    .didUpdate((key, value) => {
      if (hasChildElement(key)) {
        // update existing UI view for key
      } else {
        // insert new UI view for key
      }
    })
    .didRemove((key) => {
      // remove UI view for key
    })

ListDownlink

A ListDownlink synchronizes a shared real-time list with a remote list lane. In addition to the standard Downlink callbacks, ListDownlink supports registering willUpdate, didUpdate, willMove, didMove, willRemove, and didRemove callbacks to observe all changes to downlinked list state—whether remote or local.

A ListDownlink views its items as Swim Structure Values by default. Use the valueForm method to create a typed projection of a ListDownlink that automatically transforms its items using an Swim Structure Form.

const list = swim.downlinkList()
    .hostUri("warp://example.com")
    .nodeUri("/house")
    .laneUri("todo")
    .valueForm(swim.Form.forAny())
    .didUpdate((index, value) => /* ... */)
    .didMove((fromIndex, toIndex, value) => /* ... */)
    .didRemove((index) => /* ... */)
    .open();

ListDownlink behaves similarly to a JavaScript array. Use the ListDownlink.get method to get the item at a given index. Use the ListDownlink.set method to update the item at some index. And use the ListDownlink.splice method to insert and remove items from the list. You can also push, pop, shift, and unshift items, and move an item from one index to another.

list.get(0); // get the first item in the list
list.set(0, "build"); // locally and remotely update an item
list.push("paint"); // locally and remotely append an item

For the most part, client code can treat a ListDownlink like an ordinary JavaScript list; the WARP client will ensure that the downlink is continuously made consistent with the remote lane. Using didUpdate, didMove, and didRemove callbacks, applications can update UI list views, and other dependent components, to keep them consistent with the shared state of the remote list lane in network real-time.

swim.downlinkList()
    .didUpdate((index, value) => {
      if (hasChildElement(index)) {
        // update existing UI view at index
      } else {
        // insert new UI view at index
      }
    })
    .didMove((fromIndex, toIndex, value)) {
      // move existing UI view from old index to new index
    }
    .didRemove((index) => {
      // remove UI view at index
    })

Package Sidebar

Install

npm i @swim/client

Weekly Downloads

76

Version

4.0.0

License

Apache-2.0

Unpacked Size

3.44 MB

Total Files

21

Last publish

Collaborators

  • ajay-gov
  • c9r