npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@coclaw/pion-node

v0.4.0

Published

Node.js SDK for pion-ipc — W3C-style PeerConnection/DataChannel API over a Go WebRTC sidecar

Readme

pion-node

Node.js SDK for pion-ipc — spawn and manage a Go-based WebRTC process via stdin/stdout binary IPC, exposing a W3C-style PeerConnection/DataChannel API.

Install

npm install @coclaw/pion-node

The pion-ipc Go binary is resolved in this order:

  1. PION_IPC_BIN env var — explicit path to the binary
  2. npm platform package@coclaw/pion-ipc-{platform}-{arch} installed via optionalDependencies (automatic on npm install)
  3. System PATHpion-ipc found on $PATH

On supported platforms (linux-x64, linux-arm64, linux-arm, darwin-x64, darwin-arm64, win32-x64), the binary is automatically installed via npm. No manual setup needed.

Usage

import { PionIpc, RTCPeerConnection } from 'pion-node';

const ipc = new PionIpc();
await ipc.start();

const pc = new RTCPeerConnection({
  _ipc: ipc,
  iceServers: [{ urls: ['stun:stun.l.google.com:19302'] }],
});

const dc = pc.createDataChannel('chat');
dc.onopen = () => {
  dc.send('hello!');
};
dc.onmessage = (evt) => {
  console.log('received:', evt.data);
};

pc.onicecandidate = (evt) => {
  // send evt.candidate to remote peer via signaling
};

// Diagnostic: log selected candidate pair (host/srflx/relay)
pc.onselectedcandidatepairchange = () => {
  const pair = pc.selectedCandidatePair;
  console.log(`${pair.local.type} ↔ ${pair.remote.type}`);
};

const offer = await pc.createOffer();
// ... exchange SDP with remote peer ...

// Clean up
await pc.close();
await ipc.stop();

IPC Protocol

Binary framing over stdin/stdout:

[4B total_length LE] [2B header_length LE] [msgpack header] [raw payload]

Message types:

  • req (request): { type, id, method, pcId?, dcLabel?, isBinary? } + payload
  • res (response): { type, id, ok, error? } + payload
  • evt (event): { type, event, pcId?, dcLabel?, isBinary? } + payload

Max frame size: 16 MiB.

API

PionIpc

  • new PionIpc({ binPath?, logger?, timeout? }) -- create instance
  • start() -- spawn process, verify with ping
  • stop(timeout?) -- graceful shutdown
  • request(method, opts?, payload?) -- send RPC request, returns { header, payload }
  • Events: 'error', 'exit', and all Go-side events

RTCPeerConnection

  • new RTCPeerConnection({ _ipc, iceServers?, settings?, _pcId? }) -- create (pcId defaults to UUID)
  • createOffer() / createAnswer() -- SDP negotiation
  • setRemoteDescription(desc) / setLocalDescription(desc)
  • addIceCandidate(candidate)
  • restartIce() -- ICE restart, returns new offer
  • createDataChannel(label, opts?) -- create DataChannel (synchronous, W3C-compatible)
  • getSctpStats() -- snapshot of the underlying SCTP association (see below)
  • close()
  • Getters: connectionState, iceConnectionState, iceGatheringState, signalingState, selectedCandidatePair
  • Events: 'icecandidate', 'connectionstatechange', 'iceconnectionstatechange', 'selectedcandidatepairchange', 'icegatheringstatechange', 'signalingstatechange', 'datachannel'
  • on* property handlers for all events

RTCDataChannel

  • send(data) -- send string or Buffer (synchronous, W3C-compatible)
  • close()
  • Getters: label, ordered, readyState, bufferedAmount
  • bufferedAmountLowThreshold getter/setter
  • Events: 'open', 'close', 'message', 'error', 'bufferedamountlow'
  • on* property handlers for all events

Note on bufferedAmount: Returns the sum of JS-side send queue size and Go-side SCTP buffer (dual-source tracking). The Go-side value is updated from each dc.send ack and refreshed on bufferedamountlow events, providing accurate flow control without manual queries.

