Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

0.23.0 #157

dmotz announced in Announcements
Mar 23, 2026 · 5 comments · 3 replies
Discussion options

This version marks Trystero's biggest update since initial release. The internals have been completely rewritten with minimal changes to the public API. You'll find faster, more robust peering thanks to connection sharing and offer recycling behind the scenes. The test suite has been expanded and hardened and now tests server-side use too. Trystero also has a new public face at trystero.dev.

User-facing changes

  • Trystero is now split into scoped packages: @trystero-p2p/{nostr,mqtt,torrent,supabase,firebase,ipfs} plus @trystero-p2p/core. The root trystero package still defaults to Nostr.
  • trystero/<strategy> imports are now deprecated compatibility entry points; migrate to @trystero-p2p/<strategy> for non-default strategies.
  • joinRoom(config, roomId, onJoinError) is now joinRoom(config, roomId, callbacks). onJoinError moved to callbacks.onJoinError, and Nostr/Torrent’s old relay-reconnection flag moved into config.manualRelayReconnection.
  • joinRoom() gained a new admission-handshake layer via onPeerHandshake(peerId, send, receive, isInitiator) and handshakeTimeoutMs, so apps can accept or reject peers before they become visible to getPeers(), onPeerJoin(), actions, or media callbacks. You can use this to implement your own custom identity layer with crypto keys.
  • trickleIce is now a public config option and speeds up initial connections. Most strategies default to trickle ICE, while Torrent and IPFS keep it off unless explicitly enabled.
  • @trystero-p2p/core now exposes createStrategy and shared types/utilities, making custom signaling strategies a supported extension point. You can use this to run a signaling relay for Trystero on any software you want. The readme shows a basic example using a simple WebSocket server.
  • Media and event ergonomics improved: replaceTrack() can now send metadata, onPeerJoin() immediately replays already-active peers to late listeners, and the action name limit increased from 12 bytes to 32 bytes.
  • Firebase’s getOccupants() helper was removed. This was only used by a single strategy and removing it helps keep the API surface small. You can still replicate its functionality with the Firebase API directly.
  • Server-side use is now a more explicit part of the public surface: rtcPolyfill is documented/tested, and a recommended polyfill library endorsement for werift.

Performance and reliability notes

  • Peer connection reuse is the biggest runtime change: when the same remote peer appears in multiple rooms, Trystero now reuses a shared underlying RTCPeerConnection instead of renegotiating per room.
    Offer pooling/reuse was overhauled, especially for tracker-style signaling, so old offers can be reclaimed and recycled instead of constantly allocating fresh peer connections.
  • Large and binary sends are more resilient under backpressure, with fixes for stalled sends and related data-channel hangs.
  • Relay robustness new public relay lists and better handling of repeated pings/timeouts, which should reduce churn and improve matchmaking stability.

Please share feedback, ideas, and of course, what you build with Trystero, via GitHub discussions/issues. Go forth and build a decentralized web. 🤝


This discussion was created from the release 0.23.0.
You must be logged in to vote

Replies: 5 comments 3 replies

Comment options

I've just upgraded Chitchatter to use 0.23.0 and it seems to be working well. Thanks for the great work and congrats on the big release @dmotz!

You must be logged in to vote
0 replies
Comment options

Woohoo! SO MANY FEATURES. This is the entire wishlist in one fell swoop. TY @dmotz!

You must be logged in to vote
0 replies
Comment options

With so many under the hood changes, didn't you consider bumping the version to 1.0.0?

You must be logged in to vote
0 replies
Comment options

I just transitioned from using "onPeerJoin" to using "onPeerHandshake" for identity exchange. WAY better UX. No more peers joining without identity info! (in my case, an advertised username + pubkey).

TY @dmotz!

You must be logged in to vote
0 replies
Comment options

@rogersanick If I understand it correctly "onPeerHandshake" doesn't not stop peers joining the room. we can only use it to stop peers connecting to each other and rejected peers connections will close completely. Am I right?

Is it possible to connect to a specific peer later on If the connection was initially rejected in onPeerHandshake?

You must be logged in to vote
3 replies
Comment options

That's effectively correct.

onPeerHandshake doesn't prevent discovery / signaling (which is of course decentralized and permissionless!). It runs after a connection is established and controls whether that pending peer becomes an active peer in the room.

So yes, a rejected peer could attempt to rejoin at a later time! There's no "rejected" list, that would be maintained at the application level.

Comment options

Is rejecting the connection means closing the connection which is already established before onPeerHandshake execution? If the answer is No then how can I close connection of unwanted peers. I don't want to keep large number of open connections in browser.

How a rejected peer could attempt to connect to a specific peer agin? Rejoining the room will send the handshake request to all peers again which I want to avoid.

Comment options

dmotz Apr 9, 2026
Maintainer Author

@ansarizafar It's possible to reject a peer in one case and accept them in another, e.g. you may connect with them in Room A where they have the correct password, but reject them in Room B where they have the wrong password. In this case, there is a RTC connection open with them, but from the Trystero API perspective you don't get any events from them in Room B. If you want to always reject a peer, you app could handle that in the handshake predicate, in which case the peer connections with them eventually close after handshaking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

AltStyle によって変換されたページ (->オリジナル) /