@swim/warp implements the WARP WebSocket protocol for dynamically multiplexing large numbers of bidirectional links to streaming API endpoints, called lanes, of URI-addressed distributed objects, called nodes, that run stateful distributed processes, called Web Agents. @swim/warp is part of the @swim/mesh framework.
The name WARP stands for Web Agent Remote Protocol. The purpose of the WARP protocol is to enable bidirectional, continuously consistent, network real-time communication between stateful distributed processes, called Web Agents.
The first and most important design goal for WARP is to be extensible, forward compatible, and easy to implement in any networked environment. In particular, WARP has to work in all major web browsers, using existing networking technologies. To facilitate human understanding of the protocol and its operation, the first version of WARP is text-based. To avoid the explosion of grammars found in other human-readable protocols, like HTTP, and to aid extensibility, WARP protocol envelopes are defined as a set of structurally typed Recon records.
The second most important design goal for WARP is to support efficient multiplexing of extremely large numbers of links. WARP scales to many millions of high rate links per WebSocket connection. Imagine if every hyperlink on the Web was a real-time stream between web pages—that's the level of concurrency WARP aims to support.
The third most important design goal for WARP is minimalism. WARP supports forward-compatible, per-link subprotocols, enabling protocol stability without stagnation. The core WARP protocol remains unchanged since its original implementation in 2015, despite significant evolution of SwimOS, and its extensive use of WARP subprotocols.
Future evolution of the WARP protocol must maintain the delicate balance between extreme multiplexability, broad implementability, extensibility, forward compatibility, and minimalism.
The data structures exchanged over WARP connections are called envelopes. WARP defines 12 envelope types: event messages, command messages, link requests and responses, sync requests and responses, unlink requests and responses, auth requests and responses, and deauth requests and responses.
Envelopes can be addressed in one of three ways: host addressed, lane addressed, or link addressed. Host addressed envelopes simply get delivered to the other end of the network connection.
Lane addressed envelopes route to a particular lane, of a particular node. Nodes and lanes are each addressed by URI. Node URIs are scoped to a network host, like HTTP request URIs. Lane URIs are scoped to an encapsulating node, like a member of an object.
Link addressed envelopes route along the path of a currently open link. Links are currently addressed by the complete node and lane URIs of the remote endpoint. Explicit link addressing greatly aids human readability of the wire protocol, and compression effectively mitigates the transport overhead. Link addresses are intended to be coupled to stream identifiers in an underlying multiplexed transport protocol, such as QUIC, in a future evolution of the WARP protocol.
WARP is a symmetric protocol: any envelope type can be sent in any direction. It's perfectly valid for a server to send a link request to a client; this capability is important for reverse tunneling of links to endpoints that can only open outbound connections.
Request and response envelopes trigger link state transitions—request envelopes do not always or immediately pair with corresponding response envelopes. For example, a link request may be replied to with an unlinked response, if the link request is rejected. And a sync request only receives a matching synced response once the state of the link quiesces.
An event message is a link addressed envelope that transmits a structured data payload to the receiving end of a link.
An event message is distinguished by an
@event(node: "/house/kitchen", lane: "light") "off"
A command message is a lane addressed envelope that transmit a structured data payload to a particular lane of a particular node. Command messages may be fast-path routed via an open link to the recipient lane.
A command message is distinguished by a
@command(node: "/house/kitchen", lane: "light") "on"
Link requests and and responses
A link request is a lane addressed envelope that initiates the opening of a new link to the recipient lane. A linked response is a link addressed envelope that finalizes the opening of a new link.
A link request is distinguished by a
@link(node: "/house/kitchen", lane: "light")
A linked response is distinguished by a
@linked(node: "/house/kitchen", lane: "light")
Sync requests and responses
A sync request is a lane addressed envelope that both initiates the opening of a new link to the recipient lane, and requests synchronization with the current state of the remote lane. A synced response is a link addressed envelope that indicates completion of initial link synchronization.
A sync request is distinguished by a
@sync(node: "/house", lane: "rooms")
A synced response is distinguished by a
@synced(node: "/house lane: "rooms")
Unlink requests and responses
An unlink request is a link addressed envelope that initiates the closure of a link. An unlinked response is a link addressed envelope that finalizes the closure of a link.
An unlink request is distinguished by an
@unlink(node: "/house", lane: "power/meter")
An unlinked response is distinguished by an
@unlinked(node: "/house", lane: "power/meter")
Auth requests and responses
An auth request is a host addressed envelope that authenticates the sender. An authed response is a host addressed envelope that acknowledges the credentials of the receipient.
An auth request is distinguished by an
An authed response is distinguished by an
Deauth requests and responses
A deauth request is a host addressed envelope that deauthenticates the sender. A deauthed response is a host addressed envelope that revokes the credentials of the recipient.
A deauth request is distinguished by a
A deauthed response is distinguished by a
For an npm-managed project,
npm install @swim/warp to make it a dependency.
TypeScript sources will be installed into
node_modules/@swim/warp/lib/main. And a pre-built UMD script can
be found in
Browser applications can load
swim-mesh.js—which bundles the @swim/warp
library—along with its
swim-core.js dependency, directly from the SwimOS CDN.
<!-- Development --> <script src="https://cdn.swimos.org/js/latest/swim-core.js"></script> <script src="https://cdn.swimos.org/js/latest/swim-mesh.js"></script> <!-- Production --> <script src="https://cdn.swimos.org/js/latest/swim-core.min.js"></script> <script src="https://cdn.swimos.org/js/latest/swim-mesh.min.js"></script>
Alternatively, the standalone
swim-system.js script may be loaded
from the SwimOS CDN, which bundles @swim/warp together with all other
<!-- Development --> <script src="https://cdn.swimos.org/js/latest/swim-system.js"></script> <!-- Production --> <script src="https://cdn.swimos.org/js/latest/swim-system.min.js"></script>
@swim/warp can be imported as an ES6 module from TypeScript and other ES6-compatible environments.
import * as warp from "@swim/warp";
@swim/warp can also be used as a CommonJS module in Node.js applications.
var warp = require("@swim/warp");
When loaded by a web browser, the
swim-mesh.js script adds all
@swim/warp library exports to the global
swim namespace. The
swim-mesh.js script requires that
swim-core.js has already been loaded.
swim-system.js script also adds all @swim/warp library exports
to the global
swim namespace, making it a drop-in replacement for
swim-mesh.js when additional @swim/system
libraries are needed.