settings — pion SettingEngine knobs

Optional per-PeerConnection configuration, forwarded to the Go side at pc.create time. Every field is independently optional; omitted fields use pion defaults. Duration fields are in milliseconds (numbers). Values above 300000 ms (5 minutes) are rejected with an error — no PeerConnection is created.

| Field | Type | Pion method | Pion default | |---|---|---|---| | sctpRtoMax | number (ms) | SetSCTPRTOMax | 60000 | | sctpMaxReceiveBufferSize | number (bytes) | SetSCTPMaxReceiveBufferSize | (pion sctp package default) | | iceDisconnectedTimeout | number (ms) | SetICETimeouts (arg 1) | 5000 | | iceFailedTimeout | number (ms) | SetICETimeouts (arg 2) | 25000 | | iceKeepAliveInterval | number (ms) | SetICETimeouts (arg 3) | 2000 | | stunGatherTimeout | number (ms) | SetSTUNGatherTimeout | 5000 | | interfaceFilter | object | SetInterfaceFilter | no filter | | ipFilter | object | SetIPFilter | no filter |

The three ICE timeout fields share a single pion setter. If the caller specifies any of them, the unspecified fields fall back to the pion defaults listed above.

interfaceFilter shape: { denyPrefixes?: string[], allowPrefixes?: string[] }. Case-sensitive HasPrefix matching on the interface name. Empty lists (or empty object) install no filter. Allow narrows the candidate set; deny wins on overlap. An empty-string entry is rejected up front (would match every interface).

ipFilter shape: { denyCIDRs?: string[], allowCIDRs?: string[] }. CIDRs accept IPv4 and IPv6 (net.ParseCIDR semantics); invalid strings fail pc.create. Same allow / deny semantics as interfaceFilter.

const pc = new RTCPeerConnection({
  _ipc: ipc,
  iceServers: [{ urls: ['stun:stun.l.google.com:19302'] }],
  settings: {
    sctpRtoMax: 10000,   // shorten worst-case SCTP backoff after long idle
    iceFailedTimeout: 15000,
    interfaceFilter: { denyPrefixes: ['docker', 'br-', 'veth'] },
    ipFilter: { denyCIDRs: ['172.16.0.0/12'] },
  },
});

getSctpStats() — SCTP association snapshot

Returns a snapshot of the underlying SCTP association. Useful for diagnosing stalls after long idle periods — correlating congestionWindow and bytesSent deltas over time reveals whether the sender is stuck in loss recovery (cwnd collapsed back to ~1 MTU with bytesSent flat across samples).

Return values:

  • An object with the fields below, once the SCTP association is up.
  • null when the association has not yet been established (before DTLS handshake completes).
  • After close() the call rejects with the underlying IPC error — the PeerConnection no longer exists on the Go side.

| Field | Type | Unit | Description | |---|---|---|---| | bytesSent | number | bytes | Cumulative bytes sent on the SCTP association | | bytesReceived | number | bytes | Cumulative bytes received on the SCTP association | | srttMs | number | ms | Smoothed round-trip time; 0 before first RTT measurement | | congestionWindow | number | bytes | Current congestion window (cwnd) | | receiverWindow | number | bytes | Peer's receiver window (rwnd) | | mtu | number | bytes | Current MTU |

const stats = await pc.getSctpStats();
if (stats === null) {
  console.log('SCTP association not yet established');
} else {
  console.log(`cwnd=${stats.congestionWindow} srtt=${stats.srttMs}ms sent=${stats.bytesSent}`);
}

Not exposed (no public pion API in v1.8.36): current RTO value, t3RTX backoff level (nRtos), inflight chunk count. These would require upstream pion changes.

Do not call at high frequency. The call internally walks the PeerConnection's transceivers, candidates, and data channels. A 5-10 s sampling cadence is fine; tighter than 1 s across many PeerConnections is wasteful.

License

Apache-2.0