@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.
package/dist/browser.mjs CHANGED
@@ -6934,7 +6934,7 @@ var require_switchMap = /* @__PURE__ */ __commonJSMin(((exports) => {
6934
6934
  var innerFrom_1$6 = require_innerFrom();
6935
6935
  var lift_1$13 = require_lift();
6936
6936
  var OperatorSubscriber_1$11 = require_OperatorSubscriber();
6937
- function switchMap$2(project, resultSelector) {
6937
+ function switchMap$3(project, resultSelector) {
6938
6938
  return lift_1$13.operate(function(source, subscriber) {
6939
6939
  var innerSubscriber = null;
6940
6940
  var index = 0;
@@ -6958,7 +6958,7 @@ var require_switchMap = /* @__PURE__ */ __commonJSMin(((exports) => {
6958
6958
  }));
6959
6959
  });
6960
6960
  }
6961
- exports.switchMap = switchMap$2;
6961
+ exports.switchMap = switchMap$3;
6962
6962
  }));
6963
6963
 
6964
6964
  //#endregion
@@ -9964,8 +9964,9 @@ const selectDevice = (devices = [], selected, preferred) => {
9964
9964
  return selected;
9965
9965
  };
9966
9966
  var NavigatorDeviceController = class extends Destroyable {
9967
- constructor() {
9967
+ constructor(webRTCApiProvider) {
9968
9968
  super();
9969
+ this.webRTCApiProvider = webRTCApiProvider;
9969
9970
  this.deviceChangeHandler = () => {
9970
9971
  logger$19.debug("[DeviceController] Device change detected");
9971
9972
  this.enumerateDevices();
@@ -10047,24 +10048,22 @@ var NavigatorDeviceController = class extends Destroyable {
10047
10048
  });
10048
10049
  }
10049
10050
  init() {
10050
- if (navigator.mediaDevices) {
10051
- this.subscribeTo(this._devicesState$.pipe((0, import_cjs$20.debounceTime)(PreferencesContainer.instance.deviceDebounceTime)), (devicesState) => {
10052
- const currentSelected = this._selectedDevicesState$.value;
10053
- const newAudioInput = selectDevice(devicesState.audioinput, currentSelected.audioinput, PreferencesContainer.instance.preferredAudioInput);
10054
- const newAudioOutput = selectDevice(devicesState.audiooutput, currentSelected.audiooutput, PreferencesContainer.instance.preferredAudioOutput);
10055
- const newVideoInput = selectDevice(devicesState.videoinput, currentSelected.videoinput, PreferencesContainer.instance.preferredVideoInput);
10056
- if (newAudioInput !== currentSelected.audioinput || newAudioOutput !== currentSelected.audiooutput || newVideoInput !== currentSelected.videoinput) this._selectedDevicesState$.next({
10057
- audioinput: newAudioInput,
10058
- audiooutput: newAudioOutput,
10059
- videoinput: newVideoInput
10060
- });
10051
+ this.subscribeTo(this._devicesState$.pipe((0, import_cjs$20.debounceTime)(PreferencesContainer.instance.deviceDebounceTime)), (devicesState) => {
10052
+ const currentSelected = this._selectedDevicesState$.value;
10053
+ const newAudioInput = selectDevice(devicesState.audioinput, currentSelected.audioinput, PreferencesContainer.instance.preferredAudioInput);
10054
+ const newAudioOutput = selectDevice(devicesState.audiooutput, currentSelected.audiooutput, PreferencesContainer.instance.preferredAudioOutput);
10055
+ const newVideoInput = selectDevice(devicesState.videoinput, currentSelected.videoinput, PreferencesContainer.instance.preferredVideoInput);
10056
+ if (newAudioInput !== currentSelected.audioinput || newAudioOutput !== currentSelected.audiooutput || newVideoInput !== currentSelected.videoinput) this._selectedDevicesState$.next({
10057
+ audioinput: newAudioInput,
10058
+ audiooutput: newAudioOutput,
10059
+ videoinput: newVideoInput
10061
10060
  });
10062
- this.enumerateDevices();
10063
- }
10061
+ });
10062
+ this.enumerateDevices();
10064
10063
  }
10065
10064
  enableDeviceMonitoring() {
10066
10065
  this.disableDeviceMonitoring();
10067
- navigator.mediaDevices.addEventListener("devicechange", this.deviceChangeHandler);
10066
+ this.webRTCApiProvider.mediaDevices.addEventListener("devicechange", this.deviceChangeHandler);
10068
10067
  if (PreferencesContainer.instance.devicePollingInterval > 0) this._devicesPoolingSubscription = (0, import_cjs$20.interval)(PreferencesContainer.instance.devicePollingInterval).subscribe(() => {
10069
10068
  logger$19.debug("[DeviceController] Polling devices due to interval");
10070
10069
  this.enumerateDevices();
@@ -10072,7 +10071,7 @@ var NavigatorDeviceController = class extends Destroyable {
10072
10071
  this.enumerateDevices();
10073
10072
  }
10074
10073
  disableDeviceMonitoring() {
10075
- navigator.mediaDevices.removeEventListener("devicechange", this.deviceChangeHandler);
10074
+ this.webRTCApiProvider.mediaDevices.removeEventListener("devicechange", this.deviceChangeHandler);
10076
10075
  if (this._devicesPoolingSubscription) {
10077
10076
  this._devicesPoolingSubscription.unsubscribe();
10078
10077
  this._devicesPoolingSubscription = void 0;
@@ -10080,7 +10079,7 @@ var NavigatorDeviceController = class extends Destroyable {
10080
10079
  }
10081
10080
  async enumerateDevices() {
10082
10081
  try {
10083
- const devicesByKind = (await navigator.mediaDevices.enumerateDevices()).reduce((acc, device) => {
10082
+ const devicesByKind = (await this.webRTCApiProvider.mediaDevices.enumerateDevices()).reduce((acc, device) => {
10084
10083
  acc[device.kind].push(device);
10085
10084
  return acc;
10086
10085
  }, {
@@ -10103,7 +10102,7 @@ var NavigatorDeviceController = class extends Destroyable {
10103
10102
  if (deviceInfo.kind === "audiooutput") return null;
10104
10103
  try {
10105
10104
  const constraints = this.deviceInfoToConstraints(deviceInfo);
10106
- const stream = await navigator.mediaDevices.getUserMedia({
10105
+ const stream = await this.webRTCApiProvider.mediaDevices.getUserMedia({
10107
10106
  audio: deviceInfo.kind === "audioinput" ? constraints : false,
10108
10107
  video: deviceInfo.kind === "videoinput" ? constraints : false
10109
10108
  });
@@ -10275,9 +10274,23 @@ var DependencyContainer = class {
10275
10274
  this._webSocketConstructor = WebSocketConstructor;
10276
10275
  }
10277
10276
  get deviceController() {
10278
- this._deviceController ??= new NavigatorDeviceController();
10277
+ this._deviceController ??= new NavigatorDeviceController(this.webRTCApiProvider);
10279
10278
  return this._deviceController;
10280
10279
  }
10280
+ get webRTCApiProvider() {
10281
+ if (!this._webRTCApiProvider) {
10282
+ 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.");
10283
+ this._webRTCApiProvider = {
10284
+ RTCPeerConnection,
10285
+ mediaDevices: navigator.mediaDevices
10286
+ };
10287
+ }
10288
+ return this._webRTCApiProvider;
10289
+ }
10290
+ set webRTCApiProvider(webRTCApiProvider) {
10291
+ this._webRTCApiProvider = webRTCApiProvider;
10292
+ this._deviceController = void 0;
10293
+ }
10281
10294
  get authorizationStateKey() {
10282
10295
  return `sw:${this.subscriberId}:as`;
10283
10296
  }
@@ -12188,7 +12201,7 @@ function isJSONRPCRequest(value) {
12188
12201
  return isObject(value) && hasProperty(value, "jsonrpc") && value.jsonrpc === "2.0" && hasProperty(value, "id") && typeof value.id === "string" && hasProperty(value, "method") && typeof value.method === "string";
12189
12202
  }
12190
12203
  function isJSONRPCResponse(value) {
12191
- return isObject(value) && hasProperty(value, "jsonrpc") && value.jsonrpc === "2.0" && hasProperty(value, "id") && typeof value.id === "string" && hasProperty(value, "result");
12204
+ return isObject(value) && hasProperty(value, "jsonrpc") && value.jsonrpc === "2.0" && hasProperty(value, "id") && typeof value.id === "string" && (hasProperty(value, "result") || hasProperty(value, "error"));
12192
12205
  }
12193
12206
 
12194
12207
  //#endregion
@@ -12502,7 +12515,7 @@ var CallEventsManager = class extends Destroyable {
12502
12515
  });
12503
12516
  this.updateParticipants(sessionState.members);
12504
12517
  this._self$.value?.capabilities.updateFromRaw(capabilities);
12505
- this.updateLayouts();
12518
+ if (this._self$.value?.capabilities.setLayout) this.updateLayouts();
12506
12519
  });
12507
12520
  this.subscribeTo(this.memberUpdates$, (member) => {
12508
12521
  logger$15.debug("[CallEventsManager] Handling member update event for member ID:", member);
@@ -13230,7 +13243,7 @@ var RTCPeerConnectionController = class extends Destroyable {
13230
13243
  logger$11.debug(`[RTCPeerConnectionController] ${kind} input device selected: none`);
13231
13244
  return;
13232
13245
  }
13233
- const streamTrack = (await navigator.mediaDevices.getUserMedia({ [kind]: {
13246
+ const streamTrack = (await this.getUserMedia({ [kind]: {
13234
13247
  ...track.getConstraints(),
13235
13248
  ...this.deviceController.deviceInfoToConstraints(deviceInfo)
13236
13249
  } })).getTracks().find((t) => t.kind === kind);
@@ -13421,7 +13434,7 @@ var RTCPeerConnectionController = class extends Destroyable {
13421
13434
  };
13422
13435
  }
13423
13436
  get WebRTCPeerConnectionConstructor() {
13424
- return this.options.WebRTCPeerConnectionConstructor ?? RTCPeerConnection;
13437
+ return this.options.webRTCApiProvider?.RTCPeerConnection ?? RTCPeerConnection;
13425
13438
  }
13426
13439
  get offerOptions() {
13427
13440
  const options = { iceRestart: this.firstSDPExchangeCompleted ? true : void 0 };
@@ -13688,10 +13701,12 @@ var RTCPeerConnectionController = class extends Destroyable {
13688
13701
  }
13689
13702
  }
13690
13703
  async getUserMedia(constraints) {
13691
- return this.options.getUserMedia?.(constraints) ?? navigator.mediaDevices.getUserMedia(constraints);
13704
+ return (this.options.webRTCApiProvider?.mediaDevices ?? navigator.mediaDevices).getUserMedia(constraints);
13692
13705
  }
13693
13706
  async getDisplayMedia(options) {
13694
- return this.options.getDisplayMedia?.(options) ?? navigator.mediaDevices.getDisplayMedia(options);
13707
+ const mediaDevices = this.options.webRTCApiProvider?.mediaDevices ?? navigator.mediaDevices;
13708
+ if (!mediaDevices.getDisplayMedia) throw new DependencyError("getDisplayMedia is not supported by the current WebRTC provider");
13709
+ return mediaDevices.getDisplayMedia(options);
13695
13710
  }
13696
13711
  async setupRemoteTracks() {
13697
13712
  if (!this.peerConnection) throw new DependencyError("RTCPeerConnection is not initialized");
@@ -13832,7 +13847,10 @@ function isVertoAttachMessage(value) {
13832
13847
  return value.method === "verto.attach";
13833
13848
  }
13834
13849
  function isVertoAnswerInnerParams(value) {
13835
- 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");
13850
+ return isObject(value) && hasProperty(value, "jsonrpc") && value.jsonrpc === "2.0" && hasProperty(value, "method") && value.method === "verto.answer" && isObject(value.params) && hasProperty(value.params, "callID");
13851
+ }
13852
+ function isVertoMediaInnerParams(value) {
13853
+ 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");
13836
13854
  }
13837
13855
  function isVertoMediaParamsInnerParams(value) {
13838
13856
  return isObject(value) && hasProperty(value, "jsonrpc") && value.jsonrpc === "2.0" && hasProperty(value, "method") && value.method === "verto.mediaParams" && isObject(value.params) && hasProperty(value.params, "mediaParams");
@@ -13856,11 +13874,12 @@ var VertoManager = class extends Destroyable {
13856
13874
  }
13857
13875
  };
13858
13876
  var WebRTCVertoManager = class extends VertoManager {
13859
- constructor(webRtcCallSession, attachManager, deviceController, options = {}) {
13877
+ constructor(webRtcCallSession, attachManager, deviceController, webRTCApiProvider, options = {}) {
13860
13878
  super(webRtcCallSession);
13861
13879
  this.webRtcCallSession = webRtcCallSession;
13862
13880
  this.attachManager = attachManager;
13863
13881
  this.deviceController = deviceController;
13882
+ this.webRTCApiProvider = webRTCApiProvider;
13864
13883
  this._rtcPeerConnections$ = this.createBehaviorSubject([]);
13865
13884
  this._selfId$ = this.createBehaviorSubject(null);
13866
13885
  this._signalingStatus$ = this.createBehaviorSubject(null);
@@ -13941,10 +13960,19 @@ var WebRTCVertoManager = class extends VertoManager {
13941
13960
  ].includes(connectionState)))));
13942
13961
  }
13943
13962
  initSubscriptions() {
13963
+ this.subscribeTo(this.vertoMedia$, (event) => {
13964
+ logger$10.debug("[WebRTCManager] Received Verto media event (early media SDP):", event);
13965
+ this._signalingStatus$.next("ringing");
13966
+ const { sdp, callID } = event;
13967
+ this._rtcPeerConnectionsMap.get(callID)?.updateAnswerStatus({
13968
+ status: "received",
13969
+ sdp
13970
+ });
13971
+ });
13944
13972
  this.subscribeTo(this.vertoAnswer$, (event) => {
13945
13973
  logger$10.debug("[WebRTCManager] Received Verto answer event:", event);
13946
- const { sdp } = event;
13947
- this._rtcPeerConnectionsMap.get(event.callID)?.updateAnswerStatus({
13974
+ const { sdp, callID } = event;
13975
+ this._rtcPeerConnectionsMap.get(callID)?.updateAnswerStatus({
13948
13976
  status: "received",
13949
13977
  sdp
13950
13978
  });
@@ -13985,6 +14013,9 @@ var WebRTCVertoManager = class extends VertoManager {
13985
14013
  get selfId() {
13986
14014
  return this._selfId$.value;
13987
14015
  }
14016
+ get vertoMedia$() {
14017
+ return this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoMediaInnerParams, "params"), (0, import_cjs$10.takeUntil)(this.destroyed$));
14018
+ }
13988
14019
  get vertoAnswer$() {
13989
14020
  return this.cachedObservable("vertoAnswer$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoAnswerInnerParams, "params"), (0, import_cjs$10.takeUntil)(this.destroyed$)));
13990
14021
  }
@@ -14023,7 +14054,7 @@ var WebRTCVertoManager = class extends VertoManager {
14023
14054
  }
14024
14055
  async sendLocalDescription(message, rtcPeerConnController) {
14025
14056
  const vertoMethod = message.method;
14026
- const optionalsParams = this.getSendLocalSDPOptionalParams(rtcPeerConnController);
14057
+ const optionalsParams = this.getSendLocalSDPOptionalParams(rtcPeerConnController, vertoMethod);
14027
14058
  try {
14028
14059
  const response = await this.executeVerto(message, optionalsParams);
14029
14060
  switch (vertoMethod) {
@@ -14068,7 +14099,6 @@ var WebRTCVertoManager = class extends VertoManager {
14068
14099
  this._selfId$.next(memberId);
14069
14100
  rtcPeerConnController.setMemberId(memberId);
14070
14101
  if (callId) this.webRtcCallSession.addCallId(callId);
14071
- this._signalingStatus$.next("ringing");
14072
14102
  this.attachManager.attach(this.webRtcCallSession);
14073
14103
  logger$10.info("[WebRTCManager] Verto invite successful");
14074
14104
  logger$10.debug(`[WebRTCManager] nodeid: ${this._nodeId$.value}, selfId: ${this._selfId$.value}`);
@@ -14100,6 +14130,7 @@ var WebRTCVertoManager = class extends VertoManager {
14100
14130
  inputVideoStream: options.inputVideoStream,
14101
14131
  receiveAudio: options.receiveAudio,
14102
14132
  receiveVideo: options.receiveVideo,
14133
+ webRTCApiProvider: this.webRTCApiProvider,
14103
14134
  ...this.RTCPeerConnectionConfig
14104
14135
  }, options.initOffer, this.deviceController);
14105
14136
  this.setupLocalDescriptionHandler(rtcPeerConnController);
@@ -14162,22 +14193,23 @@ var WebRTCVertoManager = class extends VertoManager {
14162
14193
  }
14163
14194
  setupVertoByeHandler() {
14164
14195
  this.subscribeTo(this.vertoBye$, () => {
14196
+ this._signalingStatus$.next("disconnected");
14165
14197
  this.attachManager.detach(this.webRtcCallSession);
14166
14198
  this.callSession?.destroy();
14167
14199
  });
14168
14200
  }
14169
- getSendLocalSDPOptionalParams(rtcPeerConnController) {
14201
+ getSendLocalSDPOptionalParams(rtcPeerConnController, vertoMethod) {
14170
14202
  let subscribe = void 0;
14171
- const initial = !rtcPeerConnController.firstSDPExchangeCompleted;
14172
- if (initial) {
14203
+ if (!rtcPeerConnController.firstSDPExchangeCompleted) {
14173
14204
  subscribe = [];
14174
14205
  if (rtcPeerConnController.isMainDevice) subscribe.push(...PreferencesContainer.instance.inviteSubscribeMainDevice);
14175
14206
  else if (rtcPeerConnController.isAdditionalDevice) subscribe.push(...PreferencesContainer.instance.inviteSubscribeAdditionalDevice);
14176
14207
  else if (rtcPeerConnController.isScreenShare) subscribe.push(...PreferencesContainer.instance.inviteSubscribeScreenshare);
14177
14208
  }
14209
+ const isInvite = vertoMethod === "verto.invite";
14178
14210
  return {
14179
14211
  callID: rtcPeerConnController.id,
14180
- node_id: initial ? "" : this._nodeId$.value ?? "",
14212
+ node_id: isInvite ? "" : this._nodeId$.value ?? "",
14181
14213
  subscribe
14182
14214
  };
14183
14215
  }
@@ -14189,7 +14221,12 @@ var WebRTCVertoManager = class extends VertoManager {
14189
14221
  this.callSession?.destroy();
14190
14222
  } else if (!vertoByeOrAccepted) {
14191
14223
  logger$10.info("[WebRTCManager] Call was not accepted, sending verto.bye.");
14192
- await this.bye("USER_BUSY");
14224
+ try {
14225
+ await this.bye("USER_BUSY");
14226
+ } finally {
14227
+ this._signalingStatus$.next("disconnected");
14228
+ this.callSession?.destroy();
14229
+ }
14193
14230
  } else {
14194
14231
  logger$10.debug("[WebRTCManager] Call accepted, sending answer");
14195
14232
  try {
@@ -14219,8 +14256,7 @@ var WebRTCVertoManager = class extends VertoManager {
14219
14256
  userVariables: {
14220
14257
  memberCallId: this.webRtcCallSession.id,
14221
14258
  memberId,
14222
- ...this.webRtcCallSession.options.userVariables,
14223
- ...PreferencesContainer.instance.userVariables
14259
+ ...this.webRtcCallSession.userVariables
14224
14260
  },
14225
14261
  screenShare: rtcPeerConnectionController.isScreenShare,
14226
14262
  additionalDevice: rtcPeerConnectionController.isAdditionalDevice,
@@ -14278,7 +14314,8 @@ var WebRTCVertoManager = class extends VertoManager {
14278
14314
  rtcPeerConnController = new RTCPeerConnectionController({
14279
14315
  ...options,
14280
14316
  ...this.RTCPeerConnectionConfig,
14281
- propose
14317
+ propose,
14318
+ webRTCApiProvider: this.webRTCApiProvider
14282
14319
  }, void 0, this.deviceController);
14283
14320
  this.setupLocalDescriptionHandler(rtcPeerConnController);
14284
14321
  if (propose === "screenshare") this._screenShareId = rtcPeerConnController.id;
@@ -14418,6 +14455,20 @@ var ParticipantFactory = class {
14418
14455
  //#region src/core/entities/Call.ts
14419
14456
  var import_cjs$9 = require_cjs();
14420
14457
  const logger$9 = getLogger();
14458
+ const fromDestinationParams = (destination) => {
14459
+ if (!destination) return {};
14460
+ try {
14461
+ const url = new URL(`destination:${destination}`);
14462
+ const params = {};
14463
+ url.searchParams.forEach((value, key) => {
14464
+ params[key] = value;
14465
+ });
14466
+ return params;
14467
+ } catch (error) {
14468
+ logger$9.warn(`Failed to parse destination URI: ${destination}`, error);
14469
+ return {};
14470
+ }
14471
+ };
14421
14472
  /**
14422
14473
  * Concrete WebRTC call implementation.
14423
14474
  *
@@ -14435,8 +14486,21 @@ var WebRTCCall = class extends Destroyable {
14435
14486
  this._errors$ = this.createSubject();
14436
14487
  this._answered$ = this.createReplaySubject();
14437
14488
  this._holdState = false;
14489
+ this._userVariables$ = this.createBehaviorSubject({ ...PreferencesContainer.instance.userVariables });
14438
14490
  this.id = options.callId ?? v4_default();
14439
14491
  this.to = options.to;
14492
+ this._userVariables$.next({
14493
+ ...this._userVariables$.value,
14494
+ ...fromDestinationParams(options.to),
14495
+ ...options.userVariables
14496
+ });
14497
+ this.subscribeTo(this.webrtcMessages$, (message) => {
14498
+ const userVars = getValueFrom(message, "params.userVariables");
14499
+ if (userVars) this._userVariables$.next({
14500
+ ...this._userVariables$.value,
14501
+ ...userVars
14502
+ });
14503
+ });
14440
14504
  const managers = initialization.initializeManagers(this);
14441
14505
  this.vertoManager = managers.vertoManager;
14442
14506
  this.callEventsManager = managers.callEventsManager;
@@ -14650,6 +14714,21 @@ var WebRTCCall = class extends Destroyable {
14650
14714
  get remoteStream() {
14651
14715
  return this.vertoManager.remoteStream;
14652
14716
  }
14717
+ /** Observable of custom user variables associated with the call. */
14718
+ get userVariables$() {
14719
+ return this._userVariables$.asObservable();
14720
+ }
14721
+ /** a copy of the current custom user variables of the call. */
14722
+ get userVariables() {
14723
+ return { ...this._userVariables$.value };
14724
+ }
14725
+ /** Merge current custom user variables of the call. */
14726
+ set userVariables(variables) {
14727
+ this._userVariables$.next({
14728
+ ...this._userVariables$.value,
14729
+ ...variables
14730
+ });
14731
+ }
14653
14732
  /** @internal */
14654
14733
  createParticipant(memberId, selfId) {
14655
14734
  if (memberId === (selfId ?? this.vertoManager.selfId)) return this.participantFactory.createSelfParticipant(memberId);
@@ -14755,7 +14834,6 @@ var WebRTCCall = class extends Destroyable {
14755
14834
  try {
14756
14835
  await this.vertoManager.bye();
14757
14836
  } finally {
14758
- this._status$.next("destroyed");
14759
14837
  this.destroy();
14760
14838
  }
14761
14839
  }
@@ -14794,6 +14872,7 @@ var WebRTCCall = class extends Destroyable {
14794
14872
  }
14795
14873
  /** Destroys the call, releasing all resources and subscriptions. */
14796
14874
  destroy() {
14875
+ this._status$.next("destroyed");
14797
14876
  this.vertoManager.destroy();
14798
14877
  this.callEventsManager.destroy();
14799
14878
  this.participantsMap.clear();
@@ -14808,10 +14887,11 @@ var WebRTCCall = class extends Destroyable {
14808
14887
  * Eliminates circular dependencies by centralizing Call and Manager creation.
14809
14888
  */
14810
14889
  var CallFactory = class {
14811
- constructor(sessionManager, deviceController, attachManager) {
14890
+ constructor(sessionManager, deviceController, attachManager, webRTCApiProvider) {
14812
14891
  this.sessionManager = sessionManager;
14813
14892
  this.deviceController = deviceController;
14814
14893
  this.attachManager = attachManager;
14894
+ this.webRTCApiProvider = webRTCApiProvider;
14815
14895
  }
14816
14896
  /**
14817
14897
  * Create a new WebRTCCall with properly initialized managers
@@ -14820,7 +14900,7 @@ var CallFactory = class {
14820
14900
  return new WebRTCCall(this.sessionManager, options, {
14821
14901
  initializeManagers: (callInstance) => {
14822
14902
  return {
14823
- vertoManager: new WebRTCVertoManager(callInstance, this.attachManager, this.deviceController, {
14903
+ vertoManager: new WebRTCVertoManager(callInstance, this.attachManager, this.deviceController, this.webRTCApiProvider, {
14824
14904
  nodeId: options.nodeId,
14825
14905
  onError: (error) => {
14826
14906
  callInstance.emitError(error);
@@ -14847,7 +14927,10 @@ var Fetcher = class {
14847
14927
  this.nextUrl = `${this.endpoint}?${params}`;
14848
14928
  }
14849
14929
  async next() {
14850
- if (!this.nextUrl) return [];
14930
+ if (!this.nextUrl) {
14931
+ this.hasMore = false;
14932
+ return [];
14933
+ }
14851
14934
  const response = await this.http.request({
14852
14935
  ...GET_PARAMS,
14853
14936
  url: this.nextUrl
@@ -14855,6 +14938,7 @@ var Fetcher = class {
14855
14938
  if (response.ok && !!response.body) {
14856
14939
  const result = JSON.parse(response.body);
14857
14940
  this.nextUrl = result.links.next;
14941
+ this.hasMore = !!this.nextUrl;
14858
14942
  return result.data.filter(this.filter).map(this.mapper);
14859
14943
  }
14860
14944
  logger$8.error("Failed to fetch entity");
@@ -14888,10 +14972,11 @@ var EntityCollection = class extends Destroyable {
14888
14972
  this.observablesRegistry.get(data.id)?.next(updated);
14889
14973
  this.values$.next(Array.from(this.collectionData.values()));
14890
14974
  };
14975
+ this._hasMore$ = this.createBehaviorSubject(true);
14891
14976
  this._destroy$ = new import_cjs$8.Subject();
14892
14977
  this.updateSubscription = this.update$.subscribe(this.upsertData);
14893
14978
  this.loading$.next(false);
14894
- 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$));
14979
+ 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$));
14895
14980
  }
14896
14981
  get loading() {
14897
14982
  return this.loading$.value;
@@ -14906,17 +14991,21 @@ var EntityCollection = class extends Destroyable {
14906
14991
  return Array.from(this.collectionData.values());
14907
14992
  }
14908
14993
  async init() {
14909
- if (this.fetchController.hasMore === false) return Promise.resolve(false);
14994
+ if (this.fetchController.hasMore === false) {
14995
+ this._hasMore$.next(false);
14996
+ return;
14997
+ }
14910
14998
  await this.fetchMore();
14911
- return this.fetchController.hasMore ?? true;
14912
14999
  }
14913
15000
  async fetchMore() {
14914
15001
  try {
14915
15002
  this.loading$.next(true);
14916
15003
  (await this.fetchController.next()).forEach(this.upsertData);
15004
+ this._hasMore$.next(this.fetchController.hasMore ?? false);
14917
15005
  this.loading$.next(false);
14918
15006
  } catch (error) {
14919
15007
  logger$8.error(`Failed to fetch initial collection data`, error);
15008
+ this._hasMore$.next(this.fetchController.hasMore ?? false);
14920
15009
  this.loading$.next(false);
14921
15010
  this.onError?.(new CollectionFetchError("fetchMore", error));
14922
15011
  }
@@ -15236,7 +15325,7 @@ const getAddressSearchURI = (options) => {
15236
15325
  return name;
15237
15326
  };
15238
15327
  var ClientSessionManager = class extends Destroyable {
15239
- constructor(credential, transport, storage, authorizationStateKey, deviceController, attachManager) {
15328
+ constructor(credential, transport, storage, authorizationStateKey, deviceController, attachManager, webRTCApiProvider) {
15240
15329
  super();
15241
15330
  this.credential = credential;
15242
15331
  this.transport = transport;
@@ -15259,7 +15348,7 @@ var ClientSessionManager = class extends Destroyable {
15259
15348
  this._calls$ = this.createBehaviorSubject({});
15260
15349
  this._iceServers$ = this.createBehaviorSubject([]);
15261
15350
  attachManager.setSession(this);
15262
- this.callFactory = new CallFactory(this, deviceController, attachManager);
15351
+ this.callFactory = new CallFactory(this, deviceController, attachManager, webRTCApiProvider);
15263
15352
  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$));
15264
15353
  }
15265
15354
  get incomingCalls$() {
@@ -15488,7 +15577,8 @@ var ClientSessionManager = class extends Destroyable {
15488
15577
  to: invite.callee_id_number,
15489
15578
  fromName: invite.caller_id_name,
15490
15579
  from: invite.caller_id_number,
15491
- displayDirection: invite.display_direction
15580
+ displayDirection: invite.display_direction,
15581
+ userVariables: invite.userVariables
15492
15582
  });
15493
15583
  await (0, import_cjs$5.firstValueFrom)(callSession.status$);
15494
15584
  this._calls$.next({
@@ -15520,12 +15610,14 @@ var ClientSessionManager = class extends Destroyable {
15520
15610
  try {
15521
15611
  const addressURI = getAddressSearchURI(options);
15522
15612
  let address;
15523
- if (!addressURI.startsWith("+")) {
15613
+ try {
15524
15614
  if (!this._directory) throw new DependencyError("Directory not initialized");
15525
15615
  const addressId = await this._directory.findAddressIdByURI(addressURI);
15526
15616
  if (!addressId) throw new DependencyError(`Address name: ${addressURI} not found`);
15527
15617
  address = this._directory.get(addressId);
15528
15618
  if (!address) throw new DependencyError(`Address ID: ${addressId} not found`);
15619
+ } catch (error) {
15620
+ logger$6.warn(`[Session] Directory lookup failed for ${addressURI}, proceeding with raw URI`);
15529
15621
  }
15530
15622
  const callSession = this.callFactory.createCall(address, { ...options });
15531
15623
  callSession.status$.pipe((0, import_cjs$5.filter)((status) => status === "destroyed"), (0, import_cjs$5.take)(1)).subscribe(() => {
@@ -16151,6 +16243,7 @@ var SignalWire = class extends Destroyable {
16151
16243
  if (this._options.storageImplementation) this._deps.storageImpl = this._options.storageImplementation;
16152
16244
  if (this._options.webSocketConstructor) this._deps.WebSocket = this._options.webSocketConstructor;
16153
16245
  if (this._options.savePreferences) this.preferences.enableSavePreferences(this._deps.storage);
16246
+ if (this._options.webRTCApiProvider) this._deps.webRTCApiProvider = this._options.webRTCApiProvider;
16154
16247
  this._deviceController = this._deps.deviceController;
16155
16248
  if (!this._options.skipDeviceMonitoring) this._deviceController.enableDeviceMonitoring();
16156
16249
  this.subscribeTo(this._deviceController.errors$, (error) => {
@@ -16275,7 +16368,7 @@ var SignalWire = class extends Destroyable {
16275
16368
  };
16276
16369
  this._transport = new TransportManager(this._deps.storage, this._deps.protocolKey, this._deps.WebSocket, PreferencesContainer.instance.relayHost ?? this._deps.relayHost, errorHandler);
16277
16370
  this._attachManager = new AttachManager(this._deps.storage, this._deps.deviceController, PreferencesContainer.instance.reconnectCallsTimeout, this._deps.attachedCallsKey);
16278
- this._clientSession = new ClientSessionManager(this._deps.credential, this._transport, this._deps.storage, this._deps.authorizationStateKey, this._deps.deviceController, this._attachManager);
16371
+ this._clientSession = new ClientSessionManager(this._deps.credential, this._transport, this._deps.storage, this._deps.authorizationStateKey, this._deps.deviceController, this._attachManager, this._deps.webRTCApiProvider);
16279
16372
  this._publicSession = new ClientSessionWrapper(this._clientSession);
16280
16373
  this.subscribeTo(this._clientSession.errors$, (error) => {
16281
16374
  this._errors$.next(error);