@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
Maintainers
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-sdkWhat 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 powersrelay.ai-enable.xyz). - Platform transports — browser picks
webSockets + webTransport + webRTC + circuit-relay; Node pickswebSockets + tcp + circuit-relay(WebRTC's native module is never loaded under Node). - Audio — browser
MediaRecordercapture +AudioContextburst playback; Node gets a silent capturing/observation transceiver. Provide your own for React Native via theAudioTransceiverinterface.
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 multiaddrPersist 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,isStartedsendChat(text)/sendChatTo(peer, text)— text chatsendRawAudio(bytes[, peer])— raw audio chunksbeginTalk() / endTalk()— browser PTT (mic capture + playback)AudioTransceiver,BrowserAudioTransceiver,NoopAudioTransceivercreateRelayServerunder@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), notbun— the Bun runtime's Node websocket shims break libp2p's local ws listener. - Peer-provided display names are not authenticated.
