resig.js
Version:
Universal reactive signal library with complete platform features: signals, animations, CRDTs, scheduling, DOM integration. Works identically across React, SolidJS, Svelte, Vue, and Qwik.
313 lines • 25 kB
JavaScript
"use strict";
/**
* WebRTC Streaming Signals
* Real-time collaboration with automatic reconnection and peer discovery
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.createWebRTCBroadcast = exports.createWebRTCStream = exports.BroadcastChannelSignaling = exports.WebRTCPeer = void 0;
const coalgebra_1 = require("./coalgebra");
// WebRTC peer connection wrapper
class WebRTCPeer {
constructor(peerId, config, signaling) {
this.peerId = peerId;
this.config = config;
this.signaling = signaling;
this.dataChannel = null;
this.reconnectAttempts = 0;
this.heartbeatTimer = null;
this.messageHandlers = new Set();
this.connection = new RTCPeerConnection({
iceServers: config.iceServers || [
{ urls: 'stun:stun.l.google.com:19302' },
],
});
this.setupConnection();
}
setupConnection() {
// Handle ICE candidates
this.connection.onicecandidate = (event) => {
if (event.candidate) {
this.signaling.iceCandidate(this.peerId, event.candidate.toJSON());
}
};
// Handle connection state changes
this.connection.onconnectionstatechange = () => {
const state = this.connection.connectionState;
if (state === 'failed' || state === 'disconnected') {
this.handleReconnection();
}
};
// Handle incoming data channels
this.connection.ondatachannel = (event) => {
this.setupDataChannel(event.channel);
};
}
setupDataChannel(channel) {
this.dataChannel = channel;
channel.onopen = () => {
this.startHeartbeat();
};
channel.onclose = () => {
this.stopHeartbeat();
};
channel.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
if (data.type === 'heartbeat') {
// Respond to heartbeat
this.send({ type: 'heartbeat-response', timestamp: Date.now() });
}
else {
this.messageHandlers.forEach((handler) => handler(data));
}
}
catch (error) {
console.error('Failed to parse WebRTC message:', error);
}
};
channel.onerror = (error) => {
console.error('WebRTC data channel error:', error);
};
}
startHeartbeat() {
if (this.heartbeatTimer)
return;
const interval = this.config.heartbeatInterval || 30000; // 30 seconds
this.heartbeatTimer = window.setInterval(() => {
this.send({ type: 'heartbeat', timestamp: Date.now() });
}, interval);
}
stopHeartbeat() {
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = null;
}
}
async handleReconnection() {
const maxAttempts = this.config.reconnectAttempts || 5;
const delay = this.config.reconnectDelay || 1000;
if (this.reconnectAttempts >= maxAttempts) {
console.error(`Failed to reconnect to peer ${this.peerId} after ${maxAttempts} attempts`);
return;
}
this.reconnectAttempts++;
console.log(`Attempting to reconnect to peer ${this.peerId} (attempt ${this.reconnectAttempts})`);
await new Promise((resolve) => setTimeout(resolve, delay * this.reconnectAttempts));
try {
await this.createOffer();
}
catch (error) {
console.error('Reconnection failed:', error);
this.handleReconnection();
}
}
async createOffer() {
// Create data channel for outgoing connections
if (!this.dataChannel) {
this.dataChannel = this.connection.createDataChannel('data', this.config.dataChannelOptions);
this.setupDataChannel(this.dataChannel);
}
const offer = await this.connection.createOffer();
await this.connection.setLocalDescription(offer);
await this.signaling.offer(this.peerId, offer);
}
async handleOffer(offer) {
await this.connection.setRemoteDescription(offer);
const answer = await this.connection.createAnswer();
await this.connection.setLocalDescription(answer);
await this.signaling.answer(this.peerId, answer);
}
async handleAnswer(answer) {
await this.connection.setRemoteDescription(answer);
this.reconnectAttempts = 0; // Reset on successful connection
}
async handleIceCandidate(candidate) {
await this.connection.addIceCandidate(new RTCIceCandidate(candidate));
}
send(data) {
if (this.dataChannel && this.dataChannel.readyState === 'open') {
try {
this.dataChannel.send(JSON.stringify(data));
return true;
}
catch (error) {
console.error('Failed to send WebRTC message:', error);
return false;
}
}
return false;
}
onMessage(handler) {
this.messageHandlers.add(handler);
return () => this.messageHandlers.delete(handler);
}
getConnectionState() {
return this.connection.connectionState;
}
close() {
this.stopHeartbeat();
if (this.dataChannel) {
this.dataChannel.close();
}
this.connection.close();
}
}
exports.WebRTCPeer = WebRTCPeer;
// Simple signaling implementation using BroadcastChannel
class BroadcastChannelSignaling {
constructor(channelName = 'webrtc-signaling') {
this.offerHandlers = new Set();
this.answerHandlers = new Set();
this.iceCandidateHandlers = new Set();
this.channel = new BroadcastChannel(channelName);
this.channel.onmessage = this.handleMessage.bind(this);
}
handleMessage(event) {
const { type, peerId, data } = event.data;
switch (type) {
case 'offer':
this.offerHandlers.forEach((handler) => handler(peerId, data));
break;
case 'answer':
this.answerHandlers.forEach((handler) => handler(peerId, data));
break;
case 'ice-candidate':
this.iceCandidateHandlers.forEach((handler) => handler(peerId, data));
break;
}
}
async offer(peerId, offer) {
this.channel.postMessage({ type: 'offer', peerId, data: offer });
}
async answer(peerId, answer) {
this.channel.postMessage({ type: 'answer', peerId, data: answer });
}
async iceCandidate(peerId, candidate) {
this.channel.postMessage({
type: 'ice-candidate',
peerId,
data: candidate,
});
}
onOffer(callback) {
this.offerHandlers.add(callback);
}
onAnswer(callback) {
this.answerHandlers.add(callback);
}
onIceCandidate(callback) {
this.iceCandidateHandlers.add(callback);
}
close() {
this.channel.close();
}
}
exports.BroadcastChannelSignaling = BroadcastChannelSignaling;
// Create WebRTC streaming signal
const createWebRTCStream = (peerId, config = {}, signaling) => {
const stream = (0, coalgebra_1.createStreamingSignal)(null);
const sig = signaling || new BroadcastChannelSignaling();
const peer = new WebRTCPeer(peerId, config, sig);
// Handle incoming messages
peer.onMessage((data) => {
if (typeof data === 'object' &&
data !== null &&
'type' in data &&
data.type === 'stream-data' &&
'value' in data) {
stream._set(data.value);
}
});
// Setup signaling handlers
sig.onOffer(async (fromPeerId, offer) => {
if (fromPeerId === peerId) {
await peer.handleOffer(offer);
}
});
sig.onAnswer(async (fromPeerId, answer) => {
if (fromPeerId === peerId) {
await peer.handleAnswer(answer);
}
});
sig.onIceCandidate(async (fromPeerId, candidate) => {
if (fromPeerId === peerId) {
await peer.handleIceCandidate(candidate);
}
});
// Override _set to broadcast changes
const originalSet = stream
._set;
stream._set = (value) => {
originalSet(value);
peer.send({ type: 'stream-data', value, timestamp: Date.now() });
};
// Add peer management methods
stream.peer = peer;
stream.connect = () => peer.createOffer();
stream.disconnect = () => peer.close();
stream.getConnectionState = () => peer.getConnectionState();
return stream;
};
exports.createWebRTCStream = createWebRTCStream;
// Multi-peer WebRTC stream for broadcasting to multiple peers
const createWebRTCBroadcast = (peerIds, config = {}, signaling) => {
const stream = (0, coalgebra_1.createStreamingSignal)(null);
const sig = signaling || new BroadcastChannelSignaling();
const peers = new Map();
// Create peers for each peer ID
peerIds.forEach((peerId) => {
const peer = new WebRTCPeer(peerId, config, sig);
peers.set(peerId, peer);
// Handle incoming messages from any peer
peer.onMessage((data) => {
if (typeof data === 'object' &&
data !== null &&
'type' in data &&
data.type === 'stream-data' &&
'value' in data) {
stream._set(data.value);
}
});
});
// Setup signaling for all peers
sig.onOffer(async (fromPeerId, offer) => {
const peer = peers.get(fromPeerId);
if (peer) {
await peer.handleOffer(offer);
}
});
sig.onAnswer(async (fromPeerId, answer) => {
const peer = peers.get(fromPeerId);
if (peer) {
await peer.handleAnswer(answer);
}
});
sig.onIceCandidate(async (fromPeerId, candidate) => {
const peer = peers.get(fromPeerId);
if (peer) {
await peer.handleIceCandidate(candidate);
}
});
// Override _set to broadcast to all peers
const originalSet = stream
._set;
stream._set = (value) => {
originalSet(value);
const message = { type: 'stream-data', value, timestamp: Date.now() };
peers.forEach((peer) => peer.send(message));
};
// Add broadcast management methods
stream.peers = peers;
stream.connectAll = async () => {
const peerArray = Array.from(peers.values());
for (const peer of peerArray) {
await peer.createOffer();
}
};
stream.disconnectAll = () => {
peers.forEach((peer) => peer.close());
};
return stream;
};
exports.createWebRTCBroadcast = createWebRTCBroadcast;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2VicnRjLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3N0cmVhbWluZy93ZWJydGMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7R0FHRzs7O0FBRUgsMkNBQXFFO0FBbUNyRSxpQ0FBaUM7QUFDakMsTUFBYSxVQUFVO0lBT3JCLFlBQ1MsTUFBYyxFQUNiLE1BQTBCLEVBQzFCLFNBQXdCO1FBRnpCLFdBQU0sR0FBTixNQUFNLENBQVE7UUFDYixXQUFNLEdBQU4sTUFBTSxDQUFvQjtRQUMxQixjQUFTLEdBQVQsU0FBUyxDQUFlO1FBUjFCLGdCQUFXLEdBQTBCLElBQUksQ0FBQztRQUMxQyxzQkFBaUIsR0FBRyxDQUFDLENBQUM7UUFDdEIsbUJBQWMsR0FBa0IsSUFBSSxDQUFDO1FBQ3JDLG9CQUFlLEdBQUcsSUFBSSxHQUFHLEVBQTJCLENBQUM7UUFPM0QsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLGlCQUFpQixDQUFDO1lBQ3RDLFVBQVUsRUFBRSxNQUFNLENBQUMsVUFBVSxJQUFJO2dCQUMvQixFQUFFLElBQUksRUFBRSw4QkFBOEIsRUFBRTthQUN6QztTQUNGLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztJQUN6QixDQUFDO0lBRU8sZUFBZTtRQUNyQix3QkFBd0I7UUFDeEIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxjQUFjLEdBQUcsQ0FBQyxLQUFLLEVBQUUsRUFBRTtZQUN6QyxJQUFJLEtBQUssQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDcEIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7WUFDckUsQ0FBQztRQUNILENBQUMsQ0FBQztRQUVGLGtDQUFrQztRQUNsQyxJQUFJLENBQUMsVUFBVSxDQUFDLHVCQUF1QixHQUFHLEdBQUcsRUFBRTtZQUM3QyxNQUFNLEtB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