@signalwire/js 4.0.0-dev-20260911135809 → 4.0.0-dev-20260911173516

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/browser.mjs CHANGED
@@ -9405,6 +9405,20 @@ var AuxiliaryLegTimeoutError = class extends Error {
9405
9405
  this.name = "AuxiliaryLegTimeoutError";
9406
9406
  }
9407
9407
  };
9408
+ /**
9409
+ * An auxiliary leg was removed before it finished connecting.
9410
+ *
9411
+ * Typed rather than a bare resolve so a caller awaiting the start can tell a
9412
+ * cancel apart from a share that actually came up — the public methods return
9413
+ * `void`, so the promise is the only signal they have.
9414
+ */
9415
+ var AuxiliaryLegCancelledError = class extends Error {
9416
+ constructor(leg) {
9417
+ super(`The ${leg} leg was removed before it finished connecting`);
9418
+ this.leg = leg;
9419
+ this.name = "AuxiliaryLegCancelledError";
9420
+ }
9421
+ };
9408
9422
  var MediaTrackError = class extends Error {
9409
9423
  constructor(operation, kind, originalError) {
9410
9424
  super(`Media track ${operation} failed for ${kind}`, { cause: originalError instanceof Error ? originalError : void 0 });
@@ -9441,6 +9455,22 @@ var MediaAccessError = class extends Error {
9441
9455
  return isMediaAccessDenial(this.originalError);
9442
9456
  }
9443
9457
  };
9458
+ /**
9459
+ * Thrown by `startScreenShare()` when the call is already sharing a screen.
9460
+ *
9461
+ * A call carries at most one screen share. Accepting a second one would
9462
+ * overwrite the only reference the SDK holds to the first, leaving it
9463
+ * capturing and sending with no way to stop it — so the second request is
9464
+ * rejected and the live share is left untouched. Call `stopScreenShare()`
9465
+ * first to replace it.
9466
+ */
9467
+ var ScreenShareAlreadyActiveError = class extends Error {
9468
+ constructor(screenShareId, options) {
9469
+ super(`A screen share is already active on this call (${screenShareId}). Call stopScreenShare() before starting another one.`, options);
9470
+ this.screenShareId = screenShareId;
9471
+ this.name = "ScreenShareAlreadyActiveError";
9472
+ }
9473
+ };
9444
9474
  var DPoPInitError = class extends Error {
9445
9475
  constructor(originalError, message = "Failed to initialize DPoP key pair") {
9446
9476
  super(message, { cause: originalError instanceof Error ? originalError : void 0 });
@@ -14213,11 +14243,15 @@ var SelfParticipant = class extends Participant {
14213
14243
  /**
14214
14244
  * Starts sharing the local screen.
14215
14245
  *
14216
- * The call is unaffected when acquisition fails.
14246
+ * A call carries at most one screen share. Read `screenShareStatus` before
14247
+ * calling and treat `'starting'`/`'stopping'` as busy.
14217
14248
  *
14218
- * Known issue: stopping the share before its leg connects can leave this
14219
- * promise pending until the call ends, so do not gate UI on it.
14249
+ * The call is unaffected when acquisition fails.
14220
14250
  *
14251
+ * @throws {ScreenShareAlreadyActiveError} When this call is already
14252
+ * sharing a screen. Call {@link stopScreenShare} before starting another.
14253
+ * @throws {AuxiliaryLegCancelledError} When {@link stopScreenShare} removes
14254
+ * the share before its leg finishes connecting.
14221
14255
  * @throws The raw `getDisplayMedia` error. A dismissed picker or a
14222
14256
  * permission denial rejects with a `NotAllowedError` `DOMException` —
14223
14257
  * inspect `error.name` to tell benign cancels apart from real failures.
@@ -14226,7 +14260,8 @@ var SelfParticipant = class extends Participant {
14226
14260
  try {
14227
14261
  await this.vertoManager.addScreenMedia();
14228
14262
  } catch (error) {
14229
- logger$25.error("[Participant.startScreenShare] Screen share error:", error);
14263
+ if (error instanceof AuxiliaryLegCancelledError) logger$25.debug("[Participant.startScreenShare] Screen share cancelled before connecting.");
14264
+ else logger$25.error("[Participant.startScreenShare] Screen share error:", error);
14230
14265
  throw error;
14231
14266
  }
14232
14267
  }
@@ -14247,9 +14282,8 @@ var SelfParticipant = class extends Participant {
14247
14282
  *
14248
14283
  * The call is unaffected when acquisition fails.
14249
14284
  *
14250
- * Known issue: removing the device before its leg connects can leave this
14251
- * promise pending until the call ends, so do not gate UI on it.
14252
- *
14285
+ * @throws {AuxiliaryLegCancelledError} When {@link removeAdditionalDevice}
14286
+ * removes the device before its leg finishes connecting.
14253
14287
  * @throws The raw `getUserMedia` error (e.g. `NotAllowedError` on
14254
14288
  * permission denial) — inspect `error.name` to decide how to react — or
14255
14289
  * `AuxiliaryLegTimeoutError` if the leg does not connect in time.
@@ -14258,7 +14292,8 @@ var SelfParticipant = class extends Participant {
14258
14292
  try {
14259
14293
  await this.vertoManager.addInputDevice(options);
14260
14294
  } catch (error) {
14261
- logger$25.error("[Participant.addAdditionalDevice] Additional device error:", error);
14295
+ if (error instanceof AuxiliaryLegCancelledError) logger$25.debug("[Participant.addAdditionalDevice] Device removed before connecting.");
14296
+ else logger$25.error("[Participant.addAdditionalDevice] Additional device error:", error);
14262
14297
  throw error;
14263
14298
  }
14264
14299
  }
@@ -16189,6 +16224,9 @@ var RTCPeerConnectionController = class extends Destroyable {
16189
16224
  get propose() {
16190
16225
  return this.options.propose ?? "main";
16191
16226
  }
16227
+ get connectionState() {
16228
+ return this.peerConnection?.connectionState;
16229
+ }
16192
16230
  get isAdditionalDevice() {
16193
16231
  return this.propose === "additional-device";
16194
16232
  }
@@ -17810,6 +17848,7 @@ var WebRTCVertoManager = class extends VertoManager {
17810
17848
  }
17811
17849
  async initAdditionalPeerConnection(propose, options) {
17812
17850
  const isScreenShare = propose === "screenshare";
17851
+ if (isScreenShare && this._screenShareId && this._rtcPeerConnectionsMap.has(this._screenShareId)) throw new ScreenShareAlreadyActiveError(this._screenShareId);
17813
17852
  let firstPeerConnectionError;
17814
17853
  let rtcPeerConnController = null;
17815
17854
  try {
@@ -17829,20 +17868,26 @@ var WebRTCVertoManager = class extends VertoManager {
17829
17868
  this.reportLegError(error, rtcPeerConnController);
17830
17869
  });
17831
17870
  const pc = rtcPeerConnController;
17832
- await (0, import_cjs$15.firstValueFrom)((0, import_cjs$15.merge)(pc.localMediaSettled$.pipe((0, import_cjs$15.take)(1), (0, import_cjs$15.switchMap)(() => pc.connectionState$.pipe((0, import_cjs$15.filter)((state) => state === "connected"), (0, import_cjs$15.take)(1), (0, import_cjs$15.timeout)(DEFAULT_AUX_LEG_CONNECT_TIMEOUT_MS)))), this.legError$(pc.id)).pipe((0, import_cjs$15.takeUntil)(this.destroyed$)));
17871
+ await (0, import_cjs$15.firstValueFrom)((0, import_cjs$15.merge)(pc.localMediaSettled$.pipe((0, import_cjs$15.take)(1), (0, import_cjs$15.switchMap)(() => pc.connectionState$.pipe((0, import_cjs$15.filter)((state) => state === "connected"), (0, import_cjs$15.take)(1), (0, import_cjs$15.timeout)(DEFAULT_AUX_LEG_CONNECT_TIMEOUT_MS)))), this.legError$(pc.id)).pipe((0, import_cjs$15.takeUntil)((0, import_cjs$15.merge)(this.destroyed$, pc.destroyed$))));
17833
17872
  if (isScreenShare) this._screenShareStatus$.next("started");
17834
17873
  logger$16.info(`[WebRTCManager] Additional peer connection connected (${propose}).`);
17835
17874
  return rtcPeerConnController.id;
17836
17875
  } catch (error) {
17837
- logger$16.warn("[WebRTCManager] Error initializing additional peer connection:", error);
17838
- if (rtcPeerConnController) {
17876
+ const cancelled = error instanceof AuxiliaryLegCancelledError;
17877
+ const aborted = error instanceof import_cjs$15.EmptyError && !firstPeerConnectionError;
17878
+ if (!cancelled && !aborted) logger$16.warn("[WebRTCManager] Error initializing additional peer connection:", error);
17879
+ if (rtcPeerConnController && this._rtcPeerConnectionsMap.has(rtcPeerConnController.id)) {
17839
17880
  rtcPeerConnController.destroy();
17840
17881
  this._rtcPeerConnectionsMap.delete(rtcPeerConnController.id);
17841
17882
  this._rtcPeerConnections$.next(Array.from(this._rtcPeerConnectionsMap.values()));
17842
17883
  }
17843
17884
  if (isScreenShare) {
17844
- this._screenShareStatus$.next("none");
17845
17885
  this._screenShareId = void 0;
17886
+ this._screenShareStatus$.next("none");
17887
+ }
17888
+ if (cancelled) {
17889
+ logger$16.debug("[WebRTCManager] Additional peer connection removed before connecting.");
17890
+ throw error;
17846
17891
  }
17847
17892
  if (firstPeerConnectionError) throw firstPeerConnectionError instanceof MediaAccessError && firstPeerConnectionError.originalError instanceof Error ? firstPeerConnectionError.originalError : firstPeerConnectionError;
17848
17893
  if (error instanceof import_cjs$15.EmptyError) {
@@ -17866,7 +17911,10 @@ var WebRTCVertoManager = class extends VertoManager {
17866
17911
  if (removeTrack) return this.mainPeerConnection.stopTrackSender(removeTrack, { updateTransceiverDirection: true });
17867
17912
  }
17868
17913
  async removeScreenMedia() {
17869
- if (!["starting", "started"].includes(this._screenShareStatus$.value)) logger$16.warn("[WebRTCManager] No active screen share to stop.");
17914
+ if (!["starting", "started"].includes(this._screenShareStatus$.value)) {
17915
+ logger$16.warn("[WebRTCManager] No active screen share to stop.");
17916
+ return;
17917
+ }
17870
17918
  if (!this._screenShareId) {
17871
17919
  logger$16.debug("[WebRTCManager] No screen share peer connection found.");
17872
17920
  return;
@@ -17881,6 +17929,10 @@ var WebRTCVertoManager = class extends VertoManager {
17881
17929
  try {
17882
17930
  if (rtcPeerConnController) await this.executeVertoBye(rtcPeerConnController);
17883
17931
  } finally {
17932
+ if (rtcPeerConnController && rtcPeerConnController.connectionState !== "connected") this._legErrors$.next({
17933
+ legId: id,
17934
+ error: new AuxiliaryLegCancelledError(rtcPeerConnController.propose)
17935
+ });
17884
17936
  rtcPeerConnController?.destroy();
17885
17937
  this._rtcPeerConnectionsMap.delete(id);
17886
17938
  this._rtcPeerConnections$.next(Array.from(this._rtcPeerConnectionsMap.values()));
@@ -23566,5 +23618,5 @@ emitReadyEvent();
23566
23618
  if (typeof process === "undefined") globalThis.process = { env: { NODE_ENV: "production" } };
23567
23619
 
23568
23620
  //#endregion
23569
- export { Address, AuxiliaryLegTimeoutError, CallCreateError, CallNotReadyError, ClientPreferences, CollectionFetchError, DPoPInitError, DeviceTokenError, EmbedTokenCredentialProvider, InvalidCredentialsError, MediaAccessError, MediaTrackError, MessageParseError, OverconstrainedFallbackError, Participant, ParticipantNotReadyError, PreflightError, RecoveryError, SelfCapabilities, SelfParticipant, SignalWire, StaticCredentialProvider, TokenRefreshError, UnexpectedError, User, VertoPongError, WebRTCCall, embeddableCall, getLogger, isSelfParticipant, ready, setDebugOptions, setLogLevel, setLogger, version };
23621
+ export { Address, AuxiliaryLegCancelledError, AuxiliaryLegTimeoutError, CallCreateError, CallNotReadyError, ClientPreferences, CollectionFetchError, DPoPInitError, DeviceTokenError, EmbedTokenCredentialProvider, InvalidCredentialsError, MediaAccessError, MediaTrackError, MessageParseError, OverconstrainedFallbackError, Participant, ParticipantNotReadyError, PreflightError, RecoveryError, ScreenShareAlreadyActiveError, SelfCapabilities, SelfParticipant, SignalWire, StaticCredentialProvider, TokenRefreshError, UnexpectedError, User, VertoPongError, WebRTCCall, embeddableCall, getLogger, isSelfParticipant, ready, setDebugOptions, setLogLevel, setLogger, version };
23570
23622
  //# sourceMappingURL=browser.mjs.map