Trystero Documentation

repository·main·Indexed 25 days ago

https://github.com/dmotz/trystero

A peer-to-peer (P2P) communication library for building real-time, serverless applications. Trystero supports various signaling strategies including WebSockets, Firebase, Supabase, Nostr, MQTT, and BitTorrent. It provides tools for managing room lifecycles, broadcasting custom data actions with request-response semantics, sharing audio/video streams, and implementing end-to-end encryption via shared passwords.

Tokens
13.4K
Snippets
21
Records
92
Agent score
82%

What's inside Trystero

  1. Choose a Trystero communication strategy

    main

    Trystero supports multiple communication strategies depending on your requirements for decentralization, redundancy, and hosting.

    • Nostr (Default): Highly decentralized with hundreds of active relays. Best for high redundancy and decentralization.
    • Decentralized Alternatives: If you prefer other decentralized networks, they are recommended in this order of robustness: MQTT, BitTorrent, and IPFS.
    • Managed Middleground: For a balance between public relays and self-hosting, use the built-in Supabase or Firebase strategies.

    You can host your own relay server for any of the decentralized strategies.

  2. Join a room with Trystero

    main

    To start communicating with peers, join a room using joinRoom(config, roomId).

    • config: An object containing a unique appId.
      • Note for Firebase: Use your databaseURL as the appId.
      • Note for Supabase: Use your project URL as the appId.
    • roomId: A string representing the room/channel ID.

    By default, the trystero package uses the Nostr network for peer discovery. You can swap the discovery strategy by importing from different packages (e.g., @trystero-p2p/mqtt, @trystero-p2p/torrent, etc.).

    import {joinRoom} from 'trystero'
    
    const config = {appId: 'san_narciso_3d'}
    const room = joinRoom(config, 'yoyodyne')
  3. Use Trystero with React hooks

    main

    Trystero functions are idempotent and can be used directly in React components. For managing room lifecycles (joining/leaving) automatically when a component mounts or when the roomId changes, use the useRoom hook pattern.

    import {joinRoom} from 'trystero'
    import {useEffect, useRef} from 'react'
    
    export const useRoom = (roomConfig, roomId) => {
      const roomRef = useRef(joinRoom(roomConfig, roomId))
      const lastRoomIdRef = useRef(roomId)
    
      useEffect(() => {
        if (roomId !== lastRoomIdRef.current) {
          roomRef.current.leave()
          roomRef.current = joinRoom(roomConfig, roomId)
          lastRoomIdRef.current = roomId
        }
    
        return () => roomRef.current.leave()
      }, [roomConfig, roomId])
    
      return roomRef.current
    }
  4. Set up a self-hosted WebSocket relay

    main

    You can host your own signaling relay using the @trystero-p2p/ws-relay package.

    1. Start the server (Node/Bun/Deno):

    import {createWsRelayServer} from '@trystero-p2p/ws-relay/server'
    createWsRelayServer({port: 8080})

    2. Connect from the browser: Use the @trystero-p2p/ws-relay client and provide the relayConfig.urls option. This option is required as there are no public default servers for this strategy.

    import {joinRoom} from '@trystero-p2p/ws-relay'
    
    const room = joinRoom(
      {
        appId: 'app-id',
        relayConfig: {
          urls: ['wss://localhost:8080']
        }
      },
      'room-id'
    )
  5. Install Trystero

    main

    You can install Trystero using npm or use a CDN for direct browser integration.

    Using npm

    npm i trystero

    Using a CDN

    <script type="module">
      import {joinRoom} from 'https://esm.run/trystero'
    </script>
  6. Configure Supabase and Firebase strategies

    main

    Supabase

    1. Create a Supabase project.
    2. In Project Settings -> API, copy the Project URL and use it as appId.
    3. Copy the anon public API key and use it as relayConfig.supabaseKey.

    Firebase

    1. Create a Firebase project and a Realtime Database.
    2. Copy the databaseURL and use it as the appId.
  7. Run Trystero in Node, Bun, or Deno

    main

    To run Trystero in non-browser environments, you must provide a WebRTC polyfill via the rtcPolyfill option in the configuration object.

    import {joinRoom} from 'trystero'
    import {RTCPeerConnection} from 'werift'
    
    const room = joinRoom(
      {appId: 'your-app-id', rtcPolyfill: RTCPeerConnection},
      'your-room-name'
    )
  8. Add and handle audio/video streams

    main

    Trystero allows you to share media streams with peers in a room.

    • room.addStream(stream): Sends the provided media stream to all peers in the room.
    • room.addStream(stream, {target: peerId}): Sends the stream to a specific peer.
    • room.onPeerStream: Event triggered when a peer sends a stream. The callback receives the stream and the peerId.

    To ensure peers who join later receive your stream, call room.addStream inside the onPeerJoin handler.

  9. Configure TURN servers for WebRTC connectivity

    main

    If users are behind restrictive networks that prevent direct P2P connections, configure a TURN server in the turnConfig array within your app configuration. Each configuration object requires urls, username, and credential.

    const room = joinRoom(
      {
        // ...your app config
        turnConfig: [
          {
            // single string or list of strings of URLs to access TURN server
            urls: ['turn:your-turn-server.ok:1979'],
            username: 'username',
            credential: 'password'
          }
        ]
      },
      'roomId'
    )
  10. Enable end-to-end encryption with a custom password

    main

    By default, Trystero encrypts communications using a key derived from your appId and roomId. To prevent relay operators from potentially reversing this key, you can provide a password in the app configuration object. This password acts as a shared secret that all peers in the room must know to connect.

    joinRoom({appId: 'kinneret', password: 'MuchoMaa$'}, 'w_a_s_t_e__v_i_p')
  11. Track transmission progress for large transfers

    main

    Action sender functions support two ways to track progress:

    1. Promises: send() returns a promise that resolves when the transmission is complete.
    2. Progress Callbacks: Pass an onProgress callback in the options object. This function is called continuously with a percent (0 to 1) and a context object containing the peerId.

    Receivers can also listen for progress using the onReceiveProgress event on the action, which includes the metadata sent by the sender.

    // Sender side
    file.send(payload, {
      target: [peerIdA, peerIdB, peerIdC],
      metadata: {filename: 'paranoids.flac'},
      onProgress: (percent, {peerId}) => (loadingBars[peerId].value = percent)
    })
    
    // Receiver side
    const file = room.makeAction('file')
    file.onReceiveProgress = (percent, {peerId, metadata}) =>
      console.log(
        `${percent * 100}% done receiving ${metadata.filename} from ${peerId}`
      )
  12. Manage media streams and tracks

    main

    Trystero provides methods to broadcast and manage MediaStream and MediaStreamTrack objects to peers in the room.

    Methods:

    • addStream(stream, [options]): Broadcasts a MediaStream.
    • removeStream(stream, [options]): Stops sending a stream.
    • addTrack(track, stream, [options]): Adds a MediaStreamTrack to an existing stream.
    • removeTrack(track, [options]): Removes a track.
    • replaceTrack(oldTrack, newTrack, [options]): Replaces one track with another.

    Options for all media methods:

    • target (optional): A single peer ID (string) or an array of peer IDs. If omitted or null, the media is sent to all peers.
    • metadata (optional): Any serializable type to identify the stream/track (e.g., distinguishing webcam vs screen share).