@decentnetwork/lan 0.1.162 → 0.1.164
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.
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/ui/desktop/app.js
CHANGED
|
@@ -1688,6 +1688,12 @@ function VideoSurface({ stream, muted, style }) {
|
|
|
1688
1688
|
}, [stream]);
|
|
1689
1689
|
return /* @__PURE__ */ React.createElement("video", { ref, autoPlay: true, playsInline: true, muted: !!muted, style });
|
|
1690
1690
|
}
|
|
1691
|
+
function AudioSink({ stream }) {
|
|
1692
|
+
const ref = React.useCallback((el) => {
|
|
1693
|
+
if (el && el.srcObject !== (stream || null)) el.srcObject = stream || null;
|
|
1694
|
+
}, [stream]);
|
|
1695
|
+
return /* @__PURE__ */ React.createElement("audio", { ref, autoPlay: true });
|
|
1696
|
+
}
|
|
1691
1697
|
function IncomingCallModal({ T, ctl, peers }) {
|
|
1692
1698
|
const inc = ctl.incoming;
|
|
1693
1699
|
if (!inc) return null;
|
|
@@ -1740,7 +1746,7 @@ function CallOverlay({ T, ctl, peers }) {
|
|
|
1740
1746
|
ctl.setMuted(n);
|
|
1741
1747
|
};
|
|
1742
1748
|
const controls = /* @__PURE__ */ React.createElement("div", { style: { display: "flex", gap: 18, alignItems: "flex-start" } }, /* @__PURE__ */ React.createElement(CallBtn, { icon: muted ? "micFill" : "mic", label: muted ? T && T.unmute || "unmute" : T && T.mute || "mute", active: muted, onClick: toggleMute }), /* @__PURE__ */ React.createElement(CallBtn, { icon: "phone", label: T && T.endCall || "end", danger: true, wide: true, onClick: ctl.hangup }));
|
|
1743
|
-
return /* @__PURE__ */ React.createElement("div", { style: { position: "fixed", inset: 0, zIndex: 70, background: "var(--bg)", display: "flex", flexDirection: "column" } }, /* @__PURE__ */ React.createElement("div", { style: { height: 52, flexShrink: 0, display: "flex", alignItems: "center", gap: 10, padding: "0 18px", borderBottom: "1px solid var(--line)" } }, /* @__PURE__ */ React.createElement(Icon, { name: video ? "video" : "phone", size: 16, color: "var(--accent)", stroke: 2 }), /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 13, fontWeight: 700, color: "var(--text)" } }, name), /* @__PURE__ */ React.createElement(Tag, { tone: connected ? "ok" : "warn" }, stateLabel), /* @__PURE__ */ React.createElement("div", { style: { flex: 1 } }), connected && /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 14, fontWeight: 700, color: "var(--text)", letterSpacing: 1 } }, mm, ":", ss)), video ? /* @__PURE__ */ React.createElement("div", { style: { flex: 1, position: "relative", padding: 18 } }, /* @__PURE__ */ React.createElement("div", { style: { position: "absolute", inset: 18, borderRadius: 14, overflow: "hidden", background: "#000", border: "1px solid var(--line)" } }, ctl.remoteStream ? /* @__PURE__ */ React.createElement(VideoSurface, { stream: ctl.remoteStream, style: { width: "100%", height: "100%", objectFit: "cover" } }) : /* @__PURE__ */ React.createElement("div", { style: { width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center" } }, /* @__PURE__ */ React.createElement(DkIdenticon, { seed: call.peerId, size: 92, radius: 22 }))), /* @__PURE__ */ React.createElement("div", { style: { position: "absolute", right: 30, bottom: 30, width: 220, height: 148, borderRadius: 12, overflow: "hidden", background: "#000", border: "1px solid var(--line)" } }, ctl.localStream ? /* @__PURE__ */ React.createElement(VideoSurface, { stream: ctl.localStream, muted: true, style: { width: "100%", height: "100%", objectFit: "cover", transform: "scaleX(-1)" } }) : /* @__PURE__ */ React.createElement("div", { style: { width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center" } }, /* @__PURE__ */ React.createElement(Icon, { name: "userRound", size: 30, color: "var(--faint)", stroke: 1.4 }))), /* @__PURE__ */ React.createElement("div", { style: { position: "absolute", left: 0, right: 0, bottom: 30, display: "flex", justifyContent: "center" } }, /* @__PURE__ */ React.createElement("div", { style: { padding: "16px 26px", borderRadius: 20, background: "color-mix(in oklab, var(--panel), transparent 8%)", border: "1px solid var(--line)" } }, controls))) : /* @__PURE__ */ React.createElement("div", { style: { flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 22 } },
|
|
1749
|
+
return /* @__PURE__ */ React.createElement("div", { style: { position: "fixed", inset: 0, zIndex: 70, background: "var(--bg)", display: "flex", flexDirection: "column" } }, ctl.remoteStream && /* @__PURE__ */ React.createElement(AudioSink, { stream: ctl.remoteStream }), /* @__PURE__ */ React.createElement("div", { style: { height: 52, flexShrink: 0, display: "flex", alignItems: "center", gap: 10, padding: "0 18px", borderBottom: "1px solid var(--line)" } }, /* @__PURE__ */ React.createElement(Icon, { name: video ? "video" : "phone", size: 16, color: "var(--accent)", stroke: 2 }), /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 13, fontWeight: 700, color: "var(--text)" } }, name), /* @__PURE__ */ React.createElement(Tag, { tone: connected ? "ok" : "warn" }, stateLabel), /* @__PURE__ */ React.createElement("div", { style: { flex: 1 } }), connected && /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 14, fontWeight: 700, color: "var(--text)", letterSpacing: 1 } }, mm, ":", ss)), video ? /* @__PURE__ */ React.createElement("div", { style: { flex: 1, position: "relative", padding: 18 } }, /* @__PURE__ */ React.createElement("div", { style: { position: "absolute", inset: 18, borderRadius: 14, overflow: "hidden", background: "#000", border: "1px solid var(--line)" } }, ctl.remoteStream ? /* @__PURE__ */ React.createElement(VideoSurface, { stream: ctl.remoteStream, muted: true, style: { width: "100%", height: "100%", objectFit: "cover" } }) : /* @__PURE__ */ React.createElement("div", { style: { width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center" } }, /* @__PURE__ */ React.createElement(DkIdenticon, { seed: call.peerId, size: 92, radius: 22 }))), /* @__PURE__ */ React.createElement("div", { style: { position: "absolute", right: 30, bottom: 30, width: 220, height: 148, borderRadius: 12, overflow: "hidden", background: "#000", border: "1px solid var(--line)" } }, ctl.localStream ? /* @__PURE__ */ React.createElement(VideoSurface, { stream: ctl.localStream, muted: true, style: { width: "100%", height: "100%", objectFit: "cover", transform: "scaleX(-1)" } }) : /* @__PURE__ */ React.createElement("div", { style: { width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center" } }, /* @__PURE__ */ React.createElement(Icon, { name: "userRound", size: 30, color: "var(--faint)", stroke: 1.4 }))), /* @__PURE__ */ React.createElement("div", { style: { position: "absolute", left: 0, right: 0, bottom: 30, display: "flex", justifyContent: "center" } }, /* @__PURE__ */ React.createElement("div", { style: { padding: "16px 26px", borderRadius: 20, background: "color-mix(in oklab, var(--panel), transparent 8%)", border: "1px solid var(--line)" } }, controls))) : /* @__PURE__ */ React.createElement("div", { style: { flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 22 } }, /* @__PURE__ */ React.createElement("div", { style: { position: "relative", display: "flex", alignItems: "center", justifyContent: "center" } }, !connected && /* @__PURE__ */ React.createElement("span", { style: { position: "absolute", width: 150, height: 150, borderRadius: 999, border: "2px solid var(--accent)", animation: "dkpulse 2s ease-out infinite" } }), /* @__PURE__ */ React.createElement(DkIdenticon, { seed: call.peerId, size: 108, radius: 26 })), /* @__PURE__ */ React.createElement("div", { style: { textAlign: "center" } }, /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 22, fontWeight: 700, color: "var(--text)" } }, name), /* @__PURE__ */ React.createElement("div", { style: { marginTop: 8, fontFamily: "var(--mono)", fontSize: 12.5, color: "var(--faint)" } }, stateLabel)), /* @__PURE__ */ React.createElement("div", { style: { marginTop: 18 } }, controls)));
|
|
1744
1750
|
}
|
|
1745
1751
|
Object.assign(window, { useCallController, CallOverlay, IncomingCallModal });
|
|
1746
1752
|
const DK_DEFAULTS = (
|
|
@@ -151,7 +151,7 @@ var PeerWebRTC = (() => {
|
|
|
151
151
|
var DEFAULT_ICE_SERVERS = [
|
|
152
152
|
{ urls: "stun:stun.l.google.com:19302" }
|
|
153
153
|
];
|
|
154
|
-
var _opts, _iceServers, _sessions, _CallEngine_instances, handleSignal_fn, onOffer_fn, onAnswer_fn, onCandidate_fn, onBye_fn, onAuxiliary_fn, createSession_fn, wirePeerConnection_fn, ensureRemoteStream_fn, attachLocalMedia_fn, flushLocalCandidates_fn, drainRemoteCandidates_fn, send_fn, sendByeSafe_fn, cleanup_fn, setState_fn, _toInfo, newCallId_fn, log_fn;
|
|
154
|
+
var _opts, _iceServers, _sessions, _CallEngine_instances, handleSignal_fn, onOffer_fn, onAnswer_fn, onCandidate_fn, onBye_fn, onAuxiliary_fn, createSession_fn, wirePeerConnection_fn, ensureRemoteStream_fn, attachLocalMedia_fn, flushLocalCandidates_fn, drainRemoteCandidates_fn, send_fn, sendByeSafe_fn, cleanup_fn, setState_fn, normId_fn, _toInfo, newCallId_fn, log_fn;
|
|
155
155
|
var CallEngine = class extends Emitter {
|
|
156
156
|
constructor(opts) {
|
|
157
157
|
var _a;
|
|
@@ -232,7 +232,7 @@ var PeerWebRTC = (() => {
|
|
|
232
232
|
* local media, applies the stored offer, and sends the answer.
|
|
233
233
|
*/
|
|
234
234
|
async accept(callId) {
|
|
235
|
-
const session = __privateGet(this, _sessions).get(callId);
|
|
235
|
+
const session = __privateGet(this, _sessions).get(__privateMethod(this, _CallEngine_instances, normId_fn).call(this, callId));
|
|
236
236
|
if (!session || session.direction !== "incoming" || !session.pendingOffer) {
|
|
237
237
|
throw new Error(`accept: no pending incoming call ${callId}`);
|
|
238
238
|
}
|
|
@@ -250,7 +250,7 @@ var PeerWebRTC = (() => {
|
|
|
250
250
|
}
|
|
251
251
|
/** Reject an incoming call (sends bye/declined). */
|
|
252
252
|
async reject(callId) {
|
|
253
|
-
const session = __privateGet(this, _sessions).get(callId);
|
|
253
|
+
const session = __privateGet(this, _sessions).get(__privateMethod(this, _CallEngine_instances, normId_fn).call(this, callId));
|
|
254
254
|
if (!session)
|
|
255
255
|
return;
|
|
256
256
|
await __privateMethod(this, _CallEngine_instances, sendByeSafe_fn).call(this, session, "declined");
|
|
@@ -259,7 +259,7 @@ var PeerWebRTC = (() => {
|
|
|
259
259
|
}
|
|
260
260
|
/** Hang up an active call (sends bye/normal). */
|
|
261
261
|
async hangup(callId, reason = "normal") {
|
|
262
|
-
const session = __privateGet(this, _sessions).get(callId);
|
|
262
|
+
const session = __privateGet(this, _sessions).get(__privateMethod(this, _CallEngine_instances, normId_fn).call(this, callId));
|
|
263
263
|
if (!session)
|
|
264
264
|
return;
|
|
265
265
|
await __privateMethod(this, _CallEngine_instances, sendByeSafe_fn).call(this, session, reason);
|
|
@@ -267,7 +267,7 @@ var PeerWebRTC = (() => {
|
|
|
267
267
|
}
|
|
268
268
|
/** Enable/disable a local track kind on an active call (mute / camera off). */
|
|
269
269
|
setLocalTrackEnabled(callId, kind, enabled) {
|
|
270
|
-
const session = __privateGet(this, _sessions).get(callId);
|
|
270
|
+
const session = __privateGet(this, _sessions).get(__privateMethod(this, _CallEngine_instances, normId_fn).call(this, callId));
|
|
271
271
|
if (!(session == null ? void 0 : session.localStream))
|
|
272
272
|
return;
|
|
273
273
|
for (const track of session.localStream.getTracks()) {
|
|
@@ -315,7 +315,7 @@ var PeerWebRTC = (() => {
|
|
|
315
315
|
onOffer_fn = function(peerId, signal) {
|
|
316
316
|
if (!signal.sdp)
|
|
317
317
|
return;
|
|
318
|
-
const existing = __privateGet(this, _sessions).get(signal.callId);
|
|
318
|
+
const existing = __privateGet(this, _sessions).get(__privateMethod(this, _CallEngine_instances, normId_fn).call(this, signal.callId));
|
|
319
319
|
if (existing) {
|
|
320
320
|
existing.pendingOffer = signal.sdp;
|
|
321
321
|
return;
|
|
@@ -329,7 +329,7 @@ var PeerWebRTC = (() => {
|
|
|
329
329
|
__privateMethod(this, _CallEngine_instances, log_fn).call(this, `incoming call from ${peerId} callId=${signal.callId} audio=${audio} video=${video}`);
|
|
330
330
|
};
|
|
331
331
|
onAnswer_fn = function(peerId, signal) {
|
|
332
|
-
const session = __privateGet(this, _sessions).get(signal.callId);
|
|
332
|
+
const session = __privateGet(this, _sessions).get(__privateMethod(this, _CallEngine_instances, normId_fn).call(this, signal.callId));
|
|
333
333
|
if (!session || session.peerId !== peerId || !signal.sdp)
|
|
334
334
|
return;
|
|
335
335
|
void (async () => {
|
|
@@ -346,7 +346,7 @@ var PeerWebRTC = (() => {
|
|
|
346
346
|
};
|
|
347
347
|
onCandidate_fn = function(peerId, signal) {
|
|
348
348
|
var _a;
|
|
349
|
-
const session = __privateGet(this, _sessions).get(signal.callId);
|
|
349
|
+
const session = __privateGet(this, _sessions).get(__privateMethod(this, _CallEngine_instances, normId_fn).call(this, signal.callId));
|
|
350
350
|
if (!session || session.peerId !== peerId || !signal.candidates)
|
|
351
351
|
return;
|
|
352
352
|
for (const c of signal.candidates) {
|
|
@@ -364,7 +364,7 @@ var PeerWebRTC = (() => {
|
|
|
364
364
|
};
|
|
365
365
|
onBye_fn = function(peerId, signal) {
|
|
366
366
|
var _a;
|
|
367
|
-
const session = __privateGet(this, _sessions).get(signal.callId);
|
|
367
|
+
const session = __privateGet(this, _sessions).get(__privateMethod(this, _CallEngine_instances, normId_fn).call(this, signal.callId));
|
|
368
368
|
if (!session || session.peerId !== peerId)
|
|
369
369
|
return;
|
|
370
370
|
const reason = (_a = signal.reason) != null ? _a : "normal";
|
|
@@ -374,7 +374,7 @@ var PeerWebRTC = (() => {
|
|
|
374
374
|
__privateMethod(this, _CallEngine_instances, log_fn).call(this, `bye from ${peerId} callId=${signal.callId} reason=${reason}`);
|
|
375
375
|
};
|
|
376
376
|
onAuxiliary_fn = function(peerId, signal) {
|
|
377
|
-
const session = __privateGet(this, _sessions).get(signal.callId);
|
|
377
|
+
const session = __privateGet(this, _sessions).get(__privateMethod(this, _CallEngine_instances, normId_fn).call(this, signal.callId));
|
|
378
378
|
if (!session || session.peerId !== peerId)
|
|
379
379
|
return;
|
|
380
380
|
if (signal.type === "event") {
|
|
@@ -405,7 +405,7 @@ var PeerWebRTC = (() => {
|
|
|
405
405
|
remoteCandidateQueue: [],
|
|
406
406
|
closed: false
|
|
407
407
|
};
|
|
408
|
-
__privateGet(this, _sessions).set(callId, session);
|
|
408
|
+
__privateGet(this, _sessions).set(__privateMethod(this, _CallEngine_instances, normId_fn).call(this, callId), session);
|
|
409
409
|
__privateMethod(this, _CallEngine_instances, wirePeerConnection_fn).call(this, session);
|
|
410
410
|
return session;
|
|
411
411
|
};
|
|
@@ -523,7 +523,7 @@ var PeerWebRTC = (() => {
|
|
|
523
523
|
} catch {
|
|
524
524
|
}
|
|
525
525
|
}
|
|
526
|
-
__privateGet(this, _sessions).delete(session.callId);
|
|
526
|
+
__privateGet(this, _sessions).delete(__privateMethod(this, _CallEngine_instances, normId_fn).call(this, session.callId));
|
|
527
527
|
if (session.state !== "ended" && session.state !== "failed") {
|
|
528
528
|
session.state = endedReason === "failed" ? "failed" : "ended";
|
|
529
529
|
}
|
|
@@ -535,6 +535,15 @@ var PeerWebRTC = (() => {
|
|
|
535
535
|
session.state = state;
|
|
536
536
|
this.emit("stateChanged", __privateGet(this, _toInfo).call(this, session), state);
|
|
537
537
|
};
|
|
538
|
+
/** Canonical session key. callId is a UUID; iOS re-serializes it UPPERCASE
|
|
539
|
+
* (it parses our lowercase UUID into a `UUID` and echoes `.uuidString`), so
|
|
540
|
+
* the answer/candidates come back cased differently than the offer. Key and
|
|
541
|
+
* look up sessions case-insensitively — exactly as the native SDK does
|
|
542
|
+
* (`callId.lowercased()`). Without this, outgoing calls to iOS never match
|
|
543
|
+
* the answer → candidates never flush → ICE stalls at "connecting". */
|
|
544
|
+
normId_fn = function(callId) {
|
|
545
|
+
return callId.toLowerCase();
|
|
546
|
+
};
|
|
538
547
|
_toInfo = new WeakMap();
|
|
539
548
|
newCallId_fn = function() {
|
|
540
549
|
if (__privateGet(this, _opts).generateCallId)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decentnetwork/lan",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.164",
|
|
4
4
|
"description": "Private virtual LAN for self-hosted services and AI agents, built on Elastos Carrier. NAT-traversal, name service, ACL, all over a peer-to-peer mesh — no public IP required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"dependencies": {
|
|
81
81
|
"@decentnetwork/dora": "^0.1.13",
|
|
82
82
|
"@decentnetwork/peer": "^0.1.86",
|
|
83
|
-
"@decentnetwork/peer-webrtc": "^0.1.
|
|
83
|
+
"@decentnetwork/peer-webrtc": "^0.1.1",
|
|
84
84
|
"ink": "^5.2.1",
|
|
85
85
|
"js-yaml": "^4.1.0",
|
|
86
86
|
"node-forge": "^1.4.0",
|