
Security News
Ruby's Bundler 4.0.18 Extends Cooldown to bundle lock and bundle cache
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.
@martini-kit/transport-trystero
Advanced tools
P2P WebRTC transport for martini-kit. Multiplayer without networking servers.
P2P WebRTC transport for @martini-kit/core using Trystero.
Enables serverless peer-to-peer multiplayer with zero infrastructure costs.
pnpm add @martini-kit/transport-trystero @martini-kit/core trystero
import { TrysteroTransport } from '@martini-kit/transport-trystero';
import { GameRuntime, defineGame } from '@martini-kit/core';
// Determine host from URL
const urlParams = new URLSearchParams(window.location.search);
const roomId = urlParams.get('room');
const isHost = !roomId; // No room ID = host
// Generate room ID if host
const finalRoomId = isHost
? 'room-' + Math.random().toString(36).substring(2, 8)
: roomId;
// Create transport with explicit host mode
const transport = new TrysteroTransport({
roomId: finalRoomId,
isHost: isHost // URL determines host!
});
// Create runtime
const runtime = new GameRuntime(gameLogic, transport, {
isHost: isHost,
playerIds: [transport.getPlayerId()]
});
// Show join link for clients
if (isHost) {
const joinUrl = `${window.location.origin}?room=${finalRoomId}`;
console.log('Share this link:', joinUrl);
}
HOST (opens without ?room param)
↓
Creates new room ID
↓
Shares link: https://game.com?room=ABC123
↓
CLIENT clicks link
↓
Joins room ABC123
↓
Connects to HOST via WebRTC
↓
✅ Game session established
Key Points:
?room = host)┌─────────┐ Nostr Relays ┌─────────┐
│ HOST │◄──────(signal only)────────►│ CLIENT │
└─────────┘ └─────────┘
│ │
└────────── WebRTC Direct P2P ──────────┘
(game data flows here)
new TrysteroTransport(options: TrysteroTransportOptions)
Options:
interface TrysteroTransportOptions {
/** Unique room identifier for P2P session */
roomId: string;
/** Application ID for Trystero (prevents cross-app collisions) */
appId?: string;
/** Custom STUN/TURN servers for NAT traversal */
rtcConfig?: RTCConfiguration;
/**
* Explicitly set this peer as host (industry standard: separate host/join URLs)
* - true: This peer becomes host immediately
* - false: This peer will never be host (always client)
* - undefined: Automatic election (alphabetically lowest peer ID)
*/
isHost?: boolean;
}
Example:
const transport = new TrysteroTransport({
roomId: 'game-room-123',
appId: 'my-game',
isHost: true,
rtcConfig: {
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' }
]
}
});
Implements the Transport interface:
send(message, targetId?) - Send message to peer or broadcastonMessage(handler) - Listen for messagesonPeerJoin(handler) - Listen for peer joinsonPeerLeave(handler) - Listen for peer leavesgetPlayerId() - Get this peer's IDgetPeerIds() - Get connected peer IDsisHost() - Check if this peer is hostAdditional Methods:
waitForReady(): Promise<void>Wait for host discovery to complete (useful for automatic election mode).
const transport = new TrysteroTransport({ roomId: 'room-123' });
await transport.waitForReady();
const isHost = transport.isHost(); // Now reliable!
getCurrentHost(): string | nullGet the current host's peer ID.
const hostId = transport.getCurrentHost();
console.log('Host:', hostId);
onHostDisconnect(callback): () => voidListen for host disconnection (game should end).
transport.onHostDisconnect(() => {
alert('Host left the game!');
window.location.reload();
});
getRoom(): RoomGet the Trystero room instance (for advanced use).
const room = transport.getRoom();
Best for: Jackbox-style games, classroom multiplayer
const isHost = !new URLSearchParams(window.location.search).get('room');
const transport = new TrysteroTransport({
roomId: isHost ? generateRoomId() : roomIdFromUrl,
isHost: isHost // Explicit
});
Pros:
Best for: Symmetric multiplayer (no designated host)
const transport = new TrysteroTransport({
roomId: 'shared-room-123',
isHost: undefined // Auto-elect
});
await transport.waitForReady(); // Wait for election
const isHost = transport.isHost();
Pros:
Cons:
waitForReady() for host discoveryWhen isHost: undefined (automatic mode), the transport performs active host discovery:
1. Broadcast "host_query" message
↓
2. Wait 3 seconds for "host_announce" response
↓
3a. If response received → Use announced host
3b. If no response && no peers → Become solo host
3c. If conflict (two hosts) → Deterministic tiebreaker (lowest ID)
Tiebreaker: If multiple peers think they're host, the peer with the alphabetically lowest ID wins.
WebRTC requires STUN/TURN servers for NAT traversal:
const transport = new TrysteroTransport({
roomId: 'room-123',
// Uses Google's public STUN server
});
const transport = new TrysteroTransport({
roomId: 'room-123',
rtcConfig: {
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{
urls: 'turn:your-turn-server.com',
username: 'user',
credential: 'pass'
}
]
}
});
When to use TURN:
TURN Providers:
# Run tests
pnpm test
# Watch mode
pnpm test:watch
# Coverage
pnpm test:coverage
Current coverage: Comprehensive transport interface tests ✅
# Build
pnpm build
# Watch mode
pnpm dev
# Clean
pnpm clean
Symptoms: onPeerJoin never fires, peers list stays empty
Solutions:
roomIdappIdSymptoms: Both peers think they're host
Solutions:
isHost: true/false)waitForReady() in automatic modeThis is by design! Sticky host pattern = game ends if host leaves.
Solutions:
MIT - See LICENSE
FAQs
P2P WebRTC transport for martini-kit. Multiplayer without networking servers.
The npm package @martini-kit/transport-trystero receives a total of 1 weekly downloads. As such, @martini-kit/transport-trystero popularity was classified as not popular.
We found that @martini-kit/transport-trystero demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.

Security News
During a UK cyber test, a Mythos 5 agent used sockpuppets, social engineering, and prompt injection to try to get a maintainer to merge malware.

Company News
Socket is now in the AWS Security Hub Extended plan. Adopt it through AWS, apply committed spend, and block malicious open source packages.