@signalwire/js 4.0.0-dev-20260911172704 → 4.0.0-dev-20260911182554

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 });
@@ -14234,11 +14248,10 @@ var SelfParticipant = class extends Participant {
14234
14248
  *
14235
14249
  * The call is unaffected when acquisition fails.
14236
14250
  *
14237
- * Known issue: stopping the share before its leg connects can leave this
14238
- * promise pending until the call ends, so do not gate UI on it.
14239
- *
14240
14251
  * @throws {ScreenShareAlreadyActiveError} When this call is already
14241
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.
14242
14255
  * @throws The raw `getDisplayMedia` error. A dismissed picker or a
14243
14256
  * permission denial rejects with a `NotAllowedError` `DOMException` —
14244
14257
  * inspect `error.name` to tell benign cancels apart from real failures.
@@ -14247,7 +14260,8 @@ var SelfParticipant = class extends Participant {
14247
14260
  try {
14248
14261
  await this.vertoManager.addScreenMedia();
14249
14262
  } catch (error) {
14250
- 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);
14251
14265
  throw error;
14252
14266
  }
14253
14267
  }
@@ -14268,9 +14282,8 @@ var SelfParticipant = class extends Participant {
14268
14282
  *
14269
14283
  * The call is unaffected when acquisition fails.
14270
14284
  *
14271
- * Known issue: removing the device before its leg connects can leave this
14272
- * promise pending until the call ends, so do not gate UI on it.
14273
- *
14285
+ * @throws {AuxiliaryLegCancelledError} When {@link removeAdditionalDevice}
14286
+ * removes the device before its leg finishes connecting.
14274
14287
  * @throws The raw `getUserMedia` error (e.g. `NotAllowedError` on
14275
14288
  * permission denial) — inspect `error.name` to decide how to react — or
14276
14289
  * `AuxiliaryLegTimeoutError` if the leg does not connect in time.
@@ -14279,7 +14292,8 @@ var SelfParticipant = class extends Participant {
14279
14292
  try {
14280
14293
  await this.vertoManager.addInputDevice(options);
14281
14294
  } catch (error) {
14282
- 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);
14283
14297
  throw error;
14284
14298
  }
14285
14299
  }
@@ -16069,6 +16083,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16069
16083
  };
16070
16084
  this._isNegotiating$ = this.createBehaviorSubject(false);
16071
16085
  this._memberId = null;
16086
+ this._nodeId = null;
16072
16087
  this._iceConnectionState$ = this.createReplaySubject(1);
16073
16088
  this._connectionState$ = this.createReplaySubject(1);
16074
16089
  this._signalingState$ = this.createReplaySubject(1);
