@signalwire/js 4.0.0-dev-20260511184148 → 4.0.0-rc.0

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
@@ -9464,9 +9464,9 @@ var require_loglevel = /* @__PURE__ */ __commonJSMin(((exports, module) => {
9464
9464
  defaultLogger$1 = new Logger();
9465
9465
  defaultLogger$1.getLogger = function getLogger$1(name) {
9466
9466
  if (typeof name !== "symbol" && typeof name !== "string" || name === "") throw new TypeError("You must supply a name when creating a logger.");
9467
- var logger$32 = _loggersByName[name];
9468
- if (!logger$32) logger$32 = _loggersByName[name] = new Logger(name, defaultLogger$1.methodFactory);
9469
- return logger$32;
9467
+ var logger$33 = _loggersByName[name];
9468
+ if (!logger$33) logger$33 = _loggersByName[name] = new Logger(name, defaultLogger$1.methodFactory);
9469
+ return logger$33;
9470
9470
  };
9471
9471
  var _log = typeof window !== undefinedType ? window.log : void 0;
9472
9472
  defaultLogger$1.noConflict = function() {
@@ -9502,8 +9502,8 @@ const defaultLoggerLevel = defaultLogger.levels.WARN;
9502
9502
  defaultLogger.setLevel(defaultLoggerLevel);
9503
9503
  let userLogger = null;
9504
9504
  /** Replace the built-in logger with a custom implementation. Pass `null` to restore defaults. */
9505
- const setLogger = (logger$32) => {
9506
- userLogger = logger$32;
9505
+ const setLogger = (logger$33) => {
9506
+ userLogger = logger$33;
9507
9507
  };
9508
9508
  let debugOptions = {};
9509
9509
  /** Configure debug options (e.g., `{ logWsTraffic: true }`). */
@@ -9547,8 +9547,8 @@ const wsTraffic = (options) => {
9547
9547
  loggerInstance.debug(`${options.type.toUpperCase()}: \n`, msg, "\n");
9548
9548
  };
9549
9549
  const getLogger = () => {
9550
- const logger$32 = getLoggerInstance();
9551
- return new Proxy(logger$32, { get(_target, prop, _receiver) {
9550
+ const logger$33 = getLoggerInstance();
9551
+ return new Proxy(logger$33, { get(_target, prop, _receiver) {
9552
9552
  if (prop === "wsTraffic") return wsTraffic;
9553
9553
  const instance = getLoggerInstance();
9554
9554
  const value = Reflect.get(instance, prop);
@@ -9600,7 +9600,7 @@ const asyncRetry = async ({ asyncCallable, maxRetries: retries = DEFAULT_MAX_RET
9600
9600
 
9601
9601
  //#endregion
9602
9602
  //#region src/controllers/HTTPRequestController.ts
9603
- const logger$31 = getLogger();
9603
+ const logger$32 = getLogger();
9604
9604
  const GET_PARAMS = {
9605
9605
  method: "GET",
9606
9606
  headers: { Accept: "application/json" }
@@ -9664,7 +9664,7 @@ var HTTPRequestController = class HTTPRequestController extends Destroyable {
9664
9664
  this._responses$.next(response);
9665
9665
  return response;
9666
9666
  } catch (error) {
9667
- logger$31.error("[HTTPRequestController] Request error:", error);
9667
+ logger$32.error("[HTTPRequestController] Request error:", error);
9668
9668
  this._status$.next("error");
9669
9669
  const err = error instanceof Error ? error : new Error("HTTP request failed", { cause: error });
9670
9670
  this._errors$.next(err);
@@ -9691,7 +9691,7 @@ var HTTPRequestController = class HTTPRequestController extends Destroyable {
9691
9691
  const url = this.buildURL(request.url);
9692
9692
  const headers = this.buildHeaders(request.headers);
9693
9693
  const timeout$5 = request.timeout ?? this.requestTimeout;
9694
- logger$31.debug("[HTTPRequestController] Executing request:", {
9694
+ logger$32.debug("[HTTPRequestController] Executing request:", {
9695
9695
  method: request.method,
9696
9696
  url,
9697
9697
  headers: Object.keys(headers).reduce((acc, key) => {
@@ -9711,7 +9711,7 @@ var HTTPRequestController = class HTTPRequestController extends Destroyable {
9711
9711
  });
9712
9712
  clearTimeout(timeoutId);
9713
9713
  const httpResponse = await this.convertResponse(response);
9714
- logger$31.debug("[HTTPRequestController] Response received:", {
9714
+ logger$32.debug("[HTTPRequestController] Response received:", {
9715
9715
  status: response.status,
9716
9716
  statusText: response.statusText,
9717
9717
  headers: [...response.headers.entries()],
@@ -9721,7 +9721,7 @@ var HTTPRequestController = class HTTPRequestController extends Destroyable {
9721
9721
  } catch (error) {
9722
9722
  clearTimeout(timeoutId);
9723
9723
  if (error instanceof Error && error.name === "AbortError") throw new RequestTimeoutError(`Request timeout after ${timeout$5}ms`, { cause: error });
9724
- logger$31.error("[HTTPRequestController] Request failed:", error);
9724
+ logger$32.error("[HTTPRequestController] Request failed:", error);
9725
9725
  throw error;
9726
9726
  }
9727
9727
  }
@@ -9735,8 +9735,8 @@ var HTTPRequestController = class HTTPRequestController extends Destroyable {
9735
9735
  const credential = this.getCredential();
9736
9736
  if (credential.token) {
9737
9737
  headers.Authorization = `Bearer ${credential.token}`;
9738
- logger$31.debug("[HTTPRequestController] Using Bearer token auth, token length:", credential.token.length);
9739
- } else logger$31.warn("[HTTPRequestController] No credentials available for authentication");
9738
+ logger$32.debug("[HTTPRequestController] Using Bearer token auth, token length:", credential.token.length);
9739
+ } else logger$32.warn("[HTTPRequestController] No credentials available for authentication");
9740
9740
  return headers;
9741
9741
  }
9742
9742
  /**
@@ -9906,6 +9906,13 @@ const CREDENTIAL_REFRESH_RETRY_BASE_MS = 1e3;
9906
9906
  const CREDENTIAL_REFRESH_MAX_DELAY_MS = 3e4;
9907
9907
  /** Buffer in milliseconds before token expiry to trigger refresh. */
9908
9908
  const CREDENTIAL_REFRESH_BUFFER_MS = 5e3;
9909
+ /**
9910
+ * Maximum time the coordinator will wait for `DeviceTokenManager.activate()`
9911
+ * to resolve before treating the activation as failed and falling back to
9912
+ * the developer-provided refresh path. Prevents a wedged HTTP layer from
9913
+ * leaving the session with no active refresh mechanism.
9914
+ */
9915
+ const CREDENTIAL_ACTIVATE_TIMEOUT_MS = 3e4;
9909
9916
  /** JSON-RPC error code for requester validation failure (corrupted auth state). */
9910
9917
  const RPC_ERROR_REQUESTER_VALIDATION_FAILED = -32003;
9911
9918
  /** JSON-RPC error code for invalid params (e.g., missing authentication block). */
@@ -10008,7 +10015,7 @@ function fromMsToSec(milliseconds) {
10008
10015
 
10009
10016
  //#endregion
10010
10017
  //#region src/containers/PreferencesContainer.ts
10011
- const logger$30 = getLogger();
10018
+ const logger$31 = getLogger();
10012
10019
  var PreferencesContainer = class PreferencesContainer {
10013
10020
  static get instance() {
10014
10021
  this._instance ??= new PreferencesContainer();
@@ -10670,7 +10677,7 @@ var ClientPreferences = class {
10670
10677
  if (!this._storage) return;
10671
10678
  const data = collectStoredPreferences();
10672
10679
  this._storage.setItem(PREFERENCES_STORAGE_KEY, data, "local").catch((error) => {
10673
- logger$30.error(`[ClientPreferences] Failed to save preferences: ${String(error)}`);
10680
+ logger$31.error(`[ClientPreferences] Failed to save preferences: ${String(error)}`);
10674
10681
  });
10675
10682
  }
10676
10683
  /** Loads preferences from storage and applies them to the container. */
@@ -10679,7 +10686,7 @@ var ClientPreferences = class {
10679
10686
  this._storage.getItem(PREFERENCES_STORAGE_KEY, "local").then((stored) => {
10680
10687
  if (stored) applyStoredPreferences(stored);
10681
10688
  }).catch((error) => {
10682
- logger$30.error(`[ClientPreferences] Failed to load preferences: ${String(error)}`);
10689
+ logger$31.error(`[ClientPreferences] Failed to load preferences: ${String(error)}`);
10683
10690
  });
10684
10691
  }
10685
10692
  };
@@ -10701,7 +10708,7 @@ function toError(value) {
10701
10708
  //#endregion
10702
10709
  //#region src/controllers/NavigatorDeviceController.ts
10703
10710
  var import_cjs$29 = require_cjs();
10704
- const logger$29 = getLogger();
10711
+ const logger$30 = getLogger();
10705
10712
  /** Maps a device kind to its storage key. */
10706
10713
  const DEVICE_STORAGE_KEYS = {
10707
10714
  audioinput: DEVICE_STORAGE_KEY_AUDIO_INPUT,
@@ -10723,7 +10730,7 @@ var NavigatorDeviceController = class extends Destroyable {
10723
10730
  super();
10724
10731
  this.webRTCApiProvider = webRTCApiProvider;
10725
10732
  this.deviceChangeHandler = () => {
10726
- logger$29.debug("[DeviceController] Device change detected");
10733
+ logger$30.debug("[DeviceController] Device change detected");
10727
10734
  this.enumerateDevices();
10728
10735
  };
10729
10736
  this._devicesState$ = this.createBehaviorSubject(initialDevicesState);
@@ -10788,13 +10795,13 @@ var NavigatorDeviceController = class extends Destroyable {
10788
10795
  return this.cachedObservable("videoInputDevices$", () => this._devicesState$.pipe((0, import_cjs$29.map)((state) => state.videoinput), (0, import_cjs$29.distinctUntilChanged)(), (0, import_cjs$29.takeUntil)(this.destroyed$)));
10789
10796
  }
10790
10797
  get selectedAudioInputDevice$() {
10791
- return this.cachedObservable("selectedAudioInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$29.map)((state) => state.audioinput), (0, import_cjs$29.distinctUntilChanged)(), (0, import_cjs$29.takeUntil)(this.destroyed$), (0, import_cjs$29.tap)((info) => logger$29.debug("[DeviceController] Selected audio input device changed:", info))));
10798
+ return this.cachedObservable("selectedAudioInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$29.map)((state) => state.audioinput), (0, import_cjs$29.distinctUntilChanged)(), (0, import_cjs$29.takeUntil)(this.destroyed$), (0, import_cjs$29.tap)((info) => logger$30.debug("[DeviceController] Selected audio input device changed:", info))));
10792
10799
  }
10793
10800
  get selectedAudioOutputDevice$() {
10794
- return this.cachedObservable("selectedAudioOutputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$29.map)((state) => state.audiooutput), (0, import_cjs$29.distinctUntilChanged)(), (0, import_cjs$29.takeUntil)(this.destroyed$), (0, import_cjs$29.tap)((info) => logger$29.debug("[DeviceController] Selected audio output device changed:", info))));
10801
+ return this.cachedObservable("selectedAudioOutputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$29.map)((state) => state.audiooutput), (0, import_cjs$29.distinctUntilChanged)(), (0, import_cjs$29.takeUntil)(this.destroyed$), (0, import_cjs$29.tap)((info) => logger$30.debug("[DeviceController] Selected audio output device changed:", info))));
10795
10802
  }
10796
10803
  get selectedVideoInputDevice$() {
10797
- return this.cachedObservable("selectedVideoInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$29.map)((state) => state.videoinput), (0, import_cjs$29.distinctUntilChanged)(), (0, import_cjs$29.takeUntil)(this.destroyed$), (0, import_cjs$29.tap)((info) => logger$29.debug("[DeviceController] Selected video input device changed:", info))));
10804
+ return this.cachedObservable("selectedVideoInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$29.map)((state) => state.videoinput), (0, import_cjs$29.distinctUntilChanged)(), (0, import_cjs$29.takeUntil)(this.destroyed$), (0, import_cjs$29.tap)((info) => logger$30.debug("[DeviceController] Selected video input device changed:", info))));
10798
10805
  }
10799
10806
  get selectedAudioInputDevice() {
10800
10807
  if (this._audioInputDisabled$.value) return null;
@@ -10869,7 +10876,7 @@ var NavigatorDeviceController = class extends Destroyable {
10869
10876
  if (device) this.persistDeviceSelection("audioinput", device);
10870
10877
  }
10871
10878
  selectVideoInputDevice(device) {
10872
- logger$29.debug("[DeviceController] Setting selected video input device:", device);
10879
+ logger$30.debug("[DeviceController] Setting selected video input device:", device);
10873
10880
  if (this._videoInputDisabled$.value && device) this._videoInputDisabled$.next(false);
10874
10881
  const previous = this._selectedDevicesState$.value.videoinput;
10875
10882
  if (previous && previous.deviceId !== device?.deviceId) this._deviceHistory.push("videoinput", previous);
@@ -10926,7 +10933,7 @@ var NavigatorDeviceController = class extends Destroyable {
10926
10933
  }
10927
10934
  const fromHistory = this._deviceHistory.findInHistory(kind, devices);
10928
10935
  if (fromHistory) {
10929
- logger$29.debug(`[DeviceController] Device disappeared, falling back to history: ${fromHistory.label}`);
10936
+ logger$30.debug(`[DeviceController] Device disappeared, falling back to history: ${fromHistory.label}`);
10930
10937
  this.emitDeviceRecovered(kind, selected, fromHistory, "device_disconnected");
10931
10938
  return fromHistory;
10932
10939
  }
@@ -10979,7 +10986,7 @@ var NavigatorDeviceController = class extends Destroyable {
10979
10986
  try {
10980
10987
  await this._storageManager.setItem(DEVICE_STORAGE_KEYS[kind], stored, "local");
10981
10988
  } catch (error) {
10982
- logger$29.error(`[DeviceController] Failed to persist device selection for ${kind}:`, error);
10989
+ logger$30.error(`[DeviceController] Failed to persist device selection for ${kind}:`, error);
10983
10990
  }
10984
10991
  }
10985
10992
  async loadPersistedDevices() {
@@ -10995,7 +11002,7 @@ var NavigatorDeviceController = class extends Destroyable {
10995
11002
  [kind]: stored
10996
11003
  };
10997
11004
  } catch (error) {
10998
- logger$29.error(`[DeviceController] Failed to load persisted device for ${kind}:`, error);
11005
+ logger$30.error(`[DeviceController] Failed to load persisted device for ${kind}:`, error);
10999
11006
  }
11000
11007
  }
11001
11008
  /** Clears device history, persisted selections, and re-enumerates devices. */
@@ -11013,7 +11020,7 @@ var NavigatorDeviceController = class extends Destroyable {
11013
11020
  this.disableDeviceMonitoring();
11014
11021
  this.webRTCApiProvider.mediaDevices.addEventListener("devicechange", this.deviceChangeHandler);
11015
11022
  if (PreferencesContainer.instance.devicePollingInterval > 0) this._devicesPoolingSubscription = (0, import_cjs$29.interval)(PreferencesContainer.instance.devicePollingInterval).subscribe(() => {
11016
- logger$29.debug("[DeviceController] Polling devices due to interval");
11023
+ logger$30.debug("[DeviceController] Polling devices due to interval");
11017
11024
  this.enumerateDevices();
11018
11025
  });
11019
11026
  this.enumerateDevices();
@@ -11039,13 +11046,13 @@ var NavigatorDeviceController = class extends Destroyable {
11039
11046
  videoinput: []
11040
11047
  });
11041
11048
  this._devicesState$.next(devicesByKind);
11042
- logger$29.debug("[DeviceController] Devices enumerated:", {
11049
+ logger$30.debug("[DeviceController] Devices enumerated:", {
11043
11050
  audioInputs: devicesByKind.audioinput.length,
11044
11051
  audioOutputs: devicesByKind.audiooutput.length,
11045
11052
  videoInputs: devicesByKind.videoinput.length
11046
11053
  });
11047
11054
  } catch (error) {
11048
- logger$29.error("[DeviceController] Failed to enumerate devices:", error);
11055
+ logger$30.error("[DeviceController] Failed to enumerate devices:", error);
11049
11056
  this._errors$.next(toError(error));
11050
11057
  }
11051
11058
  }
@@ -11061,7 +11068,7 @@ var NavigatorDeviceController = class extends Destroyable {
11061
11068
  stream.getTracks().forEach((t) => t.stop());
11062
11069
  return capabilities;
11063
11070
  } catch (error) {
11064
- logger$29.error("[DeviceController] Failed to get device capabilities:", error);
11071
+ logger$30.error("[DeviceController] Failed to get device capabilities:", error);
11065
11072
  this._errors$.next(toError(error));
11066
11073
  throw error;
11067
11074
  }
@@ -11312,7 +11319,7 @@ var DependencyContainer = class {
11312
11319
 
11313
11320
  //#endregion
11314
11321
  //#region src/controllers/CryptoController.ts
11315
- const logger$28 = getLogger();
11322
+ const logger$29 = getLogger();
11316
11323
  const DPOP_DB_NAME = "sw-dpop";
11317
11324
  const DPOP_DB_VERSION = 1;
11318
11325
  const DPOP_STORE_NAME = "keys";
@@ -11371,7 +11378,7 @@ async function loadKeyPairFromDB() {
11371
11378
  tx.oncomplete = () => db.close();
11372
11379
  });
11373
11380
  } catch (error) {
11374
- logger$28.warn("[DPoP] Failed to load key pair from IndexedDB:", error);
11381
+ logger$29.warn("[DPoP] Failed to load key pair from IndexedDB:", error);
11375
11382
  return null;
11376
11383
  }
11377
11384
  }
@@ -11391,7 +11398,7 @@ async function saveKeyPairToDB(keyPair) {
11391
11398
  };
11392
11399
  });
11393
11400
  } catch (error) {
11394
- logger$28.warn("[DPoP] Failed to save key pair to IndexedDB:", error);
11401
+ logger$29.warn("[DPoP] Failed to save key pair to IndexedDB:", error);
11395
11402
  }
11396
11403
  }
11397
11404
  async function deleteKeyPairFromDB() {
@@ -11410,7 +11417,7 @@ async function deleteKeyPairFromDB() {
11410
11417
  };
11411
11418
  });
11412
11419
  } catch (error) {
11413
- logger$28.warn("[DPoP] Failed to delete key pair from IndexedDB:", error);
11420
+ logger$29.warn("[DPoP] Failed to delete key pair from IndexedDB:", error);
11414
11421
  }
11415
11422
  }
11416
11423
  /**
@@ -11470,13 +11477,13 @@ var CryptoController = class {
11470
11477
  this._publicJwk = await crypto.subtle.exportKey("jwk", stored.publicKey);
11471
11478
  this._fingerprint = await computeJwkThumbprint(this._publicJwk);
11472
11479
  this._initialized = true;
11473
- logger$28.debug("[DPoP] Key pair restored from IndexedDB, fingerprint:", this._fingerprint);
11480
+ logger$29.debug("[DPoP] Key pair restored from IndexedDB, fingerprint:", this._fingerprint);
11474
11481
  return this._fingerprint;
11475
11482
  } catch (error) {
11476
- logger$28.warn("[DPoP] Stored key pair unusable, generating new one:", error);
11483
+ logger$29.warn("[DPoP] Stored key pair unusable, generating new one:", error);
11477
11484
  await deleteKeyPairFromDB();
11478
11485
  }
11479
- logger$28.debug("[DPoP] Generating RSA key pair");
11486
+ logger$29.debug("[DPoP] Generating RSA key pair");
11480
11487
  this._keyPair = await crypto.subtle.generateKey({
11481
11488
  name: "RSASSA-PKCS1-v1_5",
11482
11489
  modulusLength: 2048,
@@ -11491,7 +11498,7 @@ var CryptoController = class {
11491
11498
  this._fingerprint = await computeJwkThumbprint(this._publicJwk);
11492
11499
  this._initialized = true;
11493
11500
  await saveKeyPairToDB(this._keyPair);
11494
- logger$28.debug("[DPoP] Key pair generated and persisted, fingerprint:", this._fingerprint);
11501
+ logger$29.debug("[DPoP] Key pair generated and persisted, fingerprint:", this._fingerprint);
11495
11502
  return this._fingerprint;
11496
11503
  }
11497
11504
  /**
@@ -11557,7 +11564,7 @@ var CryptoController = class {
11557
11564
  this._fingerprint = null;
11558
11565
  this._initialized = false;
11559
11566
  deleteKeyPairFromDB();
11560
- logger$28.debug("[DPoP] Controller destroyed");
11567
+ logger$29.debug("[DPoP] Controller destroyed");
11561
11568
  }
11562
11569
  get publicJwk() {
11563
11570
  if (!this._publicJwk) throw new DPoPInitError("CryptoController not initialized. Call init() first.");
@@ -11581,7 +11588,7 @@ var CryptoController = class {
11581
11588
  //#endregion
11582
11589
  //#region src/controllers/NetworkMonitor.ts
11583
11590
  var import_cjs$28 = require_cjs();
11584
- const logger$27 = getLogger();
11591
+ const logger$28 = getLogger();
11585
11592
  /**
11586
11593
  * Safely check whether we are running in a browser environment
11587
11594
  * with `window` and the relevant event targets.
@@ -11638,7 +11645,7 @@ var NetworkMonitor = class extends Destroyable {
11638
11645
  }
11639
11646
  attachListeners() {
11640
11647
  if (!hasBrowserNetworkEvents()) {
11641
- logger$27.debug("NetworkMonitor: no browser environment detected, skipping event listeners");
11648
+ logger$28.debug("NetworkMonitor: no browser environment detected, skipping event listeners");
11642
11649
  return;
11643
11650
  }
11644
11651
  window.addEventListener("online", this._onOnline);
@@ -11646,7 +11653,7 @@ var NetworkMonitor = class extends Destroyable {
11646
11653
  const connection = getNetworkConnection();
11647
11654
  if (connection) connection.addEventListener("change", this._onConnectionChange);
11648
11655
  this._listenersAttached = true;
11649
- logger$27.debug("NetworkMonitor: event listeners attached");
11656
+ logger$28.debug("NetworkMonitor: event listeners attached");
11650
11657
  }
11651
11658
  removeListeners() {
11652
11659
  if (!this._listenersAttached) return;
@@ -11657,10 +11664,10 @@ var NetworkMonitor = class extends Destroyable {
11657
11664
  if (connection) connection.removeEventListener("change", this._onConnectionChange);
11658
11665
  }
11659
11666
  this._listenersAttached = false;
11660
- logger$27.debug("NetworkMonitor: event listeners removed");
11667
+ logger$28.debug("NetworkMonitor: event listeners removed");
11661
11668
  }
11662
11669
  handleOnline() {
11663
- logger$27.info("NetworkMonitor: browser went online");
11670
+ logger$28.info("NetworkMonitor: browser went online");
11664
11671
  this._isOnline$.next(true);
11665
11672
  this._networkChange$.next({
11666
11673
  type: "online",
@@ -11669,7 +11676,7 @@ var NetworkMonitor = class extends Destroyable {
11669
11676
  });
11670
11677
  }
11671
11678
  handleOffline() {
11672
- logger$27.info("NetworkMonitor: browser went offline");
11679
+ logger$28.info("NetworkMonitor: browser went offline");
11673
11680
  this._isOnline$.next(false);
11674
11681
  this._networkChange$.next({
11675
11682
  type: "offline",
@@ -11678,7 +11685,7 @@ var NetworkMonitor = class extends Destroyable {
11678
11685
  }
11679
11686
  handleConnectionChange() {
11680
11687
  const networkType = getNetworkType();
11681
- logger$27.info(`NetworkMonitor: connection changed — effectiveType=${networkType ?? "unknown"}`);
11688
+ logger$28.info(`NetworkMonitor: connection changed — effectiveType=${networkType ?? "unknown"}`);
11682
11689
  this._networkChange$.next({
11683
11690
  type: "connection_change",
11684
11691
  timestamp: Date.now(),
@@ -11794,7 +11801,7 @@ function getNavigatorMediaDevices() {
11794
11801
  //#endregion
11795
11802
  //#region src/controllers/PreflightRunner.ts
11796
11803
  var import_cjs$27 = require_cjs();
11797
- const logger$26 = getLogger();
11804
+ const logger$27 = getLogger();
11798
11805
  const DEFAULT_MEDIA_TEST_DURATION_S = 10;
11799
11806
  const ICE_GATHERING_TIMEOUT_MS = 1e4;
11800
11807
  const SIGNALING_RTT_TIMEOUT_MS = 5e3;
@@ -11843,7 +11850,7 @@ var PreflightRunner = class extends Destroyable {
11843
11850
  if (!this._options.skipMediaTest) try {
11844
11851
  bandwidth = await this.testMediaBandwidth(destination);
11845
11852
  } catch (error) {
11846
- logger$26.warn("[PreflightRunner] Media bandwidth test failed:", error);
11853
+ logger$27.warn("[PreflightRunner] Media bandwidth test failed:", error);
11847
11854
  warnings.push("Media bandwidth test failed");
11848
11855
  }
11849
11856
  return {
@@ -11855,7 +11862,7 @@ var PreflightRunner = class extends Destroyable {
11855
11862
  warnings
11856
11863
  };
11857
11864
  } catch (error) {
11858
- logger$26.error("[PreflightRunner] Preflight test failed:", error);
11865
+ logger$27.error("[PreflightRunner] Preflight test failed:", error);
11859
11866
  throw new PreflightError("preflight", error instanceof Error ? error : new Error(String(error)));
11860
11867
  } finally {
11861
11868
  this.destroy();
@@ -11886,7 +11893,7 @@ var PreflightRunner = class extends Destroyable {
11886
11893
  if (track.kind === "video" && track.readyState === "live") videoWorking = true;
11887
11894
  }
11888
11895
  } catch (error) {
11889
- logger$26.warn("[PreflightRunner] Device test failed:", error);
11896
+ logger$27.warn("[PreflightRunner] Device test failed:", error);
11890
11897
  } finally {
11891
11898
  if (audioStream) audioStream.getTracks().forEach((t) => t.stop());
11892
11899
  }
@@ -11944,7 +11951,7 @@ var PreflightRunner = class extends Destroyable {
11944
11951
  rttMs
11945
11952
  };
11946
11953
  } catch (error) {
11947
- logger$26.warn("[PreflightRunner] ICE connectivity test failed:", error);
11954
+ logger$27.warn("[PreflightRunner] ICE connectivity test failed:", error);
11948
11955
  return {
11949
11956
  type: "failed",
11950
11957
  turnReachable: false,
@@ -11992,7 +11999,7 @@ var PreflightRunner = class extends Destroyable {
11992
11999
  //#endregion
11993
12000
  //#region src/controllers/VisibilityController.ts
11994
12001
  var import_cjs$26 = require_cjs();
11995
- const logger$25 = getLogger();
12002
+ const logger$26 = getLogger();
11996
12003
  /**
11997
12004
  * Checks whether the document visibility API is available.
11998
12005
  */
@@ -12029,8 +12036,8 @@ var VisibilityController = class extends Destroyable {
12029
12036
  this._boundHandler = this._handleVisibilityChange.bind(this);
12030
12037
  if (this._hasVisibilityApi) {
12031
12038
  document.addEventListener("visibilitychange", this._boundHandler);
12032
- logger$25.debug("VisibilityController: listening for visibilitychange events");
12033
- } else logger$25.debug("VisibilityController: document visibility API not available, defaulting to visible");
12039
+ logger$26.debug("VisibilityController: listening for visibilitychange events");
12040
+ } else logger$26.debug("VisibilityController: document visibility API not available, defaulting to visible");
12034
12041
  }
12035
12042
  /**
12036
12043
  * Observable of the current visibility state.
@@ -12055,7 +12062,7 @@ var VisibilityController = class extends Destroyable {
12055
12062
  destroy() {
12056
12063
  if (this._hasVisibilityApi) {
12057
12064
  document.removeEventListener("visibilitychange", this._boundHandler);
12058
- logger$25.debug("VisibilityController: removed visibilitychange listener");
12065
+ logger$26.debug("VisibilityController: removed visibilitychange listener");
12059
12066
  }
12060
12067
  super.destroy();
12061
12068
  }
@@ -12073,7 +12080,7 @@ var VisibilityController = class extends Destroyable {
12073
12080
  timestamp: Date.now()
12074
12081
  };
12075
12082
  this._visibilityChange$.next(changeEvent);
12076
- logger$25.debug("VisibilityController: visibility changed", {
12083
+ logger$26.debug("VisibilityController: visibility changed", {
12077
12084
  from: previousState,
12078
12085
  to: newState
12079
12086
  });
@@ -12314,7 +12321,7 @@ const RPCEventAckResponse = (id) => makeRPCResponse({
12314
12321
 
12315
12322
  //#endregion
12316
12323
  //#region src/managers/AttachManager.ts
12317
- const logger$24 = getLogger();
12324
+ const logger$25 = getLogger();
12318
12325
  var AttachManager = class {
12319
12326
  constructor(storage, deviceController, reconnectCallsTimeout, attachKey) {
12320
12327
  this.storage = storage;
@@ -12335,7 +12342,7 @@ var AttachManager = class {
12335
12342
  try {
12336
12343
  return await this.storage.getItem(this.attachKey) ?? {};
12337
12344
  } catch (error) {
12338
- logger$24.warn("[AttachManager] Failed to retrieve attached calls from storage", error);
12345
+ logger$25.warn("[AttachManager] Failed to retrieve attached calls from storage", error);
12339
12346
  return {};
12340
12347
  }
12341
12348
  }
@@ -12343,7 +12350,7 @@ var AttachManager = class {
12343
12350
  try {
12344
12351
  await this.storage.setItem(this.attachKey, attached);
12345
12352
  } catch (error) {
12346
- logger$24.warn("[AttachManager] Failed to write attached calls to storage", error);
12353
+ logger$25.warn("[AttachManager] Failed to write attached calls to storage", error);
12347
12354
  }
12348
12355
  }
12349
12356
  /**
@@ -12362,7 +12369,7 @@ var AttachManager = class {
12362
12369
  }
12363
12370
  async attach(call) {
12364
12371
  if (!call.to) {
12365
- logger$24.warn("[AttachManager] Skip attach for calls with no destination");
12372
+ logger$25.warn("[AttachManager] Skip attach for calls with no destination");
12366
12373
  return;
12367
12374
  }
12368
12375
  const destination = call.to;
@@ -12415,15 +12422,15 @@ var AttachManager = class {
12415
12422
  callId,
12416
12423
  ...options
12417
12424
  });
12418
- logger$24.info(`[AttachManager] Reattached call ${callId} (attempt ${attempt})`);
12425
+ logger$25.info(`[AttachManager] Reattached call ${callId} (attempt ${attempt})`);
12419
12426
  succeeded = true;
12420
12427
  break;
12421
12428
  } catch (error) {
12422
- logger$24.warn(`[AttachManager] Reattach attempt ${attempt}/3 failed for call ${callId}:`, error);
12429
+ logger$25.warn(`[AttachManager] Reattach attempt ${attempt}/3 failed for call ${callId}:`, error);
12423
12430
  if (attempt < 3) await new Promise((r) => setTimeout(r, (attempt + 1) * 1e3));
12424
12431
  }
12425
12432
  if (!succeeded) {
12426
- logger$24.warn(`[AttachManager] Reattach failed after 3 attempts for call ${callId}, removing reference`);
12433
+ logger$25.warn(`[AttachManager] Reattach failed after 3 attempts for call ${callId}, removing reference`);
12427
12434
  await this.detach({
12428
12435
  id: callId,
12429
12436
  mediaDirections: attachment.mediaDirections
@@ -13590,7 +13597,7 @@ function toggleHandraiseMethod(is) {
13590
13597
 
13591
13598
  //#endregion
13592
13599
  //#region src/core/entities/Participant.ts
13593
- const logger$23 = getLogger();
13600
+ const logger$24 = getLogger();
13594
13601
  const initialState = {};
13595
13602
  /**
13596
13603
  * Represents a participant in a call.
@@ -14023,7 +14030,7 @@ var SelfParticipant = class extends Participant {
14023
14030
  try {
14024
14031
  await this.vertoManager.addScreenMedia();
14025
14032
  } catch (error) {
14026
- logger$23.error("[Participant.startScreenShare] Screen share error:", error);
14033
+ logger$24.error("[Participant.startScreenShare] Screen share error:", error);
14027
14034
  }
14028
14035
  }
14029
14036
  /** Observable of the current screen share status. */
@@ -14043,7 +14050,7 @@ var SelfParticipant = class extends Participant {
14043
14050
  try {
14044
14051
  await this.vertoManager.addInputDevice(options);
14045
14052
  } catch (error) {
14046
- logger$23.error("[Participant.startScreenShare] Screen share error:", error);
14053
+ logger$24.error("[Participant.startScreenShare] Screen share error:", error);
14047
14054
  }
14048
14055
  }
14049
14056
  /** Removes an additional media input device by ID. */
@@ -14105,7 +14112,7 @@ var SelfParticipant = class extends Participant {
14105
14112
  */
14106
14113
  exitStudioModeIfActive() {
14107
14114
  if (this._studioAudio$.value) {
14108
- logger$23.debug("[SelfParticipant] Exiting studio audio mode due to individual flag toggle");
14115
+ logger$24.debug("[SelfParticipant] Exiting studio audio mode due to individual flag toggle");
14109
14116
  this._studioAudio$.next(false);
14110
14117
  }
14111
14118
  }
@@ -14129,7 +14136,7 @@ var SelfParticipant = class extends Participant {
14129
14136
  try {
14130
14137
  await super.mute();
14131
14138
  } catch (error) {
14132
- logger$23.warn("[Participant.toggleAudioInput] Server Error while muting audio input, proceeding with local toggle anyway", error);
14139
+ logger$24.warn("[Participant.toggleAudioInput] Server Error while muting audio input, proceeding with local toggle anyway", error);
14133
14140
  } finally {
14134
14141
  this.vertoManager.muteMainAudioInputDevice();
14135
14142
  }
@@ -14139,7 +14146,7 @@ var SelfParticipant = class extends Participant {
14139
14146
  try {
14140
14147
  await super.unmute();
14141
14148
  } catch (error) {
14142
- logger$23.warn("[Participant.toggleAudioInput] Server Error while unmuting audio input, proceeding with local toggle anyway", error);
14149
+ logger$24.warn("[Participant.toggleAudioInput] Server Error while unmuting audio input, proceeding with local toggle anyway", error);
14143
14150
  } finally {
14144
14151
  await this.vertoManager.unmuteMainAudioInputDevice();
14145
14152
  }
@@ -14149,7 +14156,7 @@ var SelfParticipant = class extends Participant {
14149
14156
  try {
14150
14157
  await super.muteVideo();
14151
14158
  } catch (error) {
14152
- logger$23.warn("[Participant.toggleVideoInput] Server Error while muting video input, proceeding with local toggle anyway", error);
14159
+ logger$24.warn("[Participant.toggleVideoInput] Server Error while muting video input, proceeding with local toggle anyway", error);
14153
14160
  } finally {
14154
14161
  this.vertoManager.muteMainVideoInputDevice();
14155
14162
  }
@@ -14159,7 +14166,7 @@ var SelfParticipant = class extends Participant {
14159
14166
  try {
14160
14167
  await super.unmuteVideo();
14161
14168
  } catch (error) {
14162
- logger$23.warn("[Participant.toggleVideoInput] Server Error while unmuting video input, proceeding with local toggle anyway", error);
14169
+ logger$24.warn("[Participant.toggleVideoInput] Server Error while unmuting video input, proceeding with local toggle anyway", error);
14163
14170
  } finally {
14164
14171
  await this.vertoManager.unmuteMainVideoInputDevice();
14165
14172
  }
@@ -14364,7 +14371,7 @@ function filterAs(predicate, resultPath) {
14364
14371
  //#endregion
14365
14372
  //#region src/operators/throwOnRPCError.ts
14366
14373
  var import_cjs$21 = require_cjs();
14367
- const logger$22 = getLogger();
14374
+ const logger$23 = getLogger();
14368
14375
  /**
14369
14376
  * RxJS operator that throws a {@link JSONRPCError} when the RPC response contains an error.
14370
14377
  * Passes successful responses through unchanged.
@@ -14372,14 +14379,14 @@ const logger$22 = getLogger();
14372
14379
  function throwOnRPCError() {
14373
14380
  return (0, import_cjs$21.map)((response) => {
14374
14381
  if (response.error) {
14375
- logger$22.error("[throwOnRPCError] RPC error response:", {
14382
+ logger$23.error("[throwOnRPCError] RPC error response:", {
14376
14383
  code: response.error.code,
14377
14384
  message: response.error.message,
14378
14385
  data: response.error.data
14379
14386
  });
14380
14387
  throw new JSONRPCError(response.error.code, response.error.message, response.error.data);
14381
14388
  }
14382
- logger$22.debug("[throwOnRPCError] RPC successful response:", response);
14389
+ logger$23.debug("[throwOnRPCError] RPC successful response:", response);
14383
14390
  return response;
14384
14391
  });
14385
14392
  }
@@ -14387,7 +14394,7 @@ function throwOnRPCError() {
14387
14394
  //#endregion
14388
14395
  //#region src/managers/CallEventsManager.ts
14389
14396
  var import_cjs$20 = require_cjs();
14390
- const logger$21 = getLogger();
14397
+ const logger$22 = getLogger();
14391
14398
  const initialSessionState = {};
14392
14399
  /** @internal */
14393
14400
  var CallEventsManager = class extends Destroyable {
@@ -14491,7 +14498,7 @@ var CallEventsManager = class extends Destroyable {
14491
14498
  }
14492
14499
  initSubscriptions() {
14493
14500
  this.subscribeTo(this.callJoinedEvent$, (callJoinedEvent) => {
14494
- logger$21.debug("[CallEventsManager] Handling call.joined event for call/session IDs:", {
14501
+ logger$22.debug("[CallEventsManager] Handling call.joined event for call/session IDs:", {
14495
14502
  callId: callJoinedEvent.call_id,
14496
14503
  roomSessionId: callJoinedEvent.room_session_id
14497
14504
  });
@@ -14518,19 +14525,19 @@ var CallEventsManager = class extends Destroyable {
14518
14525
  if (this._self$.value?.capabilities.setLayout) this.updateLayouts();
14519
14526
  });
14520
14527
  this.subscribeTo(this.memberUpdates$, (member) => {
14521
- logger$21.debug("[CallEventsManager] Handling member update event for member ID:", member);
14528
+ logger$22.debug("[CallEventsManager] Handling member update event for member ID:", member);
14522
14529
  this.upsertParticipant(member);
14523
14530
  });
14524
14531
  this.subscribeTo(this.webRtcCallSession.memberLeft$, (memberLeftEvent) => {
14525
- logger$21.debug("[CallEventsManager] Handling member.left event for member ID:", memberLeftEvent.member.member_id);
14532
+ logger$22.debug("[CallEventsManager] Handling member.left event for member ID:", memberLeftEvent.member.member_id);
14526
14533
  const participants = { ...this._participants$.value };
14527
14534
  if (memberLeftEvent.member.member_id in participants) {
14528
14535
  delete participants[memberLeftEvent.member.member_id];
14529
14536
  this._participants$.next(participants);
14530
- } else logger$21.warn(`[CallEventsManager] Received member.left event for unknown member ID: ${memberLeftEvent.member.member_id}`);
14537
+ } else logger$22.warn(`[CallEventsManager] Received member.left event for unknown member ID: ${memberLeftEvent.member.member_id}`);
14531
14538
  });
14532
14539
  this.subscribeTo(this.webRtcCallSession.callUpdated$, (callUpdatedEvent) => {
14533
- logger$21.debug("[CallEventsManager] Handling call.updated event:", callUpdatedEvent);
14540
+ logger$22.debug("[CallEventsManager] Handling call.updated event:", callUpdatedEvent);
14534
14541
  const roomSession = callUpdatedEvent.room_session;
14535
14542
  this._sessionState$.next({
14536
14543
  ...this._sessionState$.value,
@@ -14545,7 +14552,7 @@ var CallEventsManager = class extends Destroyable {
14545
14552
  });
14546
14553
  });
14547
14554
  this.subscribeTo(this.layoutChangedEvent$, (layoutChangedEvent) => {
14548
- logger$21.debug("[CallEventsManager] Handling layout.changed event:", layoutChangedEvent);
14555
+ logger$22.debug("[CallEventsManager] Handling layout.changed event:", layoutChangedEvent);
14549
14556
  this._sessionState$.next({
14550
14557
  ...this._sessionState$.value,
14551
14558
  layout_name: layoutChangedEvent.id,
@@ -14555,10 +14562,10 @@ var CallEventsManager = class extends Destroyable {
14555
14562
  });
14556
14563
  }
14557
14564
  updateParticipantPositions(layoutChangedEvent) {
14558
- if (Object.keys(this._participants$.value).length > 0 && !layoutChangedEvent.layers.some((layer) => !!layer.member_id)) logger$21.warn("[CallEventsManager] No layers with member_id found in layout.changed event. Nothing to update.");
14565
+ if (Object.keys(this._participants$.value).length > 0 && !layoutChangedEvent.layers.some((layer) => !!layer.member_id)) logger$22.warn("[CallEventsManager] No layers with member_id found in layout.changed event. Nothing to update.");
14559
14566
  layoutChangedEvent.layers.filter((layer) => !!layer.member_id).filter((layer) => {
14560
14567
  if (!(layer.member_id in this._participants$.value)) {
14561
- logger$21.warn(`[CallEventsManager] Skipping layout layer for unknown member_id: ${layer.member_id}`);
14568
+ logger$22.warn(`[CallEventsManager] Skipping layout layer for unknown member_id: ${layer.member_id}`);
14562
14569
  return false;
14563
14570
  }
14564
14571
  return true;
@@ -14581,7 +14588,7 @@ var CallEventsManager = class extends Destroyable {
14581
14588
  layouts: response.result.layouts
14582
14589
  });
14583
14590
  }).catch((error) => {
14584
- logger$21.error("[CallEventsManager] Error fetching layouts:", error);
14591
+ logger$22.error("[CallEventsManager] Error fetching layouts:", error);
14585
14592
  });
14586
14593
  }
14587
14594
  updateParticipants(members) {
@@ -14597,7 +14604,7 @@ var CallEventsManager = class extends Destroyable {
14597
14604
  }
14598
14605
  const participant = this._participants$.value[member.member_id];
14599
14606
  const oldValue = participant.value;
14600
- logger$21.debug("[CallEventsManager] Updating participant:", member.member_id, {
14607
+ logger$22.debug("[CallEventsManager] Updating participant:", member.member_id, {
14601
14608
  oldValue,
14602
14609
  newValue: member
14603
14610
  });
@@ -14610,17 +14617,17 @@ var CallEventsManager = class extends Destroyable {
14610
14617
  }
14611
14618
  get callJoinedEvent$() {
14612
14619
  return this.cachedObservable("callJoinedEvent$", () => this.webRtcCallSession.callEvent$.pipe((0, import_cjs$20.filter)(isCallJoinedPayload), (0, import_cjs$20.tap)((event) => {
14613
- logger$21.debug("[CallEventsManager] Call joined event:", event);
14620
+ logger$22.debug("[CallEventsManager] Call joined event:", event);
14614
14621
  })));
14615
14622
  }
14616
14623
  get layoutChangedEvent$() {
14617
14624
  return this.cachedObservable("layoutChangedEvent$", () => this.webRtcCallSession.callEvent$.pipe(filterAs(isLayoutChangedPayload, "layout"), (0, import_cjs$20.tap)((event) => {
14618
- logger$21.debug("[CallEventsManager] Layout changed event:", event);
14625
+ logger$22.debug("[CallEventsManager] Layout changed event:", event);
14619
14626
  })));
14620
14627
  }
14621
14628
  get memberUpdates$() {
14622
14629
  return this.cachedObservable("memberUpdates$", () => (0, import_cjs$20.merge)(this.webRtcCallSession.memberJoined$, this.webRtcCallSession.memberUpdated$, this.webRtcCallSession.memberTalking$).pipe((0, import_cjs$20.map)((event) => event.member), (0, import_cjs$20.tap)((event) => {
14623
- logger$21.debug("[CallEventsManager] Member update event:", event);
14630
+ logger$22.debug("[CallEventsManager] Member update event:", event);
14624
14631
  })));
14625
14632
  }
14626
14633
  destroy() {
@@ -14877,7 +14884,7 @@ function appendStereoParams(fmtpLine, maxBitrate) {
14877
14884
  //#endregion
14878
14885
  //#region src/controllers/ICEGatheringController.ts
14879
14886
  var import_cjs$19 = require_cjs();
14880
- const logger$20 = getLogger();
14887
+ const logger$21 = getLogger();
14881
14888
  var ICEGatheringController = class extends Destroyable {
14882
14889
  constructor(peerConnection, peerConnectionControllerNegotiating$, options = {}) {
14883
14890
  super();
@@ -14885,23 +14892,23 @@ var ICEGatheringController = class extends Destroyable {
14885
14892
  this.peerConnectionControllerNegotiating$ = peerConnectionControllerNegotiating$;
14886
14893
  this.onicegatheringstatechangeHandler = () => {
14887
14894
  const { iceGatheringState } = this.peerConnection;
14888
- logger$20.debug(`[ICEGatheringController] ICE gathering state changed to: ${iceGatheringState}`);
14895
+ logger$21.debug(`[ICEGatheringController] ICE gathering state changed to: ${iceGatheringState}`);
14889
14896
  if (iceGatheringState === "gathering") this._iceCandidatesState.next({
14890
14897
  state: "gathering",
14891
14898
  validSDP: false
14892
14899
  });
14893
14900
  };
14894
14901
  this.onicecandidateHandler = (event) => {
14895
- logger$20.debug("[ICEGatheringController] ICE candidate event received:", event.candidate);
14902
+ logger$21.debug("[ICEGatheringController] ICE candidate event received:", event.candidate);
14896
14903
  this.removeTimer("iceCandidateTimer");
14897
14904
  if (event.candidate) this.iceCandidateTimer = setTimeout(() => {
14898
14905
  if (this.peerConnection.iceGatheringState !== "complete") {
14899
- logger$20.warn("[ICEGatheringController] ICE candidate timeout, using current SDP");
14906
+ logger$21.warn("[ICEGatheringController] ICE candidate timeout, using current SDP");
14900
14907
  this.handleICECandidateTimeout();
14901
14908
  }
14902
14909
  }, this.iceCandidateTimeout);
14903
14910
  else {
14904
- logger$20.debug("[ICEGatheringController] ICE gathering completed: null candidate received");
14911
+ logger$21.debug("[ICEGatheringController] ICE gathering completed: null candidate received");
14905
14912
  this.removeTimer("iceGatheringTimer");
14906
14913
  this.handleICEGatheringComplete();
14907
14914
  }
@@ -14919,7 +14926,7 @@ var ICEGatheringController = class extends Destroyable {
14919
14926
  this.setupEventListeners();
14920
14927
  this.iceGatheringTimer = setTimeout(() => {
14921
14928
  if (this.peerConnection.iceGatheringState !== "complete") {
14922
- logger$20.warn("[ICEGatheringController] ICE gathering timeout, using current SDP");
14929
+ logger$21.warn("[ICEGatheringController] ICE gathering timeout, using current SDP");
14923
14930
  this.handleICEGatheringTimeout();
14924
14931
  }
14925
14932
  }, this.iceGatheringTimeout);
@@ -14946,9 +14953,9 @@ var ICEGatheringController = class extends Destroyable {
14946
14953
  this.relayOnly = value;
14947
14954
  }
14948
14955
  handleICEGatheringComplete() {
14949
- logger$20.debug("[ICEGatheringController] Handling ICE gathering complete");
14950
- logger$20.debug(`[ICEGatheringController] Checking ICE gathering state: ${this.peerConnection.iceGatheringState}`);
14951
- logger$20.debug("[ICEGatheringController] ICE gathering complete");
14956
+ logger$21.debug("[ICEGatheringController] Handling ICE gathering complete");
14957
+ logger$21.debug(`[ICEGatheringController] Checking ICE gathering state: ${this.peerConnection.iceGatheringState}`);
14958
+ logger$21.debug("[ICEGatheringController] ICE gathering complete");
14952
14959
  this._iceCandidatesState.next({
14953
14960
  state: "complete",
14954
14961
  validSDP: this.hasValidLocalDescriptionSDP
@@ -14964,21 +14971,21 @@ var ICEGatheringController = class extends Destroyable {
14964
14971
  this.removeTimer("iceGatheringTimer");
14965
14972
  const validSDP = this.hasValidLocalDescriptionSDP;
14966
14973
  if (validSDP) {
14967
- logger$20.debug("[ICEGatheringController] Local SDP is valid");
14974
+ logger$21.debug("[ICEGatheringController] Local SDP is valid");
14968
14975
  this._iceCandidatesState.next({
14969
14976
  state: "timeout",
14970
14977
  validSDP
14971
14978
  });
14972
14979
  this.stopGathering();
14973
- } else logger$20.debug("### ICE gathering timeout\n", this.peerConnection.localDescription?.sdp);
14980
+ } else logger$21.debug("### ICE gathering timeout\n", this.peerConnection.localDescription?.sdp);
14974
14981
  }
14975
14982
  handleICECandidateTimeout() {
14976
14983
  if (this.iceCandidateTimer) this.removeTimer("iceCandidateTimer");
14977
- logger$20.warn("[ICEGatheringController] ICE candidate timeout");
14984
+ logger$21.warn("[ICEGatheringController] ICE candidate timeout");
14978
14985
  const validSDP = this.hasValidLocalDescriptionSDP;
14979
14986
  if (!validSDP && !this.relayOnly) this.restartICEGatheringWithRelayOnly();
14980
14987
  else {
14981
- logger$20.debug("[ICEGatheringController] Using current SDP due to ICE candidate timeout");
14988
+ logger$21.debug("[ICEGatheringController] Using current SDP due to ICE candidate timeout");
14982
14989
  this._iceCandidatesState.next({
14983
14990
  state: "timeout",
14984
14991
  validSDP
@@ -14987,7 +14994,7 @@ var ICEGatheringController = class extends Destroyable {
14987
14994
  }
14988
14995
  }
14989
14996
  restartICEGatheringWithRelayOnly() {
14990
- logger$20.debug("[ICEGatheringController] Restarting ICE gathering with relay-only candidates");
14997
+ logger$21.debug("[ICEGatheringController] Restarting ICE gathering with relay-only candidates");
14991
14998
  this.relayOnly = true;
14992
14999
  this.peerConnection.setConfiguration({
14993
15000
  ...this.peerConnection.getConfiguration(),
@@ -15002,7 +15009,7 @@ var ICEGatheringController = class extends Destroyable {
15002
15009
  }
15003
15010
  }
15004
15011
  clearAllTimers() {
15005
- logger$20.debug("[ICEGatheringController] Clearing all timers");
15012
+ logger$21.debug("[ICEGatheringController] Clearing all timers");
15006
15013
  this.removeTimer("iceGatheringTimer");
15007
15014
  this.removeTimer("iceCandidateTimer");
15008
15015
  }
@@ -15011,7 +15018,7 @@ var ICEGatheringController = class extends Destroyable {
15011
15018
  this.peerConnection.removeEventListener("icecandidate", this.onicecandidateHandler);
15012
15019
  }
15013
15020
  destroy() {
15014
- logger$20.debug("[ICEGatheringController] Destroying ICEGatheringController");
15021
+ logger$21.debug("[ICEGatheringController] Destroying ICEGatheringController");
15015
15022
  this.clearAllTimers();
15016
15023
  this.removeEventListeners();
15017
15024
  super.destroy();
@@ -15021,7 +15028,7 @@ var ICEGatheringController = class extends Destroyable {
15021
15028
  //#endregion
15022
15029
  //#region src/controllers/LocalAudioPipeline.ts
15023
15030
  var import_cjs$18 = require_cjs();
15024
- const logger$19 = getLogger();
15031
+ const logger$20 = getLogger();
15025
15032
  /**
15026
15033
  * Web Audio pipeline for the local microphone stream.
15027
15034
  *
@@ -15133,7 +15140,7 @@ var LocalAudioPipeline = class extends Destroyable {
15133
15140
  try {
15134
15141
  this._inputSource.disconnect();
15135
15142
  } catch (error) {
15136
- logger$19.debug("[LocalAudioPipeline] input disconnect warning:", error);
15143
+ logger$20.debug("[LocalAudioPipeline] input disconnect warning:", error);
15137
15144
  }
15138
15145
  this._inputSource = null;
15139
15146
  }
@@ -15143,7 +15150,7 @@ var LocalAudioPipeline = class extends Destroyable {
15143
15150
  this._inputSource = this._audioContext.createMediaStreamSource(this._inputStream);
15144
15151
  this._inputSource.connect(this._gainNode);
15145
15152
  if (this._audioContext.state === "suspended") this._audioContext.resume().catch((error) => {
15146
- logger$19.warn("[LocalAudioPipeline] AudioContext resume failed:", error);
15153
+ logger$20.warn("[LocalAudioPipeline] AudioContext resume failed:", error);
15147
15154
  });
15148
15155
  }
15149
15156
  destroy() {
@@ -15158,7 +15165,7 @@ var LocalAudioPipeline = class extends Destroyable {
15158
15165
  this._analyser.disconnect();
15159
15166
  } catch {}
15160
15167
  this._audioContext.close().catch((error) => {
15161
- logger$19.debug("[LocalAudioPipeline] audio context close warning:", error);
15168
+ logger$20.debug("[LocalAudioPipeline] audio context close warning:", error);
15162
15169
  });
15163
15170
  super.destroy();
15164
15171
  }
@@ -15185,7 +15192,7 @@ var LocalAudioPipeline = class extends Destroyable {
15185
15192
  //#endregion
15186
15193
  //#region src/controllers/LocalStreamController.ts
15187
15194
  var import_cjs$17 = require_cjs();
15188
- const logger$18 = getLogger();
15195
+ const logger$19 = getLogger();
15189
15196
  var LocalStreamController = class extends Destroyable {
15190
15197
  constructor(options) {
15191
15198
  super();
@@ -15223,26 +15230,26 @@ var LocalStreamController = class extends Destroyable {
15223
15230
  * Build the local media stream based on the provided options.
15224
15231
  */
15225
15232
  async buildLocalStream() {
15226
- logger$18.debug("[LocalStreamController] Building local media stream.");
15233
+ logger$19.debug("[LocalStreamController] Building local media stream.");
15227
15234
  let stream;
15228
15235
  if (this.options.inputAudioStream ?? this.options.inputVideoStream) {
15229
15236
  const tracks = [...this.options.inputAudioStream?.getTracks() ?? [], ...this.options.inputVideoStream?.getTracks() ?? []];
15230
15237
  stream = new MediaStream(tracks);
15231
15238
  } else if (this.options.propose === "screenshare") {
15232
- logger$18.debug("[LocalStreamController] Requesting display media for screen sharing with audio:", Boolean(this.options.inputAudioDeviceConstraints));
15239
+ logger$19.debug("[LocalStreamController] Requesting display media for screen sharing with audio:", Boolean(this.options.inputAudioDeviceConstraints));
15233
15240
  stream = await this.options.getDisplayMedia({
15234
15241
  video: true,
15235
15242
  audio: Boolean(this.options.inputAudioDeviceConstraints)
15236
15243
  });
15237
- logger$18.debug("[LocalStreamController] Screen share media obtained:", stream);
15244
+ logger$19.debug("[LocalStreamController] Screen share media obtained:", stream);
15238
15245
  } else {
15239
15246
  const constraints = {
15240
15247
  audio: this.options.inputAudioDeviceConstraints,
15241
15248
  video: this.options.inputVideoDeviceConstraints
15242
15249
  };
15243
- logger$18.debug("[LocalStreamController] Requesting user media with constraints:", constraints);
15250
+ logger$19.debug("[LocalStreamController] Requesting user media with constraints:", constraints);
15244
15251
  stream = await this.options.getUserMedia(constraints);
15245
- logger$18.debug("[LocalStreamController] User media obtained:", stream);
15252
+ logger$19.debug("[LocalStreamController] User media obtained:", stream);
15246
15253
  }
15247
15254
  this._localStream$.next(stream);
15248
15255
  this._localAudioTracks$.next(stream.getAudioTracks());
@@ -15261,7 +15268,7 @@ var LocalStreamController = class extends Destroyable {
15261
15268
  this._localStream$.next(localStream);
15262
15269
  if (track.kind === "video") this._localVideoTracks$.next(localStream.getVideoTracks());
15263
15270
  else this._localAudioTracks$.next(localStream.getAudioTracks());
15264
- logger$18.debug(`[LocalStreamController] ${track.kind} track added:`, track.id);
15271
+ logger$19.debug(`[LocalStreamController] ${track.kind} track added:`, track.id);
15265
15272
  return localStream;
15266
15273
  }
15267
15274
  /**
@@ -15273,7 +15280,7 @@ var LocalStreamController = class extends Destroyable {
15273
15280
  const stream = this._localStream$.value;
15274
15281
  const track = stream?.getTracks().find((t) => t.id === trackId);
15275
15282
  if (!track) {
15276
- logger$18.debug(`[LocalStreamController] track not found: ${trackId}`);
15283
+ logger$19.debug(`[LocalStreamController] track not found: ${trackId}`);
15277
15284
  return;
15278
15285
  }
15279
15286
  track.removeEventListener("ended", this.mediaTrackEndedHandler);
@@ -15282,7 +15289,7 @@ var LocalStreamController = class extends Destroyable {
15282
15289
  this._localStream$.next(stream);
15283
15290
  if (track.kind === "video") this._localVideoTracks$.next(stream?.getVideoTracks() ?? []);
15284
15291
  else this._localAudioTracks$.next(stream?.getAudioTracks() ?? []);
15285
- logger$18.debug(`[LocalStreamController] ${track.kind} track removed:`, trackId);
15292
+ logger$19.debug(`[LocalStreamController] ${track.kind} track removed:`, trackId);
15286
15293
  return track;
15287
15294
  }
15288
15295
  /**
@@ -15317,7 +15324,7 @@ var LocalStreamController = class extends Destroyable {
15317
15324
  */
15318
15325
  stopAllTracks() {
15319
15326
  this._localStream$.value?.getTracks().forEach((track) => {
15320
- logger$18.debug(`[LocalStreamController] Stopping local track: ${track.kind}`);
15327
+ logger$19.debug(`[LocalStreamController] Stopping local track: ${track.kind}`);
15321
15328
  track.removeEventListener("ended", this.mediaTrackEndedHandler);
15322
15329
  track.stop();
15323
15330
  });
@@ -15333,7 +15340,7 @@ var LocalStreamController = class extends Destroyable {
15333
15340
 
15334
15341
  //#endregion
15335
15342
  //#region src/controllers/TransceiverController.ts
15336
- const logger$17 = getLogger();
15343
+ const logger$18 = getLogger();
15337
15344
  const getDirection = (send, recv) => {
15338
15345
  if (send && recv) return "sendrecv";
15339
15346
  else if (send && !recv) return "sendonly";
@@ -15441,7 +15448,7 @@ var TransceiverController = class extends Destroyable {
15441
15448
  sendEncodings: isAudio ? void 0 : this.sendEncodings,
15442
15449
  streams: direction === "recvonly" ? void 0 : [localStream]
15443
15450
  };
15444
- logger$17.debug(`[TransceiverController] Setting up transceiver sender for local ${track.kind} track:`, {
15451
+ logger$18.debug(`[TransceiverController] Setting up transceiver sender for local ${track.kind} track:`, {
15445
15452
  transceiver,
15446
15453
  transceiverParams
15447
15454
  });
@@ -15449,11 +15456,11 @@ var TransceiverController = class extends Destroyable {
15449
15456
  await transceiver.sender.replaceTrack(track);
15450
15457
  transceiver.direction = transceiverParams.direction;
15451
15458
  if (transceiverParams.streams?.some((stream) => Boolean(stream))) {
15452
- logger$17.debug(`[TransceiverController] Setting streams for transceiver sender for local ${track.kind} track:`, transceiverParams.streams);
15459
+ logger$18.debug(`[TransceiverController] Setting streams for transceiver sender for local ${track.kind} track:`, transceiverParams.streams);
15453
15460
  transceiver.sender.setStreams(...transceiverParams.streams);
15454
15461
  }
15455
15462
  } else {
15456
- logger$17.debug(`[TransceiverController] Adding new transceiver for local ${track.kind} track:`, track.id);
15463
+ logger$18.debug(`[TransceiverController] Adding new transceiver for local ${track.kind} track:`, track.id);
15457
15464
  this.peerConnection.addTransceiver(track, transceiverParams);
15458
15465
  }
15459
15466
  }
@@ -15467,13 +15474,13 @@ var TransceiverController = class extends Destroyable {
15467
15474
  if (options.updateTransceiverDirection) transceiver.direction = "inactive";
15468
15475
  }
15469
15476
  } catch (error) {
15470
- logger$17.error("[TransceiverController] stopTrackSender error", kind, error);
15477
+ logger$18.error("[TransceiverController] stopTrackSender error", kind, error);
15471
15478
  this.options.onError?.(new MediaTrackError("stopTrackSender", kind, error));
15472
15479
  }
15473
15480
  }
15474
15481
  async restoreTrackSender(kind) {
15475
15482
  try {
15476
- logger$17.debug("[TransceiverController] restoreTrackSender called", kind);
15483
+ logger$18.debug("[TransceiverController] restoreTrackSender called", kind);
15477
15484
  const constraints = {};
15478
15485
  const transceivers = this.transceiverByKind(kind);
15479
15486
  for (const transceiver of transceivers) {
@@ -15483,23 +15490,23 @@ var TransceiverController = class extends Destroyable {
15483
15490
  if (trackKind === "audio" || trackKind === "video") constraints[trackKind] = this.getConstraintsFor(trackKind);
15484
15491
  }
15485
15492
  }
15486
- logger$17.debug("[TransceiverController] restoreTrackSender constraints:", constraints);
15493
+ logger$18.debug("[TransceiverController] restoreTrackSender constraints:", constraints);
15487
15494
  if (Object.keys(constraints).length === 0) {
15488
- logger$17.warn("[TransceiverController] restoreTrackSender: no tracks need restoration", kind);
15495
+ logger$18.warn("[TransceiverController] restoreTrackSender: no tracks need restoration", kind);
15489
15496
  return;
15490
15497
  }
15491
15498
  const newTracks = (await this.options.getUserMedia(constraints)).getTracks();
15492
- logger$17.debug("[TransceiverController] restoreTrackSender new tracks:", newTracks);
15499
+ logger$18.debug("[TransceiverController] restoreTrackSender new tracks:", newTracks);
15493
15500
  for (const newTrack of newTracks) {
15494
15501
  this.options.localStreamController.addTrack(newTrack);
15495
15502
  const trackKind = newTrack.kind;
15496
15503
  const transceiverOfKind = this.transceiverByKind(trackKind)[0];
15497
15504
  transceiverOfKind.direction = trackKind === "audio" ? this.audioDirection : this.videoDirection;
15498
- logger$17.debug("[TransceiverController] restoreTrackSender setting direction for", trackKind, transceiverOfKind.direction);
15505
+ logger$18.debug("[TransceiverController] restoreTrackSender setting direction for", trackKind, transceiverOfKind.direction);
15499
15506
  await transceiverOfKind.sender.replaceTrack(newTrack);
15500
15507
  }
15501
15508
  } catch (error) {
15502
- logger$17.error("[TransceiverController] restoreTrackSender error", kind, error);
15509
+ logger$18.error("[TransceiverController] restoreTrackSender error", kind, error);
15503
15510
  this.options.onError?.(new MediaTrackError("restoreTrackSender", kind, error));
15504
15511
  }
15505
15512
  }
@@ -15540,14 +15547,14 @@ var TransceiverController = class extends Destroyable {
15540
15547
  };
15541
15548
  try {
15542
15549
  await track.applyConstraints(constraintsToApply);
15543
- logger$17.debug(`[TransceiverController] Updated ${kind} sender constraints:`, constraintsToApply);
15544
- logger$17.debug(`[TransceiverController] Updated ${kind} sender constraints:`, track.getConstraints());
15550
+ logger$18.debug(`[TransceiverController] Updated ${kind} sender constraints:`, constraintsToApply);
15551
+ logger$18.debug(`[TransceiverController] Updated ${kind} sender constraints:`, track.getConstraints());
15545
15552
  } catch (error) {
15546
- logger$17.warn(`[TransceiverController] applyConstraints failed for ${kind} track ${track.id}, attempting track replacement fallback:`, error);
15553
+ logger$18.warn(`[TransceiverController] applyConstraints failed for ${kind} track ${track.id}, attempting track replacement fallback:`, error);
15547
15554
  try {
15548
15555
  await this.replaceTrackFallback(sender, track, kind, constraintsToApply);
15549
15556
  } catch (fallbackError) {
15550
- logger$17.warn(`[TransceiverController] Track replacement fallback also failed for ${kind} track:`, fallbackError);
15557
+ logger$18.warn(`[TransceiverController] Track replacement fallback also failed for ${kind} track:`, fallbackError);
15551
15558
  this.options.onError?.(new MediaTrackError("updateSendersConstraints", kind, fallbackError));
15552
15559
  }
15553
15560
  }
@@ -15575,7 +15582,7 @@ var TransceiverController = class extends Destroyable {
15575
15582
  if (!newTrack) throw new MediaTrackError("replaceTrackFallback", kind, /* @__PURE__ */ new Error("getUserMedia returned no track of the requested kind"));
15576
15583
  await sender.replaceTrack(newTrack);
15577
15584
  this.options.localStreamController.addTrack(newTrack);
15578
- logger$17.debug(`[TransceiverController] Track replacement fallback succeeded for ${kind}. New track: ${newTrack.id}`);
15585
+ logger$18.debug(`[TransceiverController] Track replacement fallback succeeded for ${kind}. New track: ${newTrack.id}`);
15579
15586
  }
15580
15587
  getMediaDirections() {
15581
15588
  if (this.peerConnection.connectionState === "connected") return this.peerConnection.getTransceivers().reduce((acc, transceiver) => {
@@ -15606,7 +15613,7 @@ var TransceiverController = class extends Destroyable {
15606
15613
  //#endregion
15607
15614
  //#region src/controllers/RTCPeerConnectionController.ts
15608
15615
  var import_cjs$16 = require_cjs();
15609
- const logger$16 = getLogger();
15616
+ const logger$17 = getLogger();
15610
15617
  var RTCPeerConnectionController = class extends Destroyable {
15611
15618
  constructor(options = {}, remoteSessionDescription, deviceController) {
15612
15619
  super();
@@ -15622,43 +15629,43 @@ var RTCPeerConnectionController = class extends Destroyable {
15622
15629
  this.oniceconnectionstatechangeHandler = () => {
15623
15630
  if (this.peerConnection) {
15624
15631
  const { iceConnectionState } = this.peerConnection;
15625
- logger$16.debug(`[RTCPeerConnectionController] ICE connection state changed to: ${iceConnectionState}`);
15632
+ logger$17.debug(`[RTCPeerConnectionController] ICE connection state changed to: ${iceConnectionState}`);
15626
15633
  this._iceConnectionState$.next(this.peerConnection.iceConnectionState);
15627
15634
  }
15628
15635
  };
15629
15636
  this.onconnectionstatechangeHandler = () => {
15630
15637
  if (this.peerConnection) {
15631
15638
  const { connectionState } = this.peerConnection;
15632
- logger$16.debug(`[RTCPeerConnectionController] Connection state changed to: ${connectionState}`);
15639
+ logger$17.debug(`[RTCPeerConnectionController] Connection state changed to: ${connectionState}`);
15633
15640
  if (connectionState === "connected") this.removeConnectionTimer();
15634
15641
  this._connectionState$.next(this.peerConnection.connectionState);
15635
15642
  }
15636
15643
  };
15637
15644
  this.onsignalingstatechangeHandler = () => {
15638
- logger$16.debug(`[RTCPeerConnectionController] Signaling state changed to: ${this.peerConnection?.signalingState}`);
15645
+ logger$17.debug(`[RTCPeerConnectionController] Signaling state changed to: ${this.peerConnection?.signalingState}`);
15639
15646
  };
15640
15647
  this.onicegatheringstatechangeHandler = () => {
15641
15648
  if (this.peerConnection) this._iceGatheringState$.next(this.peerConnection.iceGatheringState);
15642
15649
  };
15643
15650
  this.onnegotiationneededHandler = (event) => {
15644
- logger$16.debug("[RTCPeerConnectionController] Negotiation needed event received.", event);
15651
+ logger$17.debug("[RTCPeerConnectionController] Negotiation needed event received.", event);
15645
15652
  this.negotiationNeeded$.next();
15646
15653
  };
15647
15654
  this.updateSelectedInputDevice = async (kind, deviceInfo) => {
15648
15655
  try {
15649
15656
  const { localStream } = this;
15650
15657
  if (!localStream) {
15651
- logger$16.warn("[RTCPeerConnectionController] No local stream available to update input device.");
15658
+ logger$17.warn("[RTCPeerConnectionController] No local stream available to update input device.");
15652
15659
  return;
15653
15660
  }
15654
- logger$16.debug(`[RTCPeerConnectionController] Updating selected ${kind} input device:`, localStream.getTracks());
15661
+ logger$17.debug(`[RTCPeerConnectionController] Updating selected ${kind} input device:`, localStream.getTracks());
15655
15662
  const track = localStream.getTracks().find((track$1) => track$1.kind === kind);
15656
15663
  if (track) {
15657
15664
  this.transceiverController?.stopTrackSender(kind);
15658
15665
  this.localStreamController.removeTrack(track.id);
15659
- logger$16.debug(`[RTCPeerConnectionController] Stopped existing ${kind} track: ${track.id}`, localStream.getTracks());
15666
+ logger$17.debug(`[RTCPeerConnectionController] Stopped existing ${kind} track: ${track.id}`, localStream.getTracks());
15660
15667
  if (!deviceInfo) {
15661
- logger$16.debug(`[RTCPeerConnectionController] ${kind} input device selected: none`);
15668
+ logger$17.debug(`[RTCPeerConnectionController] ${kind} input device selected: none`);
15662
15669
  return;
15663
15670
  }
15664
15671
  const streamTrack = (await this.getUserMedia({ [kind]: {
@@ -15666,15 +15673,15 @@ var RTCPeerConnectionController = class extends Destroyable {
15666
15673
  ...this.deviceController.deviceInfoToConstraints(deviceInfo)
15667
15674
  } })).getTracks().find((t) => t.kind === kind);
15668
15675
  if (streamTrack) {
15669
- logger$16.debug(`[RTCPeerConnectionController] Adding new ${kind} track: ${streamTrack.id}`);
15676
+ logger$17.debug(`[RTCPeerConnectionController] Adding new ${kind} track: ${streamTrack.id}`);
15670
15677
  this.localStreamController.addTrack(streamTrack);
15671
15678
  await this.transceiverController?.replaceSenderTrack(kind, streamTrack);
15672
- logger$16.debug(`[RTCPeerConnectionController] Added new ${kind} track: ${streamTrack.id}`, this.localStream?.getTracks());
15679
+ logger$17.debug(`[RTCPeerConnectionController] Added new ${kind} track: ${streamTrack.id}`, this.localStream?.getTracks());
15673
15680
  }
15674
15681
  }
15675
- logger$16.debug(`[RTCPeerConnectionController] ${kind} input device selected:`, deviceInfo?.label);
15682
+ logger$17.debug(`[RTCPeerConnectionController] ${kind} input device selected:`, deviceInfo?.label);
15676
15683
  } catch (error) {
15677
- logger$16.error(`[RTCPeerConnectionController] Failed to select ${kind} input device:`, error);
15684
+ logger$17.error(`[RTCPeerConnectionController] Failed to select ${kind} input device:`, error);
15678
15685
  this._errors$.next(toError(error));
15679
15686
  throw error;
15680
15687
  }
@@ -15924,15 +15931,15 @@ var RTCPeerConnectionController = class extends Destroyable {
15924
15931
  this.setupPeerConnection();
15925
15932
  this.subscribeTo(this.negotiationNeeded$.pipe((0, import_cjs$16.auditTime)(0), (0, import_cjs$16.exhaustMap)(async () => this.startNegotiation())), {
15926
15933
  next: () => {
15927
- logger$16.debug("[RTCPeerConnectionController] Start Negotiation completed successfully");
15934
+ logger$17.debug("[RTCPeerConnectionController] Start Negotiation completed successfully");
15928
15935
  },
15929
15936
  error: (error) => {
15930
- logger$16.error("[RTCPeerConnectionController] Start Negotiation error:", error);
15937
+ logger$17.error("[RTCPeerConnectionController] Start Negotiation error:", error);
15931
15938
  this._errors$.next(toError(error));
15932
15939
  }
15933
15940
  });
15934
15941
  this.subscribeTo((0, import_cjs$16.merge)(this.deviceController.selectedAudioInputDevice$.pipe((0, import_cjs$16.map)((deviceInfo) => ["audio", deviceInfo])), this.deviceController.selectedVideoInputDevice$.pipe((0, import_cjs$16.map)((deviceInfo) => ["video", deviceInfo]))).pipe((0, import_cjs$16.skipWhile)(() => !this.localStreamController.localStream)), async ([kind, deviceInfo]) => {
15935
- logger$16.debug(`[RTCPeerConnectionController] Selected input device changed for:`, {
15942
+ logger$17.debug(`[RTCPeerConnectionController] Selected input device changed for:`, {
15936
15943
  kind,
15937
15944
  deviceInfo
15938
15945
  });
@@ -15949,7 +15956,7 @@ var RTCPeerConnectionController = class extends Destroyable {
15949
15956
  this._initialized$.next(true);
15950
15957
  }
15951
15958
  } catch (error) {
15952
- logger$16.error("[RTCPeerConnectionController] Initialization error:", error);
15959
+ logger$17.error("[RTCPeerConnectionController] Initialization error:", error);
15953
15960
  this._errors$.next(toError(error));
15954
15961
  this.destroy();
15955
15962
  }
@@ -15981,22 +15988,22 @@ var RTCPeerConnectionController = class extends Destroyable {
15981
15988
  }
15982
15989
  async startNegotiation() {
15983
15990
  if (this.isNegotiating) {
15984
- logger$16.debug("[RTCPeerConnectionController] Negotiation already in progress, skipping.");
15991
+ logger$17.debug("[RTCPeerConnectionController] Negotiation already in progress, skipping.");
15985
15992
  return;
15986
15993
  }
15987
15994
  this.setupEventListeners();
15988
15995
  if (this.type === "answer") {
15989
- logger$16.debug("[RTCPeerConnectionController] This is an answer type still, skipping offer creation.");
15996
+ logger$17.debug("[RTCPeerConnectionController] This is an answer type still, skipping offer creation.");
15990
15997
  return;
15991
15998
  }
15992
15999
  this._isNegotiating$.next(true);
15993
- logger$16.debug("[RTCPeerConnectionController] Starting negotiation.");
16000
+ logger$17.debug("[RTCPeerConnectionController] Starting negotiation.");
15994
16001
  try {
15995
16002
  const { offerOptions } = this;
15996
- logger$16.debug("[RTCPeerConnectionController] Creating offer with options:", offerOptions);
16003
+ logger$17.debug("[RTCPeerConnectionController] Creating offer with options:", offerOptions);
15997
16004
  await this.createOffer(offerOptions);
15998
16005
  } catch (error) {
15999
- logger$16.error("[RTCPeerConnectionController] Error during negotiation:", error);
16006
+ logger$17.error("[RTCPeerConnectionController] Error during negotiation:", error);
16000
16007
  this._errors$.next(toError(error));
16001
16008
  }
16002
16009
  }
@@ -16012,14 +16019,14 @@ var RTCPeerConnectionController = class extends Destroyable {
16012
16019
  let readyToConnect = status !== "failed";
16013
16020
  try {
16014
16021
  if (status === "received" && sdp) {
16015
- logger$16.debug("[RTCPeerConnectionController] Received answer SDP:", sdp);
16022
+ logger$17.debug("[RTCPeerConnectionController] Received answer SDP:", sdp);
16016
16023
  await this._setRemoteDescription({
16017
16024
  type: "answer",
16018
16025
  sdp
16019
16026
  });
16020
16027
  }
16021
16028
  } catch (error) {
16022
- logger$16.error("[RTCPeerConnectionController] Error updating answer status:", error);
16029
+ logger$17.error("[RTCPeerConnectionController] Error updating answer status:", error);
16023
16030
  this._errors$.next(toError(error));
16024
16031
  readyToConnect = false;
16025
16032
  } finally {
@@ -16038,7 +16045,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16038
16045
  await this.handleOfferReceived();
16039
16046
  break;
16040
16047
  case "failed":
16041
- logger$16.error("[RTCPeerConnectionController] Offer failed to be processed by remote.");
16048
+ logger$17.error("[RTCPeerConnectionController] Offer failed to be processed by remote.");
16042
16049
  break;
16043
16050
  case "sent":
16044
16051
  default:
@@ -16070,7 +16077,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16070
16077
  }
16071
16078
  await this.setupLocalTracks();
16072
16079
  const { answerOptions } = this;
16073
- logger$16.debug("[RTCPeerConnectionController] Creating inbound answer with options:", answerOptions);
16080
+ logger$17.debug("[RTCPeerConnectionController] Creating inbound answer with options:", answerOptions);
16074
16081
  await this.createAnswer(answerOptions);
16075
16082
  }
16076
16083
  async handleOfferReceived() {
@@ -16078,7 +16085,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16078
16085
  this._isNegotiating$.next(true);
16079
16086
  await this._setRemoteDescription(this.sdpInit);
16080
16087
  const { answerOptions } = this;
16081
- logger$16.debug("[RTCPeerConnectionController] Creating answer with options:", answerOptions);
16088
+ logger$17.debug("[RTCPeerConnectionController] Creating answer with options:", answerOptions);
16082
16089
  await this.createAnswer(answerOptions);
16083
16090
  }
16084
16091
  readyToConnect() {
@@ -16086,7 +16093,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16086
16093
  this.connectionTimer = setTimeout(() => {
16087
16094
  this.removeConnectionTimer();
16088
16095
  if (this.peerConnection?.connectionState !== "connected") {
16089
- logger$16.debug("[RTCPeerConnectionController] Connection timeout, restarting ICE gathering with relay only.");
16096
+ logger$17.debug("[RTCPeerConnectionController] Connection timeout, restarting ICE gathering with relay only.");
16090
16097
  this.iceGatheringController.restartICEGatheringWithRelayOnly();
16091
16098
  }
16092
16099
  }, this.connectionTimeout);
@@ -16108,14 +16115,14 @@ var RTCPeerConnectionController = class extends Destroyable {
16108
16115
  const stereo = this.options.stereo ?? PreferencesContainer.instance.stereoAudio;
16109
16116
  if (preferredAudioCodecs.length > 0 || preferredVideoCodecs.length > 0) {
16110
16117
  result = setCodecPreferences(result, preferredAudioCodecs, preferredVideoCodecs);
16111
- logger$16.debug("[RTCPeerConnectionController] Applied codec preferences to SDP", {
16118
+ logger$17.debug("[RTCPeerConnectionController] Applied codec preferences to SDP", {
16112
16119
  preferredAudioCodecs,
16113
16120
  preferredVideoCodecs
16114
16121
  });
16115
16122
  }
16116
16123
  if (stereo) {
16117
16124
  result = enableStereoOpus(result);
16118
- logger$16.debug("[RTCPeerConnectionController] Applied stereo Opus to SDP");
16125
+ logger$17.debug("[RTCPeerConnectionController] Applied stereo Opus to SDP");
16119
16126
  }
16120
16127
  return Promise.resolve(result);
16121
16128
  }
@@ -16171,25 +16178,25 @@ var RTCPeerConnectionController = class extends Destroyable {
16171
16178
  ...this.peerConnection.getConfiguration(),
16172
16179
  iceTransportPolicy: "relay"
16173
16180
  });
16174
- logger$16.debug("[RTCPeerConnectionController] ICE transport policy set to relay-only");
16181
+ logger$17.debug("[RTCPeerConnectionController] ICE transport policy set to relay-only");
16175
16182
  } catch (error) {
16176
- logger$16.warn("[RTCPeerConnectionController] Failed to set relay-only policy:", error);
16183
+ logger$17.warn("[RTCPeerConnectionController] Failed to set relay-only policy:", error);
16177
16184
  }
16178
16185
  this.setupEventListeners();
16179
16186
  this._isNegotiating$.next(true);
16180
- logger$16.debug(`[RTCPeerConnectionController] Triggering ICE restart${relayOnly ? " (relay-only)" : ""}.`);
16187
+ logger$17.debug(`[RTCPeerConnectionController] Triggering ICE restart${relayOnly ? " (relay-only)" : ""}.`);
16181
16188
  try {
16182
16189
  const offer = await this.peerConnection.createOffer({ iceRestart: true });
16183
16190
  await this.setLocalDescription(offer);
16184
16191
  } catch (error) {
16185
- logger$16.error("[RTCPeerConnectionController] ICE restart offer failed:", error);
16192
+ logger$17.error("[RTCPeerConnectionController] ICE restart offer failed:", error);
16186
16193
  this._errors$.next(toError(error));
16187
16194
  this.negotiationEnded();
16188
16195
  if (policyChanged) this.restoreIceTransportPolicy();
16189
16196
  throw error;
16190
16197
  }
16191
16198
  if (policyChanged) (0, import_cjs$16.firstValueFrom)((0, import_cjs$16.race)(this._iceGatheringState$.pipe((0, import_cjs$16.filter)((state) => state === "complete"), (0, import_cjs$16.take)(1)), (0, import_cjs$16.timer)(ICE_GATHERING_COMPLETE_TIMEOUT_MS).pipe((0, import_cjs$16.map)(() => "timeout")))).then(() => this.restoreIceTransportPolicy()).catch((error) => {
16192
- logger$16.warn("[RTCPeerConnectionController] Error waiting for ICE gathering to complete:", error);
16199
+ logger$17.warn("[RTCPeerConnectionController] Error waiting for ICE gathering to complete:", error);
16193
16200
  this.restoreIceTransportPolicy();
16194
16201
  });
16195
16202
  }
@@ -16199,9 +16206,9 @@ var RTCPeerConnectionController = class extends Destroyable {
16199
16206
  ...this.peerConnection.getConfiguration(),
16200
16207
  iceTransportPolicy: this.options.relayOnly ? "relay" : "all"
16201
16208
  });
16202
- logger$16.debug("[RTCPeerConnectionController] ICE transport policy restored");
16209
+ logger$17.debug("[RTCPeerConnectionController] ICE transport policy restored");
16203
16210
  } catch (error) {
16204
- logger$16.warn("[RTCPeerConnectionController] Failed to restore ICE transport policy:", error);
16211
+ logger$17.warn("[RTCPeerConnectionController] Failed to restore ICE transport policy:", error);
16205
16212
  }
16206
16213
  }
16207
16214
  /**
@@ -16213,13 +16220,13 @@ var RTCPeerConnectionController = class extends Destroyable {
16213
16220
  await this.setupRemoteTracks();
16214
16221
  }
16215
16222
  async setupLocalTracks() {
16216
- logger$16.debug("[RTCPeerConnectionController] Setting up local tracks/transceivers.");
16223
+ logger$17.debug("[RTCPeerConnectionController] Setting up local tracks/transceivers.");
16217
16224
  const localStream = this.localStream ?? await this.localStreamController.buildLocalStream();
16218
16225
  if (this.transceiverController?.useAddStream ?? false) {
16219
- logger$16.warn("[RTCPeerConnectionController] Using deprecated addStream API to add local stream.");
16226
+ logger$17.warn("[RTCPeerConnectionController] Using deprecated addStream API to add local stream.");
16220
16227
  this.peerConnection?.addStream(localStream);
16221
16228
  if (!this.isNegotiating) {
16222
- logger$16.debug("[RTCPeerConnectionController] Forcing negotiationneeded after local tracks setup.");
16229
+ logger$17.debug("[RTCPeerConnectionController] Forcing negotiationneeded after local tracks setup.");
16223
16230
  this.negotiationNeeded$.next();
16224
16231
  }
16225
16232
  return;
@@ -16235,7 +16242,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16235
16242
  const transceivers = (kind === "audio" ? this.transceiverController?.audioTransceivers : this.transceiverController?.videoTransceivers) ?? [];
16236
16243
  await this.transceiverController?.setupTransceiverSender(track, localStream, transceivers[index]);
16237
16244
  } else {
16238
- logger$16.debug(`[RTCPeerConnectionController] Using addTrack for local ${kind} track:`, track.id);
16245
+ logger$17.debug(`[RTCPeerConnectionController] Using addTrack for local ${kind} track:`, track.id);
16239
16246
  this.peerConnection?.addTrack(track, localStream);
16240
16247
  }
16241
16248
  }
@@ -16252,7 +16259,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16252
16259
  async setupRemoteTracks() {
16253
16260
  if (!this.peerConnection) throw new DependencyError("RTCPeerConnection is not initialized");
16254
16261
  this.peerConnection.ontrack = (event) => {
16255
- logger$16.debug("[RTCPeerConnectionController] Remote track received:", event.track.kind);
16262
+ logger$17.debug("[RTCPeerConnectionController] Remote track received:", event.track.kind);
16256
16263
  if (event.streams[0]) this._remoteStream$.next(event.streams[0]);
16257
16264
  else {
16258
16265
  const existingTracks = this._remoteStream$.value?.getTracks() ?? [];
@@ -16276,7 +16283,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16276
16283
  try {
16277
16284
  stream = await this.getUserMedia({ audio: constraints });
16278
16285
  } catch (error) {
16279
- logger$16.error("[RTCPeerConnectionController] Failed to re-acquire mic for pipeline restore:", error);
16286
+ logger$17.error("[RTCPeerConnectionController] Failed to re-acquire mic for pipeline restore:", error);
16280
16287
  this._errors$.next(toError(error));
16281
16288
  return;
16282
16289
  }
@@ -16298,7 +16305,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16298
16305
  try {
16299
16306
  this._localAudioPipeline = new LocalAudioPipeline();
16300
16307
  } catch (error) {
16301
- logger$16.warn("[RTCPeerConnectionController] Failed to create LocalAudioPipeline:", error);
16308
+ logger$17.warn("[RTCPeerConnectionController] Failed to create LocalAudioPipeline:", error);
16302
16309
  return null;
16303
16310
  }
16304
16311
  this.subscribeTo(this.localStreamController.localAudioTracks$, () => {
@@ -16320,7 +16327,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16320
16327
  try {
16321
16328
  await sender.replaceTrack(this._localAudioPipeline.outputTrack);
16322
16329
  } catch (error) {
16323
- logger$16.warn("[RTCPeerConnectionController] Failed to route audio sender through pipeline:", error);
16330
+ logger$17.warn("[RTCPeerConnectionController] Failed to route audio sender through pipeline:", error);
16324
16331
  }
16325
16332
  }
16326
16333
  /**
@@ -16336,9 +16343,9 @@ var RTCPeerConnectionController = class extends Destroyable {
16336
16343
  try {
16337
16344
  const localStream = this.localStreamController.addTrack(track);
16338
16345
  this.peerConnection.addTrack(track, localStream);
16339
- logger$16.debug(`[RTCPeerConnectionController] ${track.kind} track added:`, track.id);
16346
+ logger$17.debug(`[RTCPeerConnectionController] ${track.kind} track added:`, track.id);
16340
16347
  } catch (error) {
16341
- logger$16.error(`[RTCPeerConnectionController] Failed to add ${track.kind} track:`, error);
16348
+ logger$17.error(`[RTCPeerConnectionController] Failed to add ${track.kind} track:`, error);
16342
16349
  this._errors$.next(toError(error));
16343
16350
  throw error;
16344
16351
  }
@@ -16355,15 +16362,15 @@ var RTCPeerConnectionController = class extends Destroyable {
16355
16362
  }
16356
16363
  const sender = this.peerConnection.getSenders().find((sender$1) => sender$1.track?.id === trackId);
16357
16364
  if (!sender) {
16358
- logger$16.debug(`[RTCPeerConnectionController] track not found: ${trackId}`);
16365
+ logger$17.debug(`[RTCPeerConnectionController] track not found: ${trackId}`);
16359
16366
  return;
16360
16367
  }
16361
16368
  try {
16362
16369
  this.peerConnection.removeTrack(sender);
16363
16370
  this.localStreamController.removeTrack(trackId);
16364
- logger$16.debug(`[RTCPeerConnectionController] ${sender.track?.kind} track removed:`, trackId);
16371
+ logger$17.debug(`[RTCPeerConnectionController] ${sender.track?.kind} track removed:`, trackId);
16365
16372
  } catch (error) {
16366
- logger$16.error(`[RTCPeerConnectionController] Failed to remove ${sender.track?.kind} track:`, error);
16373
+ logger$17.error(`[RTCPeerConnectionController] Failed to remove ${sender.track?.kind} track:`, error);
16367
16374
  this._errors$.next(toError(error));
16368
16375
  throw error;
16369
16376
  }
@@ -16390,7 +16397,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16390
16397
  async replaceAudioTrackWithConstraints(constraints) {
16391
16398
  const senders = this.peerConnection?.getSenders().filter((s) => s.track?.kind === "audio" && s.track.readyState === "live");
16392
16399
  if (!senders || senders.length === 0) {
16393
- logger$16.warn("[RTCPeerConnectionController] No live audio sender to replace");
16400
+ logger$17.warn("[RTCPeerConnectionController] No live audio sender to replace");
16394
16401
  return;
16395
16402
  }
16396
16403
  for (const sender of senders) {
@@ -16408,7 +16415,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16408
16415
  const newTrack = (await this.getUserMedia({ audio: mergedConstraints })).getAudioTracks()[0];
16409
16416
  await sender.replaceTrack(newTrack);
16410
16417
  this.localStreamController.addTrack(newTrack);
16411
- logger$16.debug(`[RTCPeerConnectionController] Audio track replaced for server-pushed params. New track: ${newTrack.id}`);
16418
+ logger$17.debug(`[RTCPeerConnectionController] Audio track replaced for server-pushed params. New track: ${newTrack.id}`);
16412
16419
  }
16413
16420
  }
16414
16421
  /**
@@ -16416,7 +16423,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16416
16423
  * Completes all observables to prevent memory leaks.
16417
16424
  */
16418
16425
  destroy() {
16419
- logger$16.debug(`[RTCPeerConnectionController] Destroying RTCPeerConnectionController. ${this.propose}`);
16426
+ logger$17.debug(`[RTCPeerConnectionController] Destroying RTCPeerConnectionController. ${this.propose}`);
16420
16427
  this.removeConnectionTimer();
16421
16428
  this._iceGatheringController?.destroy();
16422
16429
  this._localAudioPipeline?.destroy();
@@ -16442,7 +16449,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16442
16449
  }
16443
16450
  stopRemoteTracks() {
16444
16451
  this._remoteStream$.value?.getTracks().forEach((track) => {
16445
- logger$16.debug(`[RTCPeerConnectionController] Stopping remote track: ${track.kind}`);
16452
+ logger$17.debug(`[RTCPeerConnectionController] Stopping remote track: ${track.kind}`);
16446
16453
  track.stop();
16447
16454
  });
16448
16455
  }
@@ -16459,7 +16466,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16459
16466
  ...params,
16460
16467
  sdp: finalRemote
16461
16468
  };
16462
- logger$16.debug("[RTCPeerConnectionController] Setting remote description:", answer);
16469
+ logger$17.debug("[RTCPeerConnectionController] Setting remote description:", answer);
16463
16470
  return this.peerConnection.setRemoteDescription(answer);
16464
16471
  }
16465
16472
  };
@@ -16498,7 +16505,7 @@ function isVertoPingInnerParams(value) {
16498
16505
  //#endregion
16499
16506
  //#region src/managers/VertoManager.ts
16500
16507
  var import_cjs$15 = require_cjs();
16501
- const logger$15 = getLogger();
16508
+ const logger$16 = getLogger();
16502
16509
  /**
16503
16510
  * Decide what value goes on the `node_id` field of a `webrtc.verto` envelope.
16504
16511
  *
@@ -16554,7 +16561,7 @@ var WebRTCVertoManager = class extends VertoManager {
16554
16561
  try {
16555
16562
  await this.executeVerto(vertoModifyMessage);
16556
16563
  } catch (error) {
16557
- logger$15.warn("[WebRTCManager] Call might already be disconnected, error sending Verto hold:", error);
16564
+ logger$16.warn("[WebRTCManager] Call might already be disconnected, error sending Verto hold:", error);
16558
16565
  throw error;
16559
16566
  }
16560
16567
  }
@@ -16567,7 +16574,7 @@ var WebRTCVertoManager = class extends VertoManager {
16567
16574
  try {
16568
16575
  await this.executeVerto(vertoModifyMessage);
16569
16576
  } catch (error) {
16570
- logger$15.warn("[WebRTCManager] Call might already be disconnected, error sending Verto unhold:", error);
16577
+ logger$16.warn("[WebRTCManager] Call might already be disconnected, error sending Verto unhold:", error);
16571
16578
  throw error;
16572
16579
  }
16573
16580
  }
@@ -16620,7 +16627,7 @@ var WebRTCVertoManager = class extends VertoManager {
16620
16627
  if (event.member_id) this.setSelfIdIfNull(event.member_id);
16621
16628
  });
16622
16629
  this.subscribeTo(this.vertoMedia$, (event) => {
16623
- logger$15.debug("[WebRTCManager] Received Verto media event (early media SDP):", event);
16630
+ logger$16.debug("[WebRTCManager] Received Verto media event (early media SDP):", event);
16624
16631
  const { sdp, callID } = event;
16625
16632
  this.emitMainSignalingStatus(callID, "ringing");
16626
16633
  this._rtcPeerConnectionsMap.get(callID)?.updateAnswerStatus({
@@ -16629,7 +16636,7 @@ var WebRTCVertoManager = class extends VertoManager {
16629
16636
  });
16630
16637
  });
16631
16638
  this.subscribeTo(this.vertoAnswer$, (event) => {
16632
- logger$15.debug("[WebRTCManager] Received Verto answer event:", event);
16639
+ logger$16.debug("[WebRTCManager] Received Verto answer event:", event);
16633
16640
  const { sdp, callID } = event;
16634
16641
  this.emitMainSignalingStatus(callID, "connecting");
16635
16642
  this._rtcPeerConnectionsMap.get(callID)?.updateAnswerStatus({
@@ -16638,7 +16645,7 @@ var WebRTCVertoManager = class extends VertoManager {
16638
16645
  });
16639
16646
  });
16640
16647
  this.subscribeTo(this.vertoMediaParams$, (event) => {
16641
- logger$15.debug("[WebRTCManager] Received Verto mediaParams event:", event);
16648
+ logger$16.debug("[WebRTCManager] Received Verto mediaParams event:", event);
16642
16649
  const { mediaParams, callID } = event;
16643
16650
  const rtcPeerConnController = this._rtcPeerConnectionsMap.get(callID);
16644
16651
  const { audio, video } = mediaParams;
@@ -16652,7 +16659,7 @@ var WebRTCVertoManager = class extends VertoManager {
16652
16659
  timestamp: Date.now()
16653
16660
  });
16654
16661
  } catch (error) {
16655
- logger$15.warn("[WebRTCManager] Error applying server-pushed media params:", error);
16662
+ logger$16.warn("[WebRTCManager] Error applying server-pushed media params:", error);
16656
16663
  this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
16657
16664
  }
16658
16665
  })();
@@ -16674,13 +16681,13 @@ var WebRTCVertoManager = class extends VertoManager {
16674
16681
  */
16675
16682
  setNodeIdIfNull(nodeId) {
16676
16683
  if (!this._nodeId$.value && nodeId) {
16677
- logger$15.debug(`[WebRTCManager] Early node_id set: ${nodeId}`);
16684
+ logger$16.debug(`[WebRTCManager] Early node_id set: ${nodeId}`);
16678
16685
  this._nodeId$.next(nodeId);
16679
16686
  }
16680
16687
  }
16681
16688
  setSelfIdIfNull(selfId) {
16682
16689
  if (!this._selfId$.value && selfId) {
16683
- logger$15.debug(`[WebRTCManager] Early selfId set: ${selfId}`);
16690
+ logger$16.debug(`[WebRTCManager] Early selfId set: ${selfId}`);
16684
16691
  this._selfId$.next(selfId);
16685
16692
  }
16686
16693
  }
@@ -16689,7 +16696,7 @@ var WebRTCVertoManager = class extends VertoManager {
16689
16696
  const vertoPongMessage = VertoPong({ ...vertoPing });
16690
16697
  await this.executeVerto(vertoPongMessage);
16691
16698
  } catch (error) {
16692
- logger$15.warn("[WebRTCManager] Call might disconnect, error sending Verto pong:", error);
16699
+ logger$16.warn("[WebRTCManager] Call might disconnect, error sending Verto pong:", error);
16693
16700
  this.onError?.(new VertoPongError(error));
16694
16701
  }
16695
16702
  }
@@ -16699,7 +16706,7 @@ var WebRTCVertoManager = class extends VertoManager {
16699
16706
  if (audio) await this.mainPeerConnection.updateSendersConstraints("audio", audio);
16700
16707
  if (video) await this.mainPeerConnection.updateSendersConstraints("video", video);
16701
16708
  } catch (error) {
16702
- logger$15.warn("[WebRTCManager] Error updating media constraints:", error);
16709
+ logger$16.warn("[WebRTCManager] Error updating media constraints:", error);
16703
16710
  this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
16704
16711
  throw error;
16705
16712
  }
@@ -16729,20 +16736,20 @@ var WebRTCVertoManager = class extends VertoManager {
16729
16736
  try {
16730
16737
  const pc = this.mainPeerConnection.peerConnection;
16731
16738
  if (!pc) {
16732
- logger$15.warn("[WebRTCManager] No peer connection for keyframe request");
16739
+ logger$16.warn("[WebRTCManager] No peer connection for keyframe request");
16733
16740
  return;
16734
16741
  }
16735
16742
  const videoReceiver = pc.getReceivers().find((r) => r.track.kind === "video");
16736
16743
  if (!videoReceiver) {
16737
- logger$15.warn("[WebRTCManager] No video receiver for keyframe request");
16744
+ logger$16.warn("[WebRTCManager] No video receiver for keyframe request");
16738
16745
  return;
16739
16746
  }
16740
16747
  if (typeof videoReceiver.requestKeyFrame === "function") {
16741
16748
  videoReceiver.requestKeyFrame();
16742
- logger$15.debug("[WebRTCManager] Keyframe requested via RTCRtpReceiver.requestKeyFrame()");
16743
- } else logger$15.debug("[WebRTCManager] requestKeyFrame() not supported, skipping");
16749
+ logger$16.debug("[WebRTCManager] Keyframe requested via RTCRtpReceiver.requestKeyFrame()");
16750
+ } else logger$16.debug("[WebRTCManager] requestKeyFrame() not supported, skipping");
16744
16751
  } catch (error) {
16745
- logger$15.warn("[WebRTCManager] Keyframe request failed (non-fatal):", error);
16752
+ logger$16.warn("[WebRTCManager] Keyframe request failed (non-fatal):", error);
16746
16753
  }
16747
16754
  }
16748
16755
  /**
@@ -16760,13 +16767,13 @@ var WebRTCVertoManager = class extends VertoManager {
16760
16767
  try {
16761
16768
  const controller = this.mainPeerConnection;
16762
16769
  if (!controller.peerConnection) {
16763
- logger$15.warn("[WebRTCManager] No peer connection for ICE restart");
16770
+ logger$16.warn("[WebRTCManager] No peer connection for ICE restart");
16764
16771
  return;
16765
16772
  }
16766
16773
  await controller.triggerIceRestart(relayOnly);
16767
- logger$15.info(`[WebRTCManager] ICE restart initiated${relayOnly ? " (relay-only)" : ""}`);
16774
+ logger$16.info(`[WebRTCManager] ICE restart initiated${relayOnly ? " (relay-only)" : ""}`);
16768
16775
  } catch (error) {
16769
- logger$15.error("[WebRTCManager] ICE restart failed:", error);
16776
+ logger$16.error("[WebRTCManager] ICE restart failed:", error);
16770
16777
  throw error;
16771
16778
  }
16772
16779
  }
@@ -16784,13 +16791,13 @@ var WebRTCVertoManager = class extends VertoManager {
16784
16791
  const entries = Array.from(this._rtcPeerConnectionsMap.entries());
16785
16792
  for (const [id, controller] of entries) try {
16786
16793
  if (!controller.peerConnection) {
16787
- logger$15.debug(`[WebRTCManager] No peer connection for leg ${id}, skipping ICE restart`);
16794
+ logger$16.debug(`[WebRTCManager] No peer connection for leg ${id}, skipping ICE restart`);
16788
16795
  continue;
16789
16796
  }
16790
16797
  await controller.triggerIceRestart(relayOnly);
16791
- logger$15.info(`[WebRTCManager] ICE restart initiated for leg ${id}${relayOnly ? " (relay-only)" : ""}`);
16798
+ logger$16.info(`[WebRTCManager] ICE restart initiated for leg ${id}${relayOnly ? " (relay-only)" : ""}`);
16792
16799
  } catch (error) {
16793
- logger$15.warn(`[WebRTCManager] ICE restart failed for leg ${id}:`, error);
16800
+ logger$16.warn(`[WebRTCManager] ICE restart failed for leg ${id}:`, error);
16794
16801
  }
16795
16802
  }
16796
16803
  /**
@@ -16802,7 +16809,7 @@ var WebRTCVertoManager = class extends VertoManager {
16802
16809
  requestKeyframeAll() {
16803
16810
  for (const [id, controller] of this._rtcPeerConnectionsMap) {
16804
16811
  if (controller.isScreenShare) {
16805
- logger$15.debug(`[WebRTCManager] Skipping keyframe for send-only screen share leg ${id}`);
16812
+ logger$16.debug(`[WebRTCManager] Skipping keyframe for send-only screen share leg ${id}`);
16806
16813
  continue;
16807
16814
  }
16808
16815
  try {
@@ -16812,10 +16819,10 @@ var WebRTCVertoManager = class extends VertoManager {
16812
16819
  if (!videoReceiver) continue;
16813
16820
  if (typeof videoReceiver.requestKeyFrame === "function") {
16814
16821
  videoReceiver.requestKeyFrame();
16815
- logger$15.debug(`[WebRTCManager] Keyframe requested for leg ${id}`);
16822
+ logger$16.debug(`[WebRTCManager] Keyframe requested for leg ${id}`);
16816
16823
  }
16817
16824
  } catch (error) {
16818
- logger$15.warn(`[WebRTCManager] Keyframe request failed for leg ${id} (non-fatal):`, error);
16825
+ logger$16.warn(`[WebRTCManager] Keyframe request failed for leg ${id} (non-fatal):`, error);
16819
16826
  }
16820
16827
  }
16821
16828
  }
@@ -16876,7 +16883,7 @@ var WebRTCVertoManager = class extends VertoManager {
16876
16883
  default:
16877
16884
  }
16878
16885
  } catch (error) {
16879
- logger$15.error(`[WebRTCManager] Error sending Verto ${vertoMethod}:`, error);
16886
+ logger$16.error(`[WebRTCManager] Error sending Verto ${vertoMethod}:`, error);
16880
16887
  this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
16881
16888
  if (vertoMethod === "verto.modify") this.onModifyFailed?.();
16882
16889
  }
@@ -16891,7 +16898,7 @@ var WebRTCVertoManager = class extends VertoManager {
16891
16898
  sdp
16892
16899
  });
16893
16900
  } catch (error) {
16894
- logger$15.warn("[WebRTCManager] Error processing modify response:", error);
16901
+ logger$16.warn("[WebRTCManager] Error processing modify response:", error);
16895
16902
  const modifyError = error instanceof Error ? error : new Error(String(error), { cause: error });
16896
16903
  this.onError?.(modifyError);
16897
16904
  }
@@ -16901,7 +16908,7 @@ var WebRTCVertoManager = class extends VertoManager {
16901
16908
  const rtcPeerConnController = this._rtcPeerConnectionsMap.get(callId);
16902
16909
  if (!rtcPeerConnController) {
16903
16910
  const signalingError = new DependencyError(`Cannot emit signaling status, RTCPeerConnectionController not found for callID: ${callId}`);
16904
- logger$15.error("[WebRTCManager] Failed to emit signaling status:", {
16911
+ logger$16.error("[WebRTCManager] Failed to emit signaling status:", {
16905
16912
  callId,
16906
16913
  status,
16907
16914
  signalingError
@@ -16917,7 +16924,7 @@ var WebRTCVertoManager = class extends VertoManager {
16917
16924
  this._nodeId$.next(getValueFrom(response, "result.node_id") ?? null);
16918
16925
  const memberId = getValueFrom(response, "result.result.result.memberID") ?? null;
16919
16926
  const callId = getValueFrom(response, "result.result.result.callID") ?? null;
16920
- logger$15.debug("[WebRTCManager] Verto invite response:", {
16927
+ logger$16.debug("[WebRTCManager] Verto invite response:", {
16921
16928
  callId,
16922
16929
  memberId,
16923
16930
  response
@@ -16927,14 +16934,14 @@ var WebRTCVertoManager = class extends VertoManager {
16927
16934
  if (callId) {
16928
16935
  this.webRtcCallSession.addCallId(callId);
16929
16936
  this.attachManager.attach(this.buildAttachableCall(callId));
16930
- } else logger$15.warn("[WebRTCManager] Cannot attach call, missing callId:", {
16937
+ } else logger$16.warn("[WebRTCManager] Cannot attach call, missing callId:", {
16931
16938
  nodeId: this.nodeId,
16932
16939
  callId
16933
16940
  });
16934
- logger$15.info("[WebRTCManager] Verto invite successful");
16935
- logger$15.debug(`[WebRTCManager] nodeid: ${this._nodeId$.value}, selfId: ${this._selfId$.value}`);
16941
+ logger$16.info("[WebRTCManager] Verto invite successful");
16942
+ logger$16.debug(`[WebRTCManager] nodeid: ${this._nodeId$.value}, selfId: ${this._selfId$.value}`);
16936
16943
  } else {
16937
- logger$15.error("[WebRTCManager] Verto invite failed:", response);
16944
+ logger$16.error("[WebRTCManager] Verto invite failed:", response);
16938
16945
  const inviteError = response.error ? new JSONRPCError(response.error.code, response.error.message, response.error.data) : /* @__PURE__ */ new Error("Verto invite failed: unexpected response");
16939
16946
  this.onError?.(inviteError);
16940
16947
  }
@@ -16979,17 +16986,17 @@ var WebRTCVertoManager = class extends VertoManager {
16979
16986
  if (options.initOffer) this.handleInboundAnswer(rtcPeerConnController);
16980
16987
  }
16981
16988
  async handleInboundAnswer(rtcPeerConnController) {
16982
- logger$15.debug("[WebRTCManager] Waiting for inbound call to be accepted or rejected");
16989
+ logger$16.debug("[WebRTCManager] Waiting for inbound call to be accepted or rejected");
16983
16990
  const vertoByeOrAccepted = await (0, import_cjs$15.firstValueFrom)((0, import_cjs$15.race)(this.vertoBye$, this.webRtcCallSession.answered$).pipe((0, import_cjs$15.takeUntil)(this.destroyed$))).catch(() => null);
16984
16991
  if (vertoByeOrAccepted === null) {
16985
- logger$15.debug("[WebRTCManager] Inbound answer handler aborted (destroyed).");
16992
+ logger$16.debug("[WebRTCManager] Inbound answer handler aborted (destroyed).");
16986
16993
  return;
16987
16994
  }
16988
16995
  if (isVertoByeMessage(vertoByeOrAccepted)) {
16989
- logger$15.info("[WebRTCManager] Inbound call ended by remote before answer.");
16996
+ logger$16.info("[WebRTCManager] Inbound call ended by remote before answer.");
16990
16997
  this.callSession?.destroy();
16991
16998
  } else if (!vertoByeOrAccepted) {
16992
- logger$15.info("[WebRTCManager] Inbound call rejected by user.");
16999
+ logger$16.info("[WebRTCManager] Inbound call rejected by user.");
16993
17000
  try {
16994
17001
  await this.bye("USER_BUSY");
16995
17002
  } finally {
@@ -16997,19 +17004,19 @@ var WebRTCVertoManager = class extends VertoManager {
16997
17004
  this.callSession?.destroy();
16998
17005
  }
16999
17006
  } else {
17000
- logger$15.debug("[WebRTCManager] Inbound call accepted, creating SDP answer");
17007
+ logger$16.debug("[WebRTCManager] Inbound call accepted, creating SDP answer");
17001
17008
  const answerOptions = this.webRtcCallSession.answerMediaOptions;
17002
17009
  try {
17003
17010
  await rtcPeerConnController.acceptInbound(answerOptions);
17004
17011
  } catch (error) {
17005
- logger$15.error("[WebRTCManager] Error creating inbound answer:", error);
17012
+ logger$16.error("[WebRTCManager] Error creating inbound answer:", error);
17006
17013
  this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
17007
17014
  }
17008
17015
  }
17009
17016
  }
17010
17017
  setupVertoAttachHandler() {
17011
17018
  this.subscribeTo(this.vertoAttach$, async (vertoAttach) => {
17012
- logger$15.debug("[WebRTCManager] Received Verto attach event for existing call:", vertoAttach);
17019
+ logger$16.debug("[WebRTCManager] Received Verto attach event for existing call:", vertoAttach);
17013
17020
  const { callID } = vertoAttach;
17014
17021
  await this.attachManager.attach({
17015
17022
  nodeId: this.nodeId ?? void 0,
@@ -17081,17 +17088,17 @@ var WebRTCVertoManager = class extends VertoManager {
17081
17088
  };
17082
17089
  }
17083
17090
  async sendLocalDescriptionOnceAccepted(vertoMessageRequest, rtcPeerConnectionController) {
17084
- logger$15.debug("[WebRTCManager] Waiting for call to be accepted or ended before sending answer");
17091
+ logger$16.debug("[WebRTCManager] Waiting for call to be accepted or ended before sending answer");
17085
17092
  const vertoByeOrAccepted = await (0, import_cjs$15.firstValueFrom)((0, import_cjs$15.race)(this.vertoBye$, this.webRtcCallSession.answered$).pipe((0, import_cjs$15.takeUntil)(this.destroyed$))).catch(() => null);
17086
17093
  if (vertoByeOrAccepted === null) {
17087
- logger$15.debug("[WebRTCManager] Destroyed while waiting for call acceptance");
17094
+ logger$16.debug("[WebRTCManager] Destroyed while waiting for call acceptance");
17088
17095
  return;
17089
17096
  }
17090
17097
  if (isVertoByeMessage(vertoByeOrAccepted)) {
17091
- logger$15.info("[WebRTCManager] Call ended before answer was sent.");
17098
+ logger$16.info("[WebRTCManager] Call ended before answer was sent.");
17092
17099
  this.callSession?.destroy();
17093
17100
  } else if (!vertoByeOrAccepted) {
17094
- logger$15.info("[WebRTCManager] Call was not accepted, sending verto.bye.");
17101
+ logger$16.info("[WebRTCManager] Call was not accepted, sending verto.bye.");
17095
17102
  try {
17096
17103
  await this.bye("USER_BUSY");
17097
17104
  } finally {
@@ -17099,14 +17106,14 @@ var WebRTCVertoManager = class extends VertoManager {
17099
17106
  this.callSession?.destroy();
17100
17107
  }
17101
17108
  } else {
17102
- logger$15.debug("[WebRTCManager] Call accepted, sending answer");
17109
+ logger$16.debug("[WebRTCManager] Call accepted, sending answer");
17103
17110
  try {
17104
17111
  this.emitMainSignalingStatus(rtcPeerConnectionController.id, "connecting");
17105
17112
  await this.sendLocalDescription(vertoMessageRequest, rtcPeerConnectionController);
17106
17113
  await rtcPeerConnectionController.updateAnswerStatus({ status: "sent" });
17107
17114
  await this.attachManager.attach(this.buildAttachableCall());
17108
17115
  } catch (error) {
17109
- logger$15.error("[WebRTCManager] Error sending Verto answer:", error);
17116
+ logger$16.error("[WebRTCManager] Error sending Verto answer:", error);
17110
17117
  this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
17111
17118
  await rtcPeerConnectionController.updateAnswerStatus({ status: "failed" });
17112
17119
  }
@@ -17205,10 +17212,10 @@ var WebRTCVertoManager = class extends VertoManager {
17205
17212
  });
17206
17213
  await (0, import_cjs$15.firstValueFrom)(rtcPeerConnController.connectionState$.pipe((0, import_cjs$15.filter)((state) => state === "connected"), (0, import_cjs$15.take)(1), (0, import_cjs$15.timeout)(this._screenShareTimeoutMs), (0, import_cjs$15.takeUntil)(this.destroyed$)));
17207
17214
  this._screenShareStatus$.next("started");
17208
- logger$15.info("[WebRTCManager] Screen share started successfully.");
17215
+ logger$16.info("[WebRTCManager] Screen share started successfully.");
17209
17216
  return rtcPeerConnController.id;
17210
17217
  } catch (error) {
17211
- logger$15.warn("[WebRTCManager] Error initializing additional peer connection:", error);
17218
+ logger$16.warn("[WebRTCManager] Error initializing additional peer connection:", error);
17212
17219
  this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
17213
17220
  if (rtcPeerConnController) rtcPeerConnController.destroy();
17214
17221
  this._screenShareStatus$.next("none");
@@ -17227,9 +17234,9 @@ var WebRTCVertoManager = class extends VertoManager {
17227
17234
  if (removeTrack) return this.mainPeerConnection.stopTrackSender(removeTrack, { updateTransceiverDirection: true });
17228
17235
  }
17229
17236
  async removeScreenMedia() {
17230
- if (!["starting", "started"].includes(this._screenShareStatus$.value)) logger$15.warn("[WebRTCManager] No active screen share to stop.");
17237
+ if (!["starting", "started"].includes(this._screenShareStatus$.value)) logger$16.warn("[WebRTCManager] No active screen share to stop.");
17231
17238
  if (!this._screenShareId) {
17232
- logger$15.debug("[WebRTCManager] No screen share peer connection found.");
17239
+ logger$16.debug("[WebRTCManager] No screen share peer connection found.");
17233
17240
  return;
17234
17241
  }
17235
17242
  this._screenShareStatus$.next("stopping");
@@ -17258,7 +17265,7 @@ var WebRTCVertoManager = class extends VertoManager {
17258
17265
  dialogParams: this.dialogParams(rtcPeerConnController)
17259
17266
  }));
17260
17267
  } catch (error) {
17261
- logger$15.warn("[WebRTCManager] Call might already be disconnected, error sending Verto bye:", error);
17268
+ logger$16.warn("[WebRTCManager] Call might already be disconnected, error sending Verto bye:", error);
17262
17269
  throw error;
17263
17270
  }
17264
17271
  }
@@ -17276,7 +17283,7 @@ var WebRTCVertoManager = class extends VertoManager {
17276
17283
  try {
17277
17284
  await this.executeVerto(vertoInfoMessage);
17278
17285
  } catch (error) {
17279
- logger$15.warn("[WebRTCManager] Error sending DTMF digits:", error);
17286
+ logger$16.warn("[WebRTCManager] Error sending DTMF digits:", error);
17280
17287
  throw error;
17281
17288
  }
17282
17289
  }
@@ -17287,10 +17294,10 @@ var WebRTCVertoManager = class extends VertoManager {
17287
17294
  action: "transfer"
17288
17295
  });
17289
17296
  try {
17290
- logger$15.debug("[WebRTCManager] Transferring call with options:", options);
17297
+ logger$16.debug("[WebRTCManager] Transferring call with options:", options);
17291
17298
  await this.executeVerto(message);
17292
17299
  } catch (error) {
17293
- logger$15.error("[WebRTCManager] Error transferring call:", error);
17300
+ logger$16.error("[WebRTCManager] Error transferring call:", error);
17294
17301
  throw error;
17295
17302
  }
17296
17303
  }
@@ -17307,7 +17314,7 @@ var WebRTCVertoManager = class extends VertoManager {
17307
17314
  //#endregion
17308
17315
  //#region src/controllers/RemoteAudioMeter.ts
17309
17316
  var import_cjs$14 = require_cjs();
17310
- const logger$14 = getLogger();
17317
+ const logger$15 = getLogger();
17311
17318
  /**
17312
17319
  * Read-only audio level meter for a remote MediaStream. Attaches an
17313
17320
  * AnalyserNode to a MediaStreamAudioSourceNode so it observes the stream
@@ -17342,7 +17349,7 @@ var RemoteAudioMeter = class extends Destroyable {
17342
17349
  try {
17343
17350
  this._source.disconnect();
17344
17351
  } catch (error) {
17345
- logger$14.debug("[RemoteAudioMeter] source disconnect warning:", error);
17352
+ logger$15.debug("[RemoteAudioMeter] source disconnect warning:", error);
17346
17353
  }
17347
17354
  this._source = null;
17348
17355
  this._stream = null;
@@ -17359,7 +17366,7 @@ var RemoteAudioMeter = class extends Destroyable {
17359
17366
  this._source = null;
17360
17367
  }
17361
17368
  this._audioContext.close().catch((error) => {
17362
- logger$14.debug("[RemoteAudioMeter] audio context close warning:", error);
17369
+ logger$15.debug("[RemoteAudioMeter] audio context close warning:", error);
17363
17370
  });
17364
17371
  super.destroy();
17365
17372
  }
@@ -17378,7 +17385,7 @@ var RemoteAudioMeter = class extends Destroyable {
17378
17385
  //#endregion
17379
17386
  //#region src/controllers/RTCStatsMonitor.ts
17380
17387
  var import_cjs$13 = require_cjs();
17381
- const logger$13 = getLogger();
17388
+ const logger$14 = getLogger();
17382
17389
  const DEFAULT_POLLING_INTERVAL_MS = 1e3;
17383
17390
  const DEFAULT_BASELINE_SAMPLES = 10;
17384
17391
  const DEFAULT_NO_AUDIO_PACKET_THRESHOLD_MS = 2e3;
@@ -17468,9 +17475,9 @@ var RTCStatsMonitor = class extends Destroyable {
17468
17475
  const now = Date.now();
17469
17476
  this.lastAudioPacketChangeTime = now;
17470
17477
  this.lastVideoPacketChangeTime = now;
17471
- logger$13.debug("[RTCStatsMonitor] Starting stats monitoring");
17478
+ logger$14.debug("[RTCStatsMonitor] Starting stats monitoring");
17472
17479
  this.subscribeTo((0, import_cjs$13.interval)(this.pollingIntervalMs).pipe((0, import_cjs$13.filter)(() => this.running), (0, import_cjs$13.switchMap)(() => (0, import_cjs$13.from)(this.peerConnection.getStats()).pipe((0, import_cjs$13.catchError)((err) => {
17473
- logger$13.warn("[RTCStatsMonitor] Failed to get stats:", err);
17480
+ logger$14.warn("[RTCStatsMonitor] Failed to get stats:", err);
17474
17481
  return import_cjs$13.EMPTY;
17475
17482
  }))), (0, import_cjs$13.filter)(() => this.running), (0, import_cjs$13.map)((report) => this.extractSample(report))), (sample$1) => this._sample$.next(sample$1));
17476
17483
  this.subscribeTo(this._sample$.pipe((0, import_cjs$13.take)(this.baselineSampleCount), (0, import_cjs$13.toArray)(), (0, import_cjs$13.map)((samples) => ({
@@ -17478,7 +17485,7 @@ var RTCStatsMonitor = class extends Destroyable {
17478
17485
  jitter: samples.reduce((s, b) => s + b.audioJitter, 0) / samples.length,
17479
17486
  ready: true
17480
17487
  }))), (baseline) => {
17481
- logger$13.debug(`[RTCStatsMonitor] Baseline established: rtt=${baseline.rtt.toFixed(1)}ms, jitter=${baseline.jitter.toFixed(1)}ms`);
17488
+ logger$14.debug(`[RTCStatsMonitor] Baseline established: rtt=${baseline.rtt.toFixed(1)}ms, jitter=${baseline.jitter.toFixed(1)}ms`);
17482
17489
  this._baseline$.next(baseline);
17483
17490
  });
17484
17491
  this.subscribeTo(this._sample$.pipe((0, import_cjs$13.scan)((acc, sample$1) => ({
@@ -17515,10 +17522,10 @@ var RTCStatsMonitor = class extends Destroyable {
17515
17522
  stop() {
17516
17523
  if (!this.running) return;
17517
17524
  this.running = false;
17518
- logger$13.debug("[RTCStatsMonitor] Stopping stats monitoring");
17525
+ logger$14.debug("[RTCStatsMonitor] Stopping stats monitoring");
17519
17526
  }
17520
17527
  destroy() {
17521
- logger$13.debug("[RTCStatsMonitor] Destroying RTCStatsMonitor");
17528
+ logger$14.debug("[RTCStatsMonitor] Destroying RTCStatsMonitor");
17522
17529
  this.stop();
17523
17530
  super.destroy();
17524
17531
  }
@@ -17647,7 +17654,7 @@ var RTCStatsMonitor = class extends Destroyable {
17647
17654
  //#endregion
17648
17655
  //#region src/managers/CallRecoveryManager.ts
17649
17656
  var import_cjs$12 = require_cjs();
17650
- const logger$12 = getLogger();
17657
+ const logger$13 = getLogger();
17651
17658
  const DEFAULT_DEBOUNCE_TIME_MS = 2e3;
17652
17659
  const DEFAULT_COOLDOWN_MS = 1e4;
17653
17660
  const DEFAULT_ICE_GRACE_PERIOD_MS = 3e3;
@@ -17744,10 +17751,10 @@ var CallRecoveryManager = class extends Destroyable {
17744
17751
  */
17745
17752
  async requestIceRestart() {
17746
17753
  if (this._recoveryState$.value === "recovering") {
17747
- logger$12.info("CallRecoveryManager: manual ICE restart skipped — recovery already in progress");
17754
+ logger$13.info("CallRecoveryManager: manual ICE restart skipped — recovery already in progress");
17748
17755
  return;
17749
17756
  }
17750
- logger$12.info("CallRecoveryManager: manual ICE restart requested");
17757
+ logger$13.info("CallRecoveryManager: manual ICE restart requested");
17751
17758
  this.transitionTo("recovering");
17752
17759
  await this.executeIceRestart(false);
17753
17760
  this.startCooldown();
@@ -17763,7 +17770,7 @@ var CallRecoveryManager = class extends Destroyable {
17763
17770
  * WebSocket reconnect or call state recovers to 'connected'.
17764
17771
  */
17765
17772
  reset() {
17766
- logger$12.info("CallRecoveryManager: resetting counters");
17773
+ logger$13.info("CallRecoveryManager: resetting counters");
17767
17774
  this._attemptCount = 0;
17768
17775
  this._keyframeBurstCount = 0;
17769
17776
  this._keyframeBurstStart = 0;
@@ -17778,7 +17785,7 @@ var CallRecoveryManager = class extends Destroyable {
17778
17785
  */
17779
17786
  notifyModifyFailed() {
17780
17787
  if (this._recoveryState$.value === "cooldown" || this._recoveryState$.value === "idle") {
17781
- logger$12.info("CallRecoveryManager: verto.modify failed — re-entering recovery");
17788
+ logger$13.info("CallRecoveryManager: verto.modify failed — re-entering recovery");
17782
17789
  this._cooldownUntil = 0;
17783
17790
  this.transitionTo("idle");
17784
17791
  this.pushTrigger({
@@ -17802,7 +17809,7 @@ var CallRecoveryManager = class extends Destroyable {
17802
17809
  reason: `bandwidth ${bitrateKbps}kbps below threshold ${this._config.degradationBitrateThreshold}kbps`,
17803
17810
  timestamp: Date.now()
17804
17811
  });
17805
- logger$12.warn(`CallRecoveryManager: disabling video — bandwidth ${bitrateKbps}kbps < ${this._config.degradationBitrateThreshold}kbps`);
17812
+ logger$13.warn(`CallRecoveryManager: disabling video — bandwidth ${bitrateKbps}kbps < ${this._config.degradationBitrateThreshold}kbps`);
17806
17813
  } else if (wasConstrained && bitrateKbps >= this._config.degradationRecoveryThreshold) {
17807
17814
  this._bandwidthConstrained$.next(false);
17808
17815
  this._callbacks.enableVideo();
@@ -17811,7 +17818,7 @@ var CallRecoveryManager = class extends Destroyable {
17811
17818
  reason: `bandwidth ${bitrateKbps}kbps recovered above ${this._config.degradationRecoveryThreshold}kbps`,
17812
17819
  timestamp: Date.now()
17813
17820
  });
17814
- logger$12.info(`CallRecoveryManager: restoring video — bandwidth ${bitrateKbps}kbps >= ${this._config.degradationRecoveryThreshold}kbps`);
17821
+ logger$13.info(`CallRecoveryManager: restoring video — bandwidth ${bitrateKbps}kbps >= ${this._config.degradationRecoveryThreshold}kbps`);
17815
17822
  }
17816
17823
  }
17817
17824
  /**
@@ -17830,14 +17837,14 @@ var CallRecoveryManager = class extends Destroyable {
17830
17837
  handleWebSocketReconnect() {
17831
17838
  const pcState = this._callbacks.getPeerConnectionState();
17832
17839
  if (pcState === "connected" || pcState === "completed") {
17833
- logger$12.info("CallRecoveryManager: signal-only reconnect — peer connection still alive");
17840
+ logger$13.info("CallRecoveryManager: signal-only reconnect — peer connection still alive");
17834
17841
  this.emitEvent({
17835
17842
  action: "signal_reconnect",
17836
17843
  reason: "WebSocket reconnected, peer connection still connected",
17837
17844
  timestamp: Date.now()
17838
17845
  });
17839
17846
  } else {
17840
- logger$12.info("CallRecoveryManager: full reconnect — peer connection also down");
17847
+ logger$13.info("CallRecoveryManager: full reconnect — peer connection also down");
17841
17848
  this.emitEvent({
17842
17849
  action: "full_reconnect",
17843
17850
  reason: "WebSocket reconnected, peer connection not connected — ICE restart needed",
@@ -17861,7 +17868,7 @@ var CallRecoveryManager = class extends Destroyable {
17861
17868
  }), (0, import_cjs$12.debounceTime)(this._config.debounceTimeMs), (0, import_cjs$12.withLatestFrom)(this._inputs.signalingReady$), (0, import_cjs$12.filter)(([, signalingReady]) => this.passGateChecks(signalingReady)), (0, import_cjs$12.map)(([trigger]) => trigger), (0, import_cjs$12.exhaustMap)((trigger) => this.executeTieredRecovery(trigger)), (0, import_cjs$12.takeUntil)((0, import_cjs$12.merge)(this._destroyed$, this._pipelineStop$))), {
17862
17869
  next: () => {},
17863
17870
  error: (err) => {
17864
- logger$12.error("CallRecoveryManager: pipeline error", err);
17871
+ logger$13.error("CallRecoveryManager: pipeline error", err);
17865
17872
  this.transitionTo("idle");
17866
17873
  }
17867
17874
  });
@@ -17888,27 +17895,27 @@ var CallRecoveryManager = class extends Destroyable {
17888
17895
  reason: `no packet loss for ${this._config.packetLossRecoveryDelaySec}s — restoring video`,
17889
17896
  timestamp: Date.now()
17890
17897
  });
17891
- logger$12.info(`CallRecoveryManager: restoring video — no packet loss for ${this._config.packetLossRecoveryDelaySec}s`);
17898
+ logger$13.info(`CallRecoveryManager: restoring video — no packet loss for ${this._config.packetLossRecoveryDelaySec}s`);
17892
17899
  });
17893
17900
  }
17894
17901
  passGateChecks(signalingReady) {
17895
17902
  if (this._callbacks.isNegotiating()) {
17896
- logger$12.debug("CallRecoveryManager: gate blocked — negotiation in progress");
17903
+ logger$13.debug("CallRecoveryManager: gate blocked — negotiation in progress");
17897
17904
  this.transitionTo("idle");
17898
17905
  return false;
17899
17906
  }
17900
17907
  if (!signalingReady) {
17901
- logger$12.debug("CallRecoveryManager: gate blocked — signaling not ready");
17908
+ logger$13.debug("CallRecoveryManager: gate blocked — signaling not ready");
17902
17909
  this.transitionTo("idle");
17903
17910
  return false;
17904
17911
  }
17905
17912
  if (!this._callbacks.isCallConnected()) {
17906
- logger$12.debug("CallRecoveryManager: gate blocked — call not connected");
17913
+ logger$13.debug("CallRecoveryManager: gate blocked — call not connected");
17907
17914
  this.transitionTo("idle");
17908
17915
  return false;
17909
17916
  }
17910
17917
  if (this.isCooldownActive()) {
17911
- logger$12.debug("CallRecoveryManager: gate blocked — cooldown active");
17918
+ logger$13.debug("CallRecoveryManager: gate blocked — cooldown active");
17912
17919
  this.transitionTo("cooldown");
17913
17920
  return false;
17914
17921
  }
@@ -17919,9 +17926,9 @@ var CallRecoveryManager = class extends Destroyable {
17919
17926
  }
17920
17927
  executeTieredRecovery(trigger) {
17921
17928
  this.transitionTo("recovering");
17922
- logger$12.info(`CallRecoveryManager: starting tiered recovery — source=${trigger.source} detail=${trigger.detail}`);
17929
+ logger$13.info(`CallRecoveryManager: starting tiered recovery — source=${trigger.source} detail=${trigger.detail}`);
17923
17930
  return (0, import_cjs$12.from)(this.runTiers(trigger)).pipe((0, import_cjs$12.tap)(() => this.startCooldown()), (0, import_cjs$12.catchError)((err) => {
17924
- logger$12.error("CallRecoveryManager: tiered recovery failed", err);
17931
+ logger$13.error("CallRecoveryManager: tiered recovery failed", err);
17925
17932
  this.startCooldown();
17926
17933
  return import_cjs$12.EMPTY;
17927
17934
  }));
@@ -17929,7 +17936,7 @@ var CallRecoveryManager = class extends Destroyable {
17929
17936
  async runTiers(trigger) {
17930
17937
  this.executeKeyframe(trigger.detail);
17931
17938
  if (trigger.issueType && DEGRADATION_ONLY_ISSUES.has(trigger.issueType)) {
17932
- logger$12.debug(`CallRecoveryManager: degradation-only issue (${trigger.issueType}) — Tier 1 only, skipping ICE restart`);
17939
+ logger$13.debug(`CallRecoveryManager: degradation-only issue (${trigger.issueType}) — Tier 1 only, skipping ICE restart`);
17933
17940
  return;
17934
17941
  }
17935
17942
  if (this._attemptCount < this._config.maxAttempts) {
@@ -17946,13 +17953,13 @@ var CallRecoveryManager = class extends Destroyable {
17946
17953
  maxAttempts: this._config.maxAttempts,
17947
17954
  timestamp: Date.now()
17948
17955
  });
17949
- logger$12.warn("CallRecoveryManager: max recovery attempts reached");
17956
+ logger$13.warn("CallRecoveryManager: max recovery attempts reached");
17950
17957
  }
17951
17958
  }
17952
17959
  executeKeyframe(reason) {
17953
17960
  const now = Date.now();
17954
17961
  if (now < this._keyframeCooldownUntil) {
17955
- logger$12.debug("CallRecoveryManager: keyframe request skipped — cooldown active");
17962
+ logger$13.debug("CallRecoveryManager: keyframe request skipped — cooldown active");
17956
17963
  return;
17957
17964
  }
17958
17965
  if (now - this._keyframeBurstStart > this._config.keyframeBurstWindowMs) {
@@ -17961,7 +17968,7 @@ var CallRecoveryManager = class extends Destroyable {
17961
17968
  }
17962
17969
  if (this._keyframeBurstCount >= this._config.keyframeMaxBurst) {
17963
17970
  this._keyframeCooldownUntil = now + this._config.keyframeCooldownMs;
17964
- logger$12.debug(`CallRecoveryManager: keyframe burst limit reached (${this._config.keyframeMaxBurst}), cooldown until ${this._keyframeCooldownUntil}`);
17971
+ logger$13.debug(`CallRecoveryManager: keyframe burst limit reached (${this._config.keyframeMaxBurst}), cooldown until ${this._keyframeCooldownUntil}`);
17965
17972
  return;
17966
17973
  }
17967
17974
  this._keyframeBurstCount += 1;
@@ -17971,12 +17978,12 @@ var CallRecoveryManager = class extends Destroyable {
17971
17978
  reason,
17972
17979
  timestamp: now
17973
17980
  });
17974
- logger$12.debug(`CallRecoveryManager: keyframe requested (burst ${this._keyframeBurstCount}/${this._config.keyframeMaxBurst})`);
17981
+ logger$13.debug(`CallRecoveryManager: keyframe requested (burst ${this._keyframeBurstCount}/${this._config.keyframeMaxBurst})`);
17975
17982
  }
17976
17983
  async executeIceRestart(relayOnly) {
17977
17984
  this._attemptCount += 1;
17978
17985
  const tier = relayOnly ? "Tier 3 (relay-only)" : "Tier 2 (standard)";
17979
- logger$12.info(`CallRecoveryManager: ${tier} ICE restart — attempt ${this._attemptCount}/${this._config.maxAttempts}`);
17986
+ logger$13.info(`CallRecoveryManager: ${tier} ICE restart — attempt ${this._attemptCount}/${this._config.maxAttempts}`);
17980
17987
  this.emitEvent({
17981
17988
  action: "reinvite_started",
17982
17989
  reason: `${tier} ICE restart`,
@@ -17993,7 +18000,7 @@ var CallRecoveryManager = class extends Destroyable {
17993
18000
  maxAttempts: this._config.maxAttempts,
17994
18001
  timestamp: Date.now()
17995
18002
  });
17996
- logger$12.info(`CallRecoveryManager: ${tier} ICE restart succeeded`);
18003
+ logger$13.info(`CallRecoveryManager: ${tier} ICE restart succeeded`);
17997
18004
  this._attemptCount = 0;
17998
18005
  return true;
17999
18006
  }
@@ -18004,7 +18011,7 @@ var CallRecoveryManager = class extends Destroyable {
18004
18011
  maxAttempts: this._config.maxAttempts,
18005
18012
  timestamp: Date.now()
18006
18013
  });
18007
- logger$12.warn(`CallRecoveryManager: ${tier} ICE restart failed`);
18014
+ logger$13.warn(`CallRecoveryManager: ${tier} ICE restart failed`);
18008
18015
  return false;
18009
18016
  } catch {
18010
18017
  this.emitEvent({
@@ -18014,7 +18021,7 @@ var CallRecoveryManager = class extends Destroyable {
18014
18021
  maxAttempts: this._config.maxAttempts,
18015
18022
  timestamp: Date.now()
18016
18023
  });
18017
- logger$12.warn(`CallRecoveryManager: ${tier} ICE restart timed out`);
18024
+ logger$13.warn(`CallRecoveryManager: ${tier} ICE restart timed out`);
18018
18025
  return false;
18019
18026
  }
18020
18027
  }
@@ -18035,7 +18042,7 @@ var CallRecoveryManager = class extends Destroyable {
18035
18042
  transitionTo(state) {
18036
18043
  const prev = this._recoveryState$.value;
18037
18044
  if (prev !== state) {
18038
- logger$12.debug(`CallRecoveryManager: state ${prev} -> ${state}`);
18045
+ logger$13.debug(`CallRecoveryManager: state ${prev} -> ${state}`);
18039
18046
  this._recoveryState$.next(state);
18040
18047
  }
18041
18048
  }
@@ -18138,7 +18145,7 @@ function mosToQualityLevel(mos) {
18138
18145
  //#endregion
18139
18146
  //#region src/core/entities/Call.ts
18140
18147
  var import_cjs$11 = require_cjs();
18141
- const logger$11 = getLogger();
18148
+ const logger$12 = getLogger();
18142
18149
  /**
18143
18150
  * Ratio between the critical and warning RTT spike multipliers.
18144
18151
  * Warning threshold = baseline * warningMultiplier (default 3x)
@@ -18156,7 +18163,7 @@ const fromDestinationParams = (destination) => {
18156
18163
  });
18157
18164
  return params;
18158
18165
  } catch (error) {
18159
- logger$11.warn(`Failed to parse destination URI: ${destination}`, error);
18166
+ logger$12.warn(`Failed to parse destination URI: ${destination}`, error);
18160
18167
  return {};
18161
18168
  }
18162
18169
  };
@@ -18356,7 +18363,7 @@ var WebRTCCall = class extends Destroyable {
18356
18363
  if (isJSONRPCErrorResponse(response)) throw new JSONRPCError(parseInt(response.result?.code ?? "0"), `Error response from method ${method}: ${response.result?.code} ${response.result?.message}`, void 0, void 0, request.id);
18357
18364
  return response;
18358
18365
  } catch (error) {
18359
- logger$11.error(`[Call] Error executing method ${method} with params`, params, error);
18366
+ logger$12.error(`[Call] Error executing method ${method} with params`, params, error);
18360
18367
  throw error;
18361
18368
  }
18362
18369
  }
@@ -18559,9 +18566,9 @@ var WebRTCCall = class extends Destroyable {
18559
18566
  */
18560
18567
  initResilienceSubsystems() {
18561
18568
  const pc = this.rtcPeerConnection;
18562
- logger$11.debug(`[Call] initResilienceSubsystems: pc=${pc ? "exists" : "undefined"}, connectionState=${pc?.connectionState}`);
18569
+ logger$12.debug(`[Call] initResilienceSubsystems: pc=${pc ? "exists" : "undefined"}, connectionState=${pc?.connectionState}`);
18563
18570
  if (!pc) {
18564
- logger$11.warn("[Call] No peer connection available, skipping resilience init");
18571
+ logger$12.warn("[Call] No peer connection available, skipping resilience init");
18565
18572
  return;
18566
18573
  }
18567
18574
  try {
@@ -18596,14 +18603,14 @@ var WebRTCCall = class extends Destroyable {
18596
18603
  disableVideo: () => {
18597
18604
  try {
18598
18605
  this.vertoManager.muteMainVideoInputDevice();
18599
- logger$11.debug("[Call] Recovery manager disabled video");
18606
+ logger$12.debug("[Call] Recovery manager disabled video");
18600
18607
  } catch {
18601
- logger$11.debug("[Call] Recovery manager failed to disable video");
18608
+ logger$12.debug("[Call] Recovery manager failed to disable video");
18602
18609
  }
18603
18610
  },
18604
18611
  enableVideo: () => {
18605
18612
  this.vertoManager.unmuteMainVideoInputDevice().catch(() => {
18606
- logger$11.debug("[Call] Recovery manager failed to enable video");
18613
+ logger$12.debug("[Call] Recovery manager failed to enable video");
18607
18614
  });
18608
18615
  },
18609
18616
  isNegotiating: () => this.vertoManager.mainPeerConnection.isNegotiating,
@@ -18653,7 +18660,7 @@ var WebRTCCall = class extends Destroyable {
18653
18660
  this.subscribeTo(this._recoveryManager.recoveryEvent$, (event) => {
18654
18661
  this._recoveryEvent$.next(event);
18655
18662
  if (event.action === "max_attempts_reached") {
18656
- logger$11.warn("[Call] All recovery attempts exhausted, terminating call");
18663
+ logger$12.warn("[Call] All recovery attempts exhausted, terminating call");
18657
18664
  this.emitError({
18658
18665
  kind: "network",
18659
18666
  fatal: true,
@@ -18673,13 +18680,13 @@ var WebRTCCall = class extends Destroyable {
18673
18680
  else if (event.type === "online") this._recoveryManager?.handleWebSocketReconnect();
18674
18681
  });
18675
18682
  this.subscribeTo(this.clientSession.authenticated$.pipe((0, import_cjs$11.skip)(1), (0, import_cjs$11.filter)(Boolean)), () => {
18676
- logger$11.debug("[Call] WebSocket reconnected — notifying recovery manager");
18683
+ logger$12.debug("[Call] WebSocket reconnected — notifying recovery manager");
18677
18684
  this._recoveryManager?.handleWebSocketReconnect();
18678
18685
  });
18679
18686
  this._statsMonitor.start();
18680
- logger$11.debug("[Call] Resilience subsystems initialized for call", this.id);
18687
+ logger$12.debug("[Call] Resilience subsystems initialized for call", this.id);
18681
18688
  } catch (error) {
18682
- logger$11.warn("[Call] Failed to initialize resilience subsystems:", error);
18689
+ logger$12.warn("[Call] Failed to initialize resilience subsystems:", error);
18683
18690
  }
18684
18691
  }
18685
18692
  /**
@@ -18762,19 +18769,19 @@ var WebRTCCall = class extends Destroyable {
18762
18769
  }
18763
18770
  isCallSessionEvent(event) {
18764
18771
  try {
18765
- logger$11.debug("[Call] Checking if event is for this call session:", event);
18772
+ logger$12.debug("[Call] Checking if event is for this call session:", event);
18766
18773
  const callId = getValueFrom(event, "params.params.callID") ?? getValueFrom(event, "params.call_id");
18767
18774
  const roomSessionId = getValueFrom(event, "params.room_session_id");
18768
- logger$11.debug(`[Call] Extracted session identifiers callID: ${callId} and roomSessionID: ${roomSessionId} from event:`);
18775
+ logger$12.debug(`[Call] Extracted session identifiers callID: ${callId} and roomSessionID: ${roomSessionId} from event:`);
18769
18776
  return callId === this.id || !!callId && this.callEventsManager.isCallIdValid(callId) || !!roomSessionId && this.callEventsManager.isRoomSessionIdValid(roomSessionId);
18770
18777
  } catch (error) {
18771
- logger$11.error("[Call] Error checking if event is for this call session:", error);
18778
+ logger$12.error("[Call] Error checking if event is for this call session:", error);
18772
18779
  return false;
18773
18780
  }
18774
18781
  }
18775
18782
  get callSessionEvents$() {
18776
18783
  return this.cachedObservable("callSessionEvents$", () => this.clientSession.signalingEvent$.pipe((0, import_cjs$11.filter)((event) => this.isCallSessionEvent(event)), (0, import_cjs$11.tap)((event) => {
18777
- logger$11.debug("[Call] Received call session event:", event);
18784
+ logger$12.debug("[Call] Received call session event:", event);
18778
18785
  }), (0, import_cjs$11.takeUntil)(this.destroyed$), (0, import_cjs$11.share)()));
18779
18786
  }
18780
18787
  /** Observable of call-updated events. */
@@ -18844,16 +18851,16 @@ var WebRTCCall = class extends Destroyable {
18844
18851
  this._customSubscriptions.set(eventType, filtered$);
18845
18852
  }, (error) => {
18846
18853
  this._customSubscriptions.delete(eventType);
18847
- logger$11.warn(`[Call] verto.subscribe for '${eventType}' failed, not caching:`, error);
18854
+ logger$12.warn(`[Call] verto.subscribe for '${eventType}' failed, not caching:`, error);
18848
18855
  });
18849
18856
  this._customSubscriptions.set(eventType, filtered$);
18850
18857
  return filtered$;
18851
18858
  }
18852
18859
  get webrtcMessages$() {
18853
- return this.cachedObservable("webrtcMessages$", () => this.callSessionEvents$.pipe(filterAs(isWebrtcMessageMetadata, "params"), (0, import_cjs$11.tap)((event) => logger$11.debug("[Call] Event is a WebRTC message event:", event)), (0, import_cjs$11.takeUntil)(this.destroyed$), (0, import_cjs$11.share)()));
18860
+ return this.cachedObservable("webrtcMessages$", () => this.callSessionEvents$.pipe(filterAs(isWebrtcMessageMetadata, "params"), (0, import_cjs$11.tap)((event) => logger$12.debug("[Call] Event is a WebRTC message event:", event)), (0, import_cjs$11.takeUntil)(this.destroyed$), (0, import_cjs$11.share)()));
18854
18861
  }
18855
18862
  get callEvent$() {
18856
- return this.cachedObservable("callEvent$", () => this.callSessionEvents$.pipe(filterAs(isSignalwireCallMetadata, "params"), (0, import_cjs$11.tap)((event) => logger$11.debug("[Call] Event is a call event:", event)), (0, import_cjs$11.takeUntil)(this.destroyed$), (0, import_cjs$11.share)()));
18863
+ return this.cachedObservable("callEvent$", () => this.callSessionEvents$.pipe(filterAs(isSignalwireCallMetadata, "params"), (0, import_cjs$11.tap)((event) => logger$12.debug("[Call] Event is a call event:", event)), (0, import_cjs$11.takeUntil)(this.destroyed$), (0, import_cjs$11.share)()));
18857
18864
  }
18858
18865
  get layoutEvent$() {
18859
18866
  return this.cachedObservable("layoutEvent$", () => this.callEvent$.pipe(filterAs(isLayoutChangedMetadata, "params")));
@@ -18982,7 +18989,7 @@ var WebRTCCall = class extends Destroyable {
18982
18989
  setLocalMicrophoneGain(value) {
18983
18990
  const pipeline = this.vertoManager.ensureLocalAudioPipeline();
18984
18991
  if (!pipeline) {
18985
- logger$11.warn("[Call] setLocalMicrophoneGain: audio pipeline unavailable");
18992
+ logger$12.warn("[Call] setLocalMicrophoneGain: audio pipeline unavailable");
18986
18993
  return;
18987
18994
  }
18988
18995
  const percent = Math.max(0, Math.min(200, value));
@@ -19027,7 +19034,7 @@ var WebRTCCall = class extends Destroyable {
19027
19034
  enablePushToTalk() {
19028
19035
  const pipeline = this.vertoManager.ensureLocalAudioPipeline();
19029
19036
  if (!pipeline) {
19030
- logger$11.warn("[Call] enablePushToTalk: audio pipeline unavailable");
19037
+ logger$12.warn("[Call] enablePushToTalk: audio pipeline unavailable");
19031
19038
  return;
19032
19039
  }
19033
19040
  pipeline.setPTTActive(false);
@@ -19190,7 +19197,7 @@ var CallFactory = class {
19190
19197
  //#endregion
19191
19198
  //#region src/behaviors/Collection.ts
19192
19199
  var import_cjs$10 = require_cjs();
19193
- const logger$10 = getLogger();
19200
+ const logger$11 = getLogger();
19194
19201
  var Fetcher = class {
19195
19202
  constructor(endpoint, params, http) {
19196
19203
  this.endpoint = endpoint;
@@ -19214,7 +19221,7 @@ var Fetcher = class {
19214
19221
  this.hasMore = !!this.nextUrl;
19215
19222
  return result.data.filter(this.filter).map(this.mapper);
19216
19223
  }
19217
- logger$10.error("Failed to fetch entity");
19224
+ logger$11.error("Failed to fetch entity");
19218
19225
  return [];
19219
19226
  }
19220
19227
  async id(v) {
@@ -19290,7 +19297,7 @@ var EntityCollection = class extends Destroyable {
19290
19297
  this._hasMore$.next(this.fetchController.hasMore ?? false);
19291
19298
  this._loading$.next(false);
19292
19299
  } catch (error) {
19293
- logger$10.error(`Failed to fetch initial collection data`, error);
19300
+ logger$11.error(`Failed to fetch initial collection data`, error);
19294
19301
  this._hasMore$.next(this.fetchController.hasMore ?? false);
19295
19302
  this._loading$.next(false);
19296
19303
  this.onError?.(new CollectionFetchError("fetchMore", error));
@@ -19304,7 +19311,7 @@ var EntityCollection = class extends Destroyable {
19304
19311
  if (data) this.upsertData(data);
19305
19312
  return data;
19306
19313
  } catch (error) {
19307
- logger$10.error(`Failed to fetch data for (${String(key)}:${String(value)}) :`, error);
19314
+ logger$11.error(`Failed to fetch data for (${String(key)}:${String(value)}) :`, error);
19308
19315
  this._loading$.next(false);
19309
19316
  this.onError?.(new CollectionFetchError(`tryFetch(${String(key)})`, error));
19310
19317
  }
@@ -19553,13 +19560,13 @@ var Address = class extends Destroyable {
19553
19560
  //#endregion
19554
19561
  //#region src/core/utils.ts
19555
19562
  var import_cjs$8 = require_cjs();
19556
- const logger$9 = getLogger();
19563
+ const logger$10 = getLogger();
19557
19564
  const isRPCConnectResult = (e) => {
19558
- logger$9.debug("isRPCConnectResult check:", e);
19565
+ logger$10.debug("isRPCConnectResult check:", e);
19559
19566
  if (!e || typeof e !== "object") return false;
19560
19567
  const result = e;
19561
19568
  const is = typeof result.identity === "string" && typeof result.protocol === "string" && typeof result.authorization === "object" && typeof result.authorization.jti === "string" && typeof result.authorization.project_id === "string" && typeof result.authorization.fabric_subscriber === "object";
19562
- logger$9.debug("isRPCConnectResult check result:", is);
19569
+ logger$10.debug("isRPCConnectResult check result:", is);
19563
19570
  return is;
19564
19571
  };
19565
19572
  var PendingRPC = class PendingRPC {
@@ -19568,7 +19575,7 @@ var PendingRPC = class PendingRPC {
19568
19575
  }
19569
19576
  constructor(request, responses$, options) {
19570
19577
  this.id = v4_default();
19571
- logger$9.debug(`[PendingRPC(${this.id}) request:${request.id}: method:${request.method}] Creating PendingRPC`);
19578
+ logger$10.debug(`[PendingRPC(${this.id}) request:${request.id}: method:${request.method}] Creating PendingRPC`);
19572
19579
  this.request = request;
19573
19580
  const timeoutMs = options?.timeoutMs ?? PendingRPC.defaultTimeoutMs;
19574
19581
  const signal = options?.signal;
@@ -19594,22 +19601,22 @@ var PendingRPC = class PendingRPC {
19594
19601
  isSettled = true;
19595
19602
  if (response.error) {
19596
19603
  const rpcError = new JSONRPCError(response.error.code, response.error.message, response.error.data, void 0, request.id);
19597
- logger$9.debug(`[PendingRPC(${this.id}) request:${request.id}] Rejecting promise with RPC error:`, rpcError);
19604
+ logger$10.debug(`[PendingRPC(${this.id}) request:${request.id}] Rejecting promise with RPC error:`, rpcError);
19598
19605
  reject(rpcError);
19599
19606
  } else {
19600
- logger$9.debug(`[PendingRPC(${this.id}) request:${request.id}] Resolving promise with response:`, response);
19607
+ logger$10.debug(`[PendingRPC(${this.id}) request:${request.id}] Resolving promise with response:`, response);
19601
19608
  resolve(response);
19602
19609
  }
19603
19610
  subscription.unsubscribe();
19604
19611
  },
19605
19612
  error: (error) => {
19606
- logger$9.debug(`[PendingRPC(${this.id}) request:${request.id}] Rejecting promise with error:`, error);
19613
+ logger$10.debug(`[PendingRPC(${this.id}) request:${request.id}] Rejecting promise with error:`, error);
19607
19614
  isSettled = true;
19608
19615
  reject(error);
19609
19616
  subscription.unsubscribe();
19610
19617
  },
19611
19618
  complete: () => {
19612
- logger$9.debug(`[PendingRPC(${this.id}) request:${request.id}] Observable completed`);
19619
+ logger$10.debug(`[PendingRPC(${this.id}) request:${request.id}] Observable completed`);
19613
19620
  if (!isSettled) reject(new RPCTimeoutError(request.id, timeoutMs));
19614
19621
  subscription.unsubscribe();
19615
19622
  }
@@ -19630,7 +19637,7 @@ var PendingRPC = class PendingRPC {
19630
19637
  //#endregion
19631
19638
  //#region src/managers/ClientSessionManager.ts
19632
19639
  var import_cjs$7 = require_cjs();
19633
- const logger$8 = getLogger();
19640
+ const logger$9 = getLogger();
19634
19641
  const getAddressSearchURI = (options) => {
19635
19642
  const to = options.to?.split("?")[0];
19636
19643
  const from$9 = options.from?.startsWith("subscriber://") ? options.from.replace("subscriber://", "") : options.from;
@@ -19728,7 +19735,7 @@ var ClientSessionManager = class extends Destroyable {
19728
19735
  try {
19729
19736
  return await this.transport.execute(request, options);
19730
19737
  } catch (error) {
19731
- logger$8.debug("[Session] Execute Error", error);
19738
+ logger$9.debug("[Session] Execute Error", error);
19732
19739
  this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
19733
19740
  throw error;
19734
19741
  }
@@ -19742,13 +19749,13 @@ var ClientSessionManager = class extends Destroyable {
19742
19749
  return true;
19743
19750
  }
19744
19751
  setupMessageHandlers() {
19745
- logger$8.debug("[Session] Setting up message handlers");
19752
+ logger$9.debug("[Session] Setting up message handlers");
19746
19753
  this.subscribeTo(this.authStateEvent$, async (authStateEvent) => {
19747
- logger$8.debug("[Session] Authorization state event received:", authStateEvent);
19754
+ logger$9.debug("[Session] Authorization state event received:", authStateEvent);
19748
19755
  try {
19749
19756
  await this.updateAuthorizationStateInStorage(authStateEvent.authorization_state);
19750
19757
  } catch (error) {
19751
- logger$8.error("[Session] Failed to handle authorization state update:", error);
19758
+ logger$9.error("[Session] Failed to handle authorization state update:", error);
19752
19759
  this._errors$.next(new AuthStateHandlerError(error));
19753
19760
  }
19754
19761
  });
@@ -19756,29 +19763,29 @@ var ClientSessionManager = class extends Destroyable {
19756
19763
  if (this._authState$.value.kind === "authenticated") this._authState$.next({ kind: "unauthenticated" });
19757
19764
  });
19758
19765
  this.subscribeTo(this.transport.connectionStatus$.pipe((0, import_cjs$7.filter)((status) => status === "connected"), (0, import_cjs$7.exhaustMap)(() => {
19759
- logger$8.debug("[Session] Connection established, initiating authentication");
19766
+ logger$9.debug("[Session] Connection established, initiating authentication");
19760
19767
  return (0, import_cjs$7.from)(this.authenticate()).pipe((0, import_cjs$7.catchError)((error) => {
19761
19768
  this.handleAuthenticationError(error).catch((err) => {
19762
- logger$8.error("[Session] Error handling authentication failure:", err);
19769
+ logger$9.error("[Session] Error handling authentication failure:", err);
19763
19770
  });
19764
19771
  return import_cjs$7.EMPTY;
19765
19772
  }));
19766
19773
  })), void 0);
19767
19774
  this.subscribeTo(this.vertoInvite$, async (invite) => {
19768
- logger$8.debug("[Session] Verto invite received:", invite);
19775
+ logger$9.debug("[Session] Verto invite received:", invite);
19769
19776
  try {
19770
19777
  await this.createInboundCall(invite);
19771
19778
  } catch (error) {
19772
- logger$8.error("[Session] Error handling Verto invite:", error);
19779
+ logger$9.error("[Session] Error handling Verto invite:", error);
19773
19780
  this._errors$.next(new VertoInviteHandlerError(error));
19774
19781
  }
19775
19782
  });
19776
19783
  this.subscribeTo(this.vertoAttach$, async (attach) => {
19777
- logger$8.debug("[Session] Verto attach received:", attach);
19784
+ logger$9.debug("[Session] Verto attach received:", attach);
19778
19785
  try {
19779
19786
  await this.handleVertoAttach(attach);
19780
19787
  } catch (error) {
19781
- logger$8.error("[Session] Error handling Verto attach:", error);
19788
+ logger$9.error("[Session] Error handling Verto attach:", error);
19782
19789
  this._errors$.next(new VertoAttachHandlerError(error));
19783
19790
  }
19784
19791
  });
@@ -19788,36 +19795,36 @@ var ClientSessionManager = class extends Destroyable {
19788
19795
  const storedState = await this.storage.getItem(this.authorizationStateKey);
19789
19796
  this.authorizationState$.next(storedState ?? void 0);
19790
19797
  } catch (error) {
19791
- logger$8.error("Failed to retrieve authorization state from storage:", error);
19798
+ logger$9.error("Failed to retrieve authorization state from storage:", error);
19792
19799
  this.authorizationState$.next(void 0);
19793
19800
  }
19794
19801
  }
19795
19802
  async updateAuthorizationStateInStorage(authorizationState) {
19796
19803
  if (!authorizationState) {
19797
- logger$8.debug("[Session] Removing authorization state from storage");
19804
+ logger$9.debug("[Session] Removing authorization state from storage");
19798
19805
  try {
19799
19806
  await this.storage.removeItem(this.authorizationStateKey);
19800
19807
  this.authorizationState$.next(void 0);
19801
19808
  } catch (error) {
19802
- logger$8.error("Failed to remove authorization state from storage:", error);
19809
+ logger$9.error("Failed to remove authorization state from storage:", error);
19803
19810
  throw error;
19804
19811
  }
19805
19812
  return;
19806
19813
  }
19807
19814
  try {
19808
- logger$8.debug("[Session] Updating authorization state in storage");
19815
+ logger$9.debug("[Session] Updating authorization state in storage");
19809
19816
  await this.storage.setItem(this.authorizationStateKey, authorizationState);
19810
19817
  this.authorizationState$.next(authorizationState);
19811
19818
  } catch (error) {
19812
- logger$8.error("Failed to retrieve authorization state from storage:", error);
19819
+ logger$9.error("Failed to retrieve authorization state from storage:", error);
19813
19820
  throw error;
19814
19821
  }
19815
19822
  }
19816
19823
  get authStateEvent$() {
19817
19824
  return this.cachedObservable("authStateEvent$", () => this.signalingEvent$.pipe((0, import_cjs$7.tap)((msg) => {
19818
- logger$8.debug("[Session] Received incoming message:", msg);
19825
+ logger$9.debug("[Session] Received incoming message:", msg);
19819
19826
  }), filterAs(isSignalwireAuthorizationStateMetadata, "params"), (0, import_cjs$7.tap)((event) => {
19820
- logger$8.debug("[Session] Authorization state event received:", event.authorization_state);
19827
+ logger$9.debug("[Session] Authorization state event received:", event.authorization_state);
19821
19828
  })));
19822
19829
  }
19823
19830
  get signalingEvent$() {
@@ -19855,15 +19862,15 @@ var ClientSessionManager = class extends Destroyable {
19855
19862
  await (0, import_cjs$7.firstValueFrom)(this.authenticated$.pipe((0, import_cjs$7.takeUntil)(this.destroyed$), (0, import_cjs$7.filter)(Boolean), (0, import_cjs$7.take)(1), (0, import_cjs$7.timeout)({ first: 15e3 })));
19856
19863
  }
19857
19864
  async handleAuthenticationError(error) {
19858
- logger$8.error("Authentication error:", error);
19865
+ logger$9.error("Authentication error:", error);
19859
19866
  const isRecoverableAuthError = error instanceof JSONRPCError && (error.code === RPC_ERROR_REQUESTER_VALIDATION_FAILED || error.code === RPC_ERROR_INVALID_PARAMS || error.code === RPC_ERROR_AUTHENTICATION_FAILED);
19860
19867
  const hasStoredState = await (0, import_cjs$7.firstValueFrom)(this.authorizationState$.pipe((0, import_cjs$7.take)(1))) !== void 0;
19861
19868
  if (isRecoverableAuthError && hasStoredState) {
19862
- logger$8.debug("[Session] Recoverable auth error — cleaning up stored state and reconnecting fresh");
19869
+ logger$9.debug("[Session] Recoverable auth error — cleaning up stored state and reconnecting fresh");
19863
19870
  try {
19864
19871
  await this.cleanupStoredConnectionParams();
19865
19872
  } catch (cleanupError) {
19866
- logger$8.error("Failed to cleanup stored connection params:", cleanupError);
19873
+ logger$9.error("Failed to cleanup stored connection params:", cleanupError);
19867
19874
  } finally {
19868
19875
  this.transport.reconnect();
19869
19876
  }
@@ -19878,19 +19885,19 @@ var ClientSessionManager = class extends Destroyable {
19878
19885
  try {
19879
19886
  await this.storage.setItem(this.authorizationStateKey, authorization_state);
19880
19887
  } catch (error) {
19881
- logger$8.error("Failed to update authorization state in storage:", error);
19888
+ logger$9.error("Failed to update authorization state in storage:", error);
19882
19889
  this._errors$.next(new AuthStateHandlerError(error));
19883
19890
  }
19884
19891
  }
19885
19892
  async reauthenticate(token, dpopToken, options) {
19886
- logger$8.debug("[Session] Re-authenticating session");
19893
+ logger$9.debug("[Session] Re-authenticating session");
19887
19894
  try {
19888
19895
  let resolvedDpopToken = dpopToken;
19889
19896
  if (!resolvedDpopToken && this.dpopManager?.initialized) try {
19890
19897
  resolvedDpopToken = await this.dpopManager.createRpcProof({ method: "signalwire.reauthenticate" });
19891
19898
  } catch (error) {
19892
19899
  if (this.clientBound) throw error;
19893
- logger$8.warn("[Session] Failed to create DPoP proof for reauthenticate:", error);
19900
+ logger$9.warn("[Session] Failed to create DPoP proof for reauthenticate:", error);
19894
19901
  }
19895
19902
  const request = RPCReauthenticate({
19896
19903
  project: this._authorization$.value?.project_id ?? "",
@@ -19898,24 +19905,24 @@ var ClientSessionManager = class extends Destroyable {
19898
19905
  ...resolvedDpopToken ? { dpop_token: resolvedDpopToken } : {}
19899
19906
  });
19900
19907
  await (0, import_cjs$7.lastValueFrom)((0, import_cjs$7.from)(this.transport.execute(request)).pipe(throwOnRPCError(), (0, import_cjs$7.take)(1), (0, import_cjs$7.catchError)((err) => {
19901
- logger$8.error("[Session] Re-authentication RPC failed:", err);
19908
+ logger$9.error("[Session] Re-authentication RPC failed:", err);
19902
19909
  throw err;
19903
19910
  })));
19904
19911
  if (options?.clientBound) this._wasClientBound = true;
19905
- logger$8.debug("[Session] Re-authentication successful, updating stored auth state");
19912
+ logger$9.debug("[Session] Re-authentication successful, updating stored auth state");
19906
19913
  } catch (error) {
19907
- logger$8.error("[Session] Re-authentication failed:", error);
19914
+ logger$9.error("[Session] Re-authentication failed:", error);
19908
19915
  this._errors$.next(new AuthStateHandlerError(error));
19909
19916
  throw error;
19910
19917
  }
19911
19918
  }
19912
19919
  async authenticate() {
19913
- logger$8.debug("[Session] Starting authentication process");
19920
+ logger$9.debug("[Session] Starting authentication process");
19914
19921
  const persistedParams = await (0, import_cjs$7.firstValueFrom)((0, import_cjs$7.combineLatest)({
19915
19922
  protocol: this.transport.protocol$,
19916
19923
  authorization_state: this.authorizationState$
19917
19924
  }).pipe((0, import_cjs$7.take)(1)));
19918
- logger$8.debug("[Session] Persisted params:\n", {
19925
+ logger$9.debug("[Session] Persisted params:\n", {
19919
19926
  protocol: persistedParams.protocol,
19920
19927
  authStateLength: persistedParams.authorization_state?.length
19921
19928
  });
@@ -19923,16 +19930,16 @@ var ClientSessionManager = class extends Destroyable {
19923
19930
  const storedToken = this.getCredential().token;
19924
19931
  const isReconnect = hasReconnectState && storedToken;
19925
19932
  let dpopToken;
19926
- if (isReconnect) logger$8.debug("[Session] Reconnecting with stored jwt_token + authorization_state");
19933
+ if (isReconnect) logger$9.debug("[Session] Reconnecting with stored jwt_token + authorization_state");
19927
19934
  else if (this.onBeforeReconnect && this.clientBound) {
19928
- logger$8.debug("[Session] Refreshing credentials before fresh connect");
19935
+ logger$9.debug("[Session] Refreshing credentials before fresh connect");
19929
19936
  await this.onBeforeReconnect();
19930
19937
  }
19931
19938
  if ((!isReconnect || this.clientBound) && this.dpopManager?.initialized) try {
19932
19939
  dpopToken = await this.dpopManager.createRpcProof({ method: "signalwire.connect" });
19933
19940
  } catch (error) {
19934
19941
  if (this.clientBound) throw error;
19935
- logger$8.warn("[Session] Failed to create DPoP proof for connect, proceeding without:", error);
19942
+ logger$9.warn("[Session] Failed to create DPoP proof for connect, proceeding without:", error);
19936
19943
  }
19937
19944
  const rpcConnectRequest = RPCConnect({
19938
19945
  authentication: isReconnect ? { jwt_token: storedToken } : this.authentication,
@@ -19949,12 +19956,12 @@ var ClientSessionManager = class extends Destroyable {
19949
19956
  } : {}
19950
19957
  });
19951
19958
  const response = await (0, import_cjs$7.lastValueFrom)((0, import_cjs$7.from)(this.transport.execute(rpcConnectRequest)).pipe(throwOnRPCError(), (0, import_cjs$7.map)((res) => res.result), (0, import_cjs$7.filter)(isRPCConnectResult), (0, import_cjs$7.tap)(() => {
19952
- logger$8.debug("[Session] Response passed filter, processing authentication result");
19959
+ logger$9.debug("[Session] Response passed filter, processing authentication result");
19953
19960
  }), (0, import_cjs$7.take)(1), (0, import_cjs$7.catchError)((err) => {
19954
- logger$8.error("[Session] Authentication RPC failed:", err);
19961
+ logger$9.error("[Session] Authentication RPC failed:", err);
19955
19962
  throw err;
19956
19963
  })));
19957
- logger$8.debug("[Session] Processing authentication result:", {
19964
+ logger$9.debug("[Session] Processing authentication result:", {
19958
19965
  hasProtocol: !!response.protocol,
19959
19966
  hasAuthorization: !!response.authorization,
19960
19967
  hasIceServers: !!response.ice_servers
@@ -19963,7 +19970,7 @@ var ClientSessionManager = class extends Destroyable {
19963
19970
  this._authorization$.next(response.authorization);
19964
19971
  this._iceServers$.next(response.ice_servers ?? []);
19965
19972
  this._authState$.next({ kind: "authenticated" });
19966
- logger$8.debug("[Session] Authentication completed successfully");
19973
+ logger$9.debug("[Session] Authentication completed successfully");
19967
19974
  }
19968
19975
  async disconnect() {
19969
19976
  this.transport.disconnect();
@@ -19999,11 +20006,11 @@ var ClientSessionManager = class extends Destroyable {
19999
20006
  async handleVertoAttach(attach) {
20000
20007
  const { callID } = attach;
20001
20008
  if (callID in this._calls$.value) {
20002
- logger$8.debug(`[Session] Verto attach for existing call ${callID}, deferring to per-call handler`);
20009
+ logger$9.debug(`[Session] Verto attach for existing call ${callID}, deferring to per-call handler`);
20003
20010
  return;
20004
20011
  }
20005
20012
  const storedOptions = await this.attachManager.consumePendingAttachment(callID);
20006
- logger$8.debug(`[Session] Creating reattached call for callID: ${callID}`);
20013
+ logger$9.debug(`[Session] Creating reattached call for callID: ${callID}`);
20007
20014
  const callSession = await this.createCall({
20008
20015
  nodeId: attach.node_id,
20009
20016
  callId: callID,
@@ -20034,7 +20041,7 @@ var ClientSessionManager = class extends Destroyable {
20034
20041
  });
20035
20042
  return callSession;
20036
20043
  } catch (error) {
20037
- logger$8.error("[Session] Error creating outbound call:", error);
20044
+ logger$9.error("[Session] Error creating outbound call:", error);
20038
20045
  callSession?.destroy();
20039
20046
  const callError = new CallCreateError(error instanceof import_cjs$7.TimeoutError ? "Call create timeout" : "Call creation failed", error, "outbound");
20040
20047
  this._errors$.next(callError);
@@ -20052,7 +20059,7 @@ var ClientSessionManager = class extends Destroyable {
20052
20059
  address = this._directory.get(addressId);
20053
20060
  if (!address) throw new DependencyError(`Address ID: ${addressId} not found`);
20054
20061
  } catch {
20055
- logger$8.warn(`[Session] Directory lookup failed for ${addressURI}, proceeding with raw URI`);
20062
+ logger$9.warn(`[Session] Directory lookup failed for ${addressURI}, proceeding with raw URI`);
20056
20063
  }
20057
20064
  const callSession = this.callFactory.createCall(address, { ...options });
20058
20065
  this.subscribeTo(callSession.status$.pipe((0, import_cjs$7.filter)((status) => status === "destroyed"), (0, import_cjs$7.take)(1)), () => {
@@ -20061,7 +20068,7 @@ var ClientSessionManager = class extends Destroyable {
20061
20068
  });
20062
20069
  return callSession;
20063
20070
  } catch (error) {
20064
- logger$8.error("[Session] Error creating call session:", error);
20071
+ logger$9.error("[Session] Error creating call session:", error);
20065
20072
  throw new CallCreateError("Call create error", error, options.initOffer ? "inbound" : "outbound");
20066
20073
  }
20067
20074
  }
@@ -20110,7 +20117,7 @@ const isString = (obj) => typeof obj === "string";
20110
20117
  //#endregion
20111
20118
  //#region src/managers/ConversationsManager.ts
20112
20119
  var import_cjs$6 = require_cjs();
20113
- const logger$7 = getLogger();
20120
+ const logger$8 = getLogger();
20114
20121
  var ConversationMessagesFetcher = class extends Fetcher {
20115
20122
  constructor(groupId, http) {
20116
20123
  super(`/api/fabric/conversations/${groupId}/messages`, "page_size=100", http);
@@ -20150,13 +20157,13 @@ var ConversationsManager = class {
20150
20157
  }
20151
20158
  throw new ConversationError("Join Failed - Unexpected response");
20152
20159
  } catch (error) {
20153
- logger$7.error("[ConversationsManager] Failed to join conversation:", error);
20160
+ logger$8.error("[ConversationsManager] Failed to join conversation:", error);
20154
20161
  throw error;
20155
20162
  }
20156
20163
  }
20157
20164
  async getConversationMessageCollection(addressId) {
20158
20165
  const groupId = this.groupIds.get(addressId) ?? await this.join(addressId);
20159
- return Promise.resolve(new ConversationMessageCollection(groupId, this.clientSession.signalingEvent$.pipe(filterAs(isConversationMessageMetadata, "params"), (0, import_cjs$6.tap)((event) => logger$7.debug("[ConversationsManager ] Conversation Event:", event)), (0, import_cjs$6.map)((params) => ({ ...params }))), this.http, this.onError));
20166
+ return Promise.resolve(new ConversationMessageCollection(groupId, this.clientSession.signalingEvent$.pipe(filterAs(isConversationMessageMetadata, "params"), (0, import_cjs$6.tap)((event) => logger$8.debug("[ConversationsManager ] Conversation Event:", event)), (0, import_cjs$6.map)((params) => ({ ...params }))), this.http, this.onError));
20160
20167
  }
20161
20168
  async sendText(text, destinationAddressId) {
20162
20169
  const groupId = this.groupIds.get(destinationAddressId) ?? await this.join(destinationAddressId);
@@ -20173,7 +20180,7 @@ var ConversationsManager = class {
20173
20180
  })).ok) return;
20174
20181
  throw new ConversationError("Send Text Failed - Unexpected response");
20175
20182
  } catch (error) {
20176
- logger$7.error("[ConversationsManager] Failed to send text message:", error);
20183
+ logger$8.error("[ConversationsManager] Failed to send text message:", error);
20177
20184
  throw error;
20178
20185
  }
20179
20186
  }
@@ -20182,7 +20189,7 @@ var ConversationsManager = class {
20182
20189
  //#endregion
20183
20190
  //#region src/managers/DeviceTokenManager.ts
20184
20191
  var import_cjs$5 = require_cjs();
20185
- const logger$6 = getLogger();
20192
+ const logger$7 = getLogger();
20186
20193
  /**
20187
20194
  * Resolves the token expiry timestamp (epoch seconds) using a 3-tier priority chain:
20188
20195
  * 1. `data.expires_at` — server-provided absolute timestamp
@@ -20192,7 +20199,7 @@ const logger$6 = getLogger();
20192
20199
  function resolveExpiresAt(data) {
20193
20200
  if (data.expires_at) return data.expires_at;
20194
20201
  if (data.expires_in) return Math.floor(Date.now() / 1e3) + data.expires_in;
20195
- logger$6.warn("[DeviceToken] Could not determine token expiry, using default");
20202
+ logger$7.warn("[DeviceToken] Could not determine token expiry, using default");
20196
20203
  return Math.floor(Date.now() / 1e3) + DEVICE_TOKEN_DEFAULT_EXPIRE_IN;
20197
20204
  }
20198
20205
  /**
@@ -20225,11 +20232,12 @@ var DeviceTokenManager = class extends Destroyable {
20225
20232
  this.getCredential = getCredential;
20226
20233
  this._currentToken$ = this.createBehaviorSubject(null);
20227
20234
  this._refreshInProgress = false;
20235
+ this._paused = false;
20228
20236
  this._effectiveExpireIn = DEVICE_TOKEN_DEFAULT_EXPIRE_IN;
20229
20237
  this.subscribeTo(this._currentToken$.pipe((0, import_cjs$5.filter)(Boolean), (0, import_cjs$5.switchMap)((tokenData) => {
20230
20238
  const expiresAt = resolveExpiresAt(tokenData);
20231
20239
  const refreshIn = Math.max(expiresAt * 1e3 - Date.now() - DEVICE_TOKEN_REFRESH_BUFFER_MS, 1e3);
20232
- logger$6.debug(`[DeviceToken] Scheduling Client Bound SAT refresh in ${refreshIn}ms`);
20240
+ logger$7.debug(`[DeviceToken] Scheduling Client Bound SAT refresh in ${refreshIn}ms`);
20233
20241
  return (0, import_cjs$5.timer)(refreshIn);
20234
20242
  })), () => {
20235
20243
  this.executeRefresh();
@@ -20243,7 +20251,12 @@ var DeviceTokenManager = class extends Destroyable {
20243
20251
  * Activates the Client Bound SAT flow when the user's token has
20244
20252
  * `sat:refresh` scope.
20245
20253
  *
20246
- * Steps:
20254
+ * Returns an {@link ActivationResult} indicating whether the manager
20255
+ * took ownership of refresh duties. The caller must use the `activated`
20256
+ * boolean to decide whether to keep its own refresh path armed — when
20257
+ * `activated` is `false`, the caller is responsible for refresh.
20258
+ *
20259
+ * Steps on success:
20247
20260
  * 1. Check user's `sat_claims` for `sat:refresh` scope
20248
20261
  * 2. Call `/api/fabric/subscriber/devices/token` with a DPoP proof
20249
20262
  * 3. Reauthenticate the session with the Client Bound SAT + DPoP proof
@@ -20252,32 +20265,51 @@ var DeviceTokenManager = class extends Destroyable {
20252
20265
  async activate(user, session, updateCredential) {
20253
20266
  const { satClaims } = user;
20254
20267
  if (!satClaims?.scope?.includes(SAT_REFRESH_SCOPE)) {
20255
- logger$6.debug("[DeviceToken] No sat:refresh scope, skipping Client Bound SAT activation");
20256
- return;
20268
+ logger$7.debug("[DeviceToken] No sat:refresh scope, skipping Client Bound SAT activation");
20269
+ return {
20270
+ activated: false,
20271
+ reason: "no-scope"
20272
+ };
20257
20273
  }
20258
20274
  this._session = session;
20259
20275
  this._updateCredential = updateCredential;
20260
20276
  try {
20277
+ const cached = this._currentToken$.value;
20278
+ if (cached && this.isTokenFresh(cached)) {
20279
+ logger$7.debug("[DeviceToken] Reusing cached Client Bound SAT — skipping /devices/token");
20280
+ const rpcProof$1 = await this.dpopManager.createRpcProof({ method: "signalwire.reauthenticate" });
20281
+ await session.reauthenticate(cached.token, rpcProof$1, { clientBound: true });
20282
+ updateCredential({ token: cached.token });
20283
+ return { activated: true };
20284
+ }
20261
20285
  const tokenData = await this.obtainToken();
20262
20286
  if (!tokenData.expires_at && !tokenData.expires_in && satClaims.expires_at) tokenData.expires_at = satClaims.expires_at;
20263
20287
  this._effectiveExpireIn = resolveExpireIn(tokenData);
20264
20288
  const rpcProof = await this.dpopManager.createRpcProof({ method: "signalwire.reauthenticate" });
20265
20289
  await session.reauthenticate(tokenData.token, rpcProof, { clientBound: true });
20266
20290
  updateCredential({ token: tokenData.token });
20267
- logger$6.info("[DeviceToken] Client Bound SAT activated successfully");
20291
+ logger$7.info("[DeviceToken] Client Bound SAT activated successfully");
20268
20292
  this._currentToken$.next(tokenData);
20293
+ return { activated: true };
20269
20294
  } catch (error) {
20270
- logger$6.error("[DeviceToken] Failed to activate Client Bound SAT:", error);
20295
+ logger$7.error("[DeviceToken] Failed to activate Client Bound SAT:", error);
20271
20296
  this.errorHandler(new DPoPInitError(error, "Failed to activate Client Bound SAT"));
20272
- const credential = this.getCredential();
20273
- const expiresAt = satClaims.expires_at ?? (credential.expiry_at ? credential.expiry_at / 1e3 : Date.now() / 1e3 + DEVICE_TOKEN_DEFAULT_EXPIRE_IN / 1e3);
20274
- this._currentToken$.next({
20275
- token: credential.token ?? "",
20276
- expires_at: expiresAt
20277
- });
20297
+ return {
20298
+ activated: false,
20299
+ reason: "endpoint-failed"
20300
+ };
20278
20301
  }
20279
20302
  }
20280
20303
  /**
20304
+ * Returns true when the cached token has enough headroom before expiry to
20305
+ * be safely reused on reactivation. The headroom matches the refresh
20306
+ * buffer, so a token within the refresh window is treated as stale (the
20307
+ * reactive pipeline is about to refresh it anyway).
20308
+ */
20309
+ isTokenFresh(token) {
20310
+ return resolveExpiresAt(token) * 1e3 - Date.now() > DEVICE_TOKEN_REFRESH_BUFFER_MS;
20311
+ }
20312
+ /**
20281
20313
  * Obtains a Client Bound SAT from `/api/fabric/subscriber/devices/token`.
20282
20314
  * Returns the full {@link DeviceTokenResponse} including expiry metadata.
20283
20315
  */
@@ -20307,7 +20339,7 @@ var DeviceTokenManager = class extends Destroyable {
20307
20339
  * handled by the reactive pipeline).
20308
20340
  */
20309
20341
  async refreshToken(session, currentToken, updateCredential) {
20310
- logger$6.debug("[DeviceToken] Refreshing Client Bound SAT");
20342
+ logger$7.debug("[DeviceToken] Refreshing Client Bound SAT");
20311
20343
  const dpopProof = await this.dpopManager.createHttpProof({
20312
20344
  method: "POST",
20313
20345
  uri: DEVICE_REFRESH_ENDPOINT,
@@ -20329,7 +20361,7 @@ var DeviceTokenManager = class extends Destroyable {
20329
20361
  const rpcProof = await this.dpopManager.createRpcProof({ method: "signalwire.reauthenticate" });
20330
20362
  await session.reauthenticate(data.token, rpcProof);
20331
20363
  updateCredential({ token: data.token });
20332
- logger$6.info("[DeviceToken] Client Bound SAT refreshed successfully");
20364
+ logger$7.info("[DeviceToken] Client Bound SAT refreshed successfully");
20333
20365
  return data;
20334
20366
  }
20335
20367
  /**
@@ -20338,18 +20370,22 @@ var DeviceTokenManager = class extends Destroyable {
20338
20370
  * On all retries exhausted, emits to `errorHandler`.
20339
20371
  */
20340
20372
  async executeRefresh() {
20373
+ if (this._paused) {
20374
+ logger$7.debug("[DeviceToken] Manager paused, skipping refresh");
20375
+ return;
20376
+ }
20341
20377
  if (this._refreshInProgress) {
20342
- logger$6.debug("[DeviceToken] Refresh already in progress, skipping");
20378
+ logger$7.debug("[DeviceToken] Refresh already in progress, skipping");
20343
20379
  return;
20344
20380
  }
20345
20381
  const session = this._session;
20346
20382
  const updateCredential = this._updateCredential;
20347
20383
  if (!session || !updateCredential) {
20348
- logger$6.warn("[DeviceToken] Cannot refresh: session or updateCredential not set");
20384
+ logger$7.warn("[DeviceToken] Cannot refresh: session or updateCredential not set");
20349
20385
  return;
20350
20386
  }
20351
20387
  if (!session.authenticated) {
20352
- logger$6.debug("[DeviceToken] Session not authenticated, deferring refresh");
20388
+ logger$7.debug("[DeviceToken] Session not authenticated, deferring refresh");
20353
20389
  return;
20354
20390
  }
20355
20391
  this._refreshInProgress = true;
@@ -20359,7 +20395,7 @@ var DeviceTokenManager = class extends Destroyable {
20359
20395
  const newTokenData = await this.retryRefresh(session, currentToken, updateCredential);
20360
20396
  this._currentToken$.next(newTokenData);
20361
20397
  } catch (error) {
20362
- logger$6.error("[DeviceToken] Automatic Client Bound SAT refresh failed:", error);
20398
+ logger$7.error("[DeviceToken] Automatic Client Bound SAT refresh failed:", error);
20363
20399
  this.errorHandler(error instanceof TokenRefreshError ? error : new TokenRefreshError("Automatic token refresh failed", error));
20364
20400
  } finally {
20365
20401
  this._refreshInProgress = false;
@@ -20377,18 +20413,215 @@ var DeviceTokenManager = class extends Destroyable {
20377
20413
  lastError = error;
20378
20414
  if (attempt < DEVICE_TOKEN_REFRESH_MAX_RETRIES - 1) {
20379
20415
  const delay$1 = DEVICE_TOKEN_REFRESH_RETRY_BASE_MS * Math.pow(2, attempt);
20380
- logger$6.warn(`[DeviceToken] Refresh attempt ${attempt + 1} failed, retrying in ${delay$1}ms`);
20416
+ logger$7.warn(`[DeviceToken] Refresh attempt ${attempt + 1} failed, retrying in ${delay$1}ms`);
20381
20417
  await new Promise((resolve) => setTimeout(resolve, delay$1));
20382
20418
  }
20383
20419
  }
20384
20420
  throw lastError instanceof Error ? lastError : new TokenRefreshError("All refresh retries exhausted", lastError);
20385
20421
  }
20422
+ /**
20423
+ * Stops the reactive refresh pipeline from firing. Use when the underlying
20424
+ * session is being torn down (e.g., during {@link SignalWire.disconnect})
20425
+ * so a scheduled refresh cannot fire against a destroyed session.
20426
+ *
20427
+ * The manager's state (cached token, effective TTL, subscriptions) is
20428
+ * preserved — call {@link resume} to re-enable firing after reconnect.
20429
+ */
20430
+ pause() {
20431
+ this._paused = true;
20432
+ }
20433
+ /** Re-enables the reactive refresh pipeline after a previous {@link pause}. */
20434
+ resume() {
20435
+ this._paused = false;
20436
+ }
20386
20437
  /** Cleans up the manager, cancelling the reactive pipeline and all subscriptions. */
20387
20438
  destroy() {
20388
20439
  super.destroy();
20389
20440
  }
20390
20441
  };
20391
20442
 
20443
+ //#endregion
20444
+ //#region src/managers/CredentialRefreshCoordinator.ts
20445
+ const logger$6 = getLogger();
20446
+ const defaultDeviceTokenManagerFactory = (dpopManager, http, errorHandler, getCredential) => new DeviceTokenManager(dpopManager, http, errorHandler, getCredential);
20447
+ /**
20448
+ * Centralizes credential-refresh ownership across the two competing
20449
+ * mechanisms — developer-provided `CredentialProvider.refresh()` and the
20450
+ * Client Bound SAT path via {@link DeviceTokenManager}.
20451
+ *
20452
+ * Maintains the invariant: **at most one refresh mechanism is armed at a
20453
+ * time, and at least one is armed whenever the current credential has an
20454
+ * `expiry_at`**.
20455
+ *
20456
+ * Replaces the previous design where refresh state was distributed across
20457
+ * `SignalWire` (timer field, scheduler method, activation helper) and
20458
+ * `DeviceTokenManager` (reactive pipeline). Centralizing the invariant in
20459
+ * one component eliminates the bug class that produced issue #19074.
20460
+ *
20461
+ * Race-safety:
20462
+ * - `_activating` flag prevents overlapping `activate()` calls from racing.
20463
+ * - `_activationGeneration` lets late resolutions detect they've been
20464
+ * preempted by a newer activation (e.g., reconnect during in-flight
20465
+ * `obtainToken`).
20466
+ */
20467
+ var CredentialRefreshCoordinator = class extends Destroyable {
20468
+ constructor(dpopManager, deps) {
20469
+ super();
20470
+ this.deps = deps;
20471
+ this._activating = false;
20472
+ this._activationGeneration = 0;
20473
+ if (dpopManager?.initialized) this._deviceTokenManager = (deps.deviceTokenManagerFactory ?? defaultDeviceTokenManagerFactory)(dpopManager, deps.http, (error) => deps.notifier.onError(error), () => deps.store.read());
20474
+ }
20475
+ /** True when the Client Bound SAT path is available (DPoP initialized). */
20476
+ get clientBoundSATAvailable() {
20477
+ return this._deviceTokenManager !== void 0;
20478
+ }
20479
+ /** True when the developer-provided refresh timer is currently armed. */
20480
+ get developerRefreshArmed() {
20481
+ return this._developerTimerId !== void 0;
20482
+ }
20483
+ /**
20484
+ * Arms the developer-provided refresh timer to fire shortly before
20485
+ * `expiresAt`. Replaces any previously scheduled developer refresh.
20486
+ *
20487
+ * Idempotent — multiple calls just reschedule. On retry exhaustion,
20488
+ * invokes `deps.onRefreshExhausted` so the orchestrator can disconnect.
20489
+ */
20490
+ scheduleDeveloperRefresh(provider, expiresAt, attempt = 0) {
20491
+ if (this._developerTimerId !== void 0) clearTimeout(this._developerTimerId);
20492
+ const refreshInterval = attempt === 0 ? Math.max(expiresAt - Date.now() - CREDENTIAL_REFRESH_BUFFER_MS, 1e3) : Math.min(CREDENTIAL_REFRESH_RETRY_BASE_MS * Math.pow(2, attempt) * (.5 + Math.random() * .5), CREDENTIAL_REFRESH_MAX_DELAY_MS);
20493
+ this._developerTimerId = setTimeout(async () => {
20494
+ try {
20495
+ if (!provider.refresh) throw new InvalidCredentialsError("Credential provider does not support refresh");
20496
+ const newCredentials = await provider.refresh();
20497
+ this.deps.store.write(newCredentials);
20498
+ this.deps.store.persist(newCredentials);
20499
+ logger$6.info("[Coordinator] Credentials refreshed successfully.");
20500
+ if (newCredentials.expiry_at) this.scheduleDeveloperRefresh(provider, newCredentials.expiry_at, 0);
20501
+ } catch (error) {
20502
+ const nextAttempt = attempt + 1;
20503
+ logger$6.error(`[Coordinator] Credential refresh failed (attempt ${nextAttempt}/${CREDENTIAL_REFRESH_MAX_RETRIES}):`, error);
20504
+ this.deps.notifier.onError(error instanceof Error ? error : new Error(String(error), { cause: error }));
20505
+ if (nextAttempt < CREDENTIAL_REFRESH_MAX_RETRIES) this.scheduleDeveloperRefresh(provider, expiresAt, nextAttempt);
20506
+ else {
20507
+ logger$6.error("[Coordinator] Credential refresh exhausted all retries. Disconnecting.");
20508
+ this.deps.notifier.onError(new TokenRefreshError("Credential refresh failed after max retries"));
20509
+ this.deps.notifier.onRefreshExhausted();
20510
+ }
20511
+ }
20512
+ }, refreshInterval);
20513
+ }
20514
+ /**
20515
+ * Cancels any scheduled developer-provided refresh. Idempotent.
20516
+ *
20517
+ * @internal Used by the coordinator's own activation flow. External
20518
+ * callers should use {@link suspend} for disconnect-time quiescence —
20519
+ * `suspend()` also pauses the internal Client Bound SAT pipeline.
20520
+ */
20521
+ cancelDeveloperRefresh() {
20522
+ if (this._developerTimerId !== void 0) {
20523
+ clearTimeout(this._developerTimerId);
20524
+ this._developerTimerId = void 0;
20525
+ }
20526
+ }
20527
+ /**
20528
+ * Suspends both refresh paths — cancels the developer timer and pauses
20529
+ * the internal reactive pipeline. Use when the underlying session is
20530
+ * being torn down (e.g., {@link SignalWire.disconnect}). The next
20531
+ * {@link activate} call re-enables the internal pipeline.
20532
+ *
20533
+ * The internal manager's cached token survives — see
20534
+ * {@link DeviceTokenManager.pause} — so a subsequent reconnect can
20535
+ * skip the `/devices/token` exchange entirely.
20536
+ */
20537
+ suspend() {
20538
+ this.cancelDeveloperRefresh();
20539
+ this._deviceTokenManager?.pause();
20540
+ }
20541
+ /**
20542
+ * Asks the Client Bound SAT path to take over refresh. If it accepts,
20543
+ * the developer-provided timer (if any) is cancelled. If it declines, the
20544
+ * developer timer remains armed and a `credential_refresh_fallback`
20545
+ * warning is emitted.
20546
+ *
20547
+ * **Idempotent** — re-entrant calls during an in-flight activation are
20548
+ * dropped. Use `_activationGeneration` to detect stale resolutions
20549
+ * (e.g., a reconnect-triggered activate() that races with an earlier one).
20550
+ */
20551
+ async activate(user, session) {
20552
+ if (this._activating) {
20553
+ logger$6.debug("[Coordinator] activate() in flight; ignoring re-entrant call");
20554
+ return;
20555
+ }
20556
+ if (!this._deviceTokenManager) return;
20557
+ this._deviceTokenManager.resume();
20558
+ const generation = ++this._activationGeneration;
20559
+ this._activating = true;
20560
+ try {
20561
+ const result = await this.withActivationTimeout(this._deviceTokenManager.activate(user, session, (cred) => this.deps.store.merge(cred)));
20562
+ if (generation !== this._activationGeneration) {
20563
+ logger$6.debug("[Coordinator] activate() result discarded (preempted by newer activation)");
20564
+ return;
20565
+ }
20566
+ if (result.activated) {
20567
+ this.cancelDeveloperRefresh();
20568
+ logger$6.debug("[Coordinator] Developer refresh disabled — Client Bound SAT owns refresh");
20569
+ return;
20570
+ }
20571
+ logger$6.warn(`[SignalWire] [SW-REFRESH-FALLBACK] Client Bound SAT declined (reason=${result.reason}); using developer-provided refresh handler.`);
20572
+ this.deps.notifier.onWarning({
20573
+ code: "credential_refresh_fallback",
20574
+ source: "CredentialProvider",
20575
+ reason: result.reason,
20576
+ message: `Client Bound SAT activation declined (${result.reason}); using developer-provided refresh.`
20577
+ });
20578
+ } finally {
20579
+ this._activating = false;
20580
+ }
20581
+ }
20582
+ destroy() {
20583
+ this.cancelDeveloperRefresh();
20584
+ this._deviceTokenManager?.destroy();
20585
+ this._deviceTokenManager = void 0;
20586
+ super.destroy();
20587
+ }
20588
+ /**
20589
+ * Races the manager's `activate()` against a hard timeout. A wedged HTTP
20590
+ * layer (e.g., proxy issues) could otherwise hang the activation
20591
+ * indefinitely, leaving the session with no refresh mechanism while the
20592
+ * `_activating` guard blocks subsequent retries.
20593
+ *
20594
+ * On timeout, the manager is paused immediately. The inner `activate()`
20595
+ * may still complete in the background and emit to `_currentToken$`,
20596
+ * which would normally arm the reactive refresh pipeline; pausing
20597
+ * prevents that pipeline from firing while the developer refresh path
20598
+ * is the active mechanism — preserving the "at most one mechanism
20599
+ * armed" invariant. The next `activate()` call resumes the manager.
20600
+ */
20601
+ async withActivationTimeout(inner) {
20602
+ return new Promise((resolve) => {
20603
+ const timer$4 = setTimeout(() => {
20604
+ this._deviceTokenManager?.pause();
20605
+ resolve({
20606
+ activated: false,
20607
+ reason: "activation-timeout"
20608
+ });
20609
+ }, CREDENTIAL_ACTIVATE_TIMEOUT_MS);
20610
+ inner.then((result) => {
20611
+ clearTimeout(timer$4);
20612
+ resolve(result);
20613
+ }, (error) => {
20614
+ clearTimeout(timer$4);
20615
+ this.deps.notifier.onError(error instanceof Error ? error : new Error(String(error)));
20616
+ resolve({
20617
+ activated: false,
20618
+ reason: "endpoint-failed"
20619
+ });
20620
+ });
20621
+ });
20622
+ }
20623
+ };
20624
+
20392
20625
  //#endregion
20393
20626
  //#region src/managers/DiagnosticsCollector.ts
20394
20627
  const logger$5 = getLogger();
@@ -21102,6 +21335,7 @@ var SignalWire = class extends Destroyable {
21102
21335
  this._isConnected$ = this.createBehaviorSubject(false);
21103
21336
  this._isRegistered$ = this.createBehaviorSubject(false);
21104
21337
  this._errors$ = this.createReplaySubject(1);
21338
+ this._warnings$ = this.createReplaySubject(10);
21105
21339
  this._options = {};
21106
21340
  this._deps = new DependencyContainer();
21107
21341
  this._credentialProvider = credentialProvider;
@@ -21161,6 +21395,27 @@ var SignalWire = class extends Destroyable {
21161
21395
  */
21162
21396
  async resolveCredentials() {
21163
21397
  const fingerprint = await this.initDPoP();
21398
+ this._refreshCoordinator = new CredentialRefreshCoordinator(this._dpopManager, {
21399
+ http: this._deps.http,
21400
+ notifier: {
21401
+ onError: (error) => this._errors$.next(error),
21402
+ onWarning: (warning) => this._warnings$.next(warning),
21403
+ onRefreshExhausted: () => void this.disconnect()
21404
+ },
21405
+ store: {
21406
+ read: () => this._deps.credential,
21407
+ write: (credential) => {
21408
+ this._deps.credential = credential;
21409
+ },
21410
+ merge: (partial) => {
21411
+ this._deps.credential = {
21412
+ ...this._deps.credential,
21413
+ ...partial
21414
+ };
21415
+ },
21416
+ persist: (credential) => this.persistCredential(credential)
21417
+ }
21418
+ });
21164
21419
  if (this._credentialProvider) return this.validateCredentials(this._credentialProvider, void 0, fingerprint);
21165
21420
  for (const scope of this._deps.persistSession ? ["local", "session"] : ["session"]) try {
21166
21421
  const cached = await this._deps.storage.getItem("sw:cached_credential", scope);
@@ -21190,7 +21445,16 @@ var SignalWire = class extends Destroyable {
21190
21445
  logger$1.error("[SignalWire] Provided credentials have expired.");
21191
21446
  throw new InvalidCredentialsError("Provided credentials have expired.");
21192
21447
  }
21193
- if (_credentials.expiry_at && credentialProvider?.refresh) this.scheduleCredentialRefresh(credentialProvider, _credentials.expiry_at);
21448
+ if (_credentials.expiry_at && credentialProvider?.refresh) this._refreshCoordinator?.scheduleDeveloperRefresh(credentialProvider, _credentials.expiry_at);
21449
+ else if (_credentials.expiry_at && !credentialProvider?.refresh) {
21450
+ logger$1.warn(`[SignalWire] [SW-NO-REFRESH-HANDLER] Credential has expiry_at=${_credentials.expiry_at} but no refresh handler. Session will terminate at expiry unless the SAT has 'sat:refresh' scope.`);
21451
+ this._warnings$.next({
21452
+ code: "credential_no_refresh_handler",
21453
+ source: "CredentialProvider",
21454
+ message: "Credential has expiry_at but no refresh handler. Session will terminate at expiry unless the SAT carries 'sat:refresh' scope.",
21455
+ expiresAt: _credentials.expiry_at
21456
+ });
21457
+ }
21194
21458
  this._deps.credential = _credentials;
21195
21459
  this.persistCredential(_credentials);
21196
21460
  if (this.isConnected && this._clientSession.authenticated && _credentials.token) try {
@@ -21201,35 +21465,6 @@ var SignalWire = class extends Destroyable {
21201
21465
  this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
21202
21466
  }
21203
21467
  }
21204
- /**
21205
- * Schedules credential refresh with exponential backoff retry on failure.
21206
- * On success, resets attempt counter and schedules the next refresh.
21207
- * After exhausting retries, emits TokenRefreshError and disconnects.
21208
- */
21209
- scheduleCredentialRefresh(credentialProvider, expiresAt, attempt = 0) {
21210
- if (this._refreshTimerId !== void 0) clearTimeout(this._refreshTimerId);
21211
- const refreshInterval = attempt === 0 ? Math.max(expiresAt - Date.now() - CREDENTIAL_REFRESH_BUFFER_MS, 1e3) : Math.min(CREDENTIAL_REFRESH_RETRY_BASE_MS * Math.pow(2, attempt) * (.5 + Math.random() * .5), CREDENTIAL_REFRESH_MAX_DELAY_MS);
21212
- this._refreshTimerId = setTimeout(async () => {
21213
- try {
21214
- if (!credentialProvider.refresh) throw new InvalidCredentialsError("Credential provider does not support refresh");
21215
- const newCredentials = await credentialProvider.refresh();
21216
- this._deps.credential = newCredentials;
21217
- this.persistCredential(newCredentials);
21218
- logger$1.info("[SignalWire] Credentials refreshed successfully.");
21219
- if (newCredentials.expiry_at) this.scheduleCredentialRefresh(credentialProvider, newCredentials.expiry_at, 0);
21220
- } catch (error) {
21221
- const nextAttempt = attempt + 1;
21222
- logger$1.error(`[SignalWire] Credential refresh failed (attempt ${nextAttempt}/${CREDENTIAL_REFRESH_MAX_RETRIES}):`, error);
21223
- this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
21224
- if (nextAttempt < CREDENTIAL_REFRESH_MAX_RETRIES) this.scheduleCredentialRefresh(credentialProvider, expiresAt, nextAttempt);
21225
- else {
21226
- logger$1.error("[SignalWire] Credential refresh exhausted all retries. Disconnecting.");
21227
- this._errors$.next(new TokenRefreshError("Credential refresh failed after max retries"));
21228
- this.disconnect();
21229
- }
21230
- }
21231
- }, refreshInterval);
21232
- }
21233
21468
  /** Persist credential to localStorage when persistSession is enabled. */
21234
21469
  persistCredential(credential) {
21235
21470
  if (!credential.token) return;
@@ -21323,6 +21558,7 @@ var SignalWire = class extends Destroyable {
21323
21558
  logger$1.debug("[SignalWire] Credential expired, refreshing before reconnect");
21324
21559
  const newCredentials = await this._credentialProvider.authenticate(fingerprint ? { fingerprint } : void 0);
21325
21560
  this._deps.credential = newCredentials;
21561
+ if (newCredentials.expiry_at && this._credentialProvider.refresh) this._refreshCoordinator?.scheduleDeveloperRefresh(this._credentialProvider, newCredentials.expiry_at);
21326
21562
  logger$1.debug("[SignalWire] Credential refreshed successfully for reconnect");
21327
21563
  } catch (error) {
21328
21564
  logger$1.error("[SignalWire] Failed to refresh credentials for reconnect:", error);
@@ -21334,33 +21570,12 @@ var SignalWire = class extends Destroyable {
21334
21570
  this._errors$.next(error);
21335
21571
  });
21336
21572
  await this._clientSession.connect();
21337
- if (this._dpopManager?.initialized) {
21338
- if (this._refreshTimerId) {
21339
- clearTimeout(this._refreshTimerId);
21340
- this._refreshTimerId = void 0;
21341
- logger$1.debug("[SignalWire] Developer refresh disabled — Client Bound SAT activation starting");
21342
- }
21343
- this._deviceTokenManager = new DeviceTokenManager(this._dpopManager, this._deps.http, (error) => this._errors$.next(error), () => this._deps.credential);
21344
- await this._deviceTokenManager.activate(this._deps.user, this._clientSession, (cred) => {
21345
- this._deps.credential = {
21346
- ...this._deps.credential,
21347
- ...cred
21348
- };
21349
- });
21350
- }
21573
+ await this._refreshCoordinator?.activate(this._deps.user, this._clientSession);
21351
21574
  this.subscribeTo(this._clientSession.authenticated$.pipe((0, import_cjs$1.skip)(1), (0, import_cjs$1.filter)(Boolean)), async () => {
21352
21575
  try {
21353
- if (this._deviceTokenManager) {
21354
- await this._deviceTokenManager.activate(this._deps.user, this._clientSession, (cred) => {
21355
- this._deps.credential = {
21356
- ...this._deps.credential,
21357
- ...cred
21358
- };
21359
- });
21360
- logger$1.debug("[SignalWire] Client Bound SAT re-activated after reconnect");
21361
- }
21576
+ await this._refreshCoordinator?.activate(this._deps.user, this._clientSession);
21362
21577
  } catch (error) {
21363
- logger$1.error("[SignalWire] Client Bound SAT re-activation failed (non-fatal):", error);
21578
+ logger$1.error("[SignalWire] Refresh re-arm after reconnect failed (non-fatal):", error);
21364
21579
  this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
21365
21580
  }
21366
21581
  try {
@@ -21446,6 +21661,19 @@ var SignalWire = class extends Destroyable {
21446
21661
  get errors$() {
21447
21662
  return this.deferEmission(this._errors$.asObservable());
21448
21663
  }
21664
+ /**
21665
+ * Observable stream of non-fatal SDK warnings.
21666
+ *
21667
+ * Subscribe to detect SDK behaviors that affect session liveness or developer-facing
21668
+ * contracts but do not warrant disconnection — e.g., a fallback from Client Bound SAT
21669
+ * refresh to the developer-provided `refresh()` because the SAT lacks `sat:refresh`
21670
+ * scope. Discriminated by `code`.
21671
+ *
21672
+ * Independent from {@link errors$}: existing error consumers are not notified.
21673
+ */
21674
+ get warnings$() {
21675
+ return this.deferEmission(this._warnings$.asObservable());
21676
+ }
21449
21677
  /** Platform WebRTC capabilities detected at construction time. */
21450
21678
  get platformCapabilities() {
21451
21679
  this._platformCapabilities ??= detectPlatformCapabilities(this._options.webRTCApiProvider);
@@ -21514,7 +21742,7 @@ var SignalWire = class extends Destroyable {
21514
21742
  logger$1.warn("[SignalWire] Failed to initialize VisibilityController:", error);
21515
21743
  }
21516
21744
  try {
21517
- this._diagnosticsCollector = new DiagnosticsCollector({ sdkVersion: "3.30.0" });
21745
+ this._diagnosticsCollector = new DiagnosticsCollector({ sdkVersion: "4.0.0-rc.0" });
21518
21746
  } catch (error) {
21519
21747
  logger$1.warn("[SignalWire] Failed to initialize DiagnosticsCollector:", error);
21520
21748
  }
@@ -21526,10 +21754,7 @@ var SignalWire = class extends Destroyable {
21526
21754
  * which creates a fresh transport and session.
21527
21755
  */
21528
21756
  async disconnect() {
21529
- if (this._refreshTimerId) {
21530
- clearTimeout(this._refreshTimerId);
21531
- this._refreshTimerId = void 0;
21532
- }
21757
+ this._refreshCoordinator?.suspend();
21533
21758
  this._diagnosticsCollector?.record("connection", "disconnected");
21534
21759
  await this.teardownTransportAndSession();
21535
21760
  this._isConnected$.next(false);
@@ -21918,11 +22143,8 @@ var SignalWire = class extends Destroyable {
21918
22143
  }
21919
22144
  /** Destroys the client, clearing timers and releasing all resources. */
21920
22145
  destroy() {
21921
- if (this._refreshTimerId) {
21922
- clearTimeout(this._refreshTimerId);
21923
- this._refreshTimerId = void 0;
21924
- }
21925
- this._deviceTokenManager?.destroy();
22146
+ this._refreshCoordinator?.destroy();
22147
+ this._refreshCoordinator = void 0;
21926
22148
  this._dpopManager?.destroy();
21927
22149
  if (this._attachManager) this._attachManager.detachAll();
21928
22150
  this._transport.destroy();
@@ -22039,7 +22261,7 @@ var StaticCredentialProvider = class {
22039
22261
  /**
22040
22262
  * Library version from package.json, injected at build time.
22041
22263
  */
22042
- const version = "3.30.0";
22264
+ const version = "4.0.0-rc.0";
22043
22265
  /**
22044
22266
  * Flag indicating the library has been loaded and is ready to use.
22045
22267
  * For UMD builds: `window.SignalWire.ready`
@@ -22061,7 +22283,7 @@ const ready = true;
22061
22283
  */
22062
22284
  const emitReadyEvent = () => {
22063
22285
  if (typeof window !== "undefined") {
22064
- const event = new CustomEvent("signalwire:js:ready", { detail: { version: "3.30.0" } });
22286
+ const event = new CustomEvent("signalwire:js:ready", { detail: { version: "4.0.0-rc.0" } });
22065
22287
  window.dispatchEvent(event);
22066
22288
  }
22067
22289
  };