Skip to main content

Session

QRSession owns the handshake state machine. One instance per node; it tracks every offer it made and every connection it accepted.

import { QRSession } from '@le-space/libp2p-webrtc-qr'

const session = new QRSession(node, { rtcConfiguration })

The two sides

// offering side
const offer = await session.createOffer()
const { peerId, connection, address, ageSeconds } = await session.acceptAnswer(reply)

// answering side
const answer = await session.acceptOffer(offer)
session.addEventListener('connect', e => e.detail.peerId)

acceptOffer returns as soon as the answer is signed, not when the connection is up — the offering peer cannot finish until it reads that answer. The connection completes afterwards and reports itself through connect, or error if it never does.

Options

optiondefaultmeaning
rtcConfigurationpassed to RTCPeerConnection
compactfalseproduce v3 short codes
iceGatheringTimeout5000stop waiting for candidates
connectionTimeout30000give up on connected
answerWaitTimeouthow long the answering side holds its side open
dialAttempts, dialRetryDelay, dialSettleDelayretry shape while the peer attaches its muxer

Per call: createOffer({ compact }), acceptAnswer(text, { dial }).

Pass dial: false when you open your own protocol stream — otherwise the connection is dialled twice.

Methods, state, events

createOffer, acceptOffer, acceptAnswerthe handshake
dial, dialProtocolafter it
session.offerspending offers, keyed by session id
session.inboundconnections built from an accepted offer
eventsconnect, error

session.offers and session.inbound together are every peer connection this session is responsible for — which is what a liveness readout has to iterate.

Diagnosing a failure

import { describeIce } from '@le-space/libp2p-webrtc-qr'

describeIce(peerConnection) // one line: both candidate sets and the ICE state

That string is what a failure message should carry. "Connection failed" without it cannot be acted on by anyone.