@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.
@@ -3529,7 +3529,7 @@ var Util = class extends BinaryPackChunker {
3529
3529
  var util = new Util();
3530
3530
 
3531
3531
  // src/api.ts
3532
- var version = "2.3.7";
3532
+ var version = "2.5.0";
3533
3533
  var API = class _API {
3534
3534
  constructor(_options) {
3535
3535
  this._options = _options;
@@ -3542,6 +3542,7 @@ var API = class _API {
3542
3542
  const url = new URL(`${protocol}://${host}:${port}${path}${key}/${method}`);
3543
3543
  url.searchParams.set("ts", `${Date.now()}${Math.random()}`);
3544
3544
  url.searchParams.set("version", version);
3545
+ if (this._options.apiKey) url.searchParams.set("api_key", this._options.apiKey);
3545
3546
  const controller = new AbortController();
3546
3547
  const timeoutId = setTimeout(() => controller.abort(), _API.FETCH_TIMEOUT);
3547
3548
  return fetch(url.href, {
@@ -3566,15 +3567,16 @@ var API = class _API {
3566
3567
  throw new Error(`Could not get an ID from the server.${pathError}`);
3567
3568
  }
3568
3569
  }
3569
- /** Fetch TURN credentials from the signaling server's GET /turn endpoint. */
3570
+ /** Fetch TURN credentials from the signaling server's turn-credentials endpoint. */
3570
3571
  async getTurnCredentials() {
3571
3572
  const protocol = this._options.secure ? "https" : "http";
3572
- const { host, port } = this._options;
3573
- const url = `${protocol}://${host}:${port}/turn`;
3573
+ const { host, port, path, key } = this._options;
3574
+ const url = new URL(`${protocol}://${host}:${port}${path}${key}/turn-credentials`);
3575
+ if (this._options.apiKey) url.searchParams.set("api_key", this._options.apiKey);
3574
3576
  try {
3575
3577
  const controller = new AbortController();
3576
3578
  const timeoutId = setTimeout(() => controller.abort(), _API.FETCH_TIMEOUT);
3577
- const response = await fetch(url, {
3579
+ const response = await fetch(url.href, {
3578
3580
  referrerPolicy: this._options.referrerPolicy,
3579
3581
  signal: controller.signal
3580
3582
  }).finally(() => clearTimeout(timeoutId));
@@ -3679,6 +3681,9 @@ var ServerMessageType = /* @__PURE__ */ ((ServerMessageType2) => {
3679
3681
  ServerMessageType2["HostMigrate"] = "HOST-MIGRATE";
3680
3682
  ServerMessageType2["PresenceUpdate"] = "PRESENCE-UPDATE";
3681
3683
  ServerMessageType2["KeyExchange"] = "KEY-EXCHANGE";
3684
+ ServerMessageType2["ConnectRequest"] = "CONNECT-REQUEST";
3685
+ ServerMessageType2["DcutrConnect"] = "DCUTR-CONNECT";
3686
+ ServerMessageType2["DcutrSync"] = "DCUTR-SYNC";
3682
3687
  return ServerMessageType2;
3683
3688
  })(ServerMessageType || {});
3684
3689
  var TransportMode = /* @__PURE__ */ ((TransportMode2) => {
@@ -3704,6 +3709,11 @@ var ConnectionQuality = /* @__PURE__ */ ((ConnectionQuality2) => {
3704
3709
  ConnectionQuality2["Unknown"] = "unknown";
3705
3710
  return ConnectionQuality2;
3706
3711
  })(ConnectionQuality || {});
3712
+ var TopicClass = /* @__PURE__ */ ((TopicClass2) => {
3713
+ TopicClass2["Persistent"] = "persistent";
3714
+ TopicClass2["Ephemeral"] = "ephemeral";
3715
+ return TopicClass2;
3716
+ })(TopicClass || {});
3707
3717
 
3708
3718
  // src/dendriError.ts
3709
3719
  var import_eventemitter3 = __toESM(require_eventemitter3(), 1);
@@ -3792,6 +3802,7 @@ var Negotiator = class {
3792
3802
  }
3793
3803
  connection;
3794
3804
  _pendingCandidates = [];
3805
+ _iceCandidateFilter = null;
3795
3806
  /** Returns a PeerConnection object set up correctly (for data, media). */
3796
3807
  startConnection(options) {
3797
3808
  const peerConnection = this._startPeerConnection();
@@ -3814,6 +3825,13 @@ var Negotiator = class {
3814
3825
  _startPeerConnection() {
3815
3826
  logger_default.log("Creating RTCPeerConnection.");
3816
3827
  const peerConnection = new RTCPeerConnection(this.connection.provider?.options.config);
3828
+ if (this.connection.provider?.options.ipPolicy === "public") {
3829
+ const isPublicCandidate = (c) => {
3830
+ const sdp2 = c.candidate ?? "";
3831
+ return !sdp2.includes("typ host");
3832
+ };
3833
+ this._iceCandidateFilter = isPublicCandidate;
3834
+ }
3817
3835
  this._setupListeners(peerConnection);
3818
3836
  return peerConnection;
3819
3837
  }
@@ -3826,6 +3844,9 @@ var Negotiator = class {
3826
3844
  logger_default.log("Listening for ICE candidates.");
3827
3845
  peerConnection.onicecandidate = (evt) => {
3828
3846
  if (!evt.candidate?.candidate) return;
3847
+ if (this._iceCandidateFilter && !this._iceCandidateFilter(evt.candidate)) {
3848
+ return;
3849
+ }
3829
3850
  logger_default.log(`Received ICE candidates for ${peerId}:`, evt.candidate);
3830
3851
  provider.socket.send({
3831
3852
  type: "CANDIDATE" /* Candidate */,
@@ -4164,6 +4185,7 @@ var DataConnection = class _DataConnection extends BaseConnection {
4164
4185
  this.dataChannel.onopen = () => {
4165
4186
  logger_default.log(`DC#${this.connectionId} dc connection success`);
4166
4187
  this._open = true;
4188
+ this._applyAdaptiveBuffer(dc);
4167
4189
  this.emit("open");
4168
4190
  };
4169
4191
  this.dataChannel.onclose = () => {
@@ -4171,6 +4193,24 @@ var DataConnection = class _DataConnection extends BaseConnection {
4171
4193
  this.close();
4172
4194
  };
4173
4195
  }
4196
+ _applyAdaptiveBuffer(dc) {
4197
+ const pc = this.peerConnection;
4198
+ if (!pc || typeof pc.getStats !== "function") return;
4199
+ pc.getStats().then((stats) => {
4200
+ let rtt = null;
4201
+ stats.forEach((report) => {
4202
+ if (report.type === "candidate-pair" && report.state === "succeeded" && report.currentRoundTripTime) {
4203
+ rtt = report.currentRoundTripTime * 1e3;
4204
+ }
4205
+ });
4206
+ if (rtt !== null) {
4207
+ const bdp = 12.5 * 1024 * 1024 * (rtt / 1e3);
4208
+ const optimal = Math.max(1 * 1024 * 1024, Math.min(32 * 1024 * 1024, Math.ceil(bdp)));
4209
+ dc.bufferedAmountLowThreshold = optimal;
4210
+ }
4211
+ }).catch(() => {
4212
+ });
4213
+ }
4174
4214
  /**
4175
4215
  * Exposed functionality for users.
4176
4216
  */
@@ -4705,7 +4745,17 @@ var HybridConnection = class extends import_eventemitter32.EventEmitter {
4705
4745
  if (this._closed) {
4706
4746
  return;
4707
4747
  }
4708
- this._attemptWebRTC();
4748
+ logger_default.log(
4749
+ `HybridConnection: start peer=${this.peer} iceTimeout=${this._options.iceTimeout ?? 1e4}ms encryptRelay=${this._encryptRelay}`
4750
+ );
4751
+ if (typeof this._provider?.on !== "function") {
4752
+ this._attemptWebRTC();
4753
+ return;
4754
+ }
4755
+ this._tryConnectionReversal().then((direct) => {
4756
+ if (direct) return;
4757
+ this._attemptWebRTC();
4758
+ });
4709
4759
  }
4710
4760
  /** Send data through the best available transport, optionally tagged with a topic. */
4711
4761
  send(data, options) {
@@ -4995,10 +5045,16 @@ var HybridConnection = class extends import_eventemitter32.EventEmitter {
4995
5045
  this._dataConnection = dc;
4996
5046
  this._iceTimer = setTimeout(() => {
4997
5047
  if (this._mode !== "webrtc" /* WebRTC */) {
5048
+ logger_default.warn(
5049
+ `HybridConnection: ICE timeout after ${iceTimeout}ms for ${this.peer}, falling back to relay`
5050
+ );
4998
5051
  this._fallbackToRelay();
4999
5052
  }
5000
5053
  }, iceTimeout);
5001
5054
  this._dataConnection.on("open", () => {
5055
+ logger_default.log(
5056
+ `HybridConnection: WebRTC opened to ${this.peer} (attempt ${this._upgradeAttempts + 1})`
5057
+ );
5002
5058
  this._clearIceTimer();
5003
5059
  this._clearUpgradeTimer();
5004
5060
  this._upgradeAttempts = 0;
@@ -5039,6 +5095,7 @@ var HybridConnection = class extends import_eventemitter32.EventEmitter {
5039
5095
  /** Update the transport mode and emit if changed. */
5040
5096
  _setMode(mode) {
5041
5097
  if (this._mode !== mode) {
5098
+ logger_default.log(`HybridConnection: transport ${this._mode} -> ${mode} for ${this.peer}`);
5042
5099
  this._mode = mode;
5043
5100
  this.emit("transportChanged", mode);
5044
5101
  }
@@ -5079,6 +5136,117 @@ var HybridConnection = class extends import_eventemitter32.EventEmitter {
5079
5136
  this._attemptWebRTC();
5080
5137
  }, interval);
5081
5138
  }
5139
+ async _tryConnectionReversal() {
5140
+ if (typeof this._provider?.on !== "function") return false;
5141
+ try {
5142
+ const resp = await new Promise((resolve, reject) => {
5143
+ const timer = setTimeout(() => reject(new Error("timeout")), 3e3);
5144
+ const handler = (data) => {
5145
+ clearTimeout(timer);
5146
+ this._provider.off("CONNECT-REQUEST" /* ConnectRequest */, handler);
5147
+ resolve(data);
5148
+ };
5149
+ this._provider.on("CONNECT-REQUEST" /* ConnectRequest */, handler);
5150
+ this._provider.socket.send({
5151
+ type: "CONNECT-REQUEST" /* ConnectRequest */,
5152
+ payload: { peer: this.peer }
5153
+ });
5154
+ });
5155
+ const addr = resp?.address;
5156
+ if (!addr) return false;
5157
+ const pc = new RTCPeerConnection(this._provider.options.config);
5158
+ const dc = pc.createDataChannel("probe", { id: 0 });
5159
+ await new Promise((resolve, reject) => {
5160
+ const timer = setTimeout(() => {
5161
+ pc.close();
5162
+ reject(new Error("direct-dial-timeout"));
5163
+ }, 2500);
5164
+ dc.onopen = () => {
5165
+ clearTimeout(timer);
5166
+ resolve();
5167
+ };
5168
+ dc.onerror = () => {
5169
+ clearTimeout(timer);
5170
+ pc.close();
5171
+ reject(new Error("dc-error"));
5172
+ };
5173
+ });
5174
+ this._dataConnection = void 0;
5175
+ this._setMode("webrtc" /* WebRTC */);
5176
+ pc.close();
5177
+ return true;
5178
+ } catch {
5179
+ return false;
5180
+ }
5181
+ }
5182
+ async _gatherSrflxCandidates() {
5183
+ const pc = new RTCPeerConnection({ iceServers: this._provider.options.config?.iceServers });
5184
+ pc.createDataChannel("probe");
5185
+ const offer = await pc.createOffer();
5186
+ await pc.setLocalDescription(offer);
5187
+ const candidates = [];
5188
+ await new Promise((resolve) => {
5189
+ const timer = setTimeout(resolve, 2e3);
5190
+ pc.onicecandidate = (evt) => {
5191
+ if (!evt.candidate) {
5192
+ clearTimeout(timer);
5193
+ resolve();
5194
+ return;
5195
+ }
5196
+ if (!evt.candidate.candidate.includes("typ host")) {
5197
+ candidates.push(evt.candidate.candidate);
5198
+ }
5199
+ };
5200
+ });
5201
+ pc.close();
5202
+ return candidates;
5203
+ }
5204
+ async _dcutrHolePunch() {
5205
+ try {
5206
+ const localAddrs = await this._gatherSrflxCandidates();
5207
+ const t0 = performance.now();
5208
+ const peerAddrs = await new Promise((resolve, reject) => {
5209
+ const timer = setTimeout(() => reject(new Error("dcutr-timeout")), 8e3);
5210
+ const handler = (data) => {
5211
+ clearTimeout(timer);
5212
+ this._provider.off("DCUTR-CONNECT" /* DcutrConnect */, handler);
5213
+ resolve(data?.addresses ?? []);
5214
+ };
5215
+ this._provider.on("DCUTR-CONNECT" /* DcutrConnect */, handler);
5216
+ this._provider.socket.send({
5217
+ type: "DCUTR-CONNECT" /* DcutrConnect */,
5218
+ payload: { addresses: localAddrs }
5219
+ });
5220
+ });
5221
+ const relayRtt = performance.now() - t0;
5222
+ this._provider.socket.send({ type: "DCUTR-SYNC" /* DcutrSync */, payload: {} });
5223
+ await new Promise((r) => setTimeout(r, relayRtt / 2));
5224
+ for (let i = 0; i < Math.min(peerAddrs.length, 4); i++) {
5225
+ try {
5226
+ const pc = new RTCPeerConnection(this._provider.options.config);
5227
+ await new Promise((resolve, reject) => {
5228
+ const timer = setTimeout(() => {
5229
+ pc.close();
5230
+ reject(new Error("dc-dial-timeout"));
5231
+ }, 5e3);
5232
+ const dc = pc.createDataChannel("dcutr");
5233
+ dc.onopen = () => {
5234
+ clearTimeout(timer);
5235
+ resolve();
5236
+ };
5237
+ });
5238
+ this._dataConnection = void 0;
5239
+ this._setMode("webrtc" /* WebRTC */);
5240
+ pc.close();
5241
+ return true;
5242
+ } catch {
5243
+ }
5244
+ }
5245
+ return false;
5246
+ } catch {
5247
+ return false;
5248
+ }
5249
+ }
5082
5250
  };
5083
5251
 
5084
5252
  // src/mediaconnection.ts
@@ -5235,17 +5403,29 @@ var PollingTransport = class _PollingTransport extends SignalingTransport {
5235
5403
  _heartbeatTimer;
5236
5404
  _lastSeq = 0;
5237
5405
  _baseUrl;
5406
+ _key;
5407
+ _jwt;
5408
+ _apiKey;
5238
5409
  _pingInterval;
5239
5410
  _abortController;
5240
5411
  /** Backoff schedule base delays in milliseconds. */
5241
5412
  static BACKOFF_SCHEDULE = [0, 1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
5242
5413
  /** Random jitter range in milliseconds (applied as +/-). */
5243
5414
  static BACKOFF_JITTER = 500;
5244
- constructor(secure, host, port, path, _key, pingInterval = 5e3, _jwt) {
5415
+ constructor(secure, host, port, path, key, pingInterval = 5e3, jwt, apiKey) {
5245
5416
  super();
5246
5417
  const protocol = secure ? "https://" : "http://";
5247
5418
  this._baseUrl = `${protocol + host}:${port}${path}`;
5248
5419
  this._pingInterval = pingInterval;
5420
+ this._key = key;
5421
+ this._jwt = jwt;
5422
+ this._apiKey = apiKey;
5423
+ }
5424
+ /** Append the shared auth params (key, jwt, api_key) so every HTTP call authenticates like the WS transport. */
5425
+ _applyAuthParams(params) {
5426
+ params.set("key", this._key);
5427
+ if (this._jwt) params.set("jwt", this._jwt);
5428
+ if (this._apiKey) params.set("api_key", this._apiKey);
5249
5429
  }
5250
5430
  get reconnectAttempt() {
5251
5431
  return this._reconnectAttempt;
@@ -5273,6 +5453,7 @@ var PollingTransport = class _PollingTransport extends SignalingTransport {
5273
5453
  id: this._id,
5274
5454
  token: this._token
5275
5455
  });
5456
+ this._applyAuthParams(params);
5276
5457
  if (this._lastSeq > 0) params.set("last_seq", String(this._lastSeq));
5277
5458
  const response = await fetch(`${this._baseUrl}http/poll?${params}`, {
5278
5459
  signal: this._abortController.signal
@@ -5311,6 +5492,7 @@ var PollingTransport = class _PollingTransport extends SignalingTransport {
5311
5492
  id: this._id,
5312
5493
  token: this._token
5313
5494
  });
5495
+ this._applyAuthParams(params);
5314
5496
  try {
5315
5497
  await fetch(`${this._baseUrl}http/send?${params}`, {
5316
5498
  method: "POST",
@@ -5375,13 +5557,16 @@ var PollingTransport = class _PollingTransport extends SignalingTransport {
5375
5557
  };
5376
5558
 
5377
5559
  // src/socket.ts
5378
- var version2 = "2.3.7";
5560
+ var version2 = "2.5.0";
5379
5561
  var Socket = class _Socket extends SignalingTransport {
5380
- constructor(secure, host, port, path, key, pingInterval = 5e3, jwt) {
5562
+ constructor(secure, host, port, path, key, pingInterval = 5e3, jwt, apiKey) {
5381
5563
  super();
5382
5564
  this.pingInterval = pingInterval;
5383
5565
  const wsProtocol = secure ? "wss://" : "ws://";
5384
5566
  this._baseUrl = `${wsProtocol + host}:${port}${path}dendri?key=${key}`;
5567
+ if (apiKey) {
5568
+ this._baseUrl += `&api_key=${encodeURIComponent(apiKey)}`;
5569
+ }
5385
5570
  this._jwt = jwt;
5386
5571
  }
5387
5572
  pingInterval;
@@ -5417,7 +5602,7 @@ var Socket = class _Socket extends SignalingTransport {
5417
5602
  if (this._jwt) {
5418
5603
  wsUrl += `&jwt=${encodeURIComponent(this._jwt)}`;
5419
5604
  }
5420
- if (!!this._socket || !this._disconnected) {
5605
+ if (this._socket || !this._disconnected) {
5421
5606
  return;
5422
5607
  }
5423
5608
  this._socket = new WebSocket(`${wsUrl}&version=${version2}`);
@@ -5687,18 +5872,28 @@ var SSETransport = class _SSETransport extends SignalingTransport {
5687
5872
  _heartbeatTimer;
5688
5873
  _lastSeq = 0;
5689
5874
  _baseUrl;
5875
+ _key;
5690
5876
  _jwt;
5877
+ _apiKey;
5691
5878
  _pingInterval;
5692
5879
  /** Backoff schedule base delays in milliseconds. */
5693
5880
  static BACKOFF_SCHEDULE = [0, 1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
5694
5881
  /** Random jitter range in milliseconds (applied as +/-). */
5695
5882
  static BACKOFF_JITTER = 500;
5696
- constructor(secure, host, port, path, _key, pingInterval = 5e3, jwt) {
5883
+ constructor(secure, host, port, path, key, pingInterval = 5e3, jwt, apiKey) {
5697
5884
  super();
5698
5885
  const protocol = secure ? "https://" : "http://";
5699
5886
  this._baseUrl = `${protocol + host}:${port}${path}`;
5700
5887
  this._pingInterval = pingInterval;
5888
+ this._key = key;
5701
5889
  this._jwt = jwt;
5890
+ this._apiKey = apiKey;
5891
+ }
5892
+ /** Append the shared auth params (key, jwt, api_key) so every HTTP call authenticates like the WS transport. */
5893
+ _applyAuthParams(params) {
5894
+ params.set("key", this._key);
5895
+ if (this._jwt) params.set("jwt", this._jwt);
5896
+ if (this._apiKey) params.set("api_key", this._apiKey);
5702
5897
  }
5703
5898
  get reconnectAttempt() {
5704
5899
  return this._reconnectAttempt;
@@ -5716,10 +5911,9 @@ var SSETransport = class _SSETransport extends SignalingTransport {
5716
5911
  if (this._disconnected) return;
5717
5912
  const params = new URLSearchParams({
5718
5913
  id: this._id,
5719
- token: this._token,
5720
- key: "dendri"
5914
+ token: this._token
5721
5915
  });
5722
- if (this._jwt) params.set("jwt", this._jwt);
5916
+ this._applyAuthParams(params);
5723
5917
  if (this._lastSeq > 0) params.set("last_seq", String(this._lastSeq));
5724
5918
  const url = `${this._baseUrl}http/sse?${params}`;
5725
5919
  try {
@@ -5793,6 +5987,7 @@ var SSETransport = class _SSETransport extends SignalingTransport {
5793
5987
  id: this._id,
5794
5988
  token: this._token
5795
5989
  });
5990
+ this._applyAuthParams(params);
5796
5991
  try {
5797
5992
  await fetch(`${this._baseUrl}http/send?${params}`, {
5798
5993
  method: "POST",
@@ -5865,6 +6060,28 @@ var SSETransport = class _SSETransport extends SignalingTransport {
5865
6060
  };
5866
6061
 
5867
6062
  // src/dendri.ts
6063
+ function parseServerUrl(url) {
6064
+ let parsed;
6065
+ try {
6066
+ parsed = new URL(url);
6067
+ } catch {
6068
+ throw new Error(
6069
+ `Invalid Dendri "url" option: "${url}". Expected a full URL like "wss://signal.example.com".`
6070
+ );
6071
+ }
6072
+ const secure = parsed.protocol === "wss:" || parsed.protocol === "https:";
6073
+ if (!secure && parsed.protocol !== "ws:" && parsed.protocol !== "http:") {
6074
+ throw new Error(
6075
+ `Invalid Dendri "url" protocol: "${parsed.protocol}". Use wss://, ws://, https://, or http://.`
6076
+ );
6077
+ }
6078
+ return {
6079
+ host: parsed.hostname,
6080
+ port: parsed.port ? Number(parsed.port) : secure ? 443 : 80,
6081
+ secure,
6082
+ path: parsed.pathname || "/"
6083
+ };
6084
+ }
5868
6085
  var Dendri = class _Dendri extends EventEmitterWithError {
5869
6086
  static DEFAULT_KEY = "dendri";
5870
6087
  _serializers = {
@@ -5955,6 +6172,9 @@ var Dendri = class _Dendri extends EventEmitterWithError {
5955
6172
  } else if (id) {
5956
6173
  userId = id.toString();
5957
6174
  }
6175
+ if (providedOptions?.url) {
6176
+ providedOptions = { ...parseServerUrl(providedOptions.url), ...providedOptions };
6177
+ }
5958
6178
  const normalizedOptions = {
5959
6179
  debug: 0,
5960
6180
  // 1: Errors, 2: Warnings, 3: All logs
@@ -6008,7 +6228,7 @@ var Dendri = class _Dendri extends EventEmitterWithError {
6008
6228
  return;
6009
6229
  }
6010
6230
  }
6011
- if (!!userId && !util.validateId(userId)) {
6231
+ if (userId && !util.validateId(userId)) {
6012
6232
  this._delayedAbort("invalid-id" /* InvalidID */, `ID "${userId}" is invalid`);
6013
6233
  return;
6014
6234
  }
@@ -6073,7 +6293,8 @@ var Dendri = class _Dendri extends EventEmitterWithError {
6073
6293
  this._options.path,
6074
6294
  this._options.key,
6075
6295
  this._options.pingInterval,
6076
- this._options.jwt
6296
+ this._options.jwt,
6297
+ this._options.apiKey
6077
6298
  ) : transport === "polling" ? new PollingTransport(
6078
6299
  this._options.secure ?? false,
6079
6300
  this._options.host,
@@ -6081,7 +6302,8 @@ var Dendri = class _Dendri extends EventEmitterWithError {
6081
6302
  this._options.path,
6082
6303
  this._options.key,
6083
6304
  this._options.pingInterval,
6084
- this._options.jwt
6305
+ this._options.jwt,
6306
+ this._options.apiKey
6085
6307
  ) : new Socket(
6086
6308
  this._options.secure ?? false,
6087
6309
  this._options.host,
@@ -6089,7 +6311,8 @@ var Dendri = class _Dendri extends EventEmitterWithError {
6089
6311
  this._options.path,
6090
6312
  this._options.key,
6091
6313
  this._options.pingInterval,
6092
- this._options.jwt
6314
+ this._options.jwt,
6315
+ this._options.apiKey
6093
6316
  );
6094
6317
  socket.on("message" /* Message */, (data) => {
6095
6318
  this._handleMessage(data);
@@ -6930,7 +7153,13 @@ var Room = class extends import_eventemitter35.EventEmitter {
6930
7153
  sentViaWebRTC = true;
6931
7154
  }
6932
7155
  }
6933
- if (!sentViaWebRTC && this._peer?.socket) {
7156
+ if (this._dendriOptions?.enableRelay && this._peer?.socket) {
7157
+ this._peer.socket.send({
7158
+ type: "DATA" /* Data */,
7159
+ room: this._roomId,
7160
+ payload: wire
7161
+ });
7162
+ } else if (!sentViaWebRTC && this._peer?.socket) {
6934
7163
  this._peer.socket.send({
6935
7164
  type: "DATA" /* Data */,
6936
7165
  room: this._roomId,
@@ -6964,7 +7193,13 @@ var Room = class extends import_eventemitter35.EventEmitter {
6964
7193
  sentViaWebRTC = true;
6965
7194
  }
6966
7195
  }
6967
- if (!sentViaWebRTC && this._peer?.socket) {
7196
+ if (this._dendriOptions?.enableRelay && this._peer?.socket) {
7197
+ this._peer.socket.send({
7198
+ type: "DATA" /* Data */,
7199
+ room: this._roomId,
7200
+ payload: wire
7201
+ });
7202
+ } else if (!sentViaWebRTC && this._peer?.socket) {
6968
7203
  this._peer.socket.send({
6969
7204
  type: "DATA" /* Data */,
6970
7205
  room: this._roomId,
@@ -7155,8 +7390,8 @@ var Room = class extends import_eventemitter35.EventEmitter {
7155
7390
  const remotePeerId = conn.peer;
7156
7391
  this._connections.set(remotePeerId, conn);
7157
7392
  this._knownPeers.add(remotePeerId);
7393
+ this.emit("peerJoined", remotePeerId);
7158
7394
  conn.on("open", () => {
7159
- this.emit("peerJoined", remotePeerId);
7160
7395
  for (const [peerId, c] of this._connections) {
7161
7396
  if (peerId !== remotePeerId && c.open) {
7162
7397
  c.send({ __room: { type: "peer-joined", peerId: remotePeerId } });
@@ -7478,6 +7713,14 @@ var Room = class extends import_eventemitter35.EventEmitter {
7478
7713
  const conn = this._connections.get(peerId);
7479
7714
  if (conn?.open) {
7480
7715
  conn.send(data);
7716
+ if (this._dendriOptions?.enableRelay && this._peer?.socket) {
7717
+ this._peer.socket.send({
7718
+ type: "DATA" /* Data */,
7719
+ dst: peerId,
7720
+ room: this._roomId,
7721
+ payload: data
7722
+ });
7723
+ }
7481
7724
  return;
7482
7725
  }
7483
7726
  if (!this._isHost && this._hostId) {
@@ -7780,6 +8023,6 @@ function createDendriStore(input) {
7780
8023
  };
7781
8024
  }
7782
8025
 
7783
- export { AckManager, BaseConnectionErrorType, BufferedConnection, ConnectionQuality, ConnectionState, ConnectionType, DataConnection, DataConnectionErrorType, Dendri, DendriError, DendriErrorType, HybridConnection, PollingTransport, PresenceManager, RelayEncryption, Room, RpcError, RpcErrorCode, RpcManager, SSETransport, SerializationType, ServerMessageType, SignalingTransport, SocketEventType, TopicManager, TransportMode, createDendriStore, electNewHost, isRpcRequest, isRpcResponse, isTopicEnvelope, logger_default, util };
7784
- //# sourceMappingURL=chunk-MJW5M75V.js.map
7785
- //# sourceMappingURL=chunk-MJW5M75V.js.map
8026
+ export { AckManager, BaseConnectionErrorType, BufferedConnection, ConnectionQuality, ConnectionState, ConnectionType, DataConnection, DataConnectionErrorType, Dendri, DendriError, DendriErrorType, HybridConnection, PollingTransport, PresenceManager, RelayEncryption, Room, RpcError, RpcErrorCode, RpcManager, SSETransport, SerializationType, ServerMessageType, SignalingTransport, SocketEventType, TopicClass, TopicManager, TransportMode, createDendriStore, electNewHost, isRpcRequest, isRpcResponse, isTopicEnvelope, logger_default, util };
8027
+ //# sourceMappingURL=chunk-3CE674DE.js.map
8028
+ //# sourceMappingURL=chunk-3CE674DE.js.map