vibedate 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +331 -35
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -914,6 +914,56 @@ var webAppHtml = `<!DOCTYPE html>
|
|
|
914
914
|
.incoming-call p{ color: var(--muted); font-size: .85rem; margin: 0 0 18px; }
|
|
915
915
|
.incoming-call .ic-actions{ display: flex; gap: 10px; }
|
|
916
916
|
|
|
917
|
+
/* ---- room full-mesh group video ---- */
|
|
918
|
+
.room-panel{
|
|
919
|
+
position: fixed; right: 18px; bottom: 18px; z-index: 45;
|
|
920
|
+
background: linear-gradient(180deg, var(--bg-card), var(--bg-card-2));
|
|
921
|
+
border: 1px solid var(--border-2); border-radius: 16px; box-shadow: var(--shadow-2);
|
|
922
|
+
padding: 12px 14px; min-width: 240px; max-width: 280px; display: none;
|
|
923
|
+
}
|
|
924
|
+
.room-panel.is-open{ display: block; animation: rise var(--dur-med) var(--ease-out); }
|
|
925
|
+
.room-panel .rp-title{ font-size: .78rem; font-weight: 800; margin-bottom: 6px; display:flex; align-items:center; gap:6px; }
|
|
926
|
+
.room-panel .rp-meta{ font-size: .7rem; color: var(--muted-2); margin-bottom: 10px; line-height: 1.4; word-break: break-all; }
|
|
927
|
+
.room-panel .rp-actions{ display:flex; gap: 8px; }
|
|
928
|
+
.room-panel .rp-btn{
|
|
929
|
+
border: 0; border-radius: 9px; padding: 8px 14px; font-weight: 700; font-size: .78rem;
|
|
930
|
+
background: linear-gradient(180deg, var(--coral), var(--coral-dim)); color: #2a1109;
|
|
931
|
+
flex: 1;
|
|
932
|
+
}
|
|
933
|
+
.room-panel .rp-btn:disabled{ opacity: .4; cursor: not-allowed; }
|
|
934
|
+
.room-panel .rp-btn.is-leave{ background: var(--danger); color: #2a0a0c; }
|
|
935
|
+
.room-video{
|
|
936
|
+
position: fixed; inset: 0; z-index: 68;
|
|
937
|
+
display: none; flex-direction: column; align-items: stretch; justify-content: flex-start;
|
|
938
|
+
background: rgba(12,7,15,.86); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
|
|
939
|
+
padding: 18px 18px 80px;
|
|
940
|
+
}
|
|
941
|
+
.room-video.is-open{ display: flex; }
|
|
942
|
+
.room-video .rv-head{
|
|
943
|
+
display:flex; align-items:center; justify-content: space-between; gap: 12px;
|
|
944
|
+
margin-bottom: 14px; color: var(--fg); font-weight: 800; font-size: .9rem;
|
|
945
|
+
}
|
|
946
|
+
.room-video .rv-grid{
|
|
947
|
+
flex: 1; display: grid; gap: 12px; min-height: 0;
|
|
948
|
+
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
|
949
|
+
align-content: start;
|
|
950
|
+
}
|
|
951
|
+
.room-video .rv-tile{
|
|
952
|
+
display:flex; flex-direction: column; gap: 6px; min-width: 0;
|
|
953
|
+
}
|
|
954
|
+
.room-video .rv-tile video{
|
|
955
|
+
width: 100%; aspect-ratio: 4 / 3; background: #000; border-radius: 14px;
|
|
956
|
+
border: 1px solid var(--border-2); object-fit: cover;
|
|
957
|
+
}
|
|
958
|
+
.room-video .rv-tile .rv-label{
|
|
959
|
+
font-size: .75rem; color: var(--muted); font-weight: 600; word-break: break-all;
|
|
960
|
+
}
|
|
961
|
+
.room-video .rv-leave{
|
|
962
|
+
position: absolute; bottom: 24px; left: 50%; transform: translateX(-50%);
|
|
963
|
+
border: 0; border-radius: 999px; padding: 12px 22px; font-weight: 800; font-size: .9rem;
|
|
964
|
+
background: var(--danger); color: #2a0a0c;
|
|
965
|
+
}
|
|
966
|
+
|
|
917
967
|
/* ---- live text chat (browser <-> PeerLink over /live/message) ---- */
|
|
918
968
|
.live-actions{ display: flex; gap: 6px; flex-shrink: 0; }
|
|
919
969
|
.live-row .cbtn{
|
|
@@ -1151,6 +1201,24 @@ var webAppHtml = `<!DOCTYPE html>
|
|
|
1151
1201
|
<button class="vhangup" id="hangupBtn" type="button">Hang up</button>
|
|
1152
1202
|
</div>
|
|
1153
1203
|
|
|
1204
|
+
<aside class="room-panel" id="roomPanel" aria-label="Room">
|
|
1205
|
+
<div class="rp-title"><span class="lp-dot" aria-hidden="true"></span> Room</div>
|
|
1206
|
+
<div class="rp-meta" id="roomMeta">not in a room</div>
|
|
1207
|
+
<div class="rp-actions">
|
|
1208
|
+
<button class="rp-btn" id="roomJoinBtn" type="button">Join video</button>
|
|
1209
|
+
<button class="rp-btn is-leave" id="roomLeaveBtn" type="button" disabled>Leave</button>
|
|
1210
|
+
</div>
|
|
1211
|
+
</aside>
|
|
1212
|
+
|
|
1213
|
+
<div class="room-video" id="roomVideo" role="dialog" aria-modal="true" aria-label="Room video">
|
|
1214
|
+
<div class="rv-head">
|
|
1215
|
+
<span id="roomVideoTitle">Room video</span>
|
|
1216
|
+
<span id="roomVideoCount" style="font-weight:600;color:var(--muted);font-size:.78rem"></span>
|
|
1217
|
+
</div>
|
|
1218
|
+
<div class="rv-grid" id="roomVideoGrid"></div>
|
|
1219
|
+
<button class="rv-leave" id="roomVideoLeaveBtn" type="button">Leave video</button>
|
|
1220
|
+
</div>
|
|
1221
|
+
|
|
1154
1222
|
<script>
|
|
1155
1223
|
(function(){
|
|
1156
1224
|
"use strict";
|
|
@@ -1816,6 +1884,252 @@ var webAppHtml = `<!DOCTYPE html>
|
|
|
1816
1884
|
}
|
|
1817
1885
|
refreshPeers();
|
|
1818
1886
|
setInterval(refreshPeers, 4000);
|
|
1887
|
+
|
|
1888
|
+
/* ---- Room full-mesh group video ----------------------------------------
|
|
1889
|
+
* When vibedate open --room <name> is attached, /api/room exposes the
|
|
1890
|
+
* roster. Each browser grabs getUserMedia once and opens one
|
|
1891
|
+
* RTCPeerConnection to every other member. Deterministic offerer election
|
|
1892
|
+
* (self < other lexicographic) avoids glare. Signaling rides the local
|
|
1893
|
+
* server's merged mailbox: GET /room/signal?handle=SELF returns
|
|
1894
|
+
* { frame: { from, rtc } }, POST /room/signal { handle: TARGET, frame }
|
|
1895
|
+
* relays one rtc-* frame to that member. */
|
|
1896
|
+
var roomPanel = document.getElementById("roomPanel");
|
|
1897
|
+
var roomMeta = document.getElementById("roomMeta");
|
|
1898
|
+
var roomJoinBtn = document.getElementById("roomJoinBtn");
|
|
1899
|
+
var roomLeaveBtn = document.getElementById("roomLeaveBtn");
|
|
1900
|
+
var roomVideo = document.getElementById("roomVideo");
|
|
1901
|
+
var roomVideoGrid = document.getElementById("roomVideoGrid");
|
|
1902
|
+
var roomVideoTitle = document.getElementById("roomVideoTitle");
|
|
1903
|
+
var roomVideoCount = document.getElementById("roomVideoCount");
|
|
1904
|
+
var roomVideoLeaveBtn = document.getElementById("roomVideoLeaveBtn");
|
|
1905
|
+
|
|
1906
|
+
var roomVid = { localStream: null, peers: {}, self: null, room: null, joined: false, polling: false };
|
|
1907
|
+
var roomLastRoster = [];
|
|
1908
|
+
|
|
1909
|
+
function roomPostSignal(handle, frame){
|
|
1910
|
+
return fetch("/room/signal", {
|
|
1911
|
+
method: "POST",
|
|
1912
|
+
headers: { "content-type": "application/json" },
|
|
1913
|
+
body: JSON.stringify({ handle: handle, frame: frame })
|
|
1914
|
+
}).catch(function(){ /* best effort */ });
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
function roomFetchSignal(selfHandle, timeoutMs){
|
|
1918
|
+
var ctrl = new AbortController();
|
|
1919
|
+
var t = setTimeout(function(){ ctrl.abort(); }, timeoutMs);
|
|
1920
|
+
return fetch("/room/signal?handle=" + encodeURIComponent(selfHandle), { signal: ctrl.signal })
|
|
1921
|
+
.then(function(r){ clearTimeout(t); return r; })
|
|
1922
|
+
.catch(function(e){ clearTimeout(t); throw e; });
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
function makeRoomTile(label, muted){
|
|
1926
|
+
var tile = document.createElement("div");
|
|
1927
|
+
tile.className = "rv-tile";
|
|
1928
|
+
var vid = document.createElement("video");
|
|
1929
|
+
vid.autoplay = true;
|
|
1930
|
+
vid.playsInline = true;
|
|
1931
|
+
if (muted) vid.muted = true;
|
|
1932
|
+
var lab = document.createElement("div");
|
|
1933
|
+
lab.className = "rv-label";
|
|
1934
|
+
lab.textContent = label;
|
|
1935
|
+
tile.appendChild(vid);
|
|
1936
|
+
tile.appendChild(lab);
|
|
1937
|
+
roomVideoGrid.appendChild(tile);
|
|
1938
|
+
return vid;
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
function updateRoomCount(){
|
|
1942
|
+
var n = 0;
|
|
1943
|
+
if (roomVid.localStream) n++;
|
|
1944
|
+
for (var k in roomVid.peers) if (Object.prototype.hasOwnProperty.call(roomVid.peers, k)) n++;
|
|
1945
|
+
roomVideoCount.textContent = n ? (n + " tile" + (n === 1 ? "" : "s")) : "";
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
function connectPeer(handle, role){
|
|
1949
|
+
if (!roomVid.localStream || !roomVid.self) return null;
|
|
1950
|
+
if (roomVid.peers[handle]) return roomVid.peers[handle];
|
|
1951
|
+
var pc = new RTCPeerConnection(rtcConfig());
|
|
1952
|
+
var videoEl = makeRoomTile(handle, false);
|
|
1953
|
+
var peer = { pc: pc, videoEl: videoEl, role: role };
|
|
1954
|
+
roomVid.peers[handle] = peer;
|
|
1955
|
+
updateRoomCount();
|
|
1956
|
+
|
|
1957
|
+
roomVid.localStream.getTracks().forEach(function(t){ pc.addTrack(t, roomVid.localStream); });
|
|
1958
|
+
pc.onicecandidate = function(e){
|
|
1959
|
+
// Trickle ICE to this peer. Empty candidate = end-of-candidates marker.
|
|
1960
|
+
roomPostSignal(handle, {
|
|
1961
|
+
t: "rtc-ice",
|
|
1962
|
+
candidate: e.candidate && e.candidate.candidate ? e.candidate.candidate : ""
|
|
1963
|
+
});
|
|
1964
|
+
};
|
|
1965
|
+
pc.ontrack = function(e){
|
|
1966
|
+
if (e.streams && e.streams[0]) videoEl.srcObject = e.streams[0];
|
|
1967
|
+
};
|
|
1968
|
+
pc.onconnectionstatechange = function(){
|
|
1969
|
+
// Quiet \u2014 closed peers stay in the grid until Leave clears everything.
|
|
1970
|
+
};
|
|
1971
|
+
|
|
1972
|
+
if (role === "offerer") {
|
|
1973
|
+
(async function(){
|
|
1974
|
+
try {
|
|
1975
|
+
var offer = await pc.createOffer();
|
|
1976
|
+
await pc.setLocalDescription(offer);
|
|
1977
|
+
await roomPostSignal(handle, { t: "rtc-offer", sdp: offer.sdp });
|
|
1978
|
+
} catch(e){ /* offer failed \u2014 peer will retry on next roster refresh if still present */ }
|
|
1979
|
+
})();
|
|
1980
|
+
}
|
|
1981
|
+
return peer;
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
async function handleRoomSignal(from, rtc){
|
|
1985
|
+
if (!rtc || !from || from === roomVid.self) return;
|
|
1986
|
+
if (rtc.t === "rtc-offer") {
|
|
1987
|
+
var peer = roomVid.peers[from];
|
|
1988
|
+
if (!peer) peer = connectPeer(from, "answerer");
|
|
1989
|
+
if (!peer) return;
|
|
1990
|
+
try {
|
|
1991
|
+
await peer.pc.setRemoteDescription({ type: "offer", sdp: rtc.sdp });
|
|
1992
|
+
var answer = await peer.pc.createAnswer();
|
|
1993
|
+
await peer.pc.setLocalDescription(answer);
|
|
1994
|
+
await roomPostSignal(from, { t: "rtc-answer", sdp: answer.sdp });
|
|
1995
|
+
} catch(e){}
|
|
1996
|
+
return;
|
|
1997
|
+
}
|
|
1998
|
+
if (rtc.t === "rtc-answer") {
|
|
1999
|
+
var pAns = roomVid.peers[from];
|
|
2000
|
+
if (!pAns) return;
|
|
2001
|
+
try { await pAns.pc.setRemoteDescription({ type: "answer", sdp: rtc.sdp }); } catch(e){}
|
|
2002
|
+
return;
|
|
2003
|
+
}
|
|
2004
|
+
if (rtc.t === "rtc-ice") {
|
|
2005
|
+
var pIce = roomVid.peers[from];
|
|
2006
|
+
if (!pIce) return;
|
|
2007
|
+
// Skip empty candidate (end-of-candidates) \u2014 browsers tolerate either way.
|
|
2008
|
+
if (!rtc.candidate) return;
|
|
2009
|
+
try { await pIce.pc.addIceCandidate({ candidate: rtc.candidate }); } catch(e){}
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
|
|
2013
|
+
async function roomSignalLoop(){
|
|
2014
|
+
if (roomVid.polling) return;
|
|
2015
|
+
roomVid.polling = true;
|
|
2016
|
+
while (roomVid.joined && roomVid.self) {
|
|
2017
|
+
var res;
|
|
2018
|
+
try { res = await roomFetchSignal(roomVid.self, 5000); }
|
|
2019
|
+
catch(e){ await sleep(400); continue; }
|
|
2020
|
+
if (!res || res.status !== 200) { await sleep(400); continue; }
|
|
2021
|
+
var data;
|
|
2022
|
+
try { data = await res.json(); } catch(e){ continue; }
|
|
2023
|
+
var f = data && data.frame;
|
|
2024
|
+
if (!f) continue; // timeout empty
|
|
2025
|
+
// Sender-routed shape: { from, rtc } (or a nested frame.frame fallback).
|
|
2026
|
+
var from = f.from;
|
|
2027
|
+
var rtc = f.rtc || f.frame || f;
|
|
2028
|
+
if (from && rtc && rtc.t) await handleRoomSignal(from, rtc);
|
|
2029
|
+
}
|
|
2030
|
+
roomVid.polling = false;
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
function meshWithMembers(members){
|
|
2034
|
+
if (!roomVid.joined || !roomVid.self || !roomVid.localStream) return;
|
|
2035
|
+
var self = roomVid.self;
|
|
2036
|
+
var seen = {};
|
|
2037
|
+
(members || []).forEach(function(m){
|
|
2038
|
+
var h = m && m.handle;
|
|
2039
|
+
if (!h || h === self) return;
|
|
2040
|
+
seen[h] = true;
|
|
2041
|
+
if (roomVid.peers[h]) return;
|
|
2042
|
+
// Deterministic glare avoidance: lower handle is the offerer.
|
|
2043
|
+
if (self < h) connectPeer(h, "offerer");
|
|
2044
|
+
// else wait for their offer via the long-poll loop
|
|
2045
|
+
});
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
async function joinRoomVideo(){
|
|
2049
|
+
if (roomVid.joined) return;
|
|
2050
|
+
if (!roomVid.self || !roomVid.room) return;
|
|
2051
|
+
roomJoinBtn.disabled = true;
|
|
2052
|
+
try {
|
|
2053
|
+
roomVid.localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
|
|
2054
|
+
} catch(e){
|
|
2055
|
+
roomJoinBtn.disabled = false;
|
|
2056
|
+
roomMeta.textContent = (roomVid.room || "room") + " \xB7 camera/mic blocked";
|
|
2057
|
+
return;
|
|
2058
|
+
}
|
|
2059
|
+
roomVid.joined = true;
|
|
2060
|
+
roomVid.peers = {};
|
|
2061
|
+
roomVideoGrid.innerHTML = "";
|
|
2062
|
+
var localEl = makeRoomTile((roomVid.self || "you") + " (you)", true);
|
|
2063
|
+
localEl.srcObject = roomVid.localStream;
|
|
2064
|
+
roomVideo.classList.add("is-open");
|
|
2065
|
+
roomVideoTitle.textContent = "Room \xB7 " + roomVid.room;
|
|
2066
|
+
roomLeaveBtn.disabled = false;
|
|
2067
|
+
updateRoomCount();
|
|
2068
|
+
roomSignalLoop();
|
|
2069
|
+
// Seed mesh against the latest roster, then refresh once more for races.
|
|
2070
|
+
meshWithMembers(roomLastRoster);
|
|
2071
|
+
try {
|
|
2072
|
+
var res = await fetch("/api/room");
|
|
2073
|
+
if (res.status === 200) {
|
|
2074
|
+
var data = await res.json();
|
|
2075
|
+
var members = (data && data.members) || [];
|
|
2076
|
+
roomLastRoster = members;
|
|
2077
|
+
meshWithMembers(members);
|
|
2078
|
+
}
|
|
2079
|
+
} catch(e){}
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
function leaveRoomVideo(){
|
|
2083
|
+
roomVid.joined = false;
|
|
2084
|
+
for (var h in roomVid.peers) {
|
|
2085
|
+
if (!Object.prototype.hasOwnProperty.call(roomVid.peers, h)) continue;
|
|
2086
|
+
try { roomVid.peers[h].pc.close(); } catch(e){}
|
|
2087
|
+
}
|
|
2088
|
+
roomVid.peers = {};
|
|
2089
|
+
if (roomVid.localStream) {
|
|
2090
|
+
roomVid.localStream.getTracks().forEach(function(t){ try { t.stop(); } catch(e){} });
|
|
2091
|
+
roomVid.localStream = null;
|
|
2092
|
+
}
|
|
2093
|
+
roomVideoGrid.innerHTML = "";
|
|
2094
|
+
roomVideo.classList.remove("is-open");
|
|
2095
|
+
roomLeaveBtn.disabled = true;
|
|
2096
|
+
roomJoinBtn.disabled = !roomVid.room;
|
|
2097
|
+
updateRoomCount();
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
roomJoinBtn.addEventListener("click", function(){ joinRoomVideo().catch(function(){ leaveRoomVideo(); }); });
|
|
2101
|
+
roomLeaveBtn.addEventListener("click", leaveRoomVideo);
|
|
2102
|
+
roomVideoLeaveBtn.addEventListener("click", leaveRoomVideo);
|
|
2103
|
+
|
|
2104
|
+
async function refreshRoom(){
|
|
2105
|
+
try {
|
|
2106
|
+
var res = await fetch("/api/room");
|
|
2107
|
+
if (res.status !== 200) return;
|
|
2108
|
+
var data = await res.json();
|
|
2109
|
+
var roomName = data && data.room;
|
|
2110
|
+
if (!roomName) {
|
|
2111
|
+
if (roomVid.joined) leaveRoomVideo();
|
|
2112
|
+
roomVid.room = null;
|
|
2113
|
+
roomVid.self = null;
|
|
2114
|
+
roomLastRoster = [];
|
|
2115
|
+
roomPanel.classList.remove("is-open");
|
|
2116
|
+
return;
|
|
2117
|
+
}
|
|
2118
|
+
roomVid.room = roomName;
|
|
2119
|
+
roomVid.self = data.self || null;
|
|
2120
|
+
roomLastRoster = (data.members) || [];
|
|
2121
|
+
var n = roomLastRoster.length;
|
|
2122
|
+
roomMeta.textContent = roomName +
|
|
2123
|
+
(roomVid.self ? " \xB7 you " + roomVid.self : "") +
|
|
2124
|
+
" \xB7 " + n + " other" + (n === 1 ? "" : "s");
|
|
2125
|
+
roomPanel.classList.add("is-open");
|
|
2126
|
+
roomJoinBtn.disabled = roomVid.joined || !roomVid.self;
|
|
2127
|
+
roomLeaveBtn.disabled = !roomVid.joined;
|
|
2128
|
+
if (roomVid.joined) meshWithMembers(roomLastRoster);
|
|
2129
|
+
} catch(e){}
|
|
2130
|
+
}
|
|
2131
|
+
refreshRoom();
|
|
2132
|
+
setInterval(refreshRoom, 4000);
|
|
1819
2133
|
})();
|
|
1820
2134
|
</script>
|
|
1821
2135
|
</body>
|
|
@@ -1898,8 +2212,8 @@ function createRoomBridge(name) {
|
|
|
1898
2212
|
let session;
|
|
1899
2213
|
const messageQueue = [];
|
|
1900
2214
|
const messageWaiters = [];
|
|
1901
|
-
const
|
|
1902
|
-
const signalWaiters =
|
|
2215
|
+
const signalQueue = [];
|
|
2216
|
+
const signalWaiters = [];
|
|
1903
2217
|
const drainMessage = (m) => {
|
|
1904
2218
|
const safe = { ...m, text: sanitizePeerText(m.text) };
|
|
1905
2219
|
const waiter = messageWaiters.shift();
|
|
@@ -1913,23 +2227,15 @@ function createRoomBridge(name) {
|
|
|
1913
2227
|
}
|
|
1914
2228
|
};
|
|
1915
2229
|
const drainSignal = (from, frame) => {
|
|
1916
|
-
const
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
w(frame);
|
|
1922
|
-
return;
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1925
|
-
let box = signalBoxes.get(from);
|
|
1926
|
-
if (box === void 0) {
|
|
1927
|
-
box = [];
|
|
1928
|
-
signalBoxes.set(from, box);
|
|
2230
|
+
const tagged = { from, rtc: frame };
|
|
2231
|
+
const waiter = signalWaiters.shift();
|
|
2232
|
+
if (waiter !== void 0) {
|
|
2233
|
+
waiter(tagged);
|
|
2234
|
+
return;
|
|
1929
2235
|
}
|
|
1930
|
-
|
|
1931
|
-
if (
|
|
1932
|
-
|
|
2236
|
+
signalQueue.push(tagged);
|
|
2237
|
+
if (signalQueue.length > MAX_QUEUED_ROOM_SIGNALS) {
|
|
2238
|
+
signalQueue.splice(0, signalQueue.length - MAX_QUEUED_ROOM_SIGNALS);
|
|
1933
2239
|
}
|
|
1934
2240
|
};
|
|
1935
2241
|
return {
|
|
@@ -1972,27 +2278,17 @@ function createRoomBridge(name) {
|
|
|
1972
2278
|
sendSignal(handle2, frame) {
|
|
1973
2279
|
session?.sendSignal(handle2, frame);
|
|
1974
2280
|
},
|
|
1975
|
-
async pollSignal(
|
|
1976
|
-
|
|
1977
|
-
if (box !== void 0 && box.length > 0) return box.shift() ?? null;
|
|
2281
|
+
async pollSignal(_handle, timeoutMs) {
|
|
2282
|
+
if (signalQueue.length > 0) return signalQueue.shift() ?? null;
|
|
1978
2283
|
return new Promise((resolve) => {
|
|
1979
2284
|
const timer = setTimeout(() => {
|
|
1980
|
-
const
|
|
1981
|
-
if (
|
|
1982
|
-
const idx = waiters2.indexOf(resolve);
|
|
1983
|
-
if (idx >= 0) waiters2.splice(idx, 1);
|
|
1984
|
-
if (waiters2.length === 0) signalWaiters.delete(handle2);
|
|
1985
|
-
}
|
|
2285
|
+
const idx = signalWaiters.indexOf(resolve);
|
|
2286
|
+
if (idx >= 0) signalWaiters.splice(idx, 1);
|
|
1986
2287
|
resolve(null);
|
|
1987
2288
|
}, timeoutMs);
|
|
1988
|
-
|
|
1989
|
-
if (waiters === void 0) {
|
|
1990
|
-
waiters = [];
|
|
1991
|
-
signalWaiters.set(handle2, waiters);
|
|
1992
|
-
}
|
|
1993
|
-
waiters.push((f) => {
|
|
2289
|
+
signalWaiters.push((s) => {
|
|
1994
2290
|
clearTimeout(timer);
|
|
1995
|
-
resolve(
|
|
2291
|
+
resolve(s);
|
|
1996
2292
|
});
|
|
1997
2293
|
});
|
|
1998
2294
|
}
|
|
@@ -2312,7 +2608,7 @@ async function handle(req, res, opts) {
|
|
|
2312
2608
|
}
|
|
2313
2609
|
|
|
2314
2610
|
// src/cli.ts
|
|
2315
|
-
var VERSION = "0.7.
|
|
2611
|
+
var VERSION = "0.7.1";
|
|
2316
2612
|
function parsePort(raw) {
|
|
2317
2613
|
const n = Number(raw);
|
|
2318
2614
|
if (!Number.isInteger(n) || n < 1 || n > 65535) return void 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibedate",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Dating by tokens — matched by usage league across agentic CLIs. Raw usage stays local; only your league is shared. CLI + local web app + MCP. Local-first.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|