Skip to content
Robotadocs

@robota-sdk/agent-transport/webrtc

WebRTC peer-to-peer transport for the Robota SDK (Node.js). WebRtcTransport carries an agent runtime session over an RTCDataChannel, so a remote client can drive a live session directly, peer to peer, without session content passing through a server. It reuses the transport-neutral session bridge and wire protocol from @robota-sdk/agent-transport, the same ones the WebSocket transport uses. The package also contains the building blocks for connecting one user's devices to each other (the device mesh): peer discovery and signaling, device enrollment and a TURN relay.

Installation

npm install @robota-sdk/agent-transport @robota-sdk/agent-remote-pairing ws bittorrent-dht multicast-dns nostr-tools node-datachannel

Requires Node.js 22.12 or later. The WebRTC implementation, node-datachannel (libdatachannel, a native module), is an optional peer dependency loaded lazily. If it is not installed or has no prebuilt binary for the platform, start() fails with an explicit WebRTC transport unavailable error; there is no fallback implementation. The other libraries, ws, bittorrent-dht, multicast-dns and nostr-tools, and @robota-sdk/agent-remote-pairing are optional peer dependencies of the package, installed for this subpath only. @robota-sdk/agent-transport provides the IProtocolSession type used below.

Usage

import { WebRtcTransport, WsSignalingClient } from '@robota-sdk/agent-transport/webrtc';
import type { IProtocolSession } from '@robota-sdk/agent-transport';
 
declare const session: IProtocolSession; // e.g. a live interactive session
declare const pairingSecret: string; // shared with the remote client out of band
 
const signaling = new WsSignalingClient({
  url: 'wss://signaling.example.com',
  rendezvous: 'my-rendezvous-id',
  onError: (error) => console.error(error),
});
 
const transport = new WebRtcTransport({
  signaling,
  secret: pairingSecret,
  onPaired: () => console.log('remote client paired'),
  onPairingFailed: () => console.log('pairing failed; channel closed'),
});
 
transport.attach(session);
await transport.start(); // the host is the offerer: creates the peer and data channel, sends the offer
// ...
await transport.stop();

Admission is decided at construction. With secret, the data channel carries only pairing frames until the pairing handshake from @robota-sdk/agent-remote-pairing accepts, bound to the DTLS fingerprints of the connection; only then is the session exposed, and a mismatch or timeout closes the channel. To run without pairing (for example over loopback in tests), pass { open: true, openReason: '<why this is safe>' } instead. The constructor throws when neither is given, or when both are.

Signaling is an injected port (ISignalingClient) that only carries SDP offers/answers and ICE candidates, never session content. createInMemorySignalingPair() wires two in-process clients together for tests; WsSignalingClient joins a rendezvous on a WebSocket signaling relay.

WebRtcTransport options

OptionTypeDescription
signalingISignalingClientRequired. Exchanges SDP/ICE with the remote peer.
secretstringPairing secret; gates the data channel until the pairing handshake accepts.
open / openReasonboolean / stringRuns without a pairing gate; openReason must say why.
iceServersreadonly IIceServer[]STUN/TURN servers. Omitted: host candidates only.
forceTurnbooleanRestricts ICE to relay (TURN) candidates; needs a TURN server in iceServers.
onPaired / onPairingFailedcallbacksCalled when pairing accepts (session exposed) or rejects/times out (channel closed).
reconnectIHostReconnectConfigWith secret: admits either a first pairing (with device enrollment) or a pinned-device reconnect.
connectionApprovalIConnectionApprovalWith secret: asks an operator to approve each connection before it reaches the session.
localPeerILocalPeerProofWith secret: also requires a nonce issued at a guarded local rendezvous.
resumeBridge / onDroppedSessionResumeBridge / callbackWith secret: resumeBridge carries the paired session across channel drops; onDropped is called when a paired channel drops.
onDeliveryErrorcallbackObserves an outbound delivery failure before the channel is dropped.
personalUsageReporter / usageReporter / storedSessionUsageReporterreportersHost-owned usage read models, available to the peer only after admission.

start() before attach() throws; stop() is safe to call more than once, and starting again requires attaching again.

Other exports

  • Peers: RtcPeer, RtcChannel and loadDataChannel, one peer connection over node-datachannel.
  • Device mesh: DeviceMeshNode connects one user's devices, admitted by the device handshake. Discovery and signaling for it: DiscoveringMeshRelay, MeshMdns, MeshDht, NostrMeshRelay, WsMeshRelayClient, startLanMeshRelay.
  • Relay: TurnServer and MeshTurnRelay, a TURN relay one of the user's devices can run for its paired devices.
  • Enrollment: dialEnrollment and listenForEnrollment open the channel used to enroll a new device; they fail with EnrollmentLinkError.
  • Admission frames: localProofFrame (the local-peer nonce) and handoffGrantFrame / judgeHandoffGrant (a signed cross-device hand-off grant, verified by a host-supplied verifier).

For how the agent runtime CLI uses this for remote control and connecting your own devices, see the devices and remote access guide. See SPEC.md for the subpath contract.

License

This package is dual-licensed under the GNU AGPL-3.0 or a commercial license. See LICENSING.md.