UNPKG

@xtr-dev/zod-rpc

Version:

Simple, type-safe RPC library with Zod validation and automatic TypeScript inference

172 lines 5.83 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createWebRTCTransport = exports.WebRTCPeerConnection = exports.WebRTCTransport = void 0; const errors_1 = require("../errors"); // WebRTC types are now included in modern TypeScript/DOM libs /** * @group Transport Layer */ class WebRTCTransport { constructor(dataChannel) { this.dataChannel = dataChannel; this.setupEventHandlers(); } async send(message) { if (!this.isConnected()) { throw new errors_1.TransportError('WebRTC DataChannel is not connected'); } try { this.dataChannel.send(JSON.stringify(message)); } catch (error) { throw new errors_1.TransportError(`Failed to send message: ${error instanceof Error ? error.message : 'Unknown error'}`); } } onMessage(handler) { this.messageHandler = handler; } async connect() { return new Promise((resolve, reject) => { if (this.isConnected()) { resolve(); return; } const onOpen = () => { this.dataChannel.removeEventListener('open', onOpen); this.dataChannel.removeEventListener('error', onError); resolve(); }; const onError = (_event) => { this.dataChannel.removeEventListener('open', onOpen); this.dataChannel.removeEventListener('error', onError); reject(new errors_1.TransportError('Failed to connect WebRTC DataChannel')); }; if (this.dataChannel.readyState === 'open') { resolve(); } else { this.dataChannel.addEventListener('open', onOpen); this.dataChannel.addEventListener('error', onError); } }); } async disconnect() { return new Promise((resolve) => { if (!this.isConnected()) { resolve(); return; } const onClose = () => { this.dataChannel.removeEventListener('close', onClose); resolve(); }; this.dataChannel.addEventListener('close', onClose); this.dataChannel.close(); }); } isConnected() { return this.dataChannel.readyState === 'open'; } setupEventHandlers() { this.dataChannel.addEventListener('message', (event) => { try { const message = JSON.parse(event.data); this.messageHandler?.(message); } catch (error) { console.error('Failed to parse WebRTC message:', error); } }); this.dataChannel.addEventListener('error', (event) => { console.error('WebRTC DataChannel error:', event); }); } } exports.WebRTCTransport = WebRTCTransport; /** * @group Transport Layer */ class WebRTCPeerConnection { constructor(config) { this.peerConnection = new RTCPeerConnection(config); this.setupPeerConnectionHandlers(); } async createOffer(channelLabel = 'rpc-channel') { this.dataChannel = this.peerConnection.createDataChannel(channelLabel, { ordered: true, }); const offer = await this.peerConnection.createOffer(); await this.peerConnection.setLocalDescription(offer); // Ensure type field is present return { type: 'offer', sdp: offer.sdp, }; } async createAnswer() { const answer = await this.peerConnection.createAnswer(); await this.peerConnection.setLocalDescription(answer); // Ensure type field is present return { type: 'answer', sdp: answer.sdp, }; } async handleAnswer(answer) { await this.peerConnection.setRemoteDescription(answer); } async setRemoteDescription(description) { // Ensure the description has the required type field if (!description.type) { throw new Error('RTCSessionDescriptionInit must have a type field'); } await this.peerConnection.setRemoteDescription(description); } async addIceCandidate(candidate) { await this.peerConnection.addIceCandidate(candidate); } onIceCandidate(handler) { this.peerConnection.addEventListener('icecandidate', (event) => { handler(event.candidate); }); } onDataChannel(handler) { this.peerConnection.addEventListener('datachannel', (event) => { handler(event.channel); }); } onConnectionStateChange(handler) { this.peerConnection.addEventListener('connectionstatechange', () => { handler(this.peerConnection.connectionState); }); } getDataChannel() { return this.dataChannel; } getConnectionState() { return this.peerConnection.connectionState; } close() { this.dataChannel?.close(); this.peerConnection.close(); } setupPeerConnectionHandlers() { this.peerConnection.addEventListener('connectionstatechange', () => { console.log('WebRTC connection state:', this.peerConnection.connectionState); }); this.peerConnection.addEventListener('datachannel', (event) => { if (!this.dataChannel) { this.dataChannel = event.channel; } }); } } exports.WebRTCPeerConnection = WebRTCPeerConnection; /** * @group Transport Layer */ function createWebRTCTransport(dataChannel) { return new WebRTCTransport(dataChannel); } exports.createWebRTCTransport = createWebRTCTransport; //# sourceMappingURL=webrtc.js.map