@afterrealism/dendri-client 2.3.7 → 2.5.0
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/LICENSE +202 -21
- package/README.md +65 -72
- package/dist/{chunk-MJW5M75V.js → chunk-3CE674DE.js} +267 -24
- package/dist/chunk-3CE674DE.js.map +1 -0
- package/dist/dendri.browser.global.js +233 -18
- package/dist/dendri.browser.global.js.map +1 -1
- package/dist/dendri.cjs +266 -22
- package/dist/dendri.cjs.map +1 -1
- package/dist/dendri.d.cts +13 -4
- package/dist/dendri.d.ts +13 -4
- package/dist/dendri.js +3 -3
- package/dist/dendri.js.map +1 -1
- package/dist/dendri.min.global.js +13 -13
- package/dist/dendri.min.global.js.map +1 -1
- package/dist/serializer.msgpack.cjs +3 -3
- package/dist/serializer.msgpack.cjs.map +1 -1
- package/dist/serializer.msgpack.d.cts +31 -4
- package/dist/serializer.msgpack.d.ts +31 -4
- package/dist/serializer.msgpack.js +2 -2
- package/dist/serializer.msgpack.js.map +1 -1
- package/dist/{store-RTivRmUW.d.cts → store-C3Nwl62R.d.cts} +38 -5
- package/dist/{store-RTivRmUW.d.ts → store-C3Nwl62R.d.ts} +38 -5
- package/dist/store.cjs +256 -21
- package/dist/store.cjs.map +1 -1
- package/dist/store.d.cts +1 -1
- package/dist/store.d.ts +1 -1
- package/dist/store.js +1 -1
- package/package.json +8 -2
- package/dist/chunk-MJW5M75V.js.map +0 -1
package/dist/store.cjs
CHANGED
|
@@ -3531,7 +3531,7 @@ var Util = class extends BinaryPackChunker {
|
|
|
3531
3531
|
var util = new Util();
|
|
3532
3532
|
|
|
3533
3533
|
// src/api.ts
|
|
3534
|
-
var version = "2.
|
|
3534
|
+
var version = "2.5.0";
|
|
3535
3535
|
var API = class _API {
|
|
3536
3536
|
constructor(_options) {
|
|
3537
3537
|
this._options = _options;
|
|
@@ -3544,6 +3544,7 @@ var API = class _API {
|
|
|
3544
3544
|
const url = new URL(`${protocol}://${host}:${port}${path}${key}/${method}`);
|
|
3545
3545
|
url.searchParams.set("ts", `${Date.now()}${Math.random()}`);
|
|
3546
3546
|
url.searchParams.set("version", version);
|
|
3547
|
+
if (this._options.apiKey) url.searchParams.set("api_key", this._options.apiKey);
|
|
3547
3548
|
const controller = new AbortController();
|
|
3548
3549
|
const timeoutId = setTimeout(() => controller.abort(), _API.FETCH_TIMEOUT);
|
|
3549
3550
|
return fetch(url.href, {
|
|
@@ -3568,15 +3569,16 @@ var API = class _API {
|
|
|
3568
3569
|
throw new Error(`Could not get an ID from the server.${pathError}`);
|
|
3569
3570
|
}
|
|
3570
3571
|
}
|
|
3571
|
-
/** Fetch TURN credentials from the signaling server's
|
|
3572
|
+
/** Fetch TURN credentials from the signaling server's turn-credentials endpoint. */
|
|
3572
3573
|
async getTurnCredentials() {
|
|
3573
3574
|
const protocol = this._options.secure ? "https" : "http";
|
|
3574
|
-
const { host, port } = this._options;
|
|
3575
|
-
const url = `${protocol}://${host}:${port}/turn
|
|
3575
|
+
const { host, port, path, key } = this._options;
|
|
3576
|
+
const url = new URL(`${protocol}://${host}:${port}${path}${key}/turn-credentials`);
|
|
3577
|
+
if (this._options.apiKey) url.searchParams.set("api_key", this._options.apiKey);
|
|
3576
3578
|
try {
|
|
3577
3579
|
const controller = new AbortController();
|
|
3578
3580
|
const timeoutId = setTimeout(() => controller.abort(), _API.FETCH_TIMEOUT);
|
|
3579
|
-
const response = await fetch(url, {
|
|
3581
|
+
const response = await fetch(url.href, {
|
|
3580
3582
|
referrerPolicy: this._options.referrerPolicy,
|
|
3581
3583
|
signal: controller.signal
|
|
3582
3584
|
}).finally(() => clearTimeout(timeoutId));
|
|
@@ -3701,6 +3703,7 @@ var Negotiator = class {
|
|
|
3701
3703
|
}
|
|
3702
3704
|
connection;
|
|
3703
3705
|
_pendingCandidates = [];
|
|
3706
|
+
_iceCandidateFilter = null;
|
|
3704
3707
|
/** Returns a PeerConnection object set up correctly (for data, media). */
|
|
3705
3708
|
startConnection(options) {
|
|
3706
3709
|
const peerConnection = this._startPeerConnection();
|
|
@@ -3723,6 +3726,13 @@ var Negotiator = class {
|
|
|
3723
3726
|
_startPeerConnection() {
|
|
3724
3727
|
logger_default.log("Creating RTCPeerConnection.");
|
|
3725
3728
|
const peerConnection = new RTCPeerConnection(this.connection.provider?.options.config);
|
|
3729
|
+
if (this.connection.provider?.options.ipPolicy === "public") {
|
|
3730
|
+
const isPublicCandidate = (c) => {
|
|
3731
|
+
const sdp2 = c.candidate ?? "";
|
|
3732
|
+
return !sdp2.includes("typ host");
|
|
3733
|
+
};
|
|
3734
|
+
this._iceCandidateFilter = isPublicCandidate;
|
|
3735
|
+
}
|
|
3726
3736
|
this._setupListeners(peerConnection);
|
|
3727
3737
|
return peerConnection;
|
|
3728
3738
|
}
|
|
@@ -3735,6 +3745,9 @@ var Negotiator = class {
|
|
|
3735
3745
|
logger_default.log("Listening for ICE candidates.");
|
|
3736
3746
|
peerConnection.onicecandidate = (evt) => {
|
|
3737
3747
|
if (!evt.candidate?.candidate) return;
|
|
3748
|
+
if (this._iceCandidateFilter && !this._iceCandidateFilter(evt.candidate)) {
|
|
3749
|
+
return;
|
|
3750
|
+
}
|
|
3738
3751
|
logger_default.log(`Received ICE candidates for ${peerId}:`, evt.candidate);
|
|
3739
3752
|
provider.socket.send({
|
|
3740
3753
|
type: "CANDIDATE" /* Candidate */,
|
|
@@ -4073,6 +4086,7 @@ var DataConnection = class _DataConnection extends BaseConnection {
|
|
|
4073
4086
|
this.dataChannel.onopen = () => {
|
|
4074
4087
|
logger_default.log(`DC#${this.connectionId} dc connection success`);
|
|
4075
4088
|
this._open = true;
|
|
4089
|
+
this._applyAdaptiveBuffer(dc);
|
|
4076
4090
|
this.emit("open");
|
|
4077
4091
|
};
|
|
4078
4092
|
this.dataChannel.onclose = () => {
|
|
@@ -4080,6 +4094,24 @@ var DataConnection = class _DataConnection extends BaseConnection {
|
|
|
4080
4094
|
this.close();
|
|
4081
4095
|
};
|
|
4082
4096
|
}
|
|
4097
|
+
_applyAdaptiveBuffer(dc) {
|
|
4098
|
+
const pc = this.peerConnection;
|
|
4099
|
+
if (!pc || typeof pc.getStats !== "function") return;
|
|
4100
|
+
pc.getStats().then((stats) => {
|
|
4101
|
+
let rtt = null;
|
|
4102
|
+
stats.forEach((report) => {
|
|
4103
|
+
if (report.type === "candidate-pair" && report.state === "succeeded" && report.currentRoundTripTime) {
|
|
4104
|
+
rtt = report.currentRoundTripTime * 1e3;
|
|
4105
|
+
}
|
|
4106
|
+
});
|
|
4107
|
+
if (rtt !== null) {
|
|
4108
|
+
const bdp = 12.5 * 1024 * 1024 * (rtt / 1e3);
|
|
4109
|
+
const optimal = Math.max(1 * 1024 * 1024, Math.min(32 * 1024 * 1024, Math.ceil(bdp)));
|
|
4110
|
+
dc.bufferedAmountLowThreshold = optimal;
|
|
4111
|
+
}
|
|
4112
|
+
}).catch(() => {
|
|
4113
|
+
});
|
|
4114
|
+
}
|
|
4083
4115
|
/**
|
|
4084
4116
|
* Exposed functionality for users.
|
|
4085
4117
|
*/
|
|
@@ -4614,7 +4646,17 @@ var HybridConnection = class extends import_eventemitter32.EventEmitter {
|
|
|
4614
4646
|
if (this._closed) {
|
|
4615
4647
|
return;
|
|
4616
4648
|
}
|
|
4617
|
-
|
|
4649
|
+
logger_default.log(
|
|
4650
|
+
`HybridConnection: start peer=${this.peer} iceTimeout=${this._options.iceTimeout ?? 1e4}ms encryptRelay=${this._encryptRelay}`
|
|
4651
|
+
);
|
|
4652
|
+
if (typeof this._provider?.on !== "function") {
|
|
4653
|
+
this._attemptWebRTC();
|
|
4654
|
+
return;
|
|
4655
|
+
}
|
|
4656
|
+
this._tryConnectionReversal().then((direct) => {
|
|
4657
|
+
if (direct) return;
|
|
4658
|
+
this._attemptWebRTC();
|
|
4659
|
+
});
|
|
4618
4660
|
}
|
|
4619
4661
|
/** Send data through the best available transport, optionally tagged with a topic. */
|
|
4620
4662
|
send(data, options) {
|
|
@@ -4904,10 +4946,16 @@ var HybridConnection = class extends import_eventemitter32.EventEmitter {
|
|
|
4904
4946
|
this._dataConnection = dc;
|
|
4905
4947
|
this._iceTimer = setTimeout(() => {
|
|
4906
4948
|
if (this._mode !== "webrtc" /* WebRTC */) {
|
|
4949
|
+
logger_default.warn(
|
|
4950
|
+
`HybridConnection: ICE timeout after ${iceTimeout}ms for ${this.peer}, falling back to relay`
|
|
4951
|
+
);
|
|
4907
4952
|
this._fallbackToRelay();
|
|
4908
4953
|
}
|
|
4909
4954
|
}, iceTimeout);
|
|
4910
4955
|
this._dataConnection.on("open", () => {
|
|
4956
|
+
logger_default.log(
|
|
4957
|
+
`HybridConnection: WebRTC opened to ${this.peer} (attempt ${this._upgradeAttempts + 1})`
|
|
4958
|
+
);
|
|
4911
4959
|
this._clearIceTimer();
|
|
4912
4960
|
this._clearUpgradeTimer();
|
|
4913
4961
|
this._upgradeAttempts = 0;
|
|
@@ -4948,6 +4996,7 @@ var HybridConnection = class extends import_eventemitter32.EventEmitter {
|
|
|
4948
4996
|
/** Update the transport mode and emit if changed. */
|
|
4949
4997
|
_setMode(mode) {
|
|
4950
4998
|
if (this._mode !== mode) {
|
|
4999
|
+
logger_default.log(`HybridConnection: transport ${this._mode} -> ${mode} for ${this.peer}`);
|
|
4951
5000
|
this._mode = mode;
|
|
4952
5001
|
this.emit("transportChanged", mode);
|
|
4953
5002
|
}
|
|
@@ -4988,6 +5037,117 @@ var HybridConnection = class extends import_eventemitter32.EventEmitter {
|
|
|
4988
5037
|
this._attemptWebRTC();
|
|
4989
5038
|
}, interval);
|
|
4990
5039
|
}
|
|
5040
|
+
async _tryConnectionReversal() {
|
|
5041
|
+
if (typeof this._provider?.on !== "function") return false;
|
|
5042
|
+
try {
|
|
5043
|
+
const resp = await new Promise((resolve, reject) => {
|
|
5044
|
+
const timer = setTimeout(() => reject(new Error("timeout")), 3e3);
|
|
5045
|
+
const handler = (data) => {
|
|
5046
|
+
clearTimeout(timer);
|
|
5047
|
+
this._provider.off("CONNECT-REQUEST" /* ConnectRequest */, handler);
|
|
5048
|
+
resolve(data);
|
|
5049
|
+
};
|
|
5050
|
+
this._provider.on("CONNECT-REQUEST" /* ConnectRequest */, handler);
|
|
5051
|
+
this._provider.socket.send({
|
|
5052
|
+
type: "CONNECT-REQUEST" /* ConnectRequest */,
|
|
5053
|
+
payload: { peer: this.peer }
|
|
5054
|
+
});
|
|
5055
|
+
});
|
|
5056
|
+
const addr = resp?.address;
|
|
5057
|
+
if (!addr) return false;
|
|
5058
|
+
const pc = new RTCPeerConnection(this._provider.options.config);
|
|
5059
|
+
const dc = pc.createDataChannel("probe", { id: 0 });
|
|
5060
|
+
await new Promise((resolve, reject) => {
|
|
5061
|
+
const timer = setTimeout(() => {
|
|
5062
|
+
pc.close();
|
|
5063
|
+
reject(new Error("direct-dial-timeout"));
|
|
5064
|
+
}, 2500);
|
|
5065
|
+
dc.onopen = () => {
|
|
5066
|
+
clearTimeout(timer);
|
|
5067
|
+
resolve();
|
|
5068
|
+
};
|
|
5069
|
+
dc.onerror = () => {
|
|
5070
|
+
clearTimeout(timer);
|
|
5071
|
+
pc.close();
|
|
5072
|
+
reject(new Error("dc-error"));
|
|
5073
|
+
};
|
|
5074
|
+
});
|
|
5075
|
+
this._dataConnection = void 0;
|
|
5076
|
+
this._setMode("webrtc" /* WebRTC */);
|
|
5077
|
+
pc.close();
|
|
5078
|
+
return true;
|
|
5079
|
+
} catch {
|
|
5080
|
+
return false;
|
|
5081
|
+
}
|
|
5082
|
+
}
|
|
5083
|
+
async _gatherSrflxCandidates() {
|
|
5084
|
+
const pc = new RTCPeerConnection({ iceServers: this._provider.options.config?.iceServers });
|
|
5085
|
+
pc.createDataChannel("probe");
|
|
5086
|
+
const offer = await pc.createOffer();
|
|
5087
|
+
await pc.setLocalDescription(offer);
|
|
5088
|
+
const candidates = [];
|
|
5089
|
+
await new Promise((resolve) => {
|
|
5090
|
+
const timer = setTimeout(resolve, 2e3);
|
|
5091
|
+
pc.onicecandidate = (evt) => {
|
|
5092
|
+
if (!evt.candidate) {
|
|
5093
|
+
clearTimeout(timer);
|
|
5094
|
+
resolve();
|
|
5095
|
+
return;
|
|
5096
|
+
}
|
|
5097
|
+
if (!evt.candidate.candidate.includes("typ host")) {
|
|
5098
|
+
candidates.push(evt.candidate.candidate);
|
|
5099
|
+
}
|
|
5100
|
+
};
|
|
5101
|
+
});
|
|
5102
|
+
pc.close();
|
|
5103
|
+
return candidates;
|
|
5104
|
+
}
|
|
5105
|
+
async _dcutrHolePunch() {
|
|
5106
|
+
try {
|
|
5107
|
+
const localAddrs = await this._gatherSrflxCandidates();
|
|
5108
|
+
const t0 = performance.now();
|
|
5109
|
+
const peerAddrs = await new Promise((resolve, reject) => {
|
|
5110
|
+
const timer = setTimeout(() => reject(new Error("dcutr-timeout")), 8e3);
|
|
5111
|
+
const handler = (data) => {
|
|
5112
|
+
clearTimeout(timer);
|
|
5113
|
+
this._provider.off("DCUTR-CONNECT" /* DcutrConnect */, handler);
|
|
5114
|
+
resolve(data?.addresses ?? []);
|
|
5115
|
+
};
|
|
5116
|
+
this._provider.on("DCUTR-CONNECT" /* DcutrConnect */, handler);
|
|
5117
|
+
this._provider.socket.send({
|
|
5118
|
+
type: "DCUTR-CONNECT" /* DcutrConnect */,
|
|
5119
|
+
payload: { addresses: localAddrs }
|
|
5120
|
+
});
|
|
5121
|
+
});
|
|
5122
|
+
const relayRtt = performance.now() - t0;
|
|
5123
|
+
this._provider.socket.send({ type: "DCUTR-SYNC" /* DcutrSync */, payload: {} });
|
|
5124
|
+
await new Promise((r) => setTimeout(r, relayRtt / 2));
|
|
5125
|
+
for (let i = 0; i < Math.min(peerAddrs.length, 4); i++) {
|
|
5126
|
+
try {
|
|
5127
|
+
const pc = new RTCPeerConnection(this._provider.options.config);
|
|
5128
|
+
await new Promise((resolve, reject) => {
|
|
5129
|
+
const timer = setTimeout(() => {
|
|
5130
|
+
pc.close();
|
|
5131
|
+
reject(new Error("dc-dial-timeout"));
|
|
5132
|
+
}, 5e3);
|
|
5133
|
+
const dc = pc.createDataChannel("dcutr");
|
|
5134
|
+
dc.onopen = () => {
|
|
5135
|
+
clearTimeout(timer);
|
|
5136
|
+
resolve();
|
|
5137
|
+
};
|
|
5138
|
+
});
|
|
5139
|
+
this._dataConnection = void 0;
|
|
5140
|
+
this._setMode("webrtc" /* WebRTC */);
|
|
5141
|
+
pc.close();
|
|
5142
|
+
return true;
|
|
5143
|
+
} catch {
|
|
5144
|
+
}
|
|
5145
|
+
}
|
|
5146
|
+
return false;
|
|
5147
|
+
} catch {
|
|
5148
|
+
return false;
|
|
5149
|
+
}
|
|
5150
|
+
}
|
|
4991
5151
|
};
|
|
4992
5152
|
|
|
4993
5153
|
// src/mediaconnection.ts
|
|
@@ -5144,17 +5304,29 @@ var PollingTransport = class _PollingTransport extends SignalingTransport {
|
|
|
5144
5304
|
_heartbeatTimer;
|
|
5145
5305
|
_lastSeq = 0;
|
|
5146
5306
|
_baseUrl;
|
|
5307
|
+
_key;
|
|
5308
|
+
_jwt;
|
|
5309
|
+
_apiKey;
|
|
5147
5310
|
_pingInterval;
|
|
5148
5311
|
_abortController;
|
|
5149
5312
|
/** Backoff schedule base delays in milliseconds. */
|
|
5150
5313
|
static BACKOFF_SCHEDULE = [0, 1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
|
|
5151
5314
|
/** Random jitter range in milliseconds (applied as +/-). */
|
|
5152
5315
|
static BACKOFF_JITTER = 500;
|
|
5153
|
-
constructor(secure, host, port, path,
|
|
5316
|
+
constructor(secure, host, port, path, key, pingInterval = 5e3, jwt, apiKey) {
|
|
5154
5317
|
super();
|
|
5155
5318
|
const protocol = secure ? "https://" : "http://";
|
|
5156
5319
|
this._baseUrl = `${protocol + host}:${port}${path}`;
|
|
5157
5320
|
this._pingInterval = pingInterval;
|
|
5321
|
+
this._key = key;
|
|
5322
|
+
this._jwt = jwt;
|
|
5323
|
+
this._apiKey = apiKey;
|
|
5324
|
+
}
|
|
5325
|
+
/** Append the shared auth params (key, jwt, api_key) so every HTTP call authenticates like the WS transport. */
|
|
5326
|
+
_applyAuthParams(params) {
|
|
5327
|
+
params.set("key", this._key);
|
|
5328
|
+
if (this._jwt) params.set("jwt", this._jwt);
|
|
5329
|
+
if (this._apiKey) params.set("api_key", this._apiKey);
|
|
5158
5330
|
}
|
|
5159
5331
|
get reconnectAttempt() {
|
|
5160
5332
|
return this._reconnectAttempt;
|
|
@@ -5182,6 +5354,7 @@ var PollingTransport = class _PollingTransport extends SignalingTransport {
|
|
|
5182
5354
|
id: this._id,
|
|
5183
5355
|
token: this._token
|
|
5184
5356
|
});
|
|
5357
|
+
this._applyAuthParams(params);
|
|
5185
5358
|
if (this._lastSeq > 0) params.set("last_seq", String(this._lastSeq));
|
|
5186
5359
|
const response = await fetch(`${this._baseUrl}http/poll?${params}`, {
|
|
5187
5360
|
signal: this._abortController.signal
|
|
@@ -5220,6 +5393,7 @@ var PollingTransport = class _PollingTransport extends SignalingTransport {
|
|
|
5220
5393
|
id: this._id,
|
|
5221
5394
|
token: this._token
|
|
5222
5395
|
});
|
|
5396
|
+
this._applyAuthParams(params);
|
|
5223
5397
|
try {
|
|
5224
5398
|
await fetch(`${this._baseUrl}http/send?${params}`, {
|
|
5225
5399
|
method: "POST",
|
|
@@ -5284,13 +5458,16 @@ var PollingTransport = class _PollingTransport extends SignalingTransport {
|
|
|
5284
5458
|
};
|
|
5285
5459
|
|
|
5286
5460
|
// src/socket.ts
|
|
5287
|
-
var version2 = "2.
|
|
5461
|
+
var version2 = "2.5.0";
|
|
5288
5462
|
var Socket = class _Socket extends SignalingTransport {
|
|
5289
|
-
constructor(secure, host, port, path, key, pingInterval = 5e3, jwt) {
|
|
5463
|
+
constructor(secure, host, port, path, key, pingInterval = 5e3, jwt, apiKey) {
|
|
5290
5464
|
super();
|
|
5291
5465
|
this.pingInterval = pingInterval;
|
|
5292
5466
|
const wsProtocol = secure ? "wss://" : "ws://";
|
|
5293
5467
|
this._baseUrl = `${wsProtocol + host}:${port}${path}dendri?key=${key}`;
|
|
5468
|
+
if (apiKey) {
|
|
5469
|
+
this._baseUrl += `&api_key=${encodeURIComponent(apiKey)}`;
|
|
5470
|
+
}
|
|
5294
5471
|
this._jwt = jwt;
|
|
5295
5472
|
}
|
|
5296
5473
|
pingInterval;
|
|
@@ -5326,7 +5503,7 @@ var Socket = class _Socket extends SignalingTransport {
|
|
|
5326
5503
|
if (this._jwt) {
|
|
5327
5504
|
wsUrl += `&jwt=${encodeURIComponent(this._jwt)}`;
|
|
5328
5505
|
}
|
|
5329
|
-
if (
|
|
5506
|
+
if (this._socket || !this._disconnected) {
|
|
5330
5507
|
return;
|
|
5331
5508
|
}
|
|
5332
5509
|
this._socket = new WebSocket(`${wsUrl}&version=${version2}`);
|
|
@@ -5596,18 +5773,28 @@ var SSETransport = class _SSETransport extends SignalingTransport {
|
|
|
5596
5773
|
_heartbeatTimer;
|
|
5597
5774
|
_lastSeq = 0;
|
|
5598
5775
|
_baseUrl;
|
|
5776
|
+
_key;
|
|
5599
5777
|
_jwt;
|
|
5778
|
+
_apiKey;
|
|
5600
5779
|
_pingInterval;
|
|
5601
5780
|
/** Backoff schedule base delays in milliseconds. */
|
|
5602
5781
|
static BACKOFF_SCHEDULE = [0, 1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
|
|
5603
5782
|
/** Random jitter range in milliseconds (applied as +/-). */
|
|
5604
5783
|
static BACKOFF_JITTER = 500;
|
|
5605
|
-
constructor(secure, host, port, path,
|
|
5784
|
+
constructor(secure, host, port, path, key, pingInterval = 5e3, jwt, apiKey) {
|
|
5606
5785
|
super();
|
|
5607
5786
|
const protocol = secure ? "https://" : "http://";
|
|
5608
5787
|
this._baseUrl = `${protocol + host}:${port}${path}`;
|
|
5609
5788
|
this._pingInterval = pingInterval;
|
|
5789
|
+
this._key = key;
|
|
5610
5790
|
this._jwt = jwt;
|
|
5791
|
+
this._apiKey = apiKey;
|
|
5792
|
+
}
|
|
5793
|
+
/** Append the shared auth params (key, jwt, api_key) so every HTTP call authenticates like the WS transport. */
|
|
5794
|
+
_applyAuthParams(params) {
|
|
5795
|
+
params.set("key", this._key);
|
|
5796
|
+
if (this._jwt) params.set("jwt", this._jwt);
|
|
5797
|
+
if (this._apiKey) params.set("api_key", this._apiKey);
|
|
5611
5798
|
}
|
|
5612
5799
|
get reconnectAttempt() {
|
|
5613
5800
|
return this._reconnectAttempt;
|
|
@@ -5625,10 +5812,9 @@ var SSETransport = class _SSETransport extends SignalingTransport {
|
|
|
5625
5812
|
if (this._disconnected) return;
|
|
5626
5813
|
const params = new URLSearchParams({
|
|
5627
5814
|
id: this._id,
|
|
5628
|
-
token: this._token
|
|
5629
|
-
key: "dendri"
|
|
5815
|
+
token: this._token
|
|
5630
5816
|
});
|
|
5631
|
-
|
|
5817
|
+
this._applyAuthParams(params);
|
|
5632
5818
|
if (this._lastSeq > 0) params.set("last_seq", String(this._lastSeq));
|
|
5633
5819
|
const url = `${this._baseUrl}http/sse?${params}`;
|
|
5634
5820
|
try {
|
|
@@ -5702,6 +5888,7 @@ var SSETransport = class _SSETransport extends SignalingTransport {
|
|
|
5702
5888
|
id: this._id,
|
|
5703
5889
|
token: this._token
|
|
5704
5890
|
});
|
|
5891
|
+
this._applyAuthParams(params);
|
|
5705
5892
|
try {
|
|
5706
5893
|
await fetch(`${this._baseUrl}http/send?${params}`, {
|
|
5707
5894
|
method: "POST",
|
|
@@ -5774,6 +5961,28 @@ var SSETransport = class _SSETransport extends SignalingTransport {
|
|
|
5774
5961
|
};
|
|
5775
5962
|
|
|
5776
5963
|
// src/dendri.ts
|
|
5964
|
+
function parseServerUrl(url) {
|
|
5965
|
+
let parsed;
|
|
5966
|
+
try {
|
|
5967
|
+
parsed = new URL(url);
|
|
5968
|
+
} catch {
|
|
5969
|
+
throw new Error(
|
|
5970
|
+
`Invalid Dendri "url" option: "${url}". Expected a full URL like "wss://signal.example.com".`
|
|
5971
|
+
);
|
|
5972
|
+
}
|
|
5973
|
+
const secure = parsed.protocol === "wss:" || parsed.protocol === "https:";
|
|
5974
|
+
if (!secure && parsed.protocol !== "ws:" && parsed.protocol !== "http:") {
|
|
5975
|
+
throw new Error(
|
|
5976
|
+
`Invalid Dendri "url" protocol: "${parsed.protocol}". Use wss://, ws://, https://, or http://.`
|
|
5977
|
+
);
|
|
5978
|
+
}
|
|
5979
|
+
return {
|
|
5980
|
+
host: parsed.hostname,
|
|
5981
|
+
port: parsed.port ? Number(parsed.port) : secure ? 443 : 80,
|
|
5982
|
+
secure,
|
|
5983
|
+
path: parsed.pathname || "/"
|
|
5984
|
+
};
|
|
5985
|
+
}
|
|
5777
5986
|
var Dendri = class _Dendri extends EventEmitterWithError {
|
|
5778
5987
|
static DEFAULT_KEY = "dendri";
|
|
5779
5988
|
_serializers = {
|
|
@@ -5864,6 +6073,9 @@ var Dendri = class _Dendri extends EventEmitterWithError {
|
|
|
5864
6073
|
} else if (id) {
|
|
5865
6074
|
userId = id.toString();
|
|
5866
6075
|
}
|
|
6076
|
+
if (providedOptions?.url) {
|
|
6077
|
+
providedOptions = { ...parseServerUrl(providedOptions.url), ...providedOptions };
|
|
6078
|
+
}
|
|
5867
6079
|
const normalizedOptions = {
|
|
5868
6080
|
debug: 0,
|
|
5869
6081
|
// 1: Errors, 2: Warnings, 3: All logs
|
|
@@ -5917,7 +6129,7 @@ var Dendri = class _Dendri extends EventEmitterWithError {
|
|
|
5917
6129
|
return;
|
|
5918
6130
|
}
|
|
5919
6131
|
}
|
|
5920
|
-
if (
|
|
6132
|
+
if (userId && !util.validateId(userId)) {
|
|
5921
6133
|
this._delayedAbort("invalid-id" /* InvalidID */, `ID "${userId}" is invalid`);
|
|
5922
6134
|
return;
|
|
5923
6135
|
}
|
|
@@ -5982,7 +6194,8 @@ var Dendri = class _Dendri extends EventEmitterWithError {
|
|
|
5982
6194
|
this._options.path,
|
|
5983
6195
|
this._options.key,
|
|
5984
6196
|
this._options.pingInterval,
|
|
5985
|
-
this._options.jwt
|
|
6197
|
+
this._options.jwt,
|
|
6198
|
+
this._options.apiKey
|
|
5986
6199
|
) : transport === "polling" ? new PollingTransport(
|
|
5987
6200
|
this._options.secure ?? false,
|
|
5988
6201
|
this._options.host,
|
|
@@ -5990,7 +6203,8 @@ var Dendri = class _Dendri extends EventEmitterWithError {
|
|
|
5990
6203
|
this._options.path,
|
|
5991
6204
|
this._options.key,
|
|
5992
6205
|
this._options.pingInterval,
|
|
5993
|
-
this._options.jwt
|
|
6206
|
+
this._options.jwt,
|
|
6207
|
+
this._options.apiKey
|
|
5994
6208
|
) : new Socket(
|
|
5995
6209
|
this._options.secure ?? false,
|
|
5996
6210
|
this._options.host,
|
|
@@ -5998,7 +6212,8 @@ var Dendri = class _Dendri extends EventEmitterWithError {
|
|
|
5998
6212
|
this._options.path,
|
|
5999
6213
|
this._options.key,
|
|
6000
6214
|
this._options.pingInterval,
|
|
6001
|
-
this._options.jwt
|
|
6215
|
+
this._options.jwt,
|
|
6216
|
+
this._options.apiKey
|
|
6002
6217
|
);
|
|
6003
6218
|
socket.on("message" /* Message */, (data) => {
|
|
6004
6219
|
this._handleMessage(data);
|
|
@@ -6830,7 +7045,13 @@ var Room = class extends import_eventemitter35.EventEmitter {
|
|
|
6830
7045
|
sentViaWebRTC = true;
|
|
6831
7046
|
}
|
|
6832
7047
|
}
|
|
6833
|
-
if (
|
|
7048
|
+
if (this._dendriOptions?.enableRelay && this._peer?.socket) {
|
|
7049
|
+
this._peer.socket.send({
|
|
7050
|
+
type: "DATA" /* Data */,
|
|
7051
|
+
room: this._roomId,
|
|
7052
|
+
payload: wire
|
|
7053
|
+
});
|
|
7054
|
+
} else if (!sentViaWebRTC && this._peer?.socket) {
|
|
6834
7055
|
this._peer.socket.send({
|
|
6835
7056
|
type: "DATA" /* Data */,
|
|
6836
7057
|
room: this._roomId,
|
|
@@ -6864,7 +7085,13 @@ var Room = class extends import_eventemitter35.EventEmitter {
|
|
|
6864
7085
|
sentViaWebRTC = true;
|
|
6865
7086
|
}
|
|
6866
7087
|
}
|
|
6867
|
-
if (
|
|
7088
|
+
if (this._dendriOptions?.enableRelay && this._peer?.socket) {
|
|
7089
|
+
this._peer.socket.send({
|
|
7090
|
+
type: "DATA" /* Data */,
|
|
7091
|
+
room: this._roomId,
|
|
7092
|
+
payload: wire
|
|
7093
|
+
});
|
|
7094
|
+
} else if (!sentViaWebRTC && this._peer?.socket) {
|
|
6868
7095
|
this._peer.socket.send({
|
|
6869
7096
|
type: "DATA" /* Data */,
|
|
6870
7097
|
room: this._roomId,
|
|
@@ -7055,8 +7282,8 @@ var Room = class extends import_eventemitter35.EventEmitter {
|
|
|
7055
7282
|
const remotePeerId = conn.peer;
|
|
7056
7283
|
this._connections.set(remotePeerId, conn);
|
|
7057
7284
|
this._knownPeers.add(remotePeerId);
|
|
7285
|
+
this.emit("peerJoined", remotePeerId);
|
|
7058
7286
|
conn.on("open", () => {
|
|
7059
|
-
this.emit("peerJoined", remotePeerId);
|
|
7060
7287
|
for (const [peerId, c] of this._connections) {
|
|
7061
7288
|
if (peerId !== remotePeerId && c.open) {
|
|
7062
7289
|
c.send({ __room: { type: "peer-joined", peerId: remotePeerId } });
|
|
@@ -7378,6 +7605,14 @@ var Room = class extends import_eventemitter35.EventEmitter {
|
|
|
7378
7605
|
const conn = this._connections.get(peerId);
|
|
7379
7606
|
if (conn?.open) {
|
|
7380
7607
|
conn.send(data);
|
|
7608
|
+
if (this._dendriOptions?.enableRelay && this._peer?.socket) {
|
|
7609
|
+
this._peer.socket.send({
|
|
7610
|
+
type: "DATA" /* Data */,
|
|
7611
|
+
dst: peerId,
|
|
7612
|
+
room: this._roomId,
|
|
7613
|
+
payload: data
|
|
7614
|
+
});
|
|
7615
|
+
}
|
|
7381
7616
|
return;
|
|
7382
7617
|
}
|
|
7383
7618
|
if (!this._isHost && this._hostId) {
|