@signalwire/js 4.0.0-beta.2 → 4.0.0-beta.4

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.
@@ -6938,7 +6938,7 @@ var require_switchMap = /* @__PURE__ */ __commonJSMin(((exports) => {
6938
6938
  var innerFrom_1$6 = require_innerFrom();
6939
6939
  var lift_1$13 = require_lift();
6940
6940
  var OperatorSubscriber_1$11 = require_OperatorSubscriber();
6941
- function switchMap$2(project, resultSelector) {
6941
+ function switchMap$3(project, resultSelector) {
6942
6942
  return lift_1$13.operate(function(source, subscriber) {
6943
6943
  var innerSubscriber = null;
6944
6944
  var index = 0;
@@ -6962,7 +6962,7 @@ var require_switchMap = /* @__PURE__ */ __commonJSMin(((exports) => {
6962
6962
  }));
6963
6963
  });
6964
6964
  }
6965
- exports.switchMap = switchMap$2;
6965
+ exports.switchMap = switchMap$3;
6966
6966
  }));
6967
6967
 
6968
6968
  //#endregion
@@ -9968,8 +9968,9 @@ const selectDevice = (devices = [], selected, preferred) => {
9968
9968
  return selected;
9969
9969
  };
9970
9970
  var NavigatorDeviceController = class extends Destroyable {
9971
- constructor() {
9971
+ constructor(webRTCApiProvider) {
9972
9972
  super();
9973
+ this.webRTCApiProvider = webRTCApiProvider;
9973
9974
  this.deviceChangeHandler = () => {
9974
9975
  logger$19.debug("[DeviceController] Device change detected");
9975
9976
  this.enumerateDevices();
@@ -10051,24 +10052,22 @@ var NavigatorDeviceController = class extends Destroyable {
10051
10052
  });
10052
10053
  }
10053
10054
  init() {
10054
- if (navigator.mediaDevices) {
10055
- this.subscribeTo(this._devicesState$.pipe((0, import_cjs$20.debounceTime)(PreferencesContainer.instance.deviceDebounceTime)), (devicesState) => {
10056
- const currentSelected = this._selectedDevicesState$.value;
10057
- const newAudioInput = selectDevice(devicesState.audioinput, currentSelected.audioinput, PreferencesContainer.instance.preferredAudioInput);
10058
- const newAudioOutput = selectDevice(devicesState.audiooutput, currentSelected.audiooutput, PreferencesContainer.instance.preferredAudioOutput);
10059
- const newVideoInput = selectDevice(devicesState.videoinput, currentSelected.videoinput, PreferencesContainer.instance.preferredVideoInput);
10060
- if (newAudioInput !== currentSelected.audioinput || newAudioOutput !== currentSelected.audiooutput || newVideoInput !== currentSelected.videoinput) this._selectedDevicesState$.next({
10061
- audioinput: newAudioInput,
10062
- audiooutput: newAudioOutput,
10063
- videoinput: newVideoInput
10064
- });
10055
+ this.subscribeTo(this._devicesState$.pipe((0, import_cjs$20.debounceTime)(PreferencesContainer.instance.deviceDebounceTime)), (devicesState) => {
10056
+ const currentSelected = this._selectedDevicesState$.value;
10057
+ const newAudioInput = selectDevice(devicesState.audioinput, currentSelected.audioinput, PreferencesContainer.instance.preferredAudioInput);
10058
+ const newAudioOutput = selectDevice(devicesState.audiooutput, currentSelected.audiooutput, PreferencesContainer.instance.preferredAudioOutput);
10059
+ const newVideoInput = selectDevice(devicesState.videoinput, currentSelected.videoinput, PreferencesContainer.instance.preferredVideoInput);
10060
+ if (newAudioInput !== currentSelected.audioinput || newAudioOutput !== currentSelected.audiooutput || newVideoInput !== currentSelected.videoinput) this._selectedDevicesState$.next({
10061
+ audioinput: newAudioInput,
10062
+ audiooutput: newAudioOutput,
10063
+ videoinput: newVideoInput
10065
10064
  });
10066
- this.enumerateDevices();
10067
- }
10065
+ });
10066
+ this.enumerateDevices();
10068
10067
  }
10069
10068
  enableDeviceMonitoring() {
10070
10069
  this.disableDeviceMonitoring();
10071
- navigator.mediaDevices.addEventListener("devicechange", this.deviceChangeHandler);
10070
+ this.webRTCApiProvider.mediaDevices.addEventListener("devicechange", this.deviceChangeHandler);
10072
10071
  if (PreferencesContainer.instance.devicePollingInterval > 0) this._devicesPoolingSubscription = (0, import_cjs$20.interval)(PreferencesContainer.instance.devicePollingInterval).subscribe(() => {
10073
10072
  logger$19.debug("[DeviceController] Polling devices due to interval");
10074
10073
  this.enumerateDevices();
@@ -10076,7 +10075,7 @@ var NavigatorDeviceController = class extends Destroyable {
10076
10075
  this.enumerateDevices();
10077
10076
  }
10078
10077
  disableDeviceMonitoring() {
10079
- navigator.mediaDevices.removeEventListener("devicechange", this.deviceChangeHandler);
10078
+ this.webRTCApiProvider.mediaDevices.removeEventListener("devicechange", this.deviceChangeHandler);
10080
10079
  if (this._devicesPoolingSubscription) {
10081
10080
  this._devicesPoolingSubscription.unsubscribe();
10082
10081
  this._devicesPoolingSubscription = void 0;
@@ -10084,7 +10083,7 @@ var NavigatorDeviceController = class extends Destroyable {
10084
10083
  }
10085
10084
  async enumerateDevices() {
10086
10085
  try {
10087
- const devicesByKind = (await navigator.mediaDevices.enumerateDevices()).reduce((acc, device) => {
10086
+ const devicesByKind = (await this.webRTCApiProvider.mediaDevices.enumerateDevices()).reduce((acc, device) => {
10088
10087
  acc[device.kind].push(device);
10089
10088
  return acc;
10090
10089
  }, {
@@ -10107,7 +10106,7 @@ var NavigatorDeviceController = class extends Destroyable {
10107
10106
  if (deviceInfo.kind === "audiooutput") return null;
10108
10107
  try {
10109
10108
  const constraints = this.deviceInfoToConstraints(deviceInfo);
10110
- const stream = await navigator.mediaDevices.getUserMedia({
10109
+ const stream = await this.webRTCApiProvider.mediaDevices.getUserMedia({
10111
10110
  audio: deviceInfo.kind === "audioinput" ? constraints : false,
10112
10111
  video: deviceInfo.kind === "videoinput" ? constraints : false
10113
10112
  });
@@ -10279,9 +10278,23 @@ var DependencyContainer = class {
10279
10278
  this._webSocketConstructor = WebSocketConstructor;
10280
10279
  }
10281
10280
  get deviceController() {
10282
- this._deviceController ??= new NavigatorDeviceController();
10281
+ this._deviceController ??= new NavigatorDeviceController(this.webRTCApiProvider);
10283
10282
  return this._deviceController;
10284
10283
  }
10284
+ get webRTCApiProvider() {
10285
+ if (!this._webRTCApiProvider) {
10286
+ if (typeof RTCPeerConnection === "undefined" || typeof navigator === "undefined") throw new DependencyError("WebRTCApiProvider: RTCPeerConnection or navigator.mediaDevices is not available. Please provide a custom webRTCApiProvider in SignalWireOptions.");
10287
+ this._webRTCApiProvider = {
10288
+ RTCPeerConnection,
10289
+ mediaDevices: navigator.mediaDevices
10290
+ };
10291
+ }
10292
+ return this._webRTCApiProvider;
10293
+ }
10294
+ set webRTCApiProvider(webRTCApiProvider) {
10295
+ this._webRTCApiProvider = webRTCApiProvider;
10296
+ this._deviceController = void 0;
10297
+ }
10285
10298
  get authorizationStateKey() {
10286
10299
  return `sw:${this.subscriberId}:as`;
10287
10300
  }
@@ -12192,7 +12205,7 @@ function isJSONRPCRequest(value) {
12192
12205
  return isObject(value) && hasProperty(value, "jsonrpc") && value.jsonrpc === "2.0" && hasProperty(value, "id") && typeof value.id === "string" && hasProperty(value, "method") && typeof value.method === "string";
12193
12206
  }
12194
12207
  function isJSONRPCResponse(value) {
12195
- return isObject(value) && hasProperty(value, "jsonrpc") && value.jsonrpc === "2.0" && hasProperty(value, "id") && typeof value.id === "string" && hasProperty(value, "result");
12208
+ return isObject(value) && hasProperty(value, "jsonrpc") && value.jsonrpc === "2.0" && hasProperty(value, "id") && typeof value.id === "string" && (hasProperty(value, "result") || hasProperty(value, "error"));
12196
12209
  }
12197
12210
 
12198
12211
  //#endregion
@@ -12506,7 +12519,7 @@ var CallEventsManager = class extends Destroyable {
12506
12519
  });
12507
12520
  this.updateParticipants(sessionState.members);
12508
12521
  this._self$.value?.capabilities.updateFromRaw(capabilities);
12509
- this.updateLayouts();
12522
+ if (this._self$.value?.capabilities.setLayout) this.updateLayouts();
12510
12523
  });
12511
12524
  this.subscribeTo(this.memberUpdates$, (member) => {
12512
12525
  logger$15.debug("[CallEventsManager] Handling member update event for member ID:", member);
@@ -13234,7 +13247,7 @@ var RTCPeerConnectionController = class extends Destroyable {
13234
13247
  logger$11.debug(`[RTCPeerConnectionController] ${kind} input device selected: none`);
13235
13248
  return;
13236
13249
  }
13237
- const streamTrack = (await navigator.mediaDevices.getUserMedia({ [kind]: {
13250
+ const streamTrack = (await this.getUserMedia({ [kind]: {
13238
13251
  ...track.getConstraints(),
13239
13252
  ...this.deviceController.deviceInfoToConstraints(deviceInfo)
13240
13253
  } })).getTracks().find((t) => t.kind === kind);
@@ -13425,7 +13438,7 @@ var RTCPeerConnectionController = class extends Destroyable {
13425
13438
  };
13426
13439
  }
13427
13440
  get WebRTCPeerConnectionConstructor() {
13428
- return this.options.WebRTCPeerConnectionConstructor ?? RTCPeerConnection;
13441
+ return this.options.webRTCApiProvider?.RTCPeerConnection ?? RTCPeerConnection;
13429
13442
  }
13430
13443
  get offerOptions() {
13431
13444
  const options = { iceRestart: this.firstSDPExchangeCompleted ? true : void 0 };
@@ -13692,10 +13705,12 @@ var RTCPeerConnectionController = class extends Destroyable {
13692
13705
  }
13693
13706
  }
13694
13707
  async getUserMedia(constraints) {
13695
- return this.options.getUserMedia?.(constraints) ?? navigator.mediaDevices.getUserMedia(constraints);
13708
+ return (this.options.webRTCApiProvider?.mediaDevices ?? navigator.mediaDevices).getUserMedia(constraints);
13696
13709
  }
13697
13710
  async getDisplayMedia(options) {
13698
- return this.options.getDisplayMedia?.(options) ?? navigator.mediaDevices.getDisplayMedia(options);
13711
+ const mediaDevices = this.options.webRTCApiProvider?.mediaDevices ?? navigator.mediaDevices;
13712
+ if (!mediaDevices.getDisplayMedia) throw new DependencyError("getDisplayMedia is not supported by the current WebRTC provider");
13713
+ return mediaDevices.getDisplayMedia(options);
13699
13714
  }
13700
13715
  async setupRemoteTracks() {
13701
13716
  if (!this.peerConnection) throw new DependencyError("RTCPeerConnection is not initialized");
@@ -13836,7 +13851,10 @@ function isVertoAttachMessage(value) {
13836
13851
  return value.method === "verto.attach";
13837
13852
  }
13838
13853
  function isVertoAnswerInnerParams(value) {
13839
- return isObject(value) && hasProperty(value, "jsonrpc") && value.jsonrpc === "2.0" && hasProperty(value, "method") && value.method === "verto.answer" && isObject(value.params) && hasProperty(value.params, "callID") && hasProperty(value.params, "sdp");
13854
+ return isObject(value) && hasProperty(value, "jsonrpc") && value.jsonrpc === "2.0" && hasProperty(value, "method") && value.method === "verto.answer" && isObject(value.params) && hasProperty(value.params, "callID");
13855
+ }
13856
+ function isVertoMediaInnerParams(value) {
13857
+ return isObject(value) && hasProperty(value, "jsonrpc") && value.jsonrpc === "2.0" && hasProperty(value, "method") && value.method === "verto.media" && isObject(value.params) && hasProperty(value.params, "callID") && hasProperty(value.params, "sdp");
13840
13858
  }
13841
13859
  function isVertoMediaParamsInnerParams(value) {
13842
13860
  return isObject(value) && hasProperty(value, "jsonrpc") && value.jsonrpc === "2.0" && hasProperty(value, "method") && value.method === "verto.mediaParams" && isObject(value.params) && hasProperty(value.params, "mediaParams");
@@ -13860,11 +13878,12 @@ var VertoManager = class extends Destroyable {
13860
13878
  }
13861
13879
  };
13862
13880
  var WebRTCVertoManager = class extends VertoManager {
13863
- constructor(webRtcCallSession, attachManager, deviceController, options = {}) {
13881
+ constructor(webRtcCallSession, attachManager, deviceController, webRTCApiProvider, options = {}) {
13864
13882
  super(webRtcCallSession);
13865
13883
  this.webRtcCallSession = webRtcCallSession;
13866
13884
  this.attachManager = attachManager;
13867
13885
  this.deviceController = deviceController;
13886
+ this.webRTCApiProvider = webRTCApiProvider;
13868
13887
  this._rtcPeerConnections$ = this.createBehaviorSubject([]);
13869
13888
  this._selfId$ = this.createBehaviorSubject(null);
13870
13889
  this._signalingStatus$ = this.createBehaviorSubject(null);
@@ -13945,10 +13964,19 @@ var WebRTCVertoManager = class extends VertoManager {
13945
13964
  ].includes(connectionState)))));
13946
13965
  }
13947
13966
  initSubscriptions() {
13967
+ this.subscribeTo(this.vertoMedia$, (event) => {
13968
+ logger$10.debug("[WebRTCManager] Received Verto media event (early media SDP):", event);
13969
+ this._signalingStatus$.next("ringing");
13970
+ const { sdp, callID } = event;
13971
+ this._rtcPeerConnectionsMap.get(callID)?.updateAnswerStatus({
13972
+ status: "received",
13973
+ sdp
13974
+ });
13975
+ });
13948
13976
  this.subscribeTo(this.vertoAnswer$, (event) => {
13949
13977
  logger$10.debug("[WebRTCManager] Received Verto answer event:", event);
13950
- const { sdp } = event;
13951
- this._rtcPeerConnectionsMap.get(event.callID)?.updateAnswerStatus({
13978
+ const { sdp, callID } = event;
13979
+ this._rtcPeerConnectionsMap.get(callID)?.updateAnswerStatus({
13952
13980
  status: "received",
13953
13981
  sdp
13954
13982
  });
@@ -13989,6 +14017,9 @@ var WebRTCVertoManager = class extends VertoManager {
13989
14017
  get selfId() {
13990
14018
  return this._selfId$.value;
13991
14019
  }
14020
+ get vertoMedia$() {
14021
+ return this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoMediaInnerParams, "params"), (0, import_cjs$10.takeUntil)(this.destroyed$));
14022
+ }
13992
14023
  get vertoAnswer$() {
13993
14024
  return this.cachedObservable("vertoAnswer$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoAnswerInnerParams, "params"), (0, import_cjs$10.takeUntil)(this.destroyed$)));
13994
14025
  }
@@ -14027,7 +14058,7 @@ var WebRTCVertoManager = class extends VertoManager {
14027
14058
  }
14028
14059
  async sendLocalDescription(message, rtcPeerConnController) {
14029
14060
  const vertoMethod = message.method;
14030
- const optionalsParams = this.getSendLocalSDPOptionalParams(rtcPeerConnController);
14061
+ const optionalsParams = this.getSendLocalSDPOptionalParams(rtcPeerConnController, vertoMethod);
14031
14062
  try {
14032
14063
  const response = await this.executeVerto(message, optionalsParams);
14033
14064
  switch (vertoMethod) {
@@ -14072,7 +14103,6 @@ var WebRTCVertoManager = class extends VertoManager {
14072
14103
  this._selfId$.next(memberId);
14073
14104
  rtcPeerConnController.setMemberId(memberId);
14074
14105
  if (callId) this.webRtcCallSession.addCallId(callId);
14075
- this._signalingStatus$.next("ringing");
14076
14106
  this.attachManager.attach(this.webRtcCallSession);
14077
14107
  logger$10.info("[WebRTCManager] Verto invite successful");
14078
14108
  logger$10.debug(`[WebRTCManager] nodeid: ${this._nodeId$.value}, selfId: ${this._selfId$.value}`);
@@ -14104,6 +14134,7 @@ var WebRTCVertoManager = class extends VertoManager {
14104
14134
  inputVideoStream: options.inputVideoStream,
14105
14135
  receiveAudio: options.receiveAudio,
14106
14136
  receiveVideo: options.receiveVideo,
14137
+ webRTCApiProvider: this.webRTCApiProvider,
14107
14138
  ...this.RTCPeerConnectionConfig
14108
14139
  }, options.initOffer, this.deviceController);
14109
14140
  this.setupLocalDescriptionHandler(rtcPeerConnController);
@@ -14166,22 +14197,23 @@ var WebRTCVertoManager = class extends VertoManager {
14166
14197
  }
14167
14198
  setupVertoByeHandler() {
14168
14199
  this.subscribeTo(this.vertoBye$, () => {
14200
+ this._signalingStatus$.next("disconnected");
14169
14201
  this.attachManager.detach(this.webRtcCallSession);
14170
14202
  this.callSession?.destroy();
14171
14203
  });
14172
14204
  }
14173
- getSendLocalSDPOptionalParams(rtcPeerConnController) {
14205
+ getSendLocalSDPOptionalParams(rtcPeerConnController, vertoMethod) {
14174
14206
  let subscribe = void 0;
14175
- const initial = !rtcPeerConnController.firstSDPExchangeCompleted;
14176
- if (initial) {
14207
+ if (!rtcPeerConnController.firstSDPExchangeCompleted) {
14177
14208
  subscribe = [];
14178
14209
  if (rtcPeerConnController.isMainDevice) subscribe.push(...PreferencesContainer.instance.inviteSubscribeMainDevice);
14179
14210
  else if (rtcPeerConnController.isAdditionalDevice) subscribe.push(...PreferencesContainer.instance.inviteSubscribeAdditionalDevice);
14180
14211
  else if (rtcPeerConnController.isScreenShare) subscribe.push(...PreferencesContainer.instance.inviteSubscribeScreenshare);
14181
14212
  }
14213
+ const isInvite = vertoMethod === "verto.invite";
14182
14214
  return {
14183
14215
  callID: rtcPeerConnController.id,
14184
- node_id: initial ? "" : this._nodeId$.value ?? "",
14216
+ node_id: isInvite ? "" : this._nodeId$.value ?? "",
14185
14217
  subscribe
14186
14218
  };
14187
14219
  }
@@ -14193,7 +14225,12 @@ var WebRTCVertoManager = class extends VertoManager {
14193
14225
  this.callSession?.destroy();
14194
14226
  } else if (!vertoByeOrAccepted) {
14195
14227
  logger$10.info("[WebRTCManager] Call was not accepted, sending verto.bye.");
14196
- await this.bye("USER_BUSY");
14228
+ try {
14229
+ await this.bye("USER_BUSY");
14230
+ } finally {
14231
+ this._signalingStatus$.next("disconnected");
14232
+ this.callSession?.destroy();
14233
+ }
14197
14234
  } else {
14198
14235
  logger$10.debug("[WebRTCManager] Call accepted, sending answer");
14199
14236
  try {
@@ -14223,8 +14260,7 @@ var WebRTCVertoManager = class extends VertoManager {
14223
14260
  userVariables: {
14224
14261
  memberCallId: this.webRtcCallSession.id,
14225
14262
  memberId,
14226
- ...this.webRtcCallSession.options.userVariables,
14227
- ...PreferencesContainer.instance.userVariables
14263
+ ...this.webRtcCallSession.userVariables
14228
14264
  },
14229
14265
  screenShare: rtcPeerConnectionController.isScreenShare,
14230
14266
  additionalDevice: rtcPeerConnectionController.isAdditionalDevice,
@@ -14282,7 +14318,8 @@ var WebRTCVertoManager = class extends VertoManager {
14282
14318
  rtcPeerConnController = new RTCPeerConnectionController({
14283
14319
  ...options,
14284
14320
  ...this.RTCPeerConnectionConfig,
14285
- propose
14321
+ propose,
14322
+ webRTCApiProvider: this.webRTCApiProvider
14286
14323
  }, void 0, this.deviceController);
14287
14324
  this.setupLocalDescriptionHandler(rtcPeerConnController);
14288
14325
  if (propose === "screenshare") this._screenShareId = rtcPeerConnController.id;
@@ -14422,6 +14459,20 @@ var ParticipantFactory = class {
14422
14459
  //#region src/core/entities/Call.ts
14423
14460
  var import_cjs$9 = require_cjs();
14424
14461
  const logger$9 = getLogger();
14462
+ const fromDestinationParams = (destination) => {
14463
+ if (!destination) return {};
14464
+ try {
14465
+ const url = new URL(`destination:${destination}`);
14466
+ const params = {};
14467
+ url.searchParams.forEach((value, key) => {
14468
+ params[key] = value;
14469
+ });
14470
+ return params;
14471
+ } catch (error) {
14472
+ logger$9.warn(`Failed to parse destination URI: ${destination}`, error);
14473
+ return {};
14474
+ }
14475
+ };
14425
14476
  /**
14426
14477
  * Concrete WebRTC call implementation.
14427
14478
  *
@@ -14439,8 +14490,21 @@ var WebRTCCall = class extends Destroyable {
14439
14490
  this._errors$ = this.createSubject();
14440
14491
  this._answered$ = this.createReplaySubject();
14441
14492
  this._holdState = false;
14493
+ this._userVariables$ = this.createBehaviorSubject({ ...PreferencesContainer.instance.userVariables });
14442
14494
  this.id = options.callId ?? v4_default();
14443
14495
  this.to = options.to;
14496
+ this._userVariables$.next({
14497
+ ...this._userVariables$.value,
14498
+ ...fromDestinationParams(options.to),
14499
+ ...options.userVariables
14500
+ });
14501
+ this.subscribeTo(this.webrtcMessages$, (message) => {
14502
+ const userVars = getValueFrom(message, "params.userVariables");
14503
+ if (userVars) this._userVariables$.next({
14504
+ ...this._userVariables$.value,
14505
+ ...userVars
14506
+ });
14507
+ });
14444
14508
  const managers = initialization.initializeManagers(this);
14445
14509
  this.vertoManager = managers.vertoManager;
14446
14510
  this.callEventsManager = managers.callEventsManager;
@@ -14654,6 +14718,21 @@ var WebRTCCall = class extends Destroyable {
14654
14718
  get remoteStream() {
14655
14719
  return this.vertoManager.remoteStream;
14656
14720
  }
14721
+ /** Observable of custom user variables associated with the call. */
14722
+ get userVariables$() {
14723
+ return this._userVariables$.asObservable();
14724
+ }
14725
+ /** a copy of the current custom user variables of the call. */
14726
+ get userVariables() {
14727
+ return { ...this._userVariables$.value };
14728
+ }
14729
+ /** Merge current custom user variables of the call. */
14730
+ set userVariables(variables) {
14731
+ this._userVariables$.next({
14732
+ ...this._userVariables$.value,
14733
+ ...variables
14734
+ });
14735
+ }
14657
14736
  /** @internal */
14658
14737
  createParticipant(memberId, selfId) {
14659
14738
  if (memberId === (selfId ?? this.vertoManager.selfId)) return this.participantFactory.createSelfParticipant(memberId);
@@ -14759,7 +14838,6 @@ var WebRTCCall = class extends Destroyable {
14759
14838
  try {
14760
14839
  await this.vertoManager.bye();
14761
14840
  } finally {
14762
- this._status$.next("destroyed");
14763
14841
  this.destroy();
14764
14842
  }
14765
14843
  }
@@ -14798,6 +14876,7 @@ var WebRTCCall = class extends Destroyable {
14798
14876
  }
14799
14877
  /** Destroys the call, releasing all resources and subscriptions. */
14800
14878
  destroy() {
14879
+ this._status$.next("destroyed");
14801
14880
  this.vertoManager.destroy();
14802
14881
  this.callEventsManager.destroy();
14803
14882
  this.participantsMap.clear();
@@ -14812,10 +14891,11 @@ var WebRTCCall = class extends Destroyable {
14812
14891
  * Eliminates circular dependencies by centralizing Call and Manager creation.
14813
14892
  */
14814
14893
  var CallFactory = class {
14815
- constructor(sessionManager, deviceController, attachManager) {
14894
+ constructor(sessionManager, deviceController, attachManager, webRTCApiProvider) {
14816
14895
  this.sessionManager = sessionManager;
14817
14896
  this.deviceController = deviceController;
14818
14897
  this.attachManager = attachManager;
14898
+ this.webRTCApiProvider = webRTCApiProvider;
14819
14899
  }
14820
14900
  /**
14821
14901
  * Create a new WebRTCCall with properly initialized managers
@@ -14824,7 +14904,7 @@ var CallFactory = class {
14824
14904
  return new WebRTCCall(this.sessionManager, options, {
14825
14905
  initializeManagers: (callInstance) => {
14826
14906
  return {
14827
- vertoManager: new WebRTCVertoManager(callInstance, this.attachManager, this.deviceController, {
14907
+ vertoManager: new WebRTCVertoManager(callInstance, this.attachManager, this.deviceController, this.webRTCApiProvider, {
14828
14908
  nodeId: options.nodeId,
14829
14909
  onError: (error) => {
14830
14910
  callInstance.emitError(error);
@@ -14851,7 +14931,10 @@ var Fetcher = class {
14851
14931
  this.nextUrl = `${this.endpoint}?${params}`;
14852
14932
  }
14853
14933
  async next() {
14854
- if (!this.nextUrl) return [];
14934
+ if (!this.nextUrl) {
14935
+ this.hasMore = false;
14936
+ return [];
14937
+ }
14855
14938
  const response = await this.http.request({
14856
14939
  ...GET_PARAMS,
14857
14940
  url: this.nextUrl
@@ -14859,6 +14942,7 @@ var Fetcher = class {
14859
14942
  if (response.ok && !!response.body) {
14860
14943
  const result = JSON.parse(response.body);
14861
14944
  this.nextUrl = result.links.next;
14945
+ this.hasMore = !!this.nextUrl;
14862
14946
  return result.data.filter(this.filter).map(this.mapper);
14863
14947
  }
14864
14948
  logger$8.error("Failed to fetch entity");
@@ -14892,10 +14976,11 @@ var EntityCollection = class extends Destroyable {
14892
14976
  this.observablesRegistry.get(data.id)?.next(updated);
14893
14977
  this.values$.next(Array.from(this.collectionData.values()));
14894
14978
  };
14979
+ this._hasMore$ = this.createBehaviorSubject(true);
14895
14980
  this._destroy$ = new import_cjs$8.Subject();
14896
14981
  this.updateSubscription = this.update$.subscribe(this.upsertData);
14897
14982
  this.loading$.next(false);
14898
- this.hasMore$ = (0, import_cjs$8.defer)(() => (0, import_cjs$8.from)(this.init())).pipe((0, import_cjs$8.shareReplay)(1), (0, import_cjs$8.takeUntil)(this._destroy$));
14983
+ this.hasMore$ = (0, import_cjs$8.defer)(() => (0, import_cjs$8.from)(this.init())).pipe((0, import_cjs$8.switchMap)(() => this._hasMore$), (0, import_cjs$8.distinctUntilChanged)(), (0, import_cjs$8.shareReplay)(1), (0, import_cjs$8.takeUntil)(this._destroy$));
14899
14984
  }
14900
14985
  get loading() {
14901
14986
  return this.loading$.value;
@@ -14910,17 +14995,21 @@ var EntityCollection = class extends Destroyable {
14910
14995
  return Array.from(this.collectionData.values());
14911
14996
  }
14912
14997
  async init() {
14913
- if (this.fetchController.hasMore === false) return Promise.resolve(false);
14998
+ if (this.fetchController.hasMore === false) {
14999
+ this._hasMore$.next(false);
15000
+ return;
15001
+ }
14914
15002
  await this.fetchMore();
14915
- return this.fetchController.hasMore ?? true;
14916
15003
  }
14917
15004
  async fetchMore() {
14918
15005
  try {
14919
15006
  this.loading$.next(true);
14920
15007
  (await this.fetchController.next()).forEach(this.upsertData);
15008
+ this._hasMore$.next(this.fetchController.hasMore ?? false);
14921
15009
  this.loading$.next(false);
14922
15010
  } catch (error) {
14923
15011
  logger$8.error(`Failed to fetch initial collection data`, error);
15012
+ this._hasMore$.next(this.fetchController.hasMore ?? false);
14924
15013
  this.loading$.next(false);
14925
15014
  this.onError?.(new CollectionFetchError("fetchMore", error));
14926
15015
  }
@@ -15240,7 +15329,7 @@ const getAddressSearchURI = (options) => {
15240
15329
  return name;
15241
15330
  };
15242
15331
  var ClientSessionManager = class extends Destroyable {
15243
- constructor(credential, transport, storage, authorizationStateKey, deviceController, attachManager) {
15332
+ constructor(credential, transport, storage, authorizationStateKey, deviceController, attachManager, webRTCApiProvider) {
15244
15333
  super();
15245
15334
  this.credential = credential;
15246
15335
  this.transport = transport;
@@ -15263,7 +15352,7 @@ var ClientSessionManager = class extends Destroyable {
15263
15352
  this._calls$ = this.createBehaviorSubject({});
15264
15353
  this._iceServers$ = this.createBehaviorSubject([]);
15265
15354
  attachManager.setSession(this);
15266
- this.callFactory = new CallFactory(this, deviceController, attachManager);
15355
+ this.callFactory = new CallFactory(this, deviceController, attachManager, webRTCApiProvider);
15267
15356
  this.initialized$ = (0, import_cjs$5.defer)(() => (0, import_cjs$5.from)(this.init())).pipe((0, import_cjs$5.shareReplay)(1), (0, import_cjs$5.takeUntil)(this.destroyed$));
15268
15357
  }
15269
15358
  get incomingCalls$() {
@@ -15492,7 +15581,8 @@ var ClientSessionManager = class extends Destroyable {
15492
15581
  to: invite.callee_id_number,
15493
15582
  fromName: invite.caller_id_name,
15494
15583
  from: invite.caller_id_number,
15495
- displayDirection: invite.display_direction
15584
+ displayDirection: invite.display_direction,
15585
+ userVariables: invite.userVariables
15496
15586
  });
15497
15587
  await (0, import_cjs$5.firstValueFrom)(callSession.status$);
15498
15588
  this._calls$.next({
@@ -15524,12 +15614,14 @@ var ClientSessionManager = class extends Destroyable {
15524
15614
  try {
15525
15615
  const addressURI = getAddressSearchURI(options);
15526
15616
  let address;
15527
- if (!addressURI.startsWith("+")) {
15617
+ try {
15528
15618
  if (!this._directory) throw new DependencyError("Directory not initialized");
15529
15619
  const addressId = await this._directory.findAddressIdByURI(addressURI);
15530
15620
  if (!addressId) throw new DependencyError(`Address name: ${addressURI} not found`);
15531
15621
  address = this._directory.get(addressId);
15532
15622
  if (!address) throw new DependencyError(`Address ID: ${addressId} not found`);
15623
+ } catch (error) {
15624
+ logger$6.warn(`[Session] Directory lookup failed for ${addressURI}, proceeding with raw URI`);
15533
15625
  }
15534
15626
  const callSession = this.callFactory.createCall(address, { ...options });
15535
15627
  callSession.status$.pipe((0, import_cjs$5.filter)((status) => status === "destroyed"), (0, import_cjs$5.take)(1)).subscribe(() => {
@@ -16155,6 +16247,7 @@ var SignalWire = class extends Destroyable {
16155
16247
  if (this._options.storageImplementation) this._deps.storageImpl = this._options.storageImplementation;
16156
16248
  if (this._options.webSocketConstructor) this._deps.WebSocket = this._options.webSocketConstructor;
16157
16249
  if (this._options.savePreferences) this.preferences.enableSavePreferences(this._deps.storage);
16250
+ if (this._options.webRTCApiProvider) this._deps.webRTCApiProvider = this._options.webRTCApiProvider;
16158
16251
  this._deviceController = this._deps.deviceController;
16159
16252
  if (!this._options.skipDeviceMonitoring) this._deviceController.enableDeviceMonitoring();
16160
16253
  this.subscribeTo(this._deviceController.errors$, (error) => {
@@ -16279,7 +16372,7 @@ var SignalWire = class extends Destroyable {
16279
16372
  };
16280
16373
  this._transport = new TransportManager(this._deps.storage, this._deps.protocolKey, this._deps.WebSocket, PreferencesContainer.instance.relayHost ?? this._deps.relayHost, errorHandler);
16281
16374
  this._attachManager = new AttachManager(this._deps.storage, this._deps.deviceController, PreferencesContainer.instance.reconnectCallsTimeout, this._deps.attachedCallsKey);
16282
- this._clientSession = new ClientSessionManager(this._deps.credential, this._transport, this._deps.storage, this._deps.authorizationStateKey, this._deps.deviceController, this._attachManager);
16375
+ this._clientSession = new ClientSessionManager(this._deps.credential, this._transport, this._deps.storage, this._deps.authorizationStateKey, this._deps.deviceController, this._attachManager, this._deps.webRTCApiProvider);
16283
16376
  this._publicSession = new ClientSessionWrapper(this._clientSession);
16284
16377
  this.subscribeTo(this._clientSession.errors$, (error) => {
16285
16378
  this._errors$.next(error);