@@ -16134,6 +16149,13 @@ var RTCPeerConnectionController = class extends Destroyable {
16134
16149
  get memberId() {
16135
16150
  return this._memberId;
16136
16151
  }
16152
+ /** The node this leg's invite landed on — auxiliary legs are placed independently. */
16153
+ setNodeId(nodeId) {
16154
+ this._nodeId = nodeId;
16155
+ }
16156
+ get nodeId() {
16157
+ return this._nodeId;
16158
+ }
16137
16159
  stopTrackSender(kind, options = { updateTransceiverDirection: false }) {
16138
16160
  const audioCovered = kind === "audio" || kind === "both";
16139
16161
  if (audioCovered && this._localAudioPipeline) this.stopRawAudioInputForPipeline();
@@ -16210,6 +16232,9 @@ var RTCPeerConnectionController = class extends Destroyable {
16210
16232
  get propose() {
16211
16233
  return this.options.propose ?? "main";
16212
16234
  }
16235
+ get connectionState() {
16236
+ return this.peerConnection?.connectionState;
16237
+ }
16213
16238
  get isAdditionalDevice() {
16214
16239
  return this.propose === "additional-device";
16215
16240
  }
@@ -17282,8 +17307,8 @@ var WebRTCVertoManager = class extends VertoManager {
17282
17307
  * these identifiers before the `verto.invite` RPC response (`CALL CREATED`)
17283
17308
  * arrives. These methods let early events populate them eagerly so that
17284
17309
  * downstream RPC calls (e.g. `call.layout.list`) don't fail with empty
17285
- * identifiers. `processInviteResponse()` remains the authoritative source
17286
- * and always overwrites unconditionally.
17310
+ * identifiers. `processInviteResponse()` remains the authoritative source and
17311
+ * overwrites unconditionally — for selfId, on the main leg only.
17287
17312
  */
17288
17313
  setNodeIdIfNull(nodeId) {
17289
17314
  if (!this._nodeId$.value && nodeId) {
@@ -17321,9 +17346,9 @@ var WebRTCVertoManager = class extends VertoManager {
17321
17346
  return this._selfId$.value;
17322
17347
  }
17323
17348
  /** Build an AttachableCall from the current call state. */
17324
- buildAttachableCall(idOverride) {
17349
+ buildAttachableCall(idOverride, nodeIdOverride) {
17325
17350
  return {
17326
- nodeId: this.nodeId ?? void 0,
17351
+ nodeId: nodeIdOverride ?? this.nodeId ?? void 0,
17327
17352
  id: idOverride ?? this.webRtcCallSession.id,
17328
17353
  to: this.webRtcCallSession.to,
17329
17354
  mediaDirections: this.webRtcCallSession.mediaDirections
@@ -17556,7 +17581,7 @@ var WebRTCVertoManager = class extends VertoManager {
17556
17581
  processInviteResponse(response, rtcPeerConnController) {
17557
17582
  if (!response.error && getValueFrom(response, "result.result.result.message") === "CALL CREATED") {
17558
17583
  this.emitMainSignalingStatus(rtcPeerConnController.id, "trying");
17559
- this._nodeId$.next(getValueFrom(response, "result.node_id") ?? null);
17584
+ const nodeId = getValueFrom(response, "result.node_id") ?? null;
17560
17585
  const memberId = getValueFrom(response, "result.result.result.memberID") ?? null;
17561
17586
  const callId = getValueFrom(response, "result.result.result.callID") ?? null;
17562
17587
  logger$16.debug("[WebRTCManager] Verto invite response:", {
@@ -17564,11 +17589,15 @@ var WebRTCVertoManager = class extends VertoManager {
17564
17589
  memberId,
17565
17590
  response
17566
17591
  });
17567
- this._selfId$.next(memberId);
17568
17592
  rtcPeerConnController.setMemberId(memberId);
17593
+ rtcPeerConnController.setNodeId(nodeId);
17594
+ if (rtcPeerConnController.isMainDevice) {
17595
+ this._selfId$.next(memberId);
17596
+ this._nodeId$.next(nodeId);
17597
+ }
17569
17598
  if (callId) {
17570
17599
  this.webRtcCallSession.addCallId(callId);
17571
- this.attachManager.attach(this.buildAttachableCall(callId));
17600
+ this.attachManager.attach(this.buildAttachableCall(callId, nodeId ?? void 0));
17572
17601
  } else logger$16.warn("[WebRTCManager] Cannot attach call, missing callId:", {
17573
17602
  nodeId: this.nodeId,
17574
17603
  callId
@@ -17718,7 +17747,7 @@ var WebRTCVertoManager = class extends VertoManager {
17718
17747
  isInvite: isVertoInviteMessage(vertoMessage),
17719
17748
  reattach: this.webRtcCallSession.options.reattach === true,
17720
17749
  explicitNodeId: this.webRtcCallSession.options.nodeId,
17721
- currentNodeId: this._nodeId$.value
17750
+ currentNodeId: rtcPeerConnController.nodeId ?? this._nodeId$.value
17722
17751
  }),
17723
17752
  subscribe
17724
17753
  };
@@ -17851,13 +17880,15 @@ var WebRTCVertoManager = class extends VertoManager {
17851
17880
  this.reportLegError(error, rtcPeerConnController);
17852
17881
  });
17853
17882
  const pc = rtcPeerConnController;
17854
- 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$)));
17883
+ 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$))));
17855
17884
  if (isScreenShare) this._screenShareStatus$.next("started");
17856
17885
  logger$16.info(`[WebRTCManager] Additional peer connection connected (${propose}).`);
17857
17886
  return rtcPeerConnController.id;
17858
17887
  } catch (error) {
17859
- logger$16.warn("[WebRTCManager] Error initializing additional peer connection:", error);
17860
- if (rtcPeerConnController) {
17888
+ const cancelled = error instanceof AuxiliaryLegCancelledError;
17889
+ const aborted = error instanceof import_cjs$15.EmptyError && !firstPeerConnectionError;
17890
+ if (!cancelled && !aborted) logger$16.warn("[WebRTCManager] Error initializing additional peer connection:", error);
17891
+ if (rtcPeerConnController && this._rtcPeerConnectionsMap.has(rtcPeerConnController.id)) {
17861
17892
  rtcPeerConnController.destroy();
17862
17893
  this._rtcPeerConnectionsMap.delete(rtcPeerConnController.id);
17863
17894
  this._rtcPeerConnections$.next(Array.from(this._rtcPeerConnectionsMap.values()));
@@ -17866,6 +17897,10 @@ var WebRTCVertoManager = class extends VertoManager {
17866
17897
  this._screenShareId = void 0;
17867
17898
  this._screenShareStatus$.next("none");
17868
17899
  }
17900
+ if (cancelled) {
17901
+ logger$16.debug("[WebRTCManager] Additional peer connection removed before connecting.");
17902
+ throw error;
17903
+ }
17869
17904
  if (firstPeerConnectionError) throw firstPeerConnectionError instanceof MediaAccessError && firstPeerConnectionError.originalError instanceof Error ? firstPeerConnectionError.originalError : firstPeerConnectionError;
17870
17905
  if (error instanceof import_cjs$15.EmptyError) {
17871
17906
  logger$16.debug("[WebRTCManager] Additional peer connection aborted before connecting.");
@@ -17906,6 +17941,10 @@ var WebRTCVertoManager = class extends VertoManager {
17906
17941
  try {
17907
17942
  if (rtcPeerConnController) await this.executeVertoBye(rtcPeerConnController);
17908
17943
  } finally {
17944
+ if (rtcPeerConnController && rtcPeerConnController.connectionState !== "connected") this._legErrors$.next({
17945
+ legId: id,
17946
+ error: new AuxiliaryLegCancelledError(rtcPeerConnController.propose)
17947
+ });
17909
17948
  rtcPeerConnController?.destroy();
17910
17949
  this._rtcPeerConnectionsMap.delete(id);
17911
17950
  this._rtcPeerConnections$.next(Array.from(this._rtcPeerConnectionsMap.values()));
@@ -17920,7 +17959,10 @@ var WebRTCVertoManager = class extends VertoManager {
17920
17959
  await this.executeVerto(VertoBye({
17921
17960
  ...causeParams,
17922
17961
  dialogParams: this.dialogParams(rtcPeerConnController)
17923
- }), { callID: rtcPeerConnController.id });
17962
+ }), {
17963
+ callID: rtcPeerConnController.id,
17964
+ node_id: rtcPeerConnController.nodeId ?? void 0
17965
+ });
17924
17966
  } catch (error) {
17925
17967
  logger$16.warn("[WebRTCManager] Call might already be disconnected, error sending Verto bye:", error);
17926
17968
  throw error;
@@ -23591,5 +23633,5 @@ emitReadyEvent();
23591
23633
  if (typeof process === "undefined") globalThis.process = { env: { NODE_ENV: "production" } };
23592
23634
 
23593
23635
  //#endregion
23594
- export { Address, 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 };
23636
+ 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 };
23595
23637
  //# sourceMappingURL=browser.mjs.map