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

@yourorg/treehole-client-sdk

v0.1.1

Published

P2P audio + chat client SDK for the TreeHole network (libp2p + WebRTC). Build a browser, React Native, or CLI client.

Downloads

64

Readme

@yourorg/treehole-client-sdk

A platform-neutral TypeScript SDK for the TreeHole P2P audio + chat network. Build a browser app, a React Native client, or a Node CLI that joins the same wire — WebRTC/WebSocket/WebTransport transports, rendezvous discovery through the TreeHole relay, text chat, and push-to-talk audio.

npm i @yourorg/treehole-client-sdk

What you get

  • TreeHoleClient — connects to a relay, discovers peers via rendezvous, sends/receives chat, streams PTT audio.
  • Relay server (@yourorg/treehole-client-sdk/relay) — run your own bootstrap + circuit relay (this is what powers relay.ai-enable.xyz).
  • Platform transports — browser picks webSockets + webTransport + webRTC + circuit-relay; Node picks webSockets + tcp + circuit-relay (WebRTC's native module is never loaded under Node).
  • Audio — browser MediaRecorder capture + AudioContext burst playback; Node gets a silent capturing/observation transceiver. Provide your own for React Native via the AudioTransceiver interface.

Browser quickstart

import { TreeHoleClient } from '@yourorg/treehole-client-sdk'

const client = new TreeHoleClient({
  name: 'alice',
  // optional: relayMultiaddr, iceServers, rendezvousIntervalMs, ...
  callbacks: {
    onChat: (msg) => console.log(`${msg.name}: ${msg.text}`),
    onPeersUpdated: (peers) => console.log('peers', [...peers.keys()])
  }
})

const ptt = document.querySelector('#ptt')
ptt.addEventListener('pointerdown', () => void client.beginTalk())
ptt.addEventListener('pointerup', () => client.endTalk())

Relay resolution order: relayMultiaddr option → RELAY_MULTIADDR env → /relay.json (browser) → the public default relay.

Node quickstart

import { TreeHoleClient } from '@yourorg/treehole-client-sdk'

const client = new TreeHoleClient({
  name: 'cli',
  platform: 'node',
  callbacks: { onChat: (m) => console.log(`${m.name}: ${m.text}`) }
})

await client.start()
await client.sendChat('hello from the CLI')
// PTT audio capture is not available on Node — use a custom
// AudioTransceiver, or sendRawAudio(bytes) from an external recorder.

Run your own relay

import { createRelayServer } from '@yourorg/treehole-client-sdk/relay'

const relay = await createRelayServer({
  host: '::',      // external-facing
  wsPort: 9001,
  tcpPort: 9002,
  // announce: 'wss://relay.example.com/p2p/<stable-peer-id>'
})
console.log(relay.wsMultiaddr())
// point clients at this multiaddr

Persist a stable peer id by reusing a keypair:

import { generateKeyPair, privateKeyToProtobuf, privateKeyFromProtobuf } from '@libp2p/crypto/keys'
// save privateKeyToProtobuf(key) → hex; later privateKeyFromProtobuf(Buffer.from(hex, 'hex'))
createRelayServer({ keyPair: loadedKey })

API surface

  • TreeHoleClient.start() / stop() — peerId, peersMap, isStarted
  • sendChat(text) / sendChatTo(peer, text) — text chat
  • sendRawAudio(bytes[, peer]) — raw audio chunks
  • beginTalk() / endTalk() — browser PTT (mic capture + playback)
  • AudioTransceiver, BrowserAudioTransceiver, NoopAudioTransceiver
  • createRelayServer under @yourorg/treehole-client-sdk/relay
  • constants: DEFAULT_RELAY_MULTIADDR, CHAT_PROTOCOL, RENDEZVOUS_PROTOCOL, AUDIO_PROTOCOL
  • helpers: splitRelayString, circuitAddr, encodeChatMessage / decodeChatMessage, resolveRelayMultiaddr

Protocols

| id | purpose | | --- | --- | | /treehole/rendezvous/1.0.0 | announce + list connected peers with addresses | | /treehole/chat/1.0.0 | JSON chat messages | | /treehole/audio/1.0.0 | raw audio chunks (PTT) |

Development

bun install
bun run build      # tsup → dist/ (esm + d.ts)
bun run typecheck  # tsc --noEmit
bun run test       # typecheck + build + node --test (unit, integration, smoke)

The integration test spins up an in-process relay plus two Node clients, discovers each other over rendezvous, and exchanges chat + audio end to end.

Notes

  • Run tests with Node (≥22, --experimental-strip-types), not bun — the Bun runtime's Node websocket shims break libp2p's local ws listener.
  • Peer-provided display names are not authenticated.