(function () { const statusEl = document.getElementById('status'); const topicEl = document.getElementById('topic'); const btnJoin = document.getElementById('btnJoin'); const btnLeave = document.getElementById('btnLeave'); const peersEl = document.getElementById('peers'); const publicKeyEl = document.getElementById('publicKey'); const connStatusEl = document.getElementById('connStatus'); const rawMsgEl = document.getElementById('rawMsg'); const btnRawSend = document.getElementById('btnRawSend'); const protoMsgEl = document.getElementById('protoMsg'); const btnProtoSend = document.getElementById('btnProtoSend'); const protoStatusEl = document.getElementById('protoStatus'); const logEl = document.getElementById('log'); function setStatus(msg, className) { statusEl.textContent = msg; statusEl.className = 'status ' + (className || 'ok'); } function log(msg, type) { const line = document.createElement('div'); line.className = type || 'sys'; line.textContent = '[' + new Date().toLocaleTimeString() + '] ' + msg; logEl.appendChild(line); logEl.scrollTop = logEl.scrollHeight; } (function initWhenReady(attempts) { if (attempts >= 50) { setStatus('BridgeSwarm extension not detected. Install it and reload.', 'error'); return; } if (typeof window.BridgeSwarm === 'undefined') { setStatus('Waiting for extension…', 'warn'); setTimeout(function () { initWhenReady(attempts + 1); }, 100); return; } window.BridgeSwarm.ready().then(function () { setStatus('Ready. Join a topic to start.'); }).catch(function () { setStatus('BridgeSwarm extension not detected.', 'error'); }); })(0); let swarm = null; const connectionEntries = []; function updatePeers() { peersEl.textContent = 'Peers: ' + connectionEntries.length; if (connectionEntries.length > 0) connStatusEl.style.display = ''; } function enableConnected() { rawMsgEl.disabled = false; btnRawSend.disabled = false; protoMsgEl.disabled = false; btnProtoSend.disabled = false; } function disableConnected() { rawMsgEl.disabled = true; btnRawSend.disabled = true; protoMsgEl.disabled = true; btnProtoSend.disabled = true; } btnJoin.addEventListener('click', async function () { if (typeof window.BridgeSwarm === 'undefined') { setStatus('Extension not ready.', 'error'); return; } const topic = topicEl.value.trim() || 'sdk-demo'; if (swarm) return; try { setStatus('Joining "' + topic + '"…'); swarm = new window.BridgeSwarm({ appName: 'bridge-swarm-sdk-demo' }); swarm.on('connection', function (conn, peerInfo) { const keyShort = (peerInfo.publicKey || '').slice(0, 16) + '…'; log('Connection: peer ' + keyShort + ', topics: ' + (peerInfo.topics ? peerInfo.topics.length : 0), 'peer'); conn.on('end', function () { const i = connectionEntries.findIndex(function (e) { return e.conn === conn; }); if (i !== -1) connectionEntries.splice(i, 1); updatePeers(); if (connectionEntries.length === 0) disableConnected(); log('Peer left', 'sys'); }); conn.on('error', function (err) { log('Peer error: ' + err.message, 'err'); }); conn.on('data', function (data) { const text = new TextDecoder().decode(data); log('Raw received: ' + text, 'raw'); }); const entry = { conn, peerInfo, mux: null, channel: null }; connectionEntries.push(entry); updatePeers(); enableConnected(); const mux = swarm.createProtomux(conn); if (mux && window.BridgeSwarmProtomux) { entry.mux = mux; const c = window.BridgeSwarmProtomux.c; const ch = mux.createChannel({ protocol: 'sdk-demo/v1', onopen: function () { log('Protomux channel opened', 'protomux'); protoStatusEl.style.display = ''; }, onclose: function () { log('Protomux channel closed', 'protomux'); } }); entry.stringMsg = ch.addMessage({ encoding: c.string, onmessage: function (m) { log('Protomux (string): ' + m, 'protomux'); } }); ch.addMessage({ encoding: c.binary, onmessage: function (buf) { const str = new TextDecoder().decode(buf); log('Protomux (binary): ' + str, 'protomux'); } }); ch.open(); entry.channel = ch; } else { log('Protomux not available (ensure protomux-bundle.js is loaded)', 'err'); } }); await swarm.join(topic); const pubKey = await swarm.getPublicKey(); publicKeyEl.textContent = 'Your public key: ' + pubKey; setStatus('Joined "' + topic + '". Connect another tab to try raw and Protomux messages.'); btnJoin.disabled = true; btnLeave.disabled = false; log('Joined topic: ' + topic, 'sys'); } catch (err) { setStatus('Error: ' + err.message, 'error'); log('Error: ' + err.message, 'err'); } }); btnLeave.addEventListener('click', async function () { if (!swarm) return; try { const topic = topicEl.value.trim() || 'sdk-demo'; await swarm.leave(topic); await swarm.destroy(); connectionEntries.length = 0; updatePeers(); disableConnected(); swarm = null; setStatus('Left topic. You can join again.'); btnJoin.disabled = false; btnLeave.disabled = true; log('Left topic and destroyed swarm', 'sys'); } catch (err) { log('Error: ' + err.message, 'err'); } }); function sendRaw() { const text = rawMsgEl.value.trim(); if (!text || !swarm || connectionEntries.length === 0) return; const data = new TextEncoder().encode(text); connectionEntries.forEach(function (e) { try { e.conn.write(data); } catch (_) {} }); log('Sent raw: ' + text, 'raw'); rawMsgEl.value = ''; } function sendProtomux() { const text = protoMsgEl.value.trim(); if (!text || connectionEntries.length === 0) return; let sent = 0; connectionEntries.forEach(function (e) { if (e.stringMsg) { try { e.stringMsg.send(text); sent++; } catch (_) {} } }); if (sent > 0) { log('Sent via Protomux: ' + text, 'protomux'); protoMsgEl.value = ''; } else { log('No Protomux channel ready', 'err'); } } btnRawSend.addEventListener('click', sendRaw); rawMsgEl.addEventListener('keydown', function (e) { if (e.key === 'Enter') sendRaw(); }); btnProtoSend.addEventListener('click', sendProtomux); protoMsgEl.addEventListener('keydown', function (e) { if (e.key === 'Enter') sendProtomux(); }); })();