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

like-webrtc

v1.1.2

Published

Peer-to-peer WebRTC connections with built-in signaling.

Readme

like-webrtc

Peer-to-peer WebRTC connections with built-in signaling.

Works across browsers, Node.js, and React Native.

npm i like-webrtc

Warning: this is experimental.

Live demo: https://web.leet.ar (P2P Discord clone built in 48 hours)

Need support with WebRTC? Open a GitHub issue :)

Usage

Direct peer-to-peer connections

A peer can create a server listening on a public key as address.

Another peer can use that address to connect to the server.

import RTC from 'like-webrtc'

const rtc = new RTC()

const server = rtc.createServer(peer => {
  const channel = peer.createDataChannel('wire', { negotiated: true, id: 0 })

  channel.addEventListener('open', () => channel.send('Hello from the server'))
  channel.addEventListener('message', e => console.log('Server received:', e.data))
})

const keyPair = RTC.keyPair()

await server.listen(keyPair)
const rtc2 = new RTC()

const peer = rtc2.connect(server.publicKey)

const channel = peer.createDataChannel('wire', { negotiated: true, id: 0 })

channel.addEventListener('open', () => channel.send('Hello from the client'))
channel.addEventListener('message', e => console.log('Client received:', e.data))

A familiar API like Node.js http, but peer-to-peer and running directly in your browser.

Group peers

Peers can create servers with random key pairs.

You can announce or lookup any server under the same shared topic.

import RTC from 'like-webrtc'

const rtc = new RTC()

const server = rtc.createServer(peer => {
  console.log('New peer connection')
  // ...
})

await server.listen()
await server.announce('random-group')
const rtc2 = new RTC()

const results = await rtc2.lookup('random-group')

const peer = rtc2.connect(results[0].publicKey)
// ...

Swarm peers

Each peer runs the same code to join the swarm.

Other peers will find you.

import RTC from 'like-webrtc'

const rtc = new RTC()

const server = rtc.createServer(peer => {
  console.log('New swarm connection')
  // ...
})

await server.listen()
await server.join('random-swarm')

SIGNALING

Single signaling server:

  • wss://party.leet.ar:41337

It's a WebSocket server with a RPC protocol.

  • E2E noise encryption: meaning HTTPS/WSS is redundant.
  • Announce / Unannounce: act as a server e.g. listen/close.
  • Lookup: act as a client by finding peers.
  • Relay: bidirectional data for WebRTC SDP/ICE/ACK.

ICE

3 STUN servers:

  • stun:turn.leet.ar:3478
  • stun:stun.l.google.com:19302
  • stun:stun.cloudflare.com:3478

1 TURN server with multiple transports:

  • turn:turn.leet.ar:3478?transport=udp
  • turn:turn.leet.ar:3478?transport=tcp

API

rtc = new RTC([options])

Creates a WebRTC instance.

Options:

{
  signaling, // Defaults to 'wss://party.leet.ar:41337'.
  keyPair, // Defaults to a key pair generated from seed or random bytes.
  seed, // Seed used to generate the key pair.
  iceServers, // Defaults to the package's STUN and TURN servers.
  iceTransportPolicy, // Defaults to 'all'.
  trickle, // Defaults to true.
  RTCPeerConnection, // Optional WebRTC implementation override.
  RTCIceCandidate // Optional ICE candidate implementation override.
}

peer = rtc.connect(publicKey[, options])

Creates a P2P connection and returns a RTCPeerConnection.

Add a data channel, track, or transceiver to begin WebRTC negotiation.

Options:

{
  keyPair // Defaults to rtc.keyPair.
}

peer.isInitiator

Identifies the client (true) or server (false) side.

peer.publicKey

The local public key used for this connection as a buffer.

peer.address

The local public key used for this connection as a Base58 string.

peer.remotePublicKey

The remote peer's public key as a buffer.

server = rtc.createServer([options][, handler])

Creates a P2P server that accepts WebRTC connections.

The handler receives each incoming peer connection.

Options:

{
  keyPair, // Defaults to rtc.keyPair.
  firewall // Function or array of allowed public keys. Allows all peers by default.
}

server.on('connection', peer)

Emitted on each incoming RTCPeerConnection, same as the handler.

server.publicKey

Returns the server's public key as a buffer.

server.address

Returns the server's public key as a Base58 string.

await server.listen([keyPair])

Starts listening for connections under the server's public key so peers can connect.

await server.announce(topic)

Announces the listening server under topic and refreshes the announcement while the server listens.

The server removes the announcement when it closes.

await server.unannounce(topic)

Removes the server's announcement for topic.

The server keeps listening for direct connections.

If the server has joined topic, it will keep looking up peers.

The topic stays unannounced until you call server.announce(topic) or leave and join again.

await server.join(topic)

Finds peers that announce topic and connects to them.

If the server is listening, it also announces itself under that topic.

The server emits a connection event for each discovered connection.

Closed connections are retried after 1 second, 5 seconds, 15 seconds, then every 10 minutes.

await server.leave(topic)

Stops finding peers under topic.

If only server.join(topic) announced the topic, it also removes that announcement.

An announcement made from server.announce(topic) stays active.

Existing peer connections stay open.

Cancels retries unless the peer was also discovered under another joined topic.

await server.close()

Closes the server's peer connections, removes its topic announcements, and closes its signaling connection.

await rtc.announce(topic[, options])

Signs and sends the announcement with keyPair.

Options:

{
  keyPair // Defaults to rtc.keyPair.
}

The announcement expires unless you refresh or remove it.

await rtc.unannounce(topic[, options])

Signs and sends a request to remove the announcement with keyPair.

Options:

{
  keyPair // Defaults to rtc.keyPair.
}

peers = await rtc.lookup(topic)

Returns peers announced under topic:

[
  { publicKey }
]

An announcement can remain even after a peer abruptly disconnects, unless closed properly.

The peer can stay discoverable while reconnecting after a brief signaling drop or page refresh.

A lookup during this gap can return a peer that is still offline.

await rtc.close()

Closes the RTC instance, its servers, its peers, and its signaling.

If you called rtc.announce() directly, call rtc.unannounce() to remove those announcements.

If you do not remove these manual announcements, they remain available until expiration.

keyPair = RTC.keyPair([seed])

Creates a key pair. Pass seed to create the same key pair each time.

bytes = RTC.randomBytes(size)

Returns random bytes.

stream = RTC.WebStream(dataChannelOrWebSocket)

Wraps a WebRTC data channel or a WebSocket in a duplex stream.

Useful for interacting with common Node.js streams.

Ideas

WhatsApp relays and stores messages for 30d if the recipient is offline.

Telegram uses WebRTC with double encryption to avoid trusting SRTP/DTLS.

Discord forwards WebRTC media with SFUs so peers don't connect together.

like-webrtc can do the same for a perfect P2P experience including the browser.

  • RPC relay messages must be E2E encrypted between peers to avoid learning from connections or metadata
  • Create a tiny SFU topology from scratch using WebRTC e.g. 3 people speaking and 3000 listening
  • Signaling could be a HTTPS server with EventSource/SSE instead of a WebSocket server
  • Make deploying TURN servers easy so people can use their own and allow app creators to pay for bandwidth
  • Payments is outside of the scope of this module but it's important for peers to be able to exchange value
  • More cryptographic safety around verifying announcement signatures locally
  • WebRTC-HTTP ingestion protocol (WHIP instead of RTMP?)
  • WebRTC-HTTP egress protocol (WHEP instead of HLS/CDN?)
  • Reusable module for WebRTC audio, video, screen, etc so that creating frontend apps is easy
  • HTTPS server that helps connect to a WebRTC signaling peer to avoid TCP/HTTPS/WebSocket traffic

License

MIT. Copyright (c) Lucas Barrena