Examples
The examples folder holds three small apps. The chat and the call are modules with tests that run them over real peer connections in a browser, and the code here wires them to the DOM. Serve them all from a clone of the repository:
npm cinpm run examplesChat between tabs
Section titled “Chat between tabs”http://localhost:5173/chat/ — open it in two tabs. The chat itself, joinChat, is on the
getting started page; this is the page around it:
import type { Signaling } from 'peer-data';import { joinChat } from './chat.js';
/** Runs the chat page: the log, the form, and the peer count, over the given signaling. */export function runChatPage(signaling: Signaling): void { const log = document.querySelector<HTMLUListElement>('#log'); const status = document.querySelector<HTMLParagraphElement>('#status'); const form = document.querySelector<HTMLFormElement>('#form'); const input = document.querySelector<HTMLInputElement>('#text'); if (!log || !status || !form || !input) throw new Error('chat page markup is missing');
const name = `Guest ${String(Math.floor(Math.random() * 1000))}`; const show = (text: string): void => { const item = document.createElement('li'); item.textContent = text; log.append(item); log.scrollTop = log.scrollHeight; };
const chat = joinChat(signaling, name, { line: ({ from, text }) => { show(`${from}: ${text}`); }, peers: (count) => { status.textContent = `You are ${name}, connected to ${String(count)} ${count === 1 ? 'peer' : 'peers'}.`; }, }); status.textContent = `You are ${name}. Waiting for someone to join.`;
form.addEventListener('submit', (event) => { event.preventDefault(); const text = input.value.trim(); if (text === '') return; chat.say(text); show(`${name}: ${text}`); input.value = ''; }); window.addEventListener('pagehide', chat.leave); // A page restored from the back-forward cache has left the chat: join afresh. window.addEventListener('pageshow', (event) => { if (event.persisted) location.reload(); });}import { BroadcastChannelSignaling } from 'peer-data';import { runChatPage } from './page.js';
runChatPage(new BroadcastChannelSignaling('peer-data-chat'));Video call between tabs
Section titled “Video call between tabs”http://localhost:5173/video/ — open it in two tabs and start each. joinCall is on the
live demo page; this page shares your camera with it:
import { BroadcastChannelSignaling } from 'peer-data';import { joinCall } from './video.js';
const videos = document.querySelector<HTMLDivElement>('#videos');const start = document.querySelector<HTMLButtonElement>('#start');const status = document.querySelector<HTMLParagraphElement>('#status');if (!videos || !start || !status) throw new Error('video page markup is missing');
/** A muted, playing video element for stream. */function videoFor(stream: MediaStream, muted: boolean): HTMLVideoElement { const video = document.createElement('video'); video.autoplay = true; video.playsInline = true; video.muted = muted; video.srcObject = stream; return video;}
const startCall = async (): Promise<void> => { start.disabled = true; let stream: MediaStream; try { stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); } catch (error) { status.textContent = `No camera: ${String(error)}`; start.disabled = false; return; } videos.append(videoFor(stream, true)); status.textContent = 'Sharing your camera with every other tab that joins.';
const remote = new Map<string, HTMLVideoElement>(); const call = joinCall(new BroadcastChannelSignaling('peer-data-video'), stream, { stream: (id, theirs) => { const existing = remote.get(id); if (existing) { existing.srcObject = theirs; return; } const video = videoFor(theirs, false); remote.set(id, video); videos.append(video); }, left: (id) => { remote.get(id)?.remove(); remote.delete(id); }, }); window.addEventListener('pagehide', call.leave);};
// A page restored from the back-forward cache has left its call: start afresh.window.addEventListener('pageshow', (event) => { if (event.persisted) location.reload();});
start.addEventListener('click', () => { void startCall();});Chat through a server
Section titled “Chat through a server”http://localhost:5173/socket/ — open it in two browsers. The same chat page, signaling through the socket.io server in examples/socket/server.ts, which the dev server runs on the same port through a Vite plugin:
import { io } from 'socket.io-client';import { SocketChannel } from 'peer-data';import { runChatPage } from '../chat/page.js';
// vite-plugin.ts runs the signaling server on the examples' dev server, on the same port, so io() reaches it.runChatPage(new SocketChannel(io()));