@signalwire/js 4.0.0-dev-20260410161202 → 4.0.0-dev-20260410164129

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.
@@ -10759,7 +10759,7 @@ var NavigatorDeviceController = class extends Destroyable {
10759
10759
  enableAudioInput() {
10760
10760
  if (this._audioInputDisabled$.value) {
10761
10761
  this._audioInputDisabled$.next(false);
10762
- const restored = this._lastAudioInputBeforeDisable ?? this.audioInputDevices[0] ?? null;
10762
+ const restored = this._lastAudioInputBeforeDisable ?? this.audioInputDevices[0];
10763
10763
  this._selectedDevicesState$.next({
10764
10764
  ...this._selectedDevicesState$.value,
10765
10765
  audioinput: restored
@@ -10780,7 +10780,7 @@ var NavigatorDeviceController = class extends Destroyable {
10780
10780
  enableVideoInput() {
10781
10781
  if (this._videoInputDisabled$.value) {
10782
10782
  this._videoInputDisabled$.next(false);
10783
- const restored = this._lastVideoInputBeforeDisable ?? this.videoInputDevices[0] ?? null;
10783
+ const restored = this._lastVideoInputBeforeDisable ?? this.videoInputDevices[0];
10784
10784
  this._selectedDevicesState$.next({
10785
10785
  ...this._selectedDevicesState$.value,
10786
10786
  videoinput: restored
@@ -11717,7 +11717,7 @@ function detectScreenShareAudio() {
11717
11717
  * Safely retrieves navigator.mediaDevices, returning null if unavailable.
11718
11718
  */
11719
11719
  function getNavigatorMediaDevices() {
11720
- if (typeof navigator !== "undefined" && navigator.mediaDevices) return navigator.mediaDevices;
11720
+ if (typeof navigator !== "undefined") return navigator.mediaDevices;
11721
11721
  return null;
11722
11722
  }
11723
11723
 
@@ -11839,11 +11839,12 @@ var PreflightRunner = class extends Destroyable {
11839
11839
  let pc;
11840
11840
  try {
11841
11841
  pc = new RTCPeerConnection({ iceServers: this.iceServers });
11842
+ const peerConnection = pc;
11842
11843
  const candidateTypes = /* @__PURE__ */ new Set();
11843
11844
  const startTime = Date.now();
11844
11845
  const gatheringComplete = new Promise((resolve) => {
11845
11846
  const timer$2 = setTimeout(resolve, ICE_GATHERING_TIMEOUT_MS);
11846
- pc.onicecandidate = (event) => {
11847
+ peerConnection.onicecandidate = (event) => {
11847
11848
  if (event.candidate) {
11848
11849
  const candidateStr = event.candidate.candidate;
11849
11850
  if (candidateStr.includes("typ host")) candidateTypes.add("host");
@@ -14413,8 +14414,8 @@ var CallEventsManager = class extends Destroyable {
14413
14414
  }
14414
14415
  updateParticipantPositions(layoutChangedEvent) {
14415
14416
  if (Object.keys(this._participants$.value).length > 0 && !layoutChangedEvent.layers.some((layer) => !!layer.member_id)) logger$18.warn("[CallEventsManager] No layers with member_id found in layout.changed event. Nothing to update.");
14416
- layoutChangedEvent.layers.filter((layer) => Boolean(layer.member_id)).filter((layer) => {
14417
- if (!layer.member_id || !(layer.member_id in this._participants$.value)) {
14417
+ layoutChangedEvent.layers.filter((layer) => !!layer.member_id).filter((layer) => {
14418
+ if (!(layer.member_id in this._participants$.value)) {
14418
14419
  logger$18.warn(`[CallEventsManager] Skipping layout layer for unknown member_id: ${layer.member_id}`);
14419
14420
  return false;
14420
14421
  }
@@ -15778,7 +15779,7 @@ var RTCPeerConnectionController = class extends Destroyable {
15778
15779
  const preferredAudioCodecs = this.options.preferredAudioCodecs ?? PreferencesContainer.instance.preferredAudioCodecs;
15779
15780
  const preferredVideoCodecs = this.options.preferredVideoCodecs ?? PreferencesContainer.instance.preferredVideoCodecs;
15780
15781
  const stereo = this.options.stereo ?? PreferencesContainer.instance.stereoAudio;
15781
- if (preferredAudioCodecs && preferredAudioCodecs.length > 0 || preferredVideoCodecs && preferredVideoCodecs.length > 0) {
15782
+ if (preferredAudioCodecs.length > 0 || preferredVideoCodecs.length > 0) {
15782
15783
  result = setCodecPreferences(result, preferredAudioCodecs, preferredVideoCodecs);
15783
15784
  logger$14.debug("[RTCPeerConnectionController] Applied codec preferences to SDP", {
15784
15785
  preferredAudioCodecs,
@@ -16020,11 +16021,9 @@ var RTCPeerConnectionController = class extends Destroyable {
16020
16021
  oldTrack.stop();
16021
16022
  this.localStreamController.removeTrack(trackId);
16022
16023
  const newTrack = (await this.getUserMedia({ audio: mergedConstraints })).getAudioTracks()[0];
16023
- if (newTrack) {
16024
- await sender.replaceTrack(newTrack);
16025
- this.localStreamController.addTrack(newTrack);
16026
- logger$14.debug(`[RTCPeerConnectionController] Audio track replaced for server-pushed params. New track: ${newTrack.id}`);
16027
- }
16024
+ await sender.replaceTrack(newTrack);
16025
+ this.localStreamController.addTrack(newTrack);
16026
+ logger$14.debug(`[RTCPeerConnectionController] Audio track replaced for server-pushed params. New track: ${newTrack.id}`);
16028
16027
  }
16029
16028
  }
16030
16029
  /**
@@ -16319,7 +16318,7 @@ var WebRTCVertoManager = class extends VertoManager {
16319
16318
  logger$13.warn("[WebRTCManager] No peer connection for keyframe request");
16320
16319
  return;
16321
16320
  }
16322
- const videoReceiver = pc.getReceivers().find((r) => r.track?.kind === "video");
16321
+ const videoReceiver = pc.getReceivers().find((r) => r.track.kind === "video");
16323
16322
  if (!videoReceiver) {
16324
16323
  logger$13.warn("[WebRTCManager] No video receiver for keyframe request");
16325
16324
  return;
@@ -16395,7 +16394,7 @@ var WebRTCVertoManager = class extends VertoManager {
16395
16394
  try {
16396
16395
  const pc = controller.peerConnection;
16397
16396
  if (!pc) continue;
16398
- const videoReceiver = pc.getReceivers().find((r) => r.track?.kind === "video");
16397
+ const videoReceiver = pc.getReceivers().find((r) => r.track.kind === "video");
16399
16398
  if (!videoReceiver) continue;
16400
16399
  if (typeof videoReceiver.requestKeyFrame === "function") {
16401
16400
  videoReceiver.requestKeyFrame();
@@ -16874,6 +16873,12 @@ function computePacketLossPercent(lost, received) {
16874
16873
  if (total === 0) return 0;
16875
16874
  return lost / total * 100;
16876
16875
  }
16876
+ function isInboundRtpStat(stat) {
16877
+ return typeof stat === "object" && stat !== null && "type" in stat && stat.type === "inbound-rtp";
16878
+ }
16879
+ function isCandidatePairStat(stat) {
16880
+ return typeof stat === "object" && stat !== null && "type" in stat && stat.type === "candidate-pair";
16881
+ }
16877
16882
  var RTCStatsMonitor = class extends Destroyable {
16878
16883
  constructor(peerConnection, config = {}) {
16879
16884
  super();
@@ -17005,17 +17010,15 @@ var RTCStatsMonitor = class extends Destroyable {
17005
17010
  let roundTripTime = 0;
17006
17011
  let availableOutgoingBitrate;
17007
17012
  report.forEach((stat) => {
17008
- if (stat.type === "inbound-rtp") {
17009
- if (stat.kind === "audio") {
17010
- audioPacketsReceived += stat.packetsReceived ?? this.lastAudioPacketsReceived;
17011
- audioPacketsLost += stat.packetsLost ?? 0;
17012
- audioJitter = Math.max(audioJitter, (stat.jitter ?? 0) * 1e3);
17013
- } else if (stat.kind === "video") {
17014
- videoPacketsReceived += stat.packetsReceived ?? this.lastVideoPacketsReceived;
17015
- videoPacketsLost += stat.packetsLost ?? 0;
17016
- }
17013
+ if (isInboundRtpStat(stat)) if (stat.kind === "audio") {
17014
+ audioPacketsReceived += stat.packetsReceived ?? this.lastAudioPacketsReceived;
17015
+ audioPacketsLost += stat.packetsLost ?? 0;
17016
+ audioJitter = Math.max(audioJitter, (stat.jitter ?? 0) * 1e3);
17017
+ } else {
17018
+ videoPacketsReceived += stat.packetsReceived ?? this.lastVideoPacketsReceived;
17019
+ videoPacketsLost += stat.packetsLost ?? 0;
17017
17020
  }
17018
- if (stat.type === "candidate-pair" && stat.state === "succeeded" && stat.nominated) {
17021
+ if (isCandidatePairStat(stat) && stat.state === "succeeded" && stat.nominated) {
17019
17022
  roundTripTime = stat.currentRoundTripTime ? stat.currentRoundTripTime * 1e3 : this.lastRoundTripTime;
17020
17023
  availableOutgoingBitrate = stat.availableOutgoingBitrate ?? this.lastAvailableOutgoingBitrate;
17021
17024
  }
@@ -18056,10 +18059,10 @@ var WebRTCCall = class extends Destroyable {
18056
18059
  logger$10.debug("[Call] Recovery manager failed to enable video");
18057
18060
  });
18058
18061
  },
18059
- isNegotiating: () => this.vertoManager.mainPeerConnection?.isNegotiating ?? false,
18062
+ isNegotiating: () => this.vertoManager.mainPeerConnection.isNegotiating,
18060
18063
  isWebSocketConnected: () => this._lastMergedStatus !== "disconnected",
18061
18064
  isCallConnected: () => this._lastMergedStatus === "connected",
18062
- getPeerConnectionState: () => pc.connectionState ?? null
18065
+ getPeerConnectionState: () => pc.connectionState
18063
18066
  }, {
18064
18067
  debounceTimeMs: prefs.recoveryDebounceTime,
18065
18068
  cooldownMs: prefs.recoveryCooldown,
@@ -19274,7 +19277,7 @@ var ClientSessionManager = class extends Destroyable {
19274
19277
  */
19275
19278
  async handleVertoAttach(attach) {
19276
19279
  const { callID } = attach;
19277
- if (this._calls$.value[callID]) {
19280
+ if (callID in this._calls$.value) {
19278
19281
  logger$7.debug(`[Session] Verto attach for existing call ${callID}, deferring to per-call handler`);
19279
19282
  return;
19280
19283
  }
@@ -19976,12 +19979,12 @@ var TransportManager = class extends Destroyable {
19976
19979
  this.discardStaleEvents = () => {
19977
19980
  return (0, import_cjs$1.filter)((message) => {
19978
19981
  if (!isSignalwireRequest(message)) return true;
19979
- const eventChannel = message.params?.event_channel;
19982
+ const eventChannel = message.params.event_channel;
19980
19983
  if (!eventChannel) return true;
19981
19984
  const currentProtocol = this._currentProtocol;
19982
19985
  if (!currentProtocol) return true;
19983
19986
  if (!eventChannel.includes(currentProtocol)) {
19984
- const eventType = message.params.event_type ?? "unknown";
19987
+ const eventType = message.params.event_type;
19985
19988
  logger$2.warn(`[Transport] Discarding stale event: ${eventType} (event_channel does not match current protocol)`);
19986
19989
  return false;
19987
19990
  }
@@ -20258,7 +20261,7 @@ var SignalWire = class extends Destroyable {
20258
20261
  }
20259
20262
  if (_credentials.expiry_at && credentialProvider?.refresh) {
20260
20263
  const refreshFn = async () => {
20261
- if (!credentialProvider?.refresh) throw new InvalidCredentialsError("Credential provider does not support refresh");
20264
+ if (!credentialProvider.refresh) throw new InvalidCredentialsError("Credential provider does not support refresh");
20262
20265
  return credentialProvider.refresh();
20263
20266
  };
20264
20267
  const refreshInterval = Math.max(_credentials.expiry_at - Date.now() - 5e3, 1e3);
@@ -20666,7 +20669,7 @@ var SignalWire = class extends Destroyable {
20666
20669
  * ```
20667
20670
  */
20668
20671
  async preflight(destination, options) {
20669
- const iceServers = this._clientSession?.iceServers ?? PreferencesContainer.instance.iceServers ?? [];
20672
+ const iceServers = this._clientSession.iceServers ?? PreferencesContainer.instance.iceServers ?? [];
20670
20673
  const isConnected = this._isConnected$.value;
20671
20674
  return new PreflightRunner(this._deviceController, iceServers, isConnected, 0, async (dest, opts) => this.dial(dest, opts), options).run(destination);
20672
20675
  }
@@ -20818,6 +20821,8 @@ var SignalWire = class extends Destroyable {
20818
20821
  * Triggers the browser's media permission dialog and captures the user's device selections.
20819
20822
  *
20820
20823
  * @param options - Which permissions to request.
20824
+ * @param options.audio - Whether to request audio permission.
20825
+ * @param options.video - Whether to request video permission.
20821
20826
  * @returns The permission result with selected devices.
20822
20827
  */
20823
20828
  async requestMediaPermissions(options = {
@@ -20849,8 +20854,14 @@ var SignalWire = class extends Destroyable {
20849
20854
  logger$1.warn("[SignalWire] Media permission request failed:", error);
20850
20855
  }
20851
20856
  await this._deviceController.enumerateDevices();
20852
- if (audioGranted && selectedAudioDevice) selectedAudioDevice = this.audioInputDevices.find((d) => d.deviceId === selectedAudioDevice.deviceId) ?? selectedAudioDevice;
20853
- if (videoGranted && selectedVideoDevice) selectedVideoDevice = this.videoInputDevices.find((d) => d.deviceId === selectedVideoDevice.deviceId) ?? selectedVideoDevice;
20857
+ if (audioGranted && selectedAudioDevice) {
20858
+ const audioDeviceId = selectedAudioDevice.deviceId;
20859
+ selectedAudioDevice = this.audioInputDevices.find((d) => d.deviceId === audioDeviceId) ?? selectedAudioDevice;
20860
+ }
20861
+ if (videoGranted && selectedVideoDevice) {
20862
+ const videoDeviceId = selectedVideoDevice.deviceId;
20863
+ selectedVideoDevice = this.videoInputDevices.find((d) => d.deviceId === videoDeviceId) ?? selectedVideoDevice;
20864
+ }
20854
20865
  if (audioGranted && selectedAudioDevice && !this.selectedAudioInputDevice) this.selectAudioInputDevice(selectedAudioDevice);
20855
20866
  if (videoGranted && selectedVideoDevice && !this.selectedVideoInputDevice) this.selectVideoInputDevice(selectedVideoDevice);
20856
20867
  return {
@@ -20883,8 +20894,8 @@ var SignalWire = class extends Destroyable {
20883
20894
  this._deviceTokenManager?.destroy();
20884
20895
  this._dpopManager?.destroy();
20885
20896
  if (this._attachManager) this._attachManager.detachAll();
20886
- this._transport?.destroy();
20887
- this._clientSession?.destroy();
20897
+ this._transport.destroy();
20898
+ this._clientSession.destroy();
20888
20899
  try {
20889
20900
  this._networkMonitor?.destroy();
20890
20901
  } catch {}