@signalwire/js 4.0.0-dev-20260410164129 → 4.0.0-dev-20260413184400

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.
@@ -3394,7 +3394,7 @@ var require_map = /* @__PURE__ */ __commonJSMin(((exports) => {
3394
3394
  exports.map = void 0;
3395
3395
  var lift_1$64 = require_lift();
3396
3396
  var OperatorSubscriber_1$54 = require_OperatorSubscriber();
3397
- function map$18(project, thisArg) {
3397
+ function map$19(project, thisArg) {
3398
3398
  return lift_1$64.operate(function(source, subscriber) {
3399
3399
  var index = 0;
3400
3400
  source.subscribe(OperatorSubscriber_1$54.createOperatorSubscriber(subscriber, function(value) {
@@ -3402,7 +3402,7 @@ var require_map = /* @__PURE__ */ __commonJSMin(((exports) => {
3402
3402
  }));
3403
3403
  });
3404
3404
  }
3405
- exports.map = map$18;
3405
+ exports.map = map$19;
3406
3406
  }));
3407
3407
 
3408
3408
  //#endregion
@@ -4144,7 +4144,7 @@ var require_timer = /* @__PURE__ */ __commonJSMin(((exports) => {
4144
4144
  var async_1$11 = require_async();
4145
4145
  var isScheduler_1 = require_isScheduler();
4146
4146
  var isDate_1$1 = require_isDate();
4147
- function timer$1(dueTime, intervalOrScheduler, scheduler) {
4147
+ function timer$2(dueTime, intervalOrScheduler, scheduler) {
4148
4148
  if (dueTime === void 0) dueTime = 0;
4149
4149
  if (scheduler === void 0) scheduler = async_1$11.async;
4150
4150
  var intervalDuration = -1;
@@ -4163,7 +4163,7 @@ var require_timer = /* @__PURE__ */ __commonJSMin(((exports) => {
4163
4163
  }, due);
4164
4164
  });
4165
4165
  }
4166
- exports.timer = timer$1;
4166
+ exports.timer = timer$2;
4167
4167
  }));
4168
4168
 
4169
4169
  //#endregion
@@ -4297,7 +4297,7 @@ var require_filter = /* @__PURE__ */ __commonJSMin(((exports) => {
4297
4297
  exports.filter = void 0;
4298
4298
  var lift_1$62 = require_lift();
4299
4299
  var OperatorSubscriber_1$49 = require_OperatorSubscriber();
4300
- function filter$15(predicate, thisArg) {
4300
+ function filter$16(predicate, thisArg) {
4301
4301
  return lift_1$62.operate(function(source, subscriber) {
4302
4302
  var index = 0;
4303
4303
  source.subscribe(OperatorSubscriber_1$49.createOperatorSubscriber(subscriber, function(value) {
@@ -4305,7 +4305,7 @@ var require_filter = /* @__PURE__ */ __commonJSMin(((exports) => {
4305
4305
  }));
4306
4306
  });
4307
4307
  }
4308
- exports.filter = filter$15;
4308
+ exports.filter = filter$16;
4309
4309
  }));
4310
4310
 
4311
4311
  //#endregion
@@ -6938,7 +6938,7 @@ var require_switchMap = /* @__PURE__ */ __commonJSMin(((exports) => {
6938
6938
  var innerFrom_1$6 = require_innerFrom();
6939
6939
  var lift_1$13 = require_lift();
6940
6940
  var OperatorSubscriber_1$11 = require_OperatorSubscriber();
6941
- function switchMap$6(project, resultSelector) {
6941
+ function switchMap$7(project, resultSelector) {
6942
6942
  return lift_1$13.operate(function(source, subscriber) {
6943
6943
  var innerSubscriber = null;
6944
6944
  var index = 0;
@@ -6962,7 +6962,7 @@ var require_switchMap = /* @__PURE__ */ __commonJSMin(((exports) => {
6962
6962
  }));
6963
6963
  });
6964
6964
  }
6965
- exports.switchMap = switchMap$6;
6965
+ exports.switchMap = switchMap$7;
6966
6966
  }));
6967
6967
 
6968
6968
  //#endregion
@@ -7586,7 +7586,7 @@ var require_withLatestFrom = /* @__PURE__ */ __commonJSMin(((exports) => {
7586
7586
  var identity_1$1 = require_identity();
7587
7587
  var noop_1$1 = require_noop();
7588
7588
  var args_1 = require_args();
7589
- function withLatestFrom$1() {
7589
+ function withLatestFrom$2() {
7590
7590
  var inputs = [];
7591
7591
  for (var _i = 0; _i < arguments.length; _i++) inputs[_i] = arguments[_i];
7592
7592
  var project = args_1.popResultSelector(inputs);
@@ -7615,7 +7615,7 @@ var require_withLatestFrom = /* @__PURE__ */ __commonJSMin(((exports) => {
7615
7615
  }));
7616
7616
  });
7617
7617
  }
7618
- exports.withLatestFrom = withLatestFrom$1;
7618
+ exports.withLatestFrom = withLatestFrom$2;
7619
7619
  }));
7620
7620
 
7621
7621
  //#endregion
@@ -8937,13 +8937,13 @@ var require_cjs = /* @__PURE__ */ __commonJSMin(((exports) => {
8937
8937
 
8938
8938
  //#endregion
8939
8939
  //#region src/behaviors/Destroyable.ts
8940
- var import_cjs$27 = require_cjs();
8940
+ var import_cjs$28 = require_cjs();
8941
8941
  var Destroyable = class {
8942
8942
  constructor() {
8943
8943
  this.subscriptions = [];
8944
8944
  this.subjects = [];
8945
- this._destroyed$ = new import_cjs$27.Subject();
8946
- this._change$ = new import_cjs$27.Subject();
8945
+ this._destroyed$ = new import_cjs$28.Subject();
8946
+ this._change$ = new import_cjs$28.Subject();
8947
8947
  }
8948
8948
  destroy() {
8949
8949
  this._observableCache?.clear();
@@ -8980,7 +8980,7 @@ var Destroyable = class {
8980
8980
  this._observableCache ??= /* @__PURE__ */ new Map();
8981
8981
  let cached = this._observableCache.get(publicKey);
8982
8982
  if (!cached) {
8983
- cached = factory().pipe((0, import_cjs$27.observeOn)(import_cjs$27.asapScheduler));
8983
+ cached = factory().pipe((0, import_cjs$28.observeOn)(import_cjs$28.asapScheduler));
8984
8984
  this._observableCache.set(publicKey, cached);
8985
8985
  }
8986
8986
  return cached;
@@ -8994,32 +8994,32 @@ var Destroyable = class {
8994
8994
  * Do NOT use for observables consumed internally by the SDK.
8995
8995
  */
8996
8996
  deferEmission(observable) {
8997
- return observable.pipe((0, import_cjs$27.observeOn)(import_cjs$27.asapScheduler));
8997
+ return observable.pipe((0, import_cjs$28.observeOn)(import_cjs$28.asapScheduler));
8998
8998
  }
8999
8999
  subscribeTo(observable, observerOrNext) {
9000
9000
  const subscription = observable.subscribe(observerOrNext);
9001
9001
  this.subscriptions.push(subscription);
9002
9002
  }
9003
9003
  createSubject() {
9004
- const subject = new import_cjs$27.Subject();
9004
+ const subject = new import_cjs$28.Subject();
9005
9005
  this.subjects.push(subject);
9006
- this.subscriptions.push(subject.pipe((0, import_cjs$27.map)(() => void 0)).subscribe(this._change$));
9006
+ this.subscriptions.push(subject.pipe((0, import_cjs$28.map)(() => void 0)).subscribe(this._change$));
9007
9007
  return subject;
9008
9008
  }
9009
9009
  createReplaySubject(bufferSize, windowTime$1) {
9010
- const subject = new import_cjs$27.ReplaySubject(bufferSize, windowTime$1);
9010
+ const subject = new import_cjs$28.ReplaySubject(bufferSize, windowTime$1);
9011
9011
  this.subjects.push(subject);
9012
- this.subscriptions.push(subject.pipe((0, import_cjs$27.map)(() => void 0)).subscribe(this._change$));
9012
+ this.subscriptions.push(subject.pipe((0, import_cjs$28.map)(() => void 0)).subscribe(this._change$));
9013
9013
  return subject;
9014
9014
  }
9015
9015
  createBehaviorSubject(initialValue) {
9016
- const subject = new import_cjs$27.BehaviorSubject(initialValue);
9016
+ const subject = new import_cjs$28.BehaviorSubject(initialValue);
9017
9017
  this.subjects.push(subject);
9018
- this.subscriptions.push(subject.pipe((0, import_cjs$27.skip)(1), (0, import_cjs$27.map)(() => void 0)).subscribe(this._change$));
9018
+ this.subscriptions.push(subject.pipe((0, import_cjs$28.skip)(1), (0, import_cjs$28.map)(() => void 0)).subscribe(this._change$));
9019
9019
  return subject;
9020
9020
  }
9021
9021
  get $() {
9022
- return this._change$.pipe((0, import_cjs$27.map)(() => this));
9022
+ return this._change$.pipe((0, import_cjs$28.map)(() => this));
9023
9023
  }
9024
9024
  /**
9025
9025
  * Observable that emits when the instance is destroyed
@@ -9478,9 +9478,9 @@ var require_loglevel = /* @__PURE__ */ __commonJSMin(((exports, module) => {
9478
9478
  defaultLogger$1 = new Logger();
9479
9479
  defaultLogger$1.getLogger = function getLogger$1(name) {
9480
9480
  if (typeof name !== "symbol" && typeof name !== "string" || name === "") throw new TypeError("You must supply a name when creating a logger.");
9481
- var logger$29 = _loggersByName[name];
9482
- if (!logger$29) logger$29 = _loggersByName[name] = new Logger(name, defaultLogger$1.methodFactory);
9483
- return logger$29;
9481
+ var logger$30 = _loggersByName[name];
9482
+ if (!logger$30) logger$30 = _loggersByName[name] = new Logger(name, defaultLogger$1.methodFactory);
9483
+ return logger$30;
9484
9484
  };
9485
9485
  var _log = typeof window !== undefinedType ? window.log : void 0;
9486
9486
  defaultLogger$1.noConflict = function() {
@@ -9520,15 +9520,15 @@ const shouldStringify = (payload) => {
9520
9520
  return true;
9521
9521
  };
9522
9522
  const wsTraffic = ({ type, payload }) => {
9523
- const logger$29 = getLoggerInstance();
9523
+ const logger$30 = getLoggerInstance();
9524
9524
  const { logWsTraffic } = debugOptions ?? {};
9525
9525
  if (!logWsTraffic) return;
9526
9526
  const msg = shouldStringify(payload) ? JSON.stringify(payload, null, 2) : payload;
9527
- return logger$29.debug(`${type.toUpperCase()}: \n`, msg, "\n");
9527
+ return logger$30.debug(`${type.toUpperCase()}: \n`, msg, "\n");
9528
9528
  };
9529
9529
  const getLogger = () => {
9530
- const logger$29 = getLoggerInstance();
9531
- return new Proxy(logger$29, { get(target, prop, receiver) {
9530
+ const logger$30 = getLoggerInstance();
9531
+ return new Proxy(logger$30, { get(target, prop, receiver) {
9532
9532
  if (prop === "wsTraffic") return wsTraffic;
9533
9533
  return Reflect.get(target, prop, receiver);
9534
9534
  } });
@@ -9577,8 +9577,8 @@ const asyncRetry = async ({ asyncCallable, maxRetries: retries = DEFAULT_MAX_RET
9577
9577
 
9578
9578
  //#endregion
9579
9579
  //#region src/controllers/HTTPRequestController.ts
9580
- var import_cjs$26 = require_cjs();
9581
- const logger$28 = getLogger();
9580
+ var import_cjs$27 = require_cjs();
9581
+ const logger$29 = getLogger();
9582
9582
  const GET_PARAMS = {
9583
9583
  method: "GET",
9584
9584
  headers: { Accept: "application/json" }
@@ -9613,9 +9613,9 @@ var HTTPRequestController = class HTTPRequestController {
9613
9613
  constructor(baseURL, getCredential, options = {}) {
9614
9614
  this.baseURL = baseURL;
9615
9615
  this.getCredential = getCredential;
9616
- this._responses$ = new import_cjs$26.Subject();
9617
- this._errors$ = new import_cjs$26.Subject();
9618
- this._status$ = new import_cjs$26.BehaviorSubject("idle");
9616
+ this._responses$ = new import_cjs$27.Subject();
9617
+ this._errors$ = new import_cjs$27.Subject();
9618
+ this._status$ = new import_cjs$27.BehaviorSubject("idle");
9619
9619
  this.maxRetries = options.maxRetries ?? HTTPRequestController.defaultMaxRetries;
9620
9620
  this.retryDelayMin = options.retryDelayMin ?? HTTPRequestController.defaultRetryDelayMinMs;
9621
9621
  this.retryDelayMax = options.retryDelayMax ?? HTTPRequestController.defaultRetryDelayMaxMs;
@@ -9641,7 +9641,7 @@ var HTTPRequestController = class HTTPRequestController {
9641
9641
  this._responses$.next(response);
9642
9642
  return response;
9643
9643
  } catch (error) {
9644
- logger$28.error("[HTTPRequestController] Request error:", error);
9644
+ logger$29.error("[HTTPRequestController] Request error:", error);
9645
9645
  this._status$.next("error");
9646
9646
  const err = error instanceof Error ? error : new Error("HTTP request failed", { cause: error });
9647
9647
  this._errors$.next(err);
@@ -9668,7 +9668,7 @@ var HTTPRequestController = class HTTPRequestController {
9668
9668
  const url = this.buildURL(request.url);
9669
9669
  const headers = this.buildHeaders(request.headers);
9670
9670
  const timeout$5 = request.timeout ?? this.requestTimeout;
9671
- logger$28.debug("[HTTPRequestController] Executing request:", {
9671
+ logger$29.debug("[HTTPRequestController] Executing request:", {
9672
9672
  method: request.method,
9673
9673
  url,
9674
9674
  headers: Object.keys(headers).reduce((acc, key) => {
@@ -9688,7 +9688,7 @@ var HTTPRequestController = class HTTPRequestController {
9688
9688
  });
9689
9689
  clearTimeout(timeoutId);
9690
9690
  const httpResponse = await this.convertResponse(response);
9691
- logger$28.debug("[HTTPRequestController] Response received:", {
9691
+ logger$29.debug("[HTTPRequestController] Response received:", {
9692
9692
  status: response.status,
9693
9693
  statusText: response.statusText,
9694
9694
  headers: [...response.headers.entries()],
@@ -9698,7 +9698,7 @@ var HTTPRequestController = class HTTPRequestController {
9698
9698
  } catch (error) {
9699
9699
  clearTimeout(timeoutId);
9700
9700
  if (error instanceof Error && error.name === "AbortError") throw new RequestTimeoutError(`Request timeout after ${timeout$5}ms`, { cause: error });
9701
- logger$28.error("[HTTPRequestController] Request failed:", error);
9701
+ logger$29.error("[HTTPRequestController] Request failed:", error);
9702
9702
  throw error;
9703
9703
  }
9704
9704
  }
@@ -9712,8 +9712,8 @@ var HTTPRequestController = class HTTPRequestController {
9712
9712
  const credential = this.getCredential();
9713
9713
  if (credential.token) {
9714
9714
  headers.Authorization = `Bearer ${credential.token}`;
9715
- logger$28.debug("[HTTPRequestController] Using Bearer token auth, token length:", credential.token.length);
9716
- } else logger$28.warn("[HTTPRequestController] No credentials available for authentication");
9715
+ logger$29.debug("[HTTPRequestController] Using Bearer token auth, token length:", credential.token.length);
9716
+ } else logger$29.warn("[HTTPRequestController] No credentials available for authentication");
9717
9717
  return headers;
9718
9718
  }
9719
9719
  /**
@@ -9862,6 +9862,19 @@ const DEFAULT_RECONNECT_DELAY_MAX_MS = 3e3;
9862
9862
  const DEFAULT_DEVICE_DEBOUNCE_TIME_MS = 1500;
9863
9863
  const DEFAULT_DEVICE_POLLING_INTERVAL_MS = 0;
9864
9864
  const PREFERENCES_STORAGE_KEY = "sw:preferences";
9865
+ /** Scope value that enables automatic token refresh. */
9866
+ const SAT_REFRESH_SCOPE = "sat:refresh";
9867
+ /** API endpoints for device token operations. */
9868
+ const DEVICE_TOKEN_ENDPOINT = "/api/fabric/subscriber/devices/token";
9869
+ const DEVICE_REFRESH_ENDPOINT = "/api/fabric/subscriber/devices/refresh";
9870
+ /** Default device token TTL in seconds (15 minutes). */
9871
+ const DEVICE_TOKEN_DEFAULT_EXPIRE_IN = 900;
9872
+ /** Buffer time in milliseconds before expiry to trigger refresh. */
9873
+ const DEVICE_TOKEN_REFRESH_BUFFER_MS = 3e4;
9874
+ /** Maximum retry attempts for device token refresh on transient failure. */
9875
+ const DEVICE_TOKEN_REFRESH_MAX_RETRIES = 3;
9876
+ /** Base delay in milliseconds for exponential backoff on refresh retry. */
9877
+ const DEVICE_TOKEN_REFRESH_RETRY_BASE_MS = 1e3;
9865
9878
  /** JSON-RPC error code for requester validation failure (corrupted auth state). */
9866
9879
  const RPC_ERROR_REQUESTER_VALIDATION_FAILED = -32003;
9867
9880
  /** JSON-RPC error code for invalid params (e.g., missing authentication block). */
@@ -9952,7 +9965,7 @@ function fromMsToSec(milliseconds) {
9952
9965
 
9953
9966
  //#endregion
9954
9967
  //#region src/containers/PreferencesContainer.ts
9955
- const logger$27 = getLogger();
9968
+ const logger$28 = getLogger();
9956
9969
  var PreferencesContainer = class PreferencesContainer {
9957
9970
  static get instance() {
9958
9971
  this._instance ??= new PreferencesContainer();
@@ -10614,7 +10627,7 @@ var ClientPreferences = class {
10614
10627
  if (!this._storage) return;
10615
10628
  const data = collectStoredPreferences();
10616
10629
  this._storage.setItem(PREFERENCES_STORAGE_KEY, data, "local").catch((error) => {
10617
- logger$27.error(`[ClientPreferences] Failed to save preferences: ${String(error)}`);
10630
+ logger$28.error(`[ClientPreferences] Failed to save preferences: ${String(error)}`);
10618
10631
  });
10619
10632
  }
10620
10633
  /** Loads preferences from storage and applies them to the container. */
@@ -10623,15 +10636,15 @@ var ClientPreferences = class {
10623
10636
  this._storage.getItem(PREFERENCES_STORAGE_KEY, "local").then((stored) => {
10624
10637
  if (stored) applyStoredPreferences(stored);
10625
10638
  }).catch((error) => {
10626
- logger$27.error(`[ClientPreferences] Failed to load preferences: ${String(error)}`);
10639
+ logger$28.error(`[ClientPreferences] Failed to load preferences: ${String(error)}`);
10627
10640
  });
10628
10641
  }
10629
10642
  };
10630
10643
 
10631
10644
  //#endregion
10632
10645
  //#region src/controllers/NavigatorDeviceController.ts
10633
- var import_cjs$25 = require_cjs();
10634
- const logger$26 = getLogger();
10646
+ var import_cjs$26 = require_cjs();
10647
+ const logger$27 = getLogger();
10635
10648
  /** Maps a device kind to its storage key. */
10636
10649
  const DEVICE_STORAGE_KEYS = {
10637
10650
  audioinput: DEVICE_STORAGE_KEY_AUDIO_INPUT,
@@ -10653,7 +10666,7 @@ var NavigatorDeviceController = class extends Destroyable {
10653
10666
  super();
10654
10667
  this.webRTCApiProvider = webRTCApiProvider;
10655
10668
  this.deviceChangeHandler = () => {
10656
- logger$26.debug("[DeviceController] Device change detected");
10669
+ logger$27.debug("[DeviceController] Device change detected");
10657
10670
  this.enumerateDevices();
10658
10671
  };
10659
10672
  this._devicesState$ = this.createBehaviorSubject(initialDevicesState);
@@ -10690,17 +10703,17 @@ var NavigatorDeviceController = class extends Destroyable {
10690
10703
  return {};
10691
10704
  }
10692
10705
  get errors$() {
10693
- return this.cachedObservable("errors$", () => this._errors$.asObservable().pipe((0, import_cjs$25.takeUntil)(this.destroyed$)));
10706
+ return this.cachedObservable("errors$", () => this._errors$.asObservable().pipe((0, import_cjs$26.takeUntil)(this.destroyed$)));
10694
10707
  }
10695
10708
  /** Observable that emits when the SDK auto-switches a device. */
10696
10709
  get deviceRecovered$() {
10697
- return this._deviceRecovered$.asObservable().pipe((0, import_cjs$25.takeUntil)(this.destroyed$));
10710
+ return this._deviceRecovered$.asObservable().pipe((0, import_cjs$26.takeUntil)(this.destroyed$));
10698
10711
  }
10699
10712
  get videoInputDisabled$() {
10700
- return this.cachedObservable("videoInputDisabled$", () => this._videoInputDisabled$.asObservable().pipe((0, import_cjs$25.distinctUntilChanged)(), (0, import_cjs$25.takeUntil)(this.destroyed$)));
10713
+ return this.cachedObservable("videoInputDisabled$", () => this._videoInputDisabled$.asObservable().pipe((0, import_cjs$26.distinctUntilChanged)(), (0, import_cjs$26.takeUntil)(this.destroyed$)));
10701
10714
  }
10702
10715
  get audioInputDisabled$() {
10703
- return this.cachedObservable("audioInputDisabled$", () => this._audioInputDisabled$.asObservable().pipe((0, import_cjs$25.distinctUntilChanged)(), (0, import_cjs$25.takeUntil)(this.destroyed$)));
10716
+ return this.cachedObservable("audioInputDisabled$", () => this._audioInputDisabled$.asObservable().pipe((0, import_cjs$26.distinctUntilChanged)(), (0, import_cjs$26.takeUntil)(this.destroyed$)));
10704
10717
  }
10705
10718
  get videoInputDisabled() {
10706
10719
  return this._videoInputDisabled$.value;
@@ -10709,22 +10722,22 @@ var NavigatorDeviceController = class extends Destroyable {
10709
10722
  return this._audioInputDisabled$.value;
10710
10723
  }
10711
10724
  get audioInputDevices$() {
10712
- return this.cachedObservable("audioInputDevices$", () => this._devicesState$.pipe((0, import_cjs$25.map)((state) => state.audioinput), (0, import_cjs$25.distinctUntilChanged)(), (0, import_cjs$25.takeUntil)(this.destroyed$)));
10725
+ return this.cachedObservable("audioInputDevices$", () => this._devicesState$.pipe((0, import_cjs$26.map)((state) => state.audioinput), (0, import_cjs$26.distinctUntilChanged)(), (0, import_cjs$26.takeUntil)(this.destroyed$)));
10713
10726
  }
10714
10727
  get audioOutputDevices$() {
10715
- return this.cachedObservable("audioOutputDevices$", () => this._devicesState$.pipe((0, import_cjs$25.map)((state) => state.audiooutput), (0, import_cjs$25.distinctUntilChanged)(), (0, import_cjs$25.takeUntil)(this.destroyed$)));
10728
+ return this.cachedObservable("audioOutputDevices$", () => this._devicesState$.pipe((0, import_cjs$26.map)((state) => state.audiooutput), (0, import_cjs$26.distinctUntilChanged)(), (0, import_cjs$26.takeUntil)(this.destroyed$)));
10716
10729
  }
10717
10730
  get videoInputDevices$() {
10718
- return this.cachedObservable("videoInputDevices$", () => this._devicesState$.pipe((0, import_cjs$25.map)((state) => state.videoinput), (0, import_cjs$25.distinctUntilChanged)(), (0, import_cjs$25.takeUntil)(this.destroyed$)));
10731
+ return this.cachedObservable("videoInputDevices$", () => this._devicesState$.pipe((0, import_cjs$26.map)((state) => state.videoinput), (0, import_cjs$26.distinctUntilChanged)(), (0, import_cjs$26.takeUntil)(this.destroyed$)));
10719
10732
  }
10720
10733
  get selectedAudioInputDevice$() {
10721
- return this.cachedObservable("selectedAudioInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$25.map)((state) => state.audioinput), (0, import_cjs$25.distinctUntilChanged)(), (0, import_cjs$25.takeUntil)(this.destroyed$), (0, import_cjs$25.tap)((info) => logger$26.debug("[DeviceController] Selected audio input device changed:", info))));
10734
+ return this.cachedObservable("selectedAudioInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$26.map)((state) => state.audioinput), (0, import_cjs$26.distinctUntilChanged)(), (0, import_cjs$26.takeUntil)(this.destroyed$), (0, import_cjs$26.tap)((info) => logger$27.debug("[DeviceController] Selected audio input device changed:", info))));
10722
10735
  }
10723
10736
  get selectedAudioOutputDevice$() {
10724
- return this.cachedObservable("selectedAudioOutputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$25.map)((state) => state.audiooutput), (0, import_cjs$25.distinctUntilChanged)(), (0, import_cjs$25.takeUntil)(this.destroyed$), (0, import_cjs$25.tap)((info) => logger$26.debug("[DeviceController] Selected audio output device changed:", info))));
10737
+ return this.cachedObservable("selectedAudioOutputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$26.map)((state) => state.audiooutput), (0, import_cjs$26.distinctUntilChanged)(), (0, import_cjs$26.takeUntil)(this.destroyed$), (0, import_cjs$26.tap)((info) => logger$27.debug("[DeviceController] Selected audio output device changed:", info))));
10725
10738
  }
10726
10739
  get selectedVideoInputDevice$() {
10727
- return this.cachedObservable("selectedVideoInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$25.map)((state) => state.videoinput), (0, import_cjs$25.distinctUntilChanged)(), (0, import_cjs$25.takeUntil)(this.destroyed$), (0, import_cjs$25.tap)((info) => logger$26.debug("[DeviceController] Selected video input device changed:", info))));
10740
+ return this.cachedObservable("selectedVideoInputDevice$", () => this._selectedDevicesState$.asObservable().pipe((0, import_cjs$26.map)((state) => state.videoinput), (0, import_cjs$26.distinctUntilChanged)(), (0, import_cjs$26.takeUntil)(this.destroyed$), (0, import_cjs$26.tap)((info) => logger$27.debug("[DeviceController] Selected video input device changed:", info))));
10728
10741
  }
10729
10742
  get selectedAudioInputDevice() {
10730
10743
  if (this._audioInputDisabled$.value) return null;
@@ -10799,7 +10812,7 @@ var NavigatorDeviceController = class extends Destroyable {
10799
10812
  if (device) this.persistDeviceSelection("audioinput", device);
10800
10813
  }
10801
10814
  selectVideoInputDevice(device) {
10802
- logger$26.debug("[DeviceController] Setting selected video input device:", device);
10815
+ logger$27.debug("[DeviceController] Setting selected video input device:", device);
10803
10816
  if (this._videoInputDisabled$.value && device) this._videoInputDisabled$.next(false);
10804
10817
  const previous = this._selectedDevicesState$.value.videoinput;
10805
10818
  if (previous && previous.deviceId !== device?.deviceId) this._deviceHistory.push("videoinput", previous);
@@ -10820,7 +10833,7 @@ var NavigatorDeviceController = class extends Destroyable {
10820
10833
  }
10821
10834
  init() {
10822
10835
  this.loadPersistedDevices();
10823
- this.subscribeTo(this._devicesState$.pipe((0, import_cjs$25.debounceTime)(PreferencesContainer.instance.deviceDebounceTime)), (devicesState) => {
10836
+ this.subscribeTo(this._devicesState$.pipe((0, import_cjs$26.debounceTime)(PreferencesContainer.instance.deviceDebounceTime)), (devicesState) => {
10824
10837
  const currentSelected = this._selectedDevicesState$.value;
10825
10838
  const newAudioInput = this._audioInputDisabled$.value ? null : this.resolveDevice("audioinput", devicesState.audioinput, currentSelected.audioinput, PreferencesContainer.instance.preferredAudioInput);
10826
10839
  const newAudioOutput = this.resolveDevice("audiooutput", devicesState.audiooutput, currentSelected.audiooutput, PreferencesContainer.instance.preferredAudioOutput);
@@ -10856,7 +10869,7 @@ var NavigatorDeviceController = class extends Destroyable {
10856
10869
  }
10857
10870
  const fromHistory = this._deviceHistory.findInHistory(kind, devices);
10858
10871
  if (fromHistory) {
10859
- logger$26.debug(`[DeviceController] Device disappeared, falling back to history: ${fromHistory.label}`);
10872
+ logger$27.debug(`[DeviceController] Device disappeared, falling back to history: ${fromHistory.label}`);
10860
10873
  this.emitDeviceRecovered(kind, selected, fromHistory, "device_disconnected");
10861
10874
  return fromHistory;
10862
10875
  }
@@ -10909,7 +10922,7 @@ var NavigatorDeviceController = class extends Destroyable {
10909
10922
  try {
10910
10923
  await this._storageManager.setItem(DEVICE_STORAGE_KEYS[kind], stored, "local");
10911
10924
  } catch (error) {
10912
- logger$26.error(`[DeviceController] Failed to persist device selection for ${kind}:`, error);
10925
+ logger$27.error(`[DeviceController] Failed to persist device selection for ${kind}:`, error);
10913
10926
  }
10914
10927
  }
10915
10928
  async loadPersistedDevices() {
@@ -10925,7 +10938,7 @@ var NavigatorDeviceController = class extends Destroyable {
10925
10938
  [kind]: stored
10926
10939
  };
10927
10940
  } catch (error) {
10928
- logger$26.error(`[DeviceController] Failed to load persisted device for ${kind}:`, error);
10941
+ logger$27.error(`[DeviceController] Failed to load persisted device for ${kind}:`, error);
10929
10942
  }
10930
10943
  }
10931
10944
  /** Clears device history, persisted selections, and re-enumerates devices. */
@@ -10942,8 +10955,8 @@ var NavigatorDeviceController = class extends Destroyable {
10942
10955
  enableDeviceMonitoring() {
10943
10956
  this.disableDeviceMonitoring();
10944
10957
  this.webRTCApiProvider.mediaDevices.addEventListener("devicechange", this.deviceChangeHandler);
10945
- if (PreferencesContainer.instance.devicePollingInterval > 0) this._devicesPoolingSubscription = (0, import_cjs$25.interval)(PreferencesContainer.instance.devicePollingInterval).subscribe(() => {
10946
- logger$26.debug("[DeviceController] Polling devices due to interval");
10958
+ if (PreferencesContainer.instance.devicePollingInterval > 0) this._devicesPoolingSubscription = (0, import_cjs$26.interval)(PreferencesContainer.instance.devicePollingInterval).subscribe(() => {
10959
+ logger$27.debug("[DeviceController] Polling devices due to interval");
10947
10960
  this.enumerateDevices();
10948
10961
  });
10949
10962
  this.enumerateDevices();
@@ -10969,13 +10982,13 @@ var NavigatorDeviceController = class extends Destroyable {
10969
10982
  videoinput: []
10970
10983
  });
10971
10984
  this._devicesState$.next(devicesByKind);
10972
- logger$26.debug("[DeviceController] Devices enumerated:", {
10985
+ logger$27.debug("[DeviceController] Devices enumerated:", {
10973
10986
  audioInputs: devicesByKind.audioinput.length,
10974
10987
  audioOutputs: devicesByKind.audiooutput.length,
10975
10988
  videoInputs: devicesByKind.videoinput.length
10976
10989
  });
10977
10990
  } catch (error) {
10978
- logger$26.error("[DeviceController] Failed to enumerate devices:", error);
10991
+ logger$27.error("[DeviceController] Failed to enumerate devices:", error);
10979
10992
  this._errors$.next(error);
10980
10993
  }
10981
10994
  }
@@ -10991,7 +11004,7 @@ var NavigatorDeviceController = class extends Destroyable {
10991
11004
  stream.getTracks().forEach((t) => t.stop());
10992
11005
  return capabilities;
10993
11006
  } catch (error) {
10994
- logger$26.error("[DeviceController] Failed to get device capabilities:", error);
11007
+ logger$27.error("[DeviceController] Failed to get device capabilities:", error);
10995
11008
  this._errors$.next(error);
10996
11009
  throw error;
10997
11010
  }
@@ -11242,7 +11255,7 @@ var DependencyContainer = class {
11242
11255
 
11243
11256
  //#endregion
11244
11257
  //#region src/controllers/CryptoController.ts
11245
- const logger$25 = getLogger();
11258
+ const logger$26 = getLogger();
11246
11259
  const DPOP_DB_NAME = "sw-dpop";
11247
11260
  const DPOP_DB_VERSION = 1;
11248
11261
  const DPOP_STORE_NAME = "keys";
@@ -11301,7 +11314,7 @@ async function loadKeyPairFromDB() {
11301
11314
  tx.oncomplete = () => db.close();
11302
11315
  });
11303
11316
  } catch (error) {
11304
- logger$25.warn("[DPoP] Failed to load key pair from IndexedDB:", error);
11317
+ logger$26.warn("[DPoP] Failed to load key pair from IndexedDB:", error);
11305
11318
  return null;
11306
11319
  }
11307
11320
  }
@@ -11321,7 +11334,7 @@ async function saveKeyPairToDB(keyPair) {
11321
11334
  };
11322
11335
  });
11323
11336
  } catch (error) {
11324
- logger$25.warn("[DPoP] Failed to save key pair to IndexedDB:", error);
11337
+ logger$26.warn("[DPoP] Failed to save key pair to IndexedDB:", error);
11325
11338
  }
11326
11339
  }
11327
11340
  async function deleteKeyPairFromDB() {
@@ -11340,7 +11353,7 @@ async function deleteKeyPairFromDB() {
11340
11353
  };
11341
11354
  });
11342
11355
  } catch (error) {
11343
- logger$25.warn("[DPoP] Failed to delete key pair from IndexedDB:", error);
11356
+ logger$26.warn("[DPoP] Failed to delete key pair from IndexedDB:", error);
11344
11357
  }
11345
11358
  }
11346
11359
  /**
@@ -11400,13 +11413,13 @@ var CryptoController = class {
11400
11413
  this._publicJwk = await crypto.subtle.exportKey("jwk", stored.publicKey);
11401
11414
  this._fingerprint = await computeJwkThumbprint(this._publicJwk);
11402
11415
  this._initialized = true;
11403
- logger$25.debug("[DPoP] Key pair restored from IndexedDB, fingerprint:", this._fingerprint);
11416
+ logger$26.debug("[DPoP] Key pair restored from IndexedDB, fingerprint:", this._fingerprint);
11404
11417
  return this._fingerprint;
11405
11418
  } catch (error) {
11406
- logger$25.warn("[DPoP] Stored key pair unusable, generating new one:", error);
11419
+ logger$26.warn("[DPoP] Stored key pair unusable, generating new one:", error);
11407
11420
  await deleteKeyPairFromDB();
11408
11421
  }
11409
- logger$25.debug("[DPoP] Generating RSA key pair");
11422
+ logger$26.debug("[DPoP] Generating RSA key pair");
11410
11423
  this._keyPair = await crypto.subtle.generateKey({
11411
11424
  name: "RSASSA-PKCS1-v1_5",
11412
11425
  modulusLength: 2048,
@@ -11421,7 +11434,7 @@ var CryptoController = class {
11421
11434
  this._fingerprint = await computeJwkThumbprint(this._publicJwk);
11422
11435
  this._initialized = true;
11423
11436
  await saveKeyPairToDB(this._keyPair);
11424
- logger$25.debug("[DPoP] Key pair generated and persisted, fingerprint:", this._fingerprint);
11437
+ logger$26.debug("[DPoP] Key pair generated and persisted, fingerprint:", this._fingerprint);
11425
11438
  return this._fingerprint;
11426
11439
  }
11427
11440
  /**
@@ -11487,7 +11500,7 @@ var CryptoController = class {
11487
11500
  this._fingerprint = null;
11488
11501
  this._initialized = false;
11489
11502
  deleteKeyPairFromDB();
11490
- logger$25.debug("[DPoP] Controller destroyed");
11503
+ logger$26.debug("[DPoP] Controller destroyed");
11491
11504
  }
11492
11505
  get publicJwk() {
11493
11506
  if (!this._publicJwk) throw new DPoPInitError("CryptoController not initialized. Call init() first.");
@@ -11510,8 +11523,8 @@ var CryptoController = class {
11510
11523
 
11511
11524
  //#endregion
11512
11525
  //#region src/controllers/NetworkMonitor.ts
11513
- var import_cjs$24 = require_cjs();
11514
- const logger$24 = getLogger();
11526
+ var import_cjs$25 = require_cjs();
11527
+ const logger$25 = getLogger();
11515
11528
  /**
11516
11529
  * Safely check whether we are running in a browser environment
11517
11530
  * with `window` and the relevant event targets.
@@ -11554,13 +11567,13 @@ var NetworkMonitor = class extends Destroyable {
11554
11567
  this.attachListeners();
11555
11568
  }
11556
11569
  get isOnline$() {
11557
- return this._isOnline$.asObservable().pipe((0, import_cjs$24.takeUntil)(this._destroyed$));
11570
+ return this._isOnline$.asObservable().pipe((0, import_cjs$25.takeUntil)(this._destroyed$));
11558
11571
  }
11559
11572
  get isOnline() {
11560
11573
  return this._isOnline$.value;
11561
11574
  }
11562
11575
  get networkChange$() {
11563
- return this._networkChange$.asObservable().pipe((0, import_cjs$24.takeUntil)(this._destroyed$));
11576
+ return this._networkChange$.asObservable().pipe((0, import_cjs$25.takeUntil)(this._destroyed$));
11564
11577
  }
11565
11578
  destroy() {
11566
11579
  this.removeListeners();
@@ -11568,7 +11581,7 @@ var NetworkMonitor = class extends Destroyable {
11568
11581
  }
11569
11582
  attachListeners() {
11570
11583
  if (!hasBrowserNetworkEvents()) {
11571
- logger$24.debug("NetworkMonitor: no browser environment detected, skipping event listeners");
11584
+ logger$25.debug("NetworkMonitor: no browser environment detected, skipping event listeners");
11572
11585
  return;
11573
11586
  }
11574
11587
  window.addEventListener("online", this._onOnline);
@@ -11576,7 +11589,7 @@ var NetworkMonitor = class extends Destroyable {
11576
11589
  const connection = getNetworkConnection();
11577
11590
  if (connection) connection.addEventListener("change", this._onConnectionChange);
11578
11591
  this._listenersAttached = true;
11579
- logger$24.debug("NetworkMonitor: event listeners attached");
11592
+ logger$25.debug("NetworkMonitor: event listeners attached");
11580
11593
  }
11581
11594
  removeListeners() {
11582
11595
  if (!this._listenersAttached) return;
@@ -11587,10 +11600,10 @@ var NetworkMonitor = class extends Destroyable {
11587
11600
  if (connection) connection.removeEventListener("change", this._onConnectionChange);
11588
11601
  }
11589
11602
  this._listenersAttached = false;
11590
- logger$24.debug("NetworkMonitor: event listeners removed");
11603
+ logger$25.debug("NetworkMonitor: event listeners removed");
11591
11604
  }
11592
11605
  handleOnline() {
11593
- logger$24.info("NetworkMonitor: browser went online");
11606
+ logger$25.info("NetworkMonitor: browser went online");
11594
11607
  this._isOnline$.next(true);
11595
11608
  this._networkChange$.next({
11596
11609
  type: "online",
@@ -11599,7 +11612,7 @@ var NetworkMonitor = class extends Destroyable {
11599
11612
  });
11600
11613
  }
11601
11614
  handleOffline() {
11602
- logger$24.info("NetworkMonitor: browser went offline");
11615
+ logger$25.info("NetworkMonitor: browser went offline");
11603
11616
  this._isOnline$.next(false);
11604
11617
  this._networkChange$.next({
11605
11618
  type: "offline",
@@ -11608,7 +11621,7 @@ var NetworkMonitor = class extends Destroyable {
11608
11621
  }
11609
11622
  handleConnectionChange() {
11610
11623
  const networkType = getNetworkType();
11611
- logger$24.info(`NetworkMonitor: connection changed — effectiveType=${networkType ?? "unknown"}`);
11624
+ logger$25.info(`NetworkMonitor: connection changed — effectiveType=${networkType ?? "unknown"}`);
11612
11625
  this._networkChange$.next({
11613
11626
  type: "connection_change",
11614
11627
  timestamp: Date.now(),
@@ -11723,8 +11736,8 @@ function getNavigatorMediaDevices() {
11723
11736
 
11724
11737
  //#endregion
11725
11738
  //#region src/controllers/PreflightRunner.ts
11726
- var import_cjs$23 = require_cjs();
11727
- const logger$23 = getLogger();
11739
+ var import_cjs$24 = require_cjs();
11740
+ const logger$24 = getLogger();
11728
11741
  const DEFAULT_MEDIA_TEST_DURATION_S = 10;
11729
11742
  const ICE_GATHERING_TIMEOUT_MS = 1e4;
11730
11743
  const SIGNALING_RTT_TIMEOUT_MS = 5e3;
@@ -11773,7 +11786,7 @@ var PreflightRunner = class extends Destroyable {
11773
11786
  if (!this._options.skipMediaTest) try {
11774
11787
  bandwidth = await this.testMediaBandwidth(destination);
11775
11788
  } catch (error) {
11776
- logger$23.warn("[PreflightRunner] Media bandwidth test failed:", error);
11789
+ logger$24.warn("[PreflightRunner] Media bandwidth test failed:", error);
11777
11790
  warnings.push("Media bandwidth test failed");
11778
11791
  }
11779
11792
  return {
@@ -11785,7 +11798,7 @@ var PreflightRunner = class extends Destroyable {
11785
11798
  warnings
11786
11799
  };
11787
11800
  } catch (error) {
11788
- logger$23.error("[PreflightRunner] Preflight test failed:", error);
11801
+ logger$24.error("[PreflightRunner] Preflight test failed:", error);
11789
11802
  throw new PreflightError("preflight", error instanceof Error ? error : new Error(String(error)));
11790
11803
  } finally {
11791
11804
  this.destroy();
@@ -11816,7 +11829,7 @@ var PreflightRunner = class extends Destroyable {
11816
11829
  if (track.kind === "video" && track.readyState === "live") videoWorking = true;
11817
11830
  }
11818
11831
  } catch (error) {
11819
- logger$23.warn("[PreflightRunner] Device test failed:", error);
11832
+ logger$24.warn("[PreflightRunner] Device test failed:", error);
11820
11833
  } finally {
11821
11834
  if (audioStream) audioStream.getTracks().forEach((t) => t.stop());
11822
11835
  }
@@ -11843,7 +11856,7 @@ var PreflightRunner = class extends Destroyable {
11843
11856
  const candidateTypes = /* @__PURE__ */ new Set();
11844
11857
  const startTime = Date.now();
11845
11858
  const gatheringComplete = new Promise((resolve) => {
11846
- const timer$2 = setTimeout(resolve, ICE_GATHERING_TIMEOUT_MS);
11859
+ const timer$3 = setTimeout(resolve, ICE_GATHERING_TIMEOUT_MS);
11847
11860
  peerConnection.onicecandidate = (event) => {
11848
11861
  if (event.candidate) {
11849
11862
  const candidateStr = event.candidate.candidate;
@@ -11851,7 +11864,7 @@ var PreflightRunner = class extends Destroyable {
11851
11864
  if (candidateStr.includes("typ srflx")) candidateTypes.add("srflx");
11852
11865
  if (candidateStr.includes("typ relay")) candidateTypes.add("relay");
11853
11866
  } else {
11854
- clearTimeout(timer$2);
11867
+ clearTimeout(timer$3);
11855
11868
  resolve();
11856
11869
  }
11857
11870
  };
@@ -11874,7 +11887,7 @@ var PreflightRunner = class extends Destroyable {
11874
11887
  rttMs
11875
11888
  };
11876
11889
  } catch (error) {
11877
- logger$23.warn("[PreflightRunner] ICE connectivity test failed:", error);
11890
+ logger$24.warn("[PreflightRunner] ICE connectivity test failed:", error);
11878
11891
  return {
11879
11892
  type: "failed",
11880
11893
  turnReachable: false,
@@ -11892,7 +11905,7 @@ var PreflightRunner = class extends Destroyable {
11892
11905
  audio: true,
11893
11906
  video: false
11894
11907
  });
11895
- await (0, import_cjs$23.firstValueFrom)(call.status$.pipe((0, import_cjs$23.filter)((s) => s === "connected"), (0, import_cjs$23.take)(1), (0, import_cjs$23.timeout)(SIGNALING_RTT_TIMEOUT_MS)));
11908
+ await (0, import_cjs$24.firstValueFrom)(call.status$.pipe((0, import_cjs$24.filter)((s) => s === "connected"), (0, import_cjs$24.take)(1), (0, import_cjs$24.timeout)(SIGNALING_RTT_TIMEOUT_MS)));
11896
11909
  const durationMs = this._options.duration * 1e3;
11897
11910
  await new Promise((resolve) => setTimeout(resolve, durationMs));
11898
11911
  const metrics = call.networkMetrics;
@@ -11921,8 +11934,8 @@ var PreflightRunner = class extends Destroyable {
11921
11934
 
11922
11935
  //#endregion
11923
11936
  //#region src/controllers/VisibilityController.ts
11924
- var import_cjs$22 = require_cjs();
11925
- const logger$22 = getLogger();
11937
+ var import_cjs$23 = require_cjs();
11938
+ const logger$23 = getLogger();
11926
11939
  /**
11927
11940
  * Checks whether the document visibility API is available.
11928
11941
  */
@@ -11959,15 +11972,15 @@ var VisibilityController = class extends Destroyable {
11959
11972
  this._boundHandler = this._handleVisibilityChange.bind(this);
11960
11973
  if (this._hasVisibilityApi) {
11961
11974
  document.addEventListener("visibilitychange", this._boundHandler);
11962
- logger$22.debug("VisibilityController: listening for visibilitychange events");
11963
- } else logger$22.debug("VisibilityController: document visibility API not available, defaulting to visible");
11975
+ logger$23.debug("VisibilityController: listening for visibilitychange events");
11976
+ } else logger$23.debug("VisibilityController: document visibility API not available, defaulting to visible");
11964
11977
  }
11965
11978
  /**
11966
11979
  * Observable of the current visibility state.
11967
11980
  * Emits 'visible' or 'hidden'. Always starts with the current state.
11968
11981
  */
11969
11982
  get visibility$() {
11970
- return this._visibility$.pipe((0, import_cjs$22.takeUntil)(this._destroyed$));
11983
+ return this._visibility$.pipe((0, import_cjs$23.takeUntil)(this._destroyed$));
11971
11984
  }
11972
11985
  /**
11973
11986
  * The current visibility state value.
@@ -11980,12 +11993,12 @@ var VisibilityController = class extends Destroyable {
11980
11993
  * Each event includes the previous state, new state, and timestamp.
11981
11994
  */
11982
11995
  get visibilityChange$() {
11983
- return this._visibilityChange$.pipe((0, import_cjs$22.takeUntil)(this._destroyed$));
11996
+ return this._visibilityChange$.pipe((0, import_cjs$23.takeUntil)(this._destroyed$));
11984
11997
  }
11985
11998
  destroy() {
11986
11999
  if (this._hasVisibilityApi) {
11987
12000
  document.removeEventListener("visibilitychange", this._boundHandler);
11988
- logger$22.debug("VisibilityController: removed visibilitychange listener");
12001
+ logger$23.debug("VisibilityController: removed visibilitychange listener");
11989
12002
  }
11990
12003
  super.destroy();
11991
12004
  }
@@ -12003,7 +12016,7 @@ var VisibilityController = class extends Destroyable {
12003
12016
  timestamp: Date.now()
12004
12017
  };
12005
12018
  this._visibilityChange$.next(changeEvent);
12006
- logger$22.debug("VisibilityController: visibility changed", {
12019
+ logger$23.debug("VisibilityController: visibility changed", {
12007
12020
  from: previousState,
12008
12021
  to: newState
12009
12022
  });
@@ -12012,13 +12025,13 @@ var VisibilityController = class extends Destroyable {
12012
12025
 
12013
12026
  //#endregion
12014
12027
  //#region src/behaviors/Fetchable.ts
12015
- var import_cjs$21 = require_cjs();
12028
+ var import_cjs$22 = require_cjs();
12016
12029
  var Fetchable = class extends Destroyable {
12017
12030
  constructor(fromPath, http) {
12018
12031
  super();
12019
12032
  this.fromPath = fromPath;
12020
12033
  this.http = http;
12021
- this.fetched$ = (0, import_cjs$21.defer)(() => (0, import_cjs$21.from)(this.fetch())).pipe((0, import_cjs$21.shareReplay)(1), (0, import_cjs$21.takeUntil)(this.destroyed$));
12034
+ this.fetched$ = (0, import_cjs$22.defer)(() => (0, import_cjs$22.from)(this.fetch())).pipe((0, import_cjs$22.shareReplay)(1), (0, import_cjs$22.takeUntil)(this.destroyed$));
12022
12035
  }
12023
12036
  async fetch() {
12024
12037
  const response = await this.http.request({
@@ -12253,7 +12266,7 @@ const RPCEventAckResponse = (id) => makeRPCResponse({
12253
12266
 
12254
12267
  //#endregion
12255
12268
  //#region src/managers/AttachManager.ts
12256
- const logger$21 = getLogger();
12269
+ const logger$22 = getLogger();
12257
12270
  var AttachManager = class {
12258
12271
  constructor(storage, deviceController, reconnectCallsTimeout, attachKey) {
12259
12272
  this.storage = storage;
@@ -12265,6 +12278,7 @@ var AttachManager = class {
12265
12278
  const attached = await this.readAttached();
12266
12279
  for (const callId of Object.keys(attached)) await this.detach({
12267
12280
  id: callId,
12281
+ nodeId: attached[callId].nodeId,
12268
12282
  mediaDirections: attached[callId].mediaDirections
12269
12283
  });
12270
12284
  }
@@ -12275,7 +12289,7 @@ var AttachManager = class {
12275
12289
  try {
12276
12290
  return await this.storage.getItem(this.attachKey) ?? {};
12277
12291
  } catch (error) {
12278
- logger$21.warn("[AttachManager] Failed to retrieve attached calls from storage", error);
12292
+ logger$22.warn("[AttachManager] Failed to retrieve attached calls from storage", error);
12279
12293
  return {};
12280
12294
  }
12281
12295
  }
@@ -12283,20 +12297,20 @@ var AttachManager = class {
12283
12297
  try {
12284
12298
  await this.storage.setItem(this.attachKey, attached);
12285
12299
  } catch (error) {
12286
- logger$21.warn("[AttachManager] Failed to write attached calls to storage", error);
12300
+ logger$22.warn("[AttachManager] Failed to write attached calls to storage", error);
12287
12301
  }
12288
12302
  }
12289
12303
  async attach(call) {
12290
12304
  if (!call.to) {
12291
- logger$21.warn("[AttachManager] Skip attach for calls with no destination");
12305
+ logger$22.warn("[AttachManager] Skip attach for calls with no destination");
12292
12306
  return;
12293
12307
  }
12294
12308
  const attachment = {
12309
+ nodeId: call.nodeId,
12295
12310
  destination: call.to,
12296
12311
  mediaDirections: call.mediaDirections,
12297
12312
  audioInputDevice: call.mediaDirections.audio !== "inactive" ? this.deviceController.selectedAudioInputDevice : null,
12298
12313
  videoInputDevice: call.mediaDirections.video !== "inactive" ? this.deviceController.selectedVideoInputDevice : null,
12299
- nodeId: call.nodeId,
12300
12314
  attachedAt: Date.now()
12301
12315
  };
12302
12316
  const updated = {
@@ -12339,15 +12353,15 @@ var AttachManager = class {
12339
12353
  callId,
12340
12354
  ...options
12341
12355
  });
12342
- logger$21.info(`[AttachManager] Reattached call ${callId} (attempt ${attempt})`);
12356
+ logger$22.info(`[AttachManager] Reattached call ${callId} (attempt ${attempt})`);
12343
12357
  succeeded = true;
12344
12358
  break;
12345
12359
  } catch (error) {
12346
- logger$21.warn(`[AttachManager] Reattach attempt ${attempt}/3 failed for call ${callId}:`, error);
12360
+ logger$22.warn(`[AttachManager] Reattach attempt ${attempt}/3 failed for call ${callId}:`, error);
12347
12361
  if (attempt < 3) await new Promise((r) => setTimeout(r, (attempt + 1) * 1e3));
12348
12362
  }
12349
12363
  if (!succeeded) {
12350
- logger$21.warn(`[AttachManager] Reattach failed after 3 attempts for call ${callId}, removing reference`);
12364
+ logger$22.warn(`[AttachManager] Reattach failed after 3 attempts for call ${callId}, removing reference`);
12351
12365
  await this.detach({
12352
12366
  id: callId,
12353
12367
  mediaDirections: attachment.mediaDirections
@@ -12361,12 +12375,13 @@ var AttachManager = class {
12361
12375
  */
12362
12376
  buildCallOptions(attachment) {
12363
12377
  const { audio: audioDirection, video: videoDirection } = attachment.mediaDirections;
12364
- const { audioInputDevice, videoInputDevice } = attachment;
12378
+ const { audioInputDevice, videoInputDevice, nodeId } = attachment;
12365
12379
  const receiveAudio = audioDirection.includes("recv");
12366
12380
  const receiveVideo = videoDirection.includes("recv");
12367
12381
  const sendAudio = audioDirection.includes("send");
12368
12382
  const sendVideo = videoDirection.includes("send");
12369
12383
  return {
12384
+ nodeId,
12370
12385
  receiveAudio,
12371
12386
  receiveVideo,
12372
12387
  inputAudioDeviceConstraints: sendAudio ? {
@@ -12377,7 +12392,6 @@ var AttachManager = class {
12377
12392
  video: true,
12378
12393
  ...this.deviceController.deviceInfoToConstraints(videoInputDevice)
12379
12394
  } : void 0,
12380
- nodeId: attachment.nodeId ?? void 0,
12381
12395
  reattach: true
12382
12396
  };
12383
12397
  }
@@ -13253,7 +13267,7 @@ var require_operators = /* @__PURE__ */ __commonJSMin(((exports) => {
13253
13267
  //#endregion
13254
13268
  //#region src/operators/filterNull.ts
13255
13269
  var import_operators$1 = require_operators();
13256
- var import_cjs$20 = require_cjs();
13270
+ var import_cjs$21 = require_cjs();
13257
13271
  /**
13258
13272
  * RxJS operator that filters out `null` and `undefined` values with type narrowing.
13259
13273
  *
@@ -13265,7 +13279,7 @@ var import_cjs$20 = require_cjs();
13265
13279
  * ```
13266
13280
  */
13267
13281
  function filterNull() {
13268
- return (0, import_cjs$20.filter)((value) => value != null);
13282
+ return (0, import_cjs$21.filter)((value) => value != null);
13269
13283
  }
13270
13284
 
13271
13285
  //#endregion
@@ -13393,7 +13407,7 @@ function computeCapabilities(capabilities) {
13393
13407
 
13394
13408
  //#endregion
13395
13409
  //#region src/core/capabilities/SelfCapabilities.ts
13396
- var import_cjs$19 = require_cjs();
13410
+ var import_cjs$20 = require_cjs();
13397
13411
  /**
13398
13412
  * SelfCapabilities manages the capability state for the self participant.
13399
13413
  *
@@ -13429,7 +13443,7 @@ var SelfCapabilities = class extends Destroyable {
13429
13443
  }
13430
13444
  /** Observable for self member capabilities */
13431
13445
  get self$() {
13432
- return this.cachedObservable("self$", () => this._state$.pipe((0, import_cjs$19.map)((state) => state.self), (0, import_cjs$19.distinctUntilChanged)()));
13446
+ return this.cachedObservable("self$", () => this._state$.pipe((0, import_cjs$20.map)((state) => state.self), (0, import_cjs$20.distinctUntilChanged)()));
13433
13447
  }
13434
13448
  /** Current self member capabilities */
13435
13449
  get self() {
@@ -13437,7 +13451,7 @@ var SelfCapabilities = class extends Destroyable {
13437
13451
  }
13438
13452
  /** Observable for other member capabilities */
13439
13453
  get member$() {
13440
- return this.cachedObservable("member$", () => this._state$.pipe((0, import_cjs$19.map)((state) => state.member), (0, import_cjs$19.distinctUntilChanged)()));
13454
+ return this.cachedObservable("member$", () => this._state$.pipe((0, import_cjs$20.map)((state) => state.member), (0, import_cjs$20.distinctUntilChanged)()));
13441
13455
  }
13442
13456
  /** Current other member capabilities */
13443
13457
  get member() {
@@ -13445,7 +13459,7 @@ var SelfCapabilities = class extends Destroyable {
13445
13459
  }
13446
13460
  /** Observable for end call capability */
13447
13461
  get end$() {
13448
- return this.cachedObservable("end$", () => this._state$.pipe((0, import_cjs$19.map)((state) => state.end), (0, import_cjs$19.distinctUntilChanged)()));
13462
+ return this.cachedObservable("end$", () => this._state$.pipe((0, import_cjs$20.map)((state) => state.end), (0, import_cjs$20.distinctUntilChanged)()));
13449
13463
  }
13450
13464
  /** Current end call capability */
13451
13465
  get end() {
@@ -13453,7 +13467,7 @@ var SelfCapabilities = class extends Destroyable {
13453
13467
  }
13454
13468
  /** Observable for set layout capability */
13455
13469
  get setLayout$() {
13456
- return this.cachedObservable("setLayout$", () => this._state$.pipe((0, import_cjs$19.map)((state) => state.setLayout), (0, import_cjs$19.distinctUntilChanged)()));
13470
+ return this.cachedObservable("setLayout$", () => this._state$.pipe((0, import_cjs$20.map)((state) => state.setLayout), (0, import_cjs$20.distinctUntilChanged)()));
13457
13471
  }
13458
13472
  /** Current set layout capability */
13459
13473
  get setLayout() {
@@ -13461,7 +13475,7 @@ var SelfCapabilities = class extends Destroyable {
13461
13475
  }
13462
13476
  /** Observable for send digit capability */
13463
13477
  get sendDigit$() {
13464
- return this.cachedObservable("sendDigit$", () => this._state$.pipe((0, import_cjs$19.map)((state) => state.sendDigit), (0, import_cjs$19.distinctUntilChanged)()));
13478
+ return this.cachedObservable("sendDigit$", () => this._state$.pipe((0, import_cjs$20.map)((state) => state.sendDigit), (0, import_cjs$20.distinctUntilChanged)()));
13465
13479
  }
13466
13480
  /** Current send digit capability */
13467
13481
  get sendDigit() {
@@ -13469,7 +13483,7 @@ var SelfCapabilities = class extends Destroyable {
13469
13483
  }
13470
13484
  /** Observable for vmuted hide capability */
13471
13485
  get vmutedHide$() {
13472
- return this.cachedObservable("vmutedHide$", () => this._state$.pipe((0, import_cjs$19.map)((state) => state.vmutedHide), (0, import_cjs$19.distinctUntilChanged)()));
13486
+ return this.cachedObservable("vmutedHide$", () => this._state$.pipe((0, import_cjs$20.map)((state) => state.vmutedHide), (0, import_cjs$20.distinctUntilChanged)()));
13473
13487
  }
13474
13488
  /** Current vmuted hide capability */
13475
13489
  get vmutedHide() {
@@ -13477,7 +13491,7 @@ var SelfCapabilities = class extends Destroyable {
13477
13491
  }
13478
13492
  /** Observable for lock capability */
13479
13493
  get lock$() {
13480
- return this.cachedObservable("lock$", () => this._state$.pipe((0, import_cjs$19.map)((state) => state.lock), (0, import_cjs$19.distinctUntilChanged)()));
13494
+ return this.cachedObservable("lock$", () => this._state$.pipe((0, import_cjs$20.map)((state) => state.lock), (0, import_cjs$20.distinctUntilChanged)()));
13481
13495
  }
13482
13496
  /** Current lock capability */
13483
13497
  get lock() {
@@ -13485,7 +13499,7 @@ var SelfCapabilities = class extends Destroyable {
13485
13499
  }
13486
13500
  /** Observable for device capability */
13487
13501
  get device$() {
13488
- return this.cachedObservable("device$", () => this._state$.pipe((0, import_cjs$19.map)((state) => state.device), (0, import_cjs$19.distinctUntilChanged)()));
13502
+ return this.cachedObservable("device$", () => this._state$.pipe((0, import_cjs$20.map)((state) => state.device), (0, import_cjs$20.distinctUntilChanged)()));
13489
13503
  }
13490
13504
  /** Current device capability */
13491
13505
  get device() {
@@ -13493,7 +13507,7 @@ var SelfCapabilities = class extends Destroyable {
13493
13507
  }
13494
13508
  /** Observable for screenshare capability */
13495
13509
  get screenshare$() {
13496
- return this.cachedObservable("screenshare$", () => this._state$.pipe((0, import_cjs$19.map)((state) => state.screenshare), (0, import_cjs$19.distinctUntilChanged)()));
13510
+ return this.cachedObservable("screenshare$", () => this._state$.pipe((0, import_cjs$20.map)((state) => state.screenshare), (0, import_cjs$20.distinctUntilChanged)()));
13497
13511
  }
13498
13512
  /** Current screenshare capability */
13499
13513
  get screenshare() {
@@ -13520,7 +13534,7 @@ function toggleHandraiseMethod(is) {
13520
13534
 
13521
13535
  //#endregion
13522
13536
  //#region src/core/entities/Participant.ts
13523
- const logger$20 = getLogger();
13537
+ const logger$21 = getLogger();
13524
13538
  const initialState = {};
13525
13539
  /**
13526
13540
  * Represents a participant in a call.
@@ -13898,7 +13912,7 @@ var SelfParticipant = class extends Participant {
13898
13912
  try {
13899
13913
  await this.vertoManager.addScreenMedia();
13900
13914
  } catch (error) {
13901
- logger$20.error("[Participant.startScreenShare] Screen share error:", error);
13915
+ logger$21.error("[Participant.startScreenShare] Screen share error:", error);
13902
13916
  }
13903
13917
  }
13904
13918
  /** Observable of the current screen share status. */
@@ -13918,7 +13932,7 @@ var SelfParticipant = class extends Participant {
13918
13932
  try {
13919
13933
  await this.vertoManager.addInputDevice(options);
13920
13934
  } catch (error) {
13921
- logger$20.error("[Participant.startScreenShare] Screen share error:", error);
13935
+ logger$21.error("[Participant.startScreenShare] Screen share error:", error);
13922
13936
  }
13923
13937
  }
13924
13938
  /** Removes an additional media input device by ID. */
@@ -13980,7 +13994,7 @@ var SelfParticipant = class extends Participant {
13980
13994
  */
13981
13995
  exitStudioModeIfActive() {
13982
13996
  if (this._studioAudio$.value) {
13983
- logger$20.debug("[SelfParticipant] Exiting studio audio mode due to individual flag toggle");
13997
+ logger$21.debug("[SelfParticipant] Exiting studio audio mode due to individual flag toggle");
13984
13998
  this._studioAudio$.next(false);
13985
13999
  }
13986
14000
  }
@@ -14004,7 +14018,7 @@ var SelfParticipant = class extends Participant {
14004
14018
  try {
14005
14019
  await super.mute();
14006
14020
  } catch (error) {
14007
- logger$20.warn("[Participant.toggleAudioInput] Server Error while muting audio input, proceeding with local toggle anyway", error);
14021
+ logger$21.warn("[Participant.toggleAudioInput] Server Error while muting audio input, proceeding with local toggle anyway", error);
14008
14022
  } finally {
14009
14023
  this.vertoManager.muteMainAudioInputDevice();
14010
14024
  }
@@ -14014,7 +14028,7 @@ var SelfParticipant = class extends Participant {
14014
14028
  try {
14015
14029
  await super.unmute();
14016
14030
  } catch (error) {
14017
- logger$20.warn("[Participant.toggleAudioInput] Server Error while unmuting audio input, proceeding with local toggle anyway", error);
14031
+ logger$21.warn("[Participant.toggleAudioInput] Server Error while unmuting audio input, proceeding with local toggle anyway", error);
14018
14032
  } finally {
14019
14033
  await this.vertoManager.unmuteMainAudioInputDevice();
14020
14034
  }
@@ -14024,7 +14038,7 @@ var SelfParticipant = class extends Participant {
14024
14038
  try {
14025
14039
  await super.muteVideo();
14026
14040
  } catch (error) {
14027
- logger$20.warn("[Participant.toggleVideoInput] Server Error while muting video input, proceeding with local toggle anyway", error);
14041
+ logger$21.warn("[Participant.toggleVideoInput] Server Error while muting video input, proceeding with local toggle anyway", error);
14028
14042
  } finally {
14029
14043
  this.vertoManager.muteMainVideoInputDevice();
14030
14044
  }
@@ -14034,7 +14048,7 @@ var SelfParticipant = class extends Participant {
14034
14048
  try {
14035
14049
  await super.unmuteVideo();
14036
14050
  } catch (error) {
14037
- logger$20.warn("[Participant.toggleVideoInput] Server Error while unmuting video input, proceeding with local toggle anyway", error);
14051
+ logger$21.warn("[Participant.toggleVideoInput] Server Error while unmuting video input, proceeding with local toggle anyway", error);
14038
14052
  } finally {
14039
14053
  await this.vertoManager.unmuteMainVideoInputDevice();
14040
14054
  }
@@ -14138,7 +14152,7 @@ const getValueFrom = (obj, path, defaultValue) => {
14138
14152
 
14139
14153
  //#endregion
14140
14154
  //#region src/operators/filterEventAs.ts
14141
- var import_cjs$18 = require_cjs();
14155
+ var import_cjs$19 = require_cjs();
14142
14156
  var import_operators = require_operators();
14143
14157
  /**
14144
14158
  * RxJS operator that filters events based on a predicate and maps matching events.
@@ -14172,7 +14186,7 @@ var import_operators = require_operators();
14172
14186
  * ```
14173
14187
  */
14174
14188
  function ifIsMap(predicate, mapFn) {
14175
- return (0, import_cjs$18.pipe)((0, import_operators.filter)(predicate), (0, import_operators.map)(mapFn));
14189
+ return (0, import_cjs$19.pipe)((0, import_operators.filter)(predicate), (0, import_operators.map)(mapFn));
14176
14190
  }
14177
14191
  /**
14178
14192
  * Generic RxJS operator that filters events using a type guard and extracts a property.
@@ -14214,38 +14228,38 @@ function ifIsMap(predicate, mapFn) {
14214
14228
  * ```
14215
14229
  */
14216
14230
  function filterAs(predicate, resultPath) {
14217
- return (0, import_cjs$18.pipe)(ifIsMap(predicate, (event) => {
14231
+ return (0, import_cjs$19.pipe)(ifIsMap(predicate, (event) => {
14218
14232
  return getValueFrom(event, resultPath);
14219
14233
  }), (0, import_operators.filter)((value) => value !== void 0));
14220
14234
  }
14221
14235
 
14222
14236
  //#endregion
14223
14237
  //#region src/operators/throwOnRPCError.ts
14224
- var import_cjs$17 = require_cjs();
14225
- const logger$19 = getLogger();
14238
+ var import_cjs$18 = require_cjs();
14239
+ const logger$20 = getLogger();
14226
14240
  /**
14227
14241
  * RxJS operator that throws a {@link JSONRPCError} when the RPC response contains an error.
14228
14242
  * Passes successful responses through unchanged.
14229
14243
  */
14230
14244
  function throwOnRPCError() {
14231
- return (0, import_cjs$17.map)((response) => {
14245
+ return (0, import_cjs$18.map)((response) => {
14232
14246
  if (response.error) {
14233
- logger$19.error("[throwOnRPCError] RPC error response:", {
14247
+ logger$20.error("[throwOnRPCError] RPC error response:", {
14234
14248
  code: response.error.code,
14235
14249
  message: response.error.message,
14236
14250
  data: response.error.data
14237
14251
  });
14238
14252
  throw new JSONRPCError(response.error.code, response.error.message, response.error.data);
14239
14253
  }
14240
- logger$19.debug("[throwOnRPCError] RPC successful response:", response);
14254
+ logger$20.debug("[throwOnRPCError] RPC successful response:", response);
14241
14255
  return response;
14242
14256
  });
14243
14257
  }
14244
14258
 
14245
14259
  //#endregion
14246
14260
  //#region src/managers/CallEventsManager.ts
14247
- var import_cjs$16 = require_cjs();
14248
- const logger$18 = getLogger();
14261
+ var import_cjs$17 = require_cjs();
14262
+ const logger$19 = getLogger();
14249
14263
  const initialSessionState = {};
14250
14264
  /** @internal */
14251
14265
  var CallEventsManager = class extends Destroyable {
@@ -14261,7 +14275,7 @@ var CallEventsManager = class extends Destroyable {
14261
14275
  this.initSubscriptions();
14262
14276
  }
14263
14277
  get participants$() {
14264
- return this.cachedObservable("participants$", () => this._participants$.asObservable().pipe((0, import_cjs$16.map)((participantsRecord) => Object.values(participantsRecord))));
14278
+ return this.cachedObservable("participants$", () => this._participants$.asObservable().pipe((0, import_cjs$17.map)((participantsRecord) => Object.values(participantsRecord))));
14265
14279
  }
14266
14280
  get participants() {
14267
14281
  return Object.values(this._participants$.value);
@@ -14279,40 +14293,40 @@ var CallEventsManager = class extends Destroyable {
14279
14293
  return this.callIds.has(callId);
14280
14294
  }
14281
14295
  get recording$() {
14282
- return this.cachedObservable("recording$", () => this._sessionState$.pipe((0, import_cjs$16.map)((state) => state.recording), (0, import_cjs$16.distinctUntilChanged)(), filterNull()));
14296
+ return this.cachedObservable("recording$", () => this._sessionState$.pipe((0, import_cjs$17.map)((state) => state.recording), (0, import_cjs$17.distinctUntilChanged)(), filterNull()));
14283
14297
  }
14284
14298
  get recordings$() {
14285
- return this.cachedObservable("recordings$", () => this._sessionState$.pipe((0, import_cjs$16.map)((state) => state.recordings), (0, import_cjs$16.distinctUntilChanged)(), filterNull()));
14299
+ return this.cachedObservable("recordings$", () => this._sessionState$.pipe((0, import_cjs$17.map)((state) => state.recordings), (0, import_cjs$17.distinctUntilChanged)(), filterNull()));
14286
14300
  }
14287
14301
  get streaming$() {
14288
- return this.cachedObservable("streaming$", () => this._sessionState$.pipe((0, import_cjs$16.map)((state) => state.streaming), (0, import_cjs$16.distinctUntilChanged)(), filterNull()));
14302
+ return this.cachedObservable("streaming$", () => this._sessionState$.pipe((0, import_cjs$17.map)((state) => state.streaming), (0, import_cjs$17.distinctUntilChanged)(), filterNull()));
14289
14303
  }
14290
14304
  get streams$() {
14291
- return this.cachedObservable("streams$", () => this._sessionState$.pipe((0, import_cjs$16.map)((state) => state.streams), (0, import_cjs$16.distinctUntilChanged)(), filterNull()));
14305
+ return this.cachedObservable("streams$", () => this._sessionState$.pipe((0, import_cjs$17.map)((state) => state.streams), (0, import_cjs$17.distinctUntilChanged)(), filterNull()));
14292
14306
  }
14293
14307
  get playbacks$() {
14294
- return this.cachedObservable("playbacks$", () => this._sessionState$.pipe((0, import_cjs$16.map)((state) => state.playbacks), (0, import_cjs$16.distinctUntilChanged)(), filterNull()));
14308
+ return this.cachedObservable("playbacks$", () => this._sessionState$.pipe((0, import_cjs$17.map)((state) => state.playbacks), (0, import_cjs$17.distinctUntilChanged)(), filterNull()));
14295
14309
  }
14296
14310
  get raiseHandPriority$() {
14297
- return this.cachedObservable("raiseHandPriority$", () => this._sessionState$.pipe((0, import_cjs$16.map)((state) => state.prioritize_handraise), (0, import_cjs$16.distinctUntilChanged)(), filterNull()));
14311
+ return this.cachedObservable("raiseHandPriority$", () => this._sessionState$.pipe((0, import_cjs$17.map)((state) => state.prioritize_handraise), (0, import_cjs$17.distinctUntilChanged)(), filterNull()));
14298
14312
  }
14299
14313
  get locked$() {
14300
- return this.cachedObservable("locked$", () => this._sessionState$.pipe((0, import_cjs$16.map)((state) => state.locked), (0, import_cjs$16.distinctUntilChanged)(), filterNull()));
14314
+ return this.cachedObservable("locked$", () => this._sessionState$.pipe((0, import_cjs$17.map)((state) => state.locked), (0, import_cjs$17.distinctUntilChanged)(), filterNull()));
14301
14315
  }
14302
14316
  get meta$() {
14303
- return this.cachedObservable("meta$", () => this._sessionState$.pipe((0, import_cjs$16.map)((state) => state.meta), (0, import_cjs$16.distinctUntilChanged)(), filterNull()));
14317
+ return this.cachedObservable("meta$", () => this._sessionState$.pipe((0, import_cjs$17.map)((state) => state.meta), (0, import_cjs$17.distinctUntilChanged)(), filterNull()));
14304
14318
  }
14305
14319
  get capabilities$() {
14306
- return this.cachedObservable("capabilities$", () => this._sessionState$.pipe((0, import_cjs$16.map)((state) => state.capabilities), (0, import_cjs$16.distinctUntilChanged)(), filterNull()));
14320
+ return this.cachedObservable("capabilities$", () => this._sessionState$.pipe((0, import_cjs$17.map)((state) => state.capabilities), (0, import_cjs$17.distinctUntilChanged)(), filterNull()));
14307
14321
  }
14308
14322
  get layout$() {
14309
- return this.cachedObservable("layout$", () => this._sessionState$.pipe((0, import_cjs$16.map)((state) => state.layout_name), (0, import_cjs$16.distinctUntilChanged)(), filterNull()));
14323
+ return this.cachedObservable("layout$", () => this._sessionState$.pipe((0, import_cjs$17.map)((state) => state.layout_name), (0, import_cjs$17.distinctUntilChanged)(), filterNull()));
14310
14324
  }
14311
14325
  get layouts$() {
14312
- return this.cachedObservable("layouts$", () => this._sessionState$.pipe((0, import_cjs$16.map)((state) => state.layouts), (0, import_cjs$16.distinctUntilChanged)(), filterNull()));
14326
+ return this.cachedObservable("layouts$", () => this._sessionState$.pipe((0, import_cjs$17.map)((state) => state.layouts), (0, import_cjs$17.distinctUntilChanged)(), filterNull()));
14313
14327
  }
14314
14328
  get layoutLayers$() {
14315
- return this.cachedObservable("layoutLayers$", () => this._sessionState$.pipe((0, import_cjs$16.map)((state) => state.layout_layers), (0, import_cjs$16.distinctUntilChanged)(), filterNull()));
14329
+ return this.cachedObservable("layoutLayers$", () => this._sessionState$.pipe((0, import_cjs$17.map)((state) => state.layout_layers), (0, import_cjs$17.distinctUntilChanged)(), filterNull()));
14316
14330
  }
14317
14331
  get self() {
14318
14332
  return this._self$.value;
@@ -14349,7 +14363,7 @@ var CallEventsManager = class extends Destroyable {
14349
14363
  }
14350
14364
  initSubscriptions() {
14351
14365
  this.subscribeTo(this.callJoinedEvent$, (callJoinedEvent) => {
14352
- logger$18.debug("[CallEventsManager] Handling call.joined event for call/session IDs:", {
14366
+ logger$19.debug("[CallEventsManager] Handling call.joined event for call/session IDs:", {
14353
14367
  callId: callJoinedEvent.call_id,
14354
14368
  roomSessionId: callJoinedEvent.room_session_id
14355
14369
  });
@@ -14376,19 +14390,19 @@ var CallEventsManager = class extends Destroyable {
14376
14390
  if (this._self$.value?.capabilities.setLayout) this.updateLayouts();
14377
14391
  });
14378
14392
  this.subscribeTo(this.memberUpdates$, (member) => {
14379
- logger$18.debug("[CallEventsManager] Handling member update event for member ID:", member);
14393
+ logger$19.debug("[CallEventsManager] Handling member update event for member ID:", member);
14380
14394
  this.upsertParticipant(member);
14381
14395
  });
14382
14396
  this.subscribeTo(this.webRtcCallSession.memberLeft$, (memberLeftEvent) => {
14383
- logger$18.debug("[CallEventsManager] Handling member.left event for member ID:", memberLeftEvent.member.member_id);
14397
+ logger$19.debug("[CallEventsManager] Handling member.left event for member ID:", memberLeftEvent.member.member_id);
14384
14398
  const participants = { ...this._participants$.value };
14385
14399
  if (memberLeftEvent.member.member_id in participants) {
14386
14400
  delete participants[memberLeftEvent.member.member_id];
14387
14401
  this._participants$.next(participants);
14388
- } else logger$18.warn(`[CallEventsManager] Received member.left event for unknown member ID: ${memberLeftEvent.member.member_id}`);
14402
+ } else logger$19.warn(`[CallEventsManager] Received member.left event for unknown member ID: ${memberLeftEvent.member.member_id}`);
14389
14403
  });
14390
14404
  this.subscribeTo(this.webRtcCallSession.callUpdated$, (callUpdatedEvent) => {
14391
- logger$18.debug("[CallEventsManager] Handling call.updated event:", callUpdatedEvent);
14405
+ logger$19.debug("[CallEventsManager] Handling call.updated event:", callUpdatedEvent);
14392
14406
  const roomSession = callUpdatedEvent.room_session;
14393
14407
  this._sessionState$.next({
14394
14408
  ...this._sessionState$.value,
@@ -14403,7 +14417,7 @@ var CallEventsManager = class extends Destroyable {
14403
14417
  });
14404
14418
  });
14405
14419
  this.subscribeTo(this.layoutChangedEvent$, (layoutChangedEvent) => {
14406
- logger$18.debug("[CallEventsManager] Handling layout.changed event:", layoutChangedEvent);
14420
+ logger$19.debug("[CallEventsManager] Handling layout.changed event:", layoutChangedEvent);
14407
14421
  this._sessionState$.next({
14408
14422
  ...this._sessionState$.value,
14409
14423
  layout_name: layoutChangedEvent.id,
@@ -14413,10 +14427,10 @@ var CallEventsManager = class extends Destroyable {
14413
14427
  });
14414
14428
  }
14415
14429
  updateParticipantPositions(layoutChangedEvent) {
14416
- if (Object.keys(this._participants$.value).length > 0 && !layoutChangedEvent.layers.some((layer) => !!layer.member_id)) logger$18.warn("[CallEventsManager] No layers with member_id found in layout.changed event. Nothing to update.");
14430
+ if (Object.keys(this._participants$.value).length > 0 && !layoutChangedEvent.layers.some((layer) => !!layer.member_id)) logger$19.warn("[CallEventsManager] No layers with member_id found in layout.changed event. Nothing to update.");
14417
14431
  layoutChangedEvent.layers.filter((layer) => !!layer.member_id).filter((layer) => {
14418
14432
  if (!(layer.member_id in this._participants$.value)) {
14419
- logger$18.warn(`[CallEventsManager] Skipping layout layer for unknown member_id: ${layer.member_id}`);
14433
+ logger$19.warn(`[CallEventsManager] Skipping layout layer for unknown member_id: ${layer.member_id}`);
14420
14434
  return false;
14421
14435
  }
14422
14436
  return true;
@@ -14439,7 +14453,7 @@ var CallEventsManager = class extends Destroyable {
14439
14453
  layouts: response.result.layouts
14440
14454
  });
14441
14455
  }).catch((error) => {
14442
- logger$18.error("[CallEventsManager] Error fetching layouts:", error);
14456
+ logger$19.error("[CallEventsManager] Error fetching layouts:", error);
14443
14457
  });
14444
14458
  }
14445
14459
  updateParticipants(members) {
@@ -14455,7 +14469,7 @@ var CallEventsManager = class extends Destroyable {
14455
14469
  }
14456
14470
  const participant = this._participants$.value[member.member_id];
14457
14471
  const oldValue = participant.value;
14458
- logger$18.debug("[CallEventsManager] Updating participant:", member.member_id, {
14472
+ logger$19.debug("[CallEventsManager] Updating participant:", member.member_id, {
14459
14473
  oldValue,
14460
14474
  newValue: member
14461
14475
  });
@@ -14467,18 +14481,18 @@ var CallEventsManager = class extends Destroyable {
14467
14481
  this._participants$.next(this._participants$.value);
14468
14482
  }
14469
14483
  get callJoinedEvent$() {
14470
- return this.cachedObservable("callJoinedEvent$", () => this.webRtcCallSession.callEvent$.pipe((0, import_cjs$16.filter)(isCallJoinedPayload), (0, import_cjs$16.tap)((event) => {
14471
- logger$18.debug("[CallEventsManager] Call joined event:", event);
14484
+ return this.cachedObservable("callJoinedEvent$", () => this.webRtcCallSession.callEvent$.pipe((0, import_cjs$17.filter)(isCallJoinedPayload), (0, import_cjs$17.tap)((event) => {
14485
+ logger$19.debug("[CallEventsManager] Call joined event:", event);
14472
14486
  })));
14473
14487
  }
14474
14488
  get layoutChangedEvent$() {
14475
- return this.cachedObservable("layoutChangedEvent$", () => this.webRtcCallSession.callEvent$.pipe(filterAs(isLayoutChangedPayload, "layout"), (0, import_cjs$16.tap)((event) => {
14476
- logger$18.debug("[CallEventsManager] Layout changed event:", event);
14489
+ return this.cachedObservable("layoutChangedEvent$", () => this.webRtcCallSession.callEvent$.pipe(filterAs(isLayoutChangedPayload, "layout"), (0, import_cjs$17.tap)((event) => {
14490
+ logger$19.debug("[CallEventsManager] Layout changed event:", event);
14477
14491
  })));
14478
14492
  }
14479
14493
  get memberUpdates$() {
14480
- return this.cachedObservable("memberUpdates$", () => (0, import_cjs$16.merge)(this.webRtcCallSession.memberJoined$, this.webRtcCallSession.memberUpdated$, this.webRtcCallSession.memberTalking$).pipe((0, import_cjs$16.map)((event) => event.member), (0, import_cjs$16.tap)((event) => {
14481
- logger$18.debug("[CallEventsManager] Member update event:", event);
14494
+ return this.cachedObservable("memberUpdates$", () => (0, import_cjs$17.merge)(this.webRtcCallSession.memberJoined$, this.webRtcCallSession.memberUpdated$, this.webRtcCallSession.memberTalking$).pipe((0, import_cjs$17.map)((event) => event.member), (0, import_cjs$17.tap)((event) => {
14495
+ logger$19.debug("[CallEventsManager] Member update event:", event);
14482
14496
  })));
14483
14497
  }
14484
14498
  destroy() {
@@ -14734,8 +14748,8 @@ function appendStereoParams(fmtpLine, maxBitrate) {
14734
14748
 
14735
14749
  //#endregion
14736
14750
  //#region src/controllers/ICEGatheringController.ts
14737
- var import_cjs$15 = require_cjs();
14738
- const logger$17 = getLogger();
14751
+ var import_cjs$16 = require_cjs();
14752
+ const logger$18 = getLogger();
14739
14753
  var ICEGatheringController = class extends Destroyable {
14740
14754
  constructor(peerConnection, peerConnectionControllerNegotiating$, options = {}) {
14741
14755
  super();
@@ -14743,23 +14757,23 @@ var ICEGatheringController = class extends Destroyable {
14743
14757
  this.peerConnectionControllerNegotiating$ = peerConnectionControllerNegotiating$;
14744
14758
  this.onicegatheringstatechangeHandler = () => {
14745
14759
  const { iceGatheringState } = this.peerConnection;
14746
- logger$17.debug(`[ICEGatheringController] ICE gathering state changed to: ${iceGatheringState}`);
14760
+ logger$18.debug(`[ICEGatheringController] ICE gathering state changed to: ${iceGatheringState}`);
14747
14761
  if (iceGatheringState === "gathering") this._iceCandidatesState.next({
14748
14762
  state: "gathering",
14749
14763
  validSDP: false
14750
14764
  });
14751
14765
  };
14752
14766
  this.onicecandidateHandler = (event) => {
14753
- logger$17.debug("[ICEGatheringController] ICE candidate event received:", event.candidate);
14767
+ logger$18.debug("[ICEGatheringController] ICE candidate event received:", event.candidate);
14754
14768
  this.removeTimer("iceCandidateTimer");
14755
14769
  if (event.candidate) this.iceCandidateTimer = setTimeout(() => {
14756
14770
  if (this.peerConnection.iceGatheringState !== "complete") {
14757
- logger$17.warn("[ICEGatheringController] ICE candidate timeout, using current SDP");
14771
+ logger$18.warn("[ICEGatheringController] ICE candidate timeout, using current SDP");
14758
14772
  this.handleICECandidateTimeout();
14759
14773
  }
14760
14774
  }, this.iceCandidateTimeout);
14761
14775
  else {
14762
- logger$17.debug("[ICEGatheringController] ICE gathering completed: null candidate received");
14776
+ logger$18.debug("[ICEGatheringController] ICE gathering completed: null candidate received");
14763
14777
  this.removeTimer("iceGatheringTimer");
14764
14778
  this.handleICEGatheringComplete();
14765
14779
  }
@@ -14772,12 +14786,12 @@ var ICEGatheringController = class extends Destroyable {
14772
14786
  this.iceGatheringTimeout = options.iceGatheringTimeout ?? DEFAULT_ICE_GATHERING_TIMEOUT_MS;
14773
14787
  this.relayOnly = options.relayOnly ?? false;
14774
14788
  this.setupEventListeners();
14775
- this.subscribeTo(this.peerConnectionControllerNegotiating$.pipe((0, import_cjs$15.filter)((isNegotiating) => isNegotiating)), (isNegotiating) => {
14789
+ this.subscribeTo(this.peerConnectionControllerNegotiating$.pipe((0, import_cjs$16.filter)((isNegotiating) => isNegotiating)), (isNegotiating) => {
14776
14790
  if (isNegotiating) {
14777
14791
  this.setupEventListeners();
14778
14792
  this.iceGatheringTimer = setTimeout(() => {
14779
14793
  if (this.peerConnection.iceGatheringState !== "complete") {
14780
- logger$17.warn("[ICEGatheringController] ICE gathering timeout, using current SDP");
14794
+ logger$18.warn("[ICEGatheringController] ICE gathering timeout, using current SDP");
14781
14795
  this.handleICEGatheringTimeout();
14782
14796
  }
14783
14797
  }, this.iceGatheringTimeout);
@@ -14791,7 +14805,7 @@ var ICEGatheringController = class extends Destroyable {
14791
14805
  this.peerConnection.addEventListener("icegatheringstatechange", this.onicegatheringstatechangeHandler);
14792
14806
  }
14793
14807
  get iceCandidatesState$() {
14794
- return this._iceCandidatesState.pipe((0, import_cjs$15.withLatestFrom)(this.peerConnectionControllerNegotiating$), (0, import_cjs$15.filter)(([_, isNegotiating]) => isNegotiating), (0, import_cjs$15.map)(([state, _]) => state.state));
14808
+ return this._iceCandidatesState.pipe((0, import_cjs$16.withLatestFrom)(this.peerConnectionControllerNegotiating$), (0, import_cjs$16.filter)(([_, isNegotiating]) => isNegotiating), (0, import_cjs$16.map)(([state, _]) => state.state));
14795
14809
  }
14796
14810
  get hasValidLocalDescriptionSDP() {
14797
14811
  const sdp = this.peerConnection.localDescription?.sdp;
@@ -14804,9 +14818,9 @@ var ICEGatheringController = class extends Destroyable {
14804
14818
  this.relayOnly = value;
14805
14819
  }
14806
14820
  handleICEGatheringComplete() {
14807
- logger$17.debug("[ICEGatheringController] Handling ICE gathering complete");
14808
- logger$17.debug(`[ICEGatheringController] Checking ICE gathering state: ${this.peerConnection.iceGatheringState}`);
14809
- logger$17.debug("[ICEGatheringController] ICE gathering complete");
14821
+ logger$18.debug("[ICEGatheringController] Handling ICE gathering complete");
14822
+ logger$18.debug(`[ICEGatheringController] Checking ICE gathering state: ${this.peerConnection.iceGatheringState}`);
14823
+ logger$18.debug("[ICEGatheringController] ICE gathering complete");
14810
14824
  this._iceCandidatesState.next({
14811
14825
  state: "complete",
14812
14826
  validSDP: this.hasValidLocalDescriptionSDP
@@ -14822,21 +14836,21 @@ var ICEGatheringController = class extends Destroyable {
14822
14836
  this.removeTimer("iceGatheringTimer");
14823
14837
  const validSDP = this.hasValidLocalDescriptionSDP;
14824
14838
  if (validSDP) {
14825
- logger$17.debug("[ICEGatheringController] Local SDP is valid");
14839
+ logger$18.debug("[ICEGatheringController] Local SDP is valid");
14826
14840
  this._iceCandidatesState.next({
14827
14841
  state: "timeout",
14828
14842
  validSDP
14829
14843
  });
14830
14844
  this.stopGathering();
14831
- } else logger$17.debug("### ICE gathering timeout\n", this.peerConnection.localDescription?.sdp);
14845
+ } else logger$18.debug("### ICE gathering timeout\n", this.peerConnection.localDescription?.sdp);
14832
14846
  }
14833
14847
  handleICECandidateTimeout() {
14834
14848
  if (this.iceCandidateTimer) this.removeTimer("iceCandidateTimer");
14835
- logger$17.warn("[ICEGatheringController] ICE candidate timeout");
14849
+ logger$18.warn("[ICEGatheringController] ICE candidate timeout");
14836
14850
  const validSDP = this.hasValidLocalDescriptionSDP;
14837
14851
  if (!validSDP && !this.relayOnly) this.restartICEGatheringWithRelayOnly();
14838
14852
  else {
14839
- logger$17.debug("[ICEGatheringController] Using current SDP due to ICE candidate timeout");
14853
+ logger$18.debug("[ICEGatheringController] Using current SDP due to ICE candidate timeout");
14840
14854
  this._iceCandidatesState.next({
14841
14855
  state: "timeout",
14842
14856
  validSDP
@@ -14845,7 +14859,7 @@ var ICEGatheringController = class extends Destroyable {
14845
14859
  }
14846
14860
  }
14847
14861
  restartICEGatheringWithRelayOnly() {
14848
- logger$17.debug("[ICEGatheringController] Restarting ICE gathering with relay-only candidates");
14862
+ logger$18.debug("[ICEGatheringController] Restarting ICE gathering with relay-only candidates");
14849
14863
  this.relayOnly = true;
14850
14864
  this.peerConnection.setConfiguration({
14851
14865
  ...this.peerConnection.getConfiguration(),
@@ -14853,14 +14867,14 @@ var ICEGatheringController = class extends Destroyable {
14853
14867
  });
14854
14868
  if (!(this.peerConnection.connectionState === "connected")) this.peerConnection.restartIce();
14855
14869
  }
14856
- removeTimer(timer$2) {
14857
- if (this[timer$2]) {
14858
- clearTimeout(this[timer$2]);
14859
- this[timer$2] = void 0;
14870
+ removeTimer(timer$3) {
14871
+ if (this[timer$3]) {
14872
+ clearTimeout(this[timer$3]);
14873
+ this[timer$3] = void 0;
14860
14874
  }
14861
14875
  }
14862
14876
  clearAllTimers() {
14863
- logger$17.debug("[ICEGatheringController] Clearing all timers");
14877
+ logger$18.debug("[ICEGatheringController] Clearing all timers");
14864
14878
  this.removeTimer("iceGatheringTimer");
14865
14879
  this.removeTimer("iceCandidateTimer");
14866
14880
  }
@@ -14869,7 +14883,7 @@ var ICEGatheringController = class extends Destroyable {
14869
14883
  this.peerConnection.removeEventListener("icecandidate", this.onicecandidateHandler);
14870
14884
  }
14871
14885
  destroy() {
14872
- logger$17.debug("[ICEGatheringController] Destroying ICEGatheringController");
14886
+ logger$18.debug("[ICEGatheringController] Destroying ICEGatheringController");
14873
14887
  this.clearAllTimers();
14874
14888
  this.removeEventListeners();
14875
14889
  super.destroy();
@@ -14878,8 +14892,8 @@ var ICEGatheringController = class extends Destroyable {
14878
14892
 
14879
14893
  //#endregion
14880
14894
  //#region src/controllers/LocalStreamController.ts
14881
- var import_cjs$14 = require_cjs();
14882
- const logger$16 = getLogger();
14895
+ var import_cjs$15 = require_cjs();
14896
+ const logger$17 = getLogger();
14883
14897
  var LocalStreamController = class extends Destroyable {
14884
14898
  constructor(options) {
14885
14899
  super();
@@ -14893,16 +14907,16 @@ var LocalStreamController = class extends Destroyable {
14893
14907
  this._mediaTrackEnded$ = this.createSubject();
14894
14908
  }
14895
14909
  get localStream$() {
14896
- return this._localStream$.asObservable().pipe((0, import_cjs$14.takeUntil)(this.destroyed$));
14910
+ return this._localStream$.asObservable().pipe((0, import_cjs$15.takeUntil)(this.destroyed$));
14897
14911
  }
14898
14912
  get localAudioTracks$() {
14899
- return this._localAudioTracks$.asObservable().pipe((0, import_cjs$14.takeUntil)(this.destroyed$));
14913
+ return this._localAudioTracks$.asObservable().pipe((0, import_cjs$15.takeUntil)(this.destroyed$));
14900
14914
  }
14901
14915
  get localVideoTracks$() {
14902
- return this._localVideoTracks$.asObservable().pipe((0, import_cjs$14.takeUntil)(this.destroyed$));
14916
+ return this._localVideoTracks$.asObservable().pipe((0, import_cjs$15.takeUntil)(this.destroyed$));
14903
14917
  }
14904
14918
  get mediaTrackEnded$() {
14905
- return this._mediaTrackEnded$.asObservable().pipe((0, import_cjs$14.takeUntil)(this.destroyed$));
14919
+ return this._mediaTrackEnded$.asObservable().pipe((0, import_cjs$15.takeUntil)(this.destroyed$));
14906
14920
  }
14907
14921
  get localStream() {
14908
14922
  return this._localStream$.value;
@@ -14917,26 +14931,26 @@ var LocalStreamController = class extends Destroyable {
14917
14931
  * Build the local media stream based on the provided options.
14918
14932
  */
14919
14933
  async buildLocalStream() {
14920
- logger$16.debug("[LocalStreamController] Building local media stream.");
14934
+ logger$17.debug("[LocalStreamController] Building local media stream.");
14921
14935
  let stream;
14922
14936
  if (this.options.inputAudioStream ?? this.options.inputVideoStream) {
14923
14937
  const tracks = [...this.options.inputAudioStream?.getTracks() ?? [], ...this.options.inputVideoStream?.getTracks() ?? []];
14924
14938
  stream = new MediaStream(tracks);
14925
14939
  } else if (this.options.propose === "screenshare") {
14926
- logger$16.debug("[LocalStreamController] Requesting display media for screen sharing with audio:", Boolean(this.options.inputAudioDeviceConstraints));
14940
+ logger$17.debug("[LocalStreamController] Requesting display media for screen sharing with audio:", Boolean(this.options.inputAudioDeviceConstraints));
14927
14941
  stream = await this.options.getDisplayMedia({
14928
14942
  video: true,
14929
14943
  audio: Boolean(this.options.inputAudioDeviceConstraints)
14930
14944
  });
14931
- logger$16.debug("[LocalStreamController] Screen share media obtained:", stream);
14945
+ logger$17.debug("[LocalStreamController] Screen share media obtained:", stream);
14932
14946
  } else {
14933
14947
  const constraints = {
14934
14948
  audio: this.options.inputAudioDeviceConstraints,
14935
14949
  video: this.options.inputVideoDeviceConstraints
14936
14950
  };
14937
- logger$16.debug("[LocalStreamController] Requesting user media with constraints:", constraints);
14951
+ logger$17.debug("[LocalStreamController] Requesting user media with constraints:", constraints);
14938
14952
  stream = await this.options.getUserMedia(constraints);
14939
- logger$16.debug("[LocalStreamController] User media obtained:", stream);
14953
+ logger$17.debug("[LocalStreamController] User media obtained:", stream);
14940
14954
  }
14941
14955
  this._localStream$.next(stream);
14942
14956
  return stream;
@@ -14953,7 +14967,7 @@ var LocalStreamController = class extends Destroyable {
14953
14967
  this._localStream$.next(localStream);
14954
14968
  if (track.kind === "video") this._localVideoTracks$.next(localStream.getVideoTracks());
14955
14969
  else this._localAudioTracks$.next(localStream.getAudioTracks());
14956
- logger$16.debug(`[LocalStreamController] ${track.kind} track added:`, track.id);
14970
+ logger$17.debug(`[LocalStreamController] ${track.kind} track added:`, track.id);
14957
14971
  return localStream;
14958
14972
  }
14959
14973
  /**
@@ -14965,7 +14979,7 @@ var LocalStreamController = class extends Destroyable {
14965
14979
  const stream = this._localStream$.value;
14966
14980
  const track = stream?.getTracks().find((t) => t.id === trackId);
14967
14981
  if (!track) {
14968
- logger$16.debug(`[LocalStreamController] track not found: ${trackId}`);
14982
+ logger$17.debug(`[LocalStreamController] track not found: ${trackId}`);
14969
14983
  return;
14970
14984
  }
14971
14985
  track.removeEventListener("ended", this.mediaTrackEndedHandler);
@@ -14974,7 +14988,7 @@ var LocalStreamController = class extends Destroyable {
14974
14988
  this._localStream$.next(stream);
14975
14989
  if (track.kind === "video") this._localVideoTracks$.next(stream?.getVideoTracks() ?? []);
14976
14990
  else this._localAudioTracks$.next(stream?.getAudioTracks() ?? []);
14977
- logger$16.debug(`[LocalStreamController] ${track.kind} track removed:`, trackId);
14991
+ logger$17.debug(`[LocalStreamController] ${track.kind} track removed:`, trackId);
14978
14992
  return track;
14979
14993
  }
14980
14994
  /**
@@ -15009,7 +15023,7 @@ var LocalStreamController = class extends Destroyable {
15009
15023
  */
15010
15024
  stopAllTracks() {
15011
15025
  this._localStream$.value?.getTracks().forEach((track) => {
15012
- logger$16.debug(`[LocalStreamController] Stopping local track: ${track.kind}`);
15026
+ logger$17.debug(`[LocalStreamController] Stopping local track: ${track.kind}`);
15013
15027
  track.removeEventListener("ended", this.mediaTrackEndedHandler);
15014
15028
  track.stop();
15015
15029
  });
@@ -15025,7 +15039,7 @@ var LocalStreamController = class extends Destroyable {
15025
15039
 
15026
15040
  //#endregion
15027
15041
  //#region src/controllers/TransceiverController.ts
15028
- const logger$15 = getLogger();
15042
+ const logger$16 = getLogger();
15029
15043
  const getDirection = (send, recv) => {
15030
15044
  if (send && recv) return "sendrecv";
15031
15045
  else if (send && !recv) return "sendonly";
@@ -15127,7 +15141,7 @@ var TransceiverController = class extends Destroyable {
15127
15141
  sendEncodings: isAudio ? void 0 : this.sendEncodings,
15128
15142
  streams: direction === "recvonly" ? void 0 : [localStream]
15129
15143
  };
15130
- logger$15.debug(`[TransceiverController] Setting up transceiver sender for local ${track.kind} track:`, {
15144
+ logger$16.debug(`[TransceiverController] Setting up transceiver sender for local ${track.kind} track:`, {
15131
15145
  transceiver,
15132
15146
  transceiverParams
15133
15147
  });
@@ -15135,11 +15149,11 @@ var TransceiverController = class extends Destroyable {
15135
15149
  await transceiver.sender.replaceTrack(track);
15136
15150
  transceiver.direction = transceiverParams.direction;
15137
15151
  if (transceiverParams.streams?.some((stream) => Boolean(stream))) {
15138
- logger$15.debug(`[TransceiverController] Setting streams for transceiver sender for local ${track.kind} track:`, transceiverParams.streams);
15152
+ logger$16.debug(`[TransceiverController] Setting streams for transceiver sender for local ${track.kind} track:`, transceiverParams.streams);
15139
15153
  transceiver.sender.setStreams(...transceiverParams.streams);
15140
15154
  }
15141
15155
  } else {
15142
- logger$15.debug(`[TransceiverController] Adding new transceiver for local ${track.kind} track:`, track.id);
15156
+ logger$16.debug(`[TransceiverController] Adding new transceiver for local ${track.kind} track:`, track.id);
15143
15157
  this.peerConnection.addTransceiver(track, transceiverParams);
15144
15158
  }
15145
15159
  }
@@ -15153,13 +15167,13 @@ var TransceiverController = class extends Destroyable {
15153
15167
  if (options.updateTransceiverDirection) transceiver.direction = "inactive";
15154
15168
  }
15155
15169
  } catch (error) {
15156
- logger$15.error("[TransceiverController] stopTrackSender error", kind, error);
15170
+ logger$16.error("[TransceiverController] stopTrackSender error", kind, error);
15157
15171
  this.options.onError?.(new MediaTrackError("stopTrackSender", kind, error));
15158
15172
  }
15159
15173
  }
15160
15174
  async restoreTrackSender(kind) {
15161
15175
  try {
15162
- logger$15.debug("[TransceiverController] restoreTrackSender called", kind);
15176
+ logger$16.debug("[TransceiverController] restoreTrackSender called", kind);
15163
15177
  const constraints = {};
15164
15178
  const transceivers = this.transceiverByKind(kind);
15165
15179
  for (const transceiver of transceivers) {
@@ -15169,23 +15183,23 @@ var TransceiverController = class extends Destroyable {
15169
15183
  if (trackKind === "audio" || trackKind === "video") constraints[trackKind] = this.getConstraintsFor(trackKind);
15170
15184
  }
15171
15185
  }
15172
- logger$15.debug("[TransceiverController] restoreTrackSender constraints:", constraints);
15186
+ logger$16.debug("[TransceiverController] restoreTrackSender constraints:", constraints);
15173
15187
  if (Object.keys(constraints).length === 0) {
15174
- logger$15.warn("[TransceiverController] restoreTrackSender: no tracks need restoration", kind);
15188
+ logger$16.warn("[TransceiverController] restoreTrackSender: no tracks need restoration", kind);
15175
15189
  return;
15176
15190
  }
15177
15191
  const newTracks = (await this.options.getUserMedia(constraints)).getTracks();
15178
- logger$15.debug("[TransceiverController] restoreTrackSender new tracks:", newTracks);
15192
+ logger$16.debug("[TransceiverController] restoreTrackSender new tracks:", newTracks);
15179
15193
  for (const newTrack of newTracks) {
15180
15194
  this.options.localStreamController.addTrack(newTrack);
15181
15195
  const trackKind = newTrack.kind;
15182
15196
  const transceiverOfKind = this.transceiverByKind(trackKind)[0];
15183
15197
  transceiverOfKind.direction = trackKind === "audio" ? this.audioDirection : this.videoDirection;
15184
- logger$15.debug("[TransceiverController] restoreTrackSender setting direction for", trackKind, transceiverOfKind.direction);
15198
+ logger$16.debug("[TransceiverController] restoreTrackSender setting direction for", trackKind, transceiverOfKind.direction);
15185
15199
  await transceiverOfKind.sender.replaceTrack(newTrack);
15186
15200
  }
15187
15201
  } catch (error) {
15188
- logger$15.error("[TransceiverController] restoreTrackSender error", kind, error);
15202
+ logger$16.error("[TransceiverController] restoreTrackSender error", kind, error);
15189
15203
  this.options.onError?.(new MediaTrackError("restoreTrackSender", kind, error));
15190
15204
  }
15191
15205
  }
@@ -15226,14 +15240,14 @@ var TransceiverController = class extends Destroyable {
15226
15240
  };
15227
15241
  try {
15228
15242
  await track.applyConstraints(constraintsToApply);
15229
- logger$15.debug(`[TransceiverController] Updated ${kind} sender constraints:`, constraintsToApply);
15230
- logger$15.debug(`[TransceiverController] Updated ${kind} sender constraints:`, track.getConstraints());
15243
+ logger$16.debug(`[TransceiverController] Updated ${kind} sender constraints:`, constraintsToApply);
15244
+ logger$16.debug(`[TransceiverController] Updated ${kind} sender constraints:`, track.getConstraints());
15231
15245
  } catch (error) {
15232
- logger$15.warn(`[TransceiverController] applyConstraints failed for ${kind} track ${track.id}, attempting track replacement fallback:`, error);
15246
+ logger$16.warn(`[TransceiverController] applyConstraints failed for ${kind} track ${track.id}, attempting track replacement fallback:`, error);
15233
15247
  try {
15234
15248
  await this.replaceTrackFallback(sender, track, kind, constraintsToApply);
15235
15249
  } catch (fallbackError) {
15236
- logger$15.warn(`[TransceiverController] Track replacement fallback also failed for ${kind} track:`, fallbackError);
15250
+ logger$16.warn(`[TransceiverController] Track replacement fallback also failed for ${kind} track:`, fallbackError);
15237
15251
  this.options.onError?.(new MediaTrackError("updateSendersConstraints", kind, fallbackError));
15238
15252
  }
15239
15253
  }
@@ -15261,7 +15275,7 @@ var TransceiverController = class extends Destroyable {
15261
15275
  if (!newTrack) throw new MediaTrackError("replaceTrackFallback", kind, /* @__PURE__ */ new Error("getUserMedia returned no track of the requested kind"));
15262
15276
  await sender.replaceTrack(newTrack);
15263
15277
  this.options.localStreamController.addTrack(newTrack);
15264
- logger$15.debug(`[TransceiverController] Track replacement fallback succeeded for ${kind}. New track: ${newTrack.id}`);
15278
+ logger$16.debug(`[TransceiverController] Track replacement fallback succeeded for ${kind}. New track: ${newTrack.id}`);
15265
15279
  }
15266
15280
  getMediaDirections() {
15267
15281
  if (this.peerConnection.connectionState === "connected") return this.peerConnection.getTransceivers().reduce((acc, transceiver) => {
@@ -15291,60 +15305,60 @@ var TransceiverController = class extends Destroyable {
15291
15305
 
15292
15306
  //#endregion
15293
15307
  //#region src/controllers/RTCPeerConnectionController.ts
15294
- var import_cjs$13 = require_cjs();
15295
- const logger$14 = getLogger();
15308
+ var import_cjs$14 = require_cjs();
15309
+ const logger$15 = getLogger();
15296
15310
  var RTCPeerConnectionController = class extends Destroyable {
15297
15311
  constructor(options = {}, remoteSessionDescription, deviceController) {
15298
15312
  super();
15299
15313
  this.options = options;
15300
15314
  this.firstSDPExchangeCompleted = false;
15301
15315
  this.negotiationNeeded$ = this.createSubject();
15302
- this.localDescription$ = (0, import_cjs$13.defer)(() => (0, import_cjs$13.from)(this.init())).pipe((0, import_cjs$13.switchMap)(() => this.iceGatheringController.iceCandidatesState$.pipe((0, import_cjs$13.filter)((iceCandidateState) => !["new", "gathering"].includes(iceCandidateState)), (0, import_cjs$13.tap)(() => {
15316
+ this.localDescription$ = (0, import_cjs$14.defer)(() => (0, import_cjs$14.from)(this.init())).pipe((0, import_cjs$14.switchMap)(() => this.iceGatheringController.iceCandidatesState$.pipe((0, import_cjs$14.filter)((iceCandidateState) => !["new", "gathering"].includes(iceCandidateState)), (0, import_cjs$14.tap)(() => {
15303
15317
  this.negotiationEnded();
15304
- }), (0, import_cjs$13.filter)(() => this.shouldEmitLocalDescription), (0, import_cjs$13.map)(() => this.peerConnection?.localDescription), filterNull(), (0, import_cjs$13.tap)((desc) => {
15318
+ }), (0, import_cjs$14.filter)(() => this.shouldEmitLocalDescription), (0, import_cjs$14.map)(() => this.peerConnection?.localDescription), filterNull(), (0, import_cjs$14.tap)((desc) => {
15305
15319
  if (desc.type === "answer") this._type = "offer";
15306
- }))), (0, import_cjs$13.shareReplay)(1), (0, import_cjs$13.takeUntil)(this.destroyed$));
15320
+ }))), (0, import_cjs$14.shareReplay)(1), (0, import_cjs$14.takeUntil)(this.destroyed$));
15307
15321
  this.connectionTimeout = 3e3;
15308
15322
  this.oniceconnectionstatechangeHandler = () => {
15309
15323
  if (this.peerConnection) {
15310
15324
  const { iceConnectionState } = this.peerConnection;
15311
- logger$14.debug(`[RTCPeerConnectionController] ICE connection state changed to: ${iceConnectionState}`);
15325
+ logger$15.debug(`[RTCPeerConnectionController] ICE connection state changed to: ${iceConnectionState}`);
15312
15326
  this._iceConnectionState$.next(this.peerConnection.iceConnectionState);
15313
15327
  }
15314
15328
  };
15315
15329
  this.onconnectionstatechangeHandler = () => {
15316
15330
  if (this.peerConnection) {
15317
15331
  const { connectionState } = this.peerConnection;
15318
- logger$14.debug(`[RTCPeerConnectionController] Connection state changed to: ${connectionState}`);
15332
+ logger$15.debug(`[RTCPeerConnectionController] Connection state changed to: ${connectionState}`);
15319
15333
  if (connectionState === "connected") this.removeConnectionTimer();
15320
15334
  this._connectionState$.next(this.peerConnection.connectionState);
15321
15335
  }
15322
15336
  };
15323
15337
  this.onsignalingstatechangeHandler = () => {
15324
- logger$14.debug(`[RTCPeerConnectionController] Signaling state changed to: ${this.peerConnection?.signalingState}`);
15338
+ logger$15.debug(`[RTCPeerConnectionController] Signaling state changed to: ${this.peerConnection?.signalingState}`);
15325
15339
  };
15326
15340
  this.onicegatheringstatechangeHandler = () => {
15327
15341
  if (this.peerConnection) this._iceGatheringState$.next(this.peerConnection.iceGatheringState);
15328
15342
  };
15329
15343
  this.onnegotiationneededHandler = (event) => {
15330
- logger$14.debug("[RTCPeerConnectionController] Negotiation needed event received.", event);
15344
+ logger$15.debug("[RTCPeerConnectionController] Negotiation needed event received.", event);
15331
15345
  this.negotiationNeeded$.next();
15332
15346
  };
15333
15347
  this.updateSelectedInputDevice = async (kind, deviceInfo) => {
15334
15348
  try {
15335
15349
  const { localStream } = this;
15336
15350
  if (!localStream) {
15337
- logger$14.warn("[RTCPeerConnectionController] No local stream available to update input device.");
15351
+ logger$15.warn("[RTCPeerConnectionController] No local stream available to update input device.");
15338
15352
  return;
15339
15353
  }
15340
- logger$14.debug(`[RTCPeerConnectionController] Updating selected ${kind} input device:`, localStream.getTracks());
15354
+ logger$15.debug(`[RTCPeerConnectionController] Updating selected ${kind} input device:`, localStream.getTracks());
15341
15355
  const track = localStream.getTracks().find((track$1) => track$1.kind === kind);
15342
15356
  if (track) {
15343
15357
  this.transceiverController?.stopTrackSender(kind);
15344
15358
  this.localStream?.removeTrack(track);
15345
- logger$14.debug(`[RTCPeerConnectionController] Stopped existing ${kind} track: ${track.id}`, localStream.getTracks());
15359
+ logger$15.debug(`[RTCPeerConnectionController] Stopped existing ${kind} track: ${track.id}`, localStream.getTracks());
15346
15360
  if (!deviceInfo) {
15347
- logger$14.debug(`[RTCPeerConnectionController] ${kind} input device selected: none`);
15361
+ logger$15.debug(`[RTCPeerConnectionController] ${kind} input device selected: none`);
15348
15362
  return;
15349
15363
  }
15350
15364
  const streamTrack = (await this.getUserMedia({ [kind]: {
@@ -15352,15 +15366,15 @@ var RTCPeerConnectionController = class extends Destroyable {
15352
15366
  ...this.deviceController.deviceInfoToConstraints(deviceInfo)
15353
15367
  } })).getTracks().find((t) => t.kind === kind);
15354
15368
  if (streamTrack) {
15355
- logger$14.debug(`[RTCPeerConnectionController] Adding new ${kind} track: ${streamTrack.id}`);
15369
+ logger$15.debug(`[RTCPeerConnectionController] Adding new ${kind} track: ${streamTrack.id}`);
15356
15370
  this.localStream?.addTrack(streamTrack);
15357
15371
  await this.transceiverController?.replaceSenderTrack(kind, streamTrack);
15358
- logger$14.debug(`[RTCPeerConnectionController] Added new ${kind} track: ${streamTrack.id}`, this.localStream?.getTracks());
15372
+ logger$15.debug(`[RTCPeerConnectionController] Added new ${kind} track: ${streamTrack.id}`, this.localStream?.getTracks());
15359
15373
  }
15360
15374
  }
15361
- logger$14.debug(`[RTCPeerConnectionController] ${kind} input device selected:`, deviceInfo?.label);
15375
+ logger$15.debug(`[RTCPeerConnectionController] ${kind} input device selected:`, deviceInfo?.label);
15362
15376
  } catch (error) {
15363
- logger$14.error(`[RTCPeerConnectionController] Failed to select ${kind} input device:`, error);
15377
+ logger$15.error(`[RTCPeerConnectionController] Failed to select ${kind} input device:`, error);
15364
15378
  this._errors$.next(error);
15365
15379
  throw error;
15366
15380
  }
@@ -15446,43 +15460,43 @@ var RTCPeerConnectionController = class extends Destroyable {
15446
15460
  };
15447
15461
  }
15448
15462
  get iceGatheringState$() {
15449
- return this.cachedObservable("iceGatheringState$", () => this._iceGatheringState$.asObservable().pipe((0, import_cjs$13.takeUntil)(this.destroyed$)));
15463
+ return this.cachedObservable("iceGatheringState$", () => this._iceGatheringState$.asObservable().pipe((0, import_cjs$14.takeUntil)(this.destroyed$)));
15450
15464
  }
15451
15465
  get mediaTrackEnded$() {
15452
- return this.cachedObservable("mediaTrackEnded$", () => this.localStreamController.mediaTrackEnded$.pipe((0, import_cjs$13.takeUntil)(this.destroyed$)));
15466
+ return this.cachedObservable("mediaTrackEnded$", () => this.localStreamController.mediaTrackEnded$.pipe((0, import_cjs$14.takeUntil)(this.destroyed$)));
15453
15467
  }
15454
15468
  get errors$() {
15455
- return this.cachedObservable("errors$", () => this._errors$.asObservable().pipe((0, import_cjs$13.takeUntil)(this.destroyed$)));
15469
+ return this.cachedObservable("errors$", () => this._errors$.asObservable().pipe((0, import_cjs$14.takeUntil)(this.destroyed$)));
15456
15470
  }
15457
15471
  get iceCandidates$() {
15458
- return this.cachedObservable("iceCandidates$", () => this._iceCandidates$.asObservable().pipe((0, import_cjs$13.takeUntil)(this.destroyed$)));
15472
+ return this.cachedObservable("iceCandidates$", () => this._iceCandidates$.asObservable().pipe((0, import_cjs$14.takeUntil)(this.destroyed$)));
15459
15473
  }
15460
15474
  get initialized$() {
15461
- return this.cachedObservable("initialized$", () => this._initialized$.asObservable().pipe((0, import_cjs$13.filter)((initialized) => initialized), (0, import_cjs$13.takeUntil)(this.destroyed$)));
15475
+ return this.cachedObservable("initialized$", () => this._initialized$.asObservable().pipe((0, import_cjs$14.filter)((initialized) => initialized), (0, import_cjs$14.takeUntil)(this.destroyed$)));
15462
15476
  }
15463
15477
  get remoteDescription$() {
15464
- return this.cachedObservable("remoteDescription$", () => this._remoteDescription$.asObservable().pipe((0, import_cjs$13.takeUntil)(this.destroyed$)));
15478
+ return this.cachedObservable("remoteDescription$", () => this._remoteDescription$.asObservable().pipe((0, import_cjs$14.takeUntil)(this.destroyed$)));
15465
15479
  }
15466
15480
  get localStream$() {
15467
- return this.cachedObservable("localStream$", () => this.localStreamController.localStream$.pipe((0, import_cjs$13.takeUntil)(this.destroyed$)));
15481
+ return this.cachedObservable("localStream$", () => this.localStreamController.localStream$.pipe((0, import_cjs$14.takeUntil)(this.destroyed$)));
15468
15482
  }
15469
15483
  get remoteStream$() {
15470
- return this.cachedObservable("remoteStream$", () => this._remoteStream$.asObservable().pipe((0, import_cjs$13.takeUntil)(this.destroyed$)));
15484
+ return this.cachedObservable("remoteStream$", () => this._remoteStream$.asObservable().pipe((0, import_cjs$14.takeUntil)(this.destroyed$)));
15471
15485
  }
15472
15486
  get localAudioTracks$() {
15473
- return this.cachedObservable("localAudioTracks$", () => this.localStreamController.localAudioTracks$.pipe((0, import_cjs$13.takeUntil)(this.destroyed$)));
15487
+ return this.cachedObservable("localAudioTracks$", () => this.localStreamController.localAudioTracks$.pipe((0, import_cjs$14.takeUntil)(this.destroyed$)));
15474
15488
  }
15475
15489
  get localVideoTracks$() {
15476
- return this.cachedObservable("localVideoTracks$", () => this.localStreamController.localVideoTracks$.pipe((0, import_cjs$13.takeUntil)(this.destroyed$)));
15490
+ return this.cachedObservable("localVideoTracks$", () => this.localStreamController.localVideoTracks$.pipe((0, import_cjs$14.takeUntil)(this.destroyed$)));
15477
15491
  }
15478
15492
  get iceConnectionState$() {
15479
- return this.cachedObservable("iceConnectionState$", () => this._iceConnectionState$.asObservable().pipe((0, import_cjs$13.takeUntil)(this.destroyed$)));
15493
+ return this.cachedObservable("iceConnectionState$", () => this._iceConnectionState$.asObservable().pipe((0, import_cjs$14.takeUntil)(this.destroyed$)));
15480
15494
  }
15481
15495
  get connectionState$() {
15482
- return this.cachedObservable("connectionState$", () => this._connectionState$.asObservable().pipe((0, import_cjs$13.takeUntil)(this.destroyed$)));
15496
+ return this.cachedObservable("connectionState$", () => this._connectionState$.asObservable().pipe((0, import_cjs$14.takeUntil)(this.destroyed$)));
15483
15497
  }
15484
15498
  get signalingState$() {
15485
- return this.cachedObservable("signalingState$", () => this._signalingState$.asObservable().pipe((0, import_cjs$13.takeUntil)(this.destroyed$)));
15499
+ return this.cachedObservable("signalingState$", () => this._signalingState$.asObservable().pipe((0, import_cjs$14.takeUntil)(this.destroyed$)));
15486
15500
  }
15487
15501
  get type() {
15488
15502
  return this._type;
@@ -15595,17 +15609,17 @@ var RTCPeerConnectionController = class extends Destroyable {
15595
15609
  async doInit() {
15596
15610
  try {
15597
15611
  this.setupPeerConnection();
15598
- this.subscribeTo(this.negotiationNeeded$.pipe((0, import_cjs$13.auditTime)(0), (0, import_cjs$13.exhaustMap)(async () => this.startNegotiation())), {
15612
+ this.subscribeTo(this.negotiationNeeded$.pipe((0, import_cjs$14.auditTime)(0), (0, import_cjs$14.exhaustMap)(async () => this.startNegotiation())), {
15599
15613
  next: () => {
15600
- logger$14.debug("[RTCPeerConnectionController] Start Negotiation completed successfully");
15614
+ logger$15.debug("[RTCPeerConnectionController] Start Negotiation completed successfully");
15601
15615
  },
15602
15616
  error: (error) => {
15603
- logger$14.error("[RTCPeerConnectionController] Start Negotiation error:", error);
15617
+ logger$15.error("[RTCPeerConnectionController] Start Negotiation error:", error);
15604
15618
  this._errors$.next(error);
15605
15619
  }
15606
15620
  });
15607
- this.subscribeTo((0, import_cjs$13.merge)(this.deviceController.selectedAudioInputDevice$.pipe((0, import_cjs$13.map)((deviceInfo) => ["audio", deviceInfo])), this.deviceController.selectedVideoInputDevice$.pipe((0, import_cjs$13.map)((deviceInfo) => ["video", deviceInfo]))).pipe((0, import_cjs$13.skipWhile)(() => !this.localStreamController.localStream)), async ([kind, deviceInfo]) => {
15608
- logger$14.debug(`[RTCPeerConnectionController] Selected input device changed for:`, {
15621
+ this.subscribeTo((0, import_cjs$14.merge)(this.deviceController.selectedAudioInputDevice$.pipe((0, import_cjs$14.map)((deviceInfo) => ["audio", deviceInfo])), this.deviceController.selectedVideoInputDevice$.pipe((0, import_cjs$14.map)((deviceInfo) => ["video", deviceInfo]))).pipe((0, import_cjs$14.skipWhile)(() => !this.localStreamController.localStream)), async ([kind, deviceInfo]) => {
15622
+ logger$15.debug(`[RTCPeerConnectionController] Selected input device changed for:`, {
15609
15623
  kind,
15610
15624
  deviceInfo
15611
15625
  });
@@ -15622,7 +15636,7 @@ var RTCPeerConnectionController = class extends Destroyable {
15622
15636
  this._initialized$.next(true);
15623
15637
  }
15624
15638
  } catch (error) {
15625
- logger$14.error("[RTCPeerConnectionController] Initialization error:", error);
15639
+ logger$15.error("[RTCPeerConnectionController] Initialization error:", error);
15626
15640
  this._errors$.next(error);
15627
15641
  this.destroy();
15628
15642
  }
@@ -15654,22 +15668,22 @@ var RTCPeerConnectionController = class extends Destroyable {
15654
15668
  }
15655
15669
  async startNegotiation() {
15656
15670
  if (this.isNegotiating) {
15657
- logger$14.debug("[RTCPeerConnectionController] Negotiation already in progress, skipping.");
15671
+ logger$15.debug("[RTCPeerConnectionController] Negotiation already in progress, skipping.");
15658
15672
  return;
15659
15673
  }
15660
15674
  this.setupEventListeners();
15661
15675
  if (this.type === "answer") {
15662
- logger$14.debug("[RTCPeerConnectionController] This is an answer type still, skipping offer creation.");
15676
+ logger$15.debug("[RTCPeerConnectionController] This is an answer type still, skipping offer creation.");
15663
15677
  return;
15664
15678
  }
15665
15679
  this._isNegotiating$.next(true);
15666
- logger$14.debug("[RTCPeerConnectionController] Starting negotiation.");
15680
+ logger$15.debug("[RTCPeerConnectionController] Starting negotiation.");
15667
15681
  try {
15668
15682
  const { offerOptions } = this;
15669
- logger$14.debug("[RTCPeerConnectionController] Creating offer with options:", offerOptions);
15683
+ logger$15.debug("[RTCPeerConnectionController] Creating offer with options:", offerOptions);
15670
15684
  await this.createOffer(offerOptions);
15671
15685
  } catch (error) {
15672
- logger$14.error("[RTCPeerConnectionController] Error during negotiation:", error);
15686
+ logger$15.error("[RTCPeerConnectionController] Error during negotiation:", error);
15673
15687
  this._errors$.next(error);
15674
15688
  }
15675
15689
  }
@@ -15685,14 +15699,14 @@ var RTCPeerConnectionController = class extends Destroyable {
15685
15699
  let readyToConnect = status !== "failed";
15686
15700
  try {
15687
15701
  if (status === "received" && sdp) {
15688
- logger$14.debug("[RTCPeerConnectionController] Received answer SDP:", sdp);
15702
+ logger$15.debug("[RTCPeerConnectionController] Received answer SDP:", sdp);
15689
15703
  await this._setRemoteDescription({
15690
15704
  type: "answer",
15691
15705
  sdp
15692
15706
  });
15693
15707
  }
15694
15708
  } catch (error) {
15695
- logger$14.error("[RTCPeerConnectionController] Error updating answer status:", error);
15709
+ logger$15.error("[RTCPeerConnectionController] Error updating answer status:", error);
15696
15710
  this._errors$.next(error);
15697
15711
  readyToConnect = false;
15698
15712
  } finally {
@@ -15711,7 +15725,7 @@ var RTCPeerConnectionController = class extends Destroyable {
15711
15725
  await this.handleOfferReceived();
15712
15726
  break;
15713
15727
  case "failed":
15714
- logger$14.error("[RTCPeerConnectionController] Offer failed to be processed by remote.");
15728
+ logger$15.error("[RTCPeerConnectionController] Offer failed to be processed by remote.");
15715
15729
  break;
15716
15730
  case "sent":
15717
15731
  default:
@@ -15743,7 +15757,7 @@ var RTCPeerConnectionController = class extends Destroyable {
15743
15757
  }
15744
15758
  await this.setupLocalTracks();
15745
15759
  const { answerOptions } = this;
15746
- logger$14.debug("[RTCPeerConnectionController] Creating inbound answer with options:", answerOptions);
15760
+ logger$15.debug("[RTCPeerConnectionController] Creating inbound answer with options:", answerOptions);
15747
15761
  await this.createAnswer(answerOptions);
15748
15762
  }
15749
15763
  async handleOfferReceived() {
@@ -15751,7 +15765,7 @@ var RTCPeerConnectionController = class extends Destroyable {
15751
15765
  this._isNegotiating$.next(true);
15752
15766
  await this._setRemoteDescription(this.sdpInit);
15753
15767
  const { answerOptions } = this;
15754
- logger$14.debug("[RTCPeerConnectionController] Creating answer with options:", answerOptions);
15768
+ logger$15.debug("[RTCPeerConnectionController] Creating answer with options:", answerOptions);
15755
15769
  await this.createAnswer(answerOptions);
15756
15770
  }
15757
15771
  readyToConnect() {
@@ -15759,7 +15773,7 @@ var RTCPeerConnectionController = class extends Destroyable {
15759
15773
  this.connectionTimer = setTimeout(() => {
15760
15774
  this.removeConnectionTimer();
15761
15775
  if (this.peerConnection?.connectionState !== "connected") {
15762
- logger$14.debug("[RTCPeerConnectionController] Connection timeout, restarting ICE gathering with relay only.");
15776
+ logger$15.debug("[RTCPeerConnectionController] Connection timeout, restarting ICE gathering with relay only.");
15763
15777
  this.iceGatheringController.restartICEGatheringWithRelayOnly();
15764
15778
  }
15765
15779
  }, this.connectionTimeout);
@@ -15781,14 +15795,14 @@ var RTCPeerConnectionController = class extends Destroyable {
15781
15795
  const stereo = this.options.stereo ?? PreferencesContainer.instance.stereoAudio;
15782
15796
  if (preferredAudioCodecs.length > 0 || preferredVideoCodecs.length > 0) {
15783
15797
  result = setCodecPreferences(result, preferredAudioCodecs, preferredVideoCodecs);
15784
- logger$14.debug("[RTCPeerConnectionController] Applied codec preferences to SDP", {
15798
+ logger$15.debug("[RTCPeerConnectionController] Applied codec preferences to SDP", {
15785
15799
  preferredAudioCodecs,
15786
15800
  preferredVideoCodecs
15787
15801
  });
15788
15802
  }
15789
15803
  if (stereo) {
15790
15804
  result = enableStereoOpus(result);
15791
- logger$14.debug("[RTCPeerConnectionController] Applied stereo Opus to SDP");
15805
+ logger$15.debug("[RTCPeerConnectionController] Applied stereo Opus to SDP");
15792
15806
  }
15793
15807
  return Promise.resolve(result);
15794
15808
  }
@@ -15847,18 +15861,18 @@ var RTCPeerConnectionController = class extends Destroyable {
15847
15861
  ...this.peerConnection.getConfiguration(),
15848
15862
  iceTransportPolicy: "relay"
15849
15863
  });
15850
- logger$14.debug("[RTCPeerConnectionController] ICE transport policy set to relay-only");
15864
+ logger$15.debug("[RTCPeerConnectionController] ICE transport policy set to relay-only");
15851
15865
  } catch (error) {
15852
- logger$14.warn("[RTCPeerConnectionController] Failed to set relay-only policy:", error);
15866
+ logger$15.warn("[RTCPeerConnectionController] Failed to set relay-only policy:", error);
15853
15867
  }
15854
15868
  this.setupEventListeners();
15855
15869
  this._isNegotiating$.next(true);
15856
- logger$14.debug(`[RTCPeerConnectionController] Triggering ICE restart${relayOnly ? " (relay-only)" : ""}.`);
15870
+ logger$15.debug(`[RTCPeerConnectionController] Triggering ICE restart${relayOnly ? " (relay-only)" : ""}.`);
15857
15871
  try {
15858
15872
  const offer = await this.peerConnection.createOffer({ iceRestart: true });
15859
15873
  await this.setLocalDescription(offer);
15860
15874
  } catch (error) {
15861
- logger$14.error("[RTCPeerConnectionController] ICE restart offer failed:", error);
15875
+ logger$15.error("[RTCPeerConnectionController] ICE restart offer failed:", error);
15862
15876
  this._errors$.next(error);
15863
15877
  this.negotiationEnded();
15864
15878
  if (policyChanged) this.restoreIceTransportPolicy();
@@ -15872,9 +15886,9 @@ var RTCPeerConnectionController = class extends Destroyable {
15872
15886
  ...this.peerConnection.getConfiguration(),
15873
15887
  iceTransportPolicy: this.options.relayOnly ? "relay" : "all"
15874
15888
  });
15875
- logger$14.debug("[RTCPeerConnectionController] ICE transport policy restored");
15889
+ logger$15.debug("[RTCPeerConnectionController] ICE transport policy restored");
15876
15890
  } catch (error) {
15877
- logger$14.warn("[RTCPeerConnectionController] Failed to restore ICE transport policy:", error);
15891
+ logger$15.warn("[RTCPeerConnectionController] Failed to restore ICE transport policy:", error);
15878
15892
  }
15879
15893
  }
15880
15894
  /**
@@ -15886,13 +15900,13 @@ var RTCPeerConnectionController = class extends Destroyable {
15886
15900
  await this.setupRemoteTracks();
15887
15901
  }
15888
15902
  async setupLocalTracks() {
15889
- logger$14.debug("[RTCPeerConnectionController] Setting up local tracks/transceivers.");
15903
+ logger$15.debug("[RTCPeerConnectionController] Setting up local tracks/transceivers.");
15890
15904
  const localStream = this.localStream ?? await this.localStreamController.buildLocalStream();
15891
15905
  if (this.transceiverController?.useAddStream ?? false) {
15892
- logger$14.warn("[RTCPeerConnectionController] Using deprecated addStream API to add local stream.");
15906
+ logger$15.warn("[RTCPeerConnectionController] Using deprecated addStream API to add local stream.");
15893
15907
  this.peerConnection?.addStream(localStream);
15894
15908
  if (!this.isNegotiating) {
15895
- logger$14.debug("[RTCPeerConnectionController] Forcing negotiationneeded after local tracks setup.");
15909
+ logger$15.debug("[RTCPeerConnectionController] Forcing negotiationneeded after local tracks setup.");
15896
15910
  this.negotiationNeeded$.next();
15897
15911
  }
15898
15912
  return;
@@ -15908,7 +15922,7 @@ var RTCPeerConnectionController = class extends Destroyable {
15908
15922
  const transceivers = (kind === "audio" ? this.transceiverController?.audioTransceivers : this.transceiverController?.videoTransceivers) ?? [];
15909
15923
  await this.transceiverController?.setupTransceiverSender(track, localStream, transceivers[index]);
15910
15924
  } else {
15911
- logger$14.debug(`[RTCPeerConnectionController] Using addTrack for local ${kind} track:`, track.id);
15925
+ logger$15.debug(`[RTCPeerConnectionController] Using addTrack for local ${kind} track:`, track.id);
15912
15926
  this.peerConnection?.addTrack(track, localStream);
15913
15927
  }
15914
15928
  }
@@ -15925,7 +15939,7 @@ var RTCPeerConnectionController = class extends Destroyable {
15925
15939
  async setupRemoteTracks() {
15926
15940
  if (!this.peerConnection) throw new DependencyError("RTCPeerConnection is not initialized");
15927
15941
  this.peerConnection.ontrack = (event) => {
15928
- logger$14.debug("[RTCPeerConnectionController] Remote track received:", event.track.kind);
15942
+ logger$15.debug("[RTCPeerConnectionController] Remote track received:", event.track.kind);
15929
15943
  if (event.streams[0]) this._remoteStream$.next(event.streams[0]);
15930
15944
  else {
15931
15945
  const existingTracks = this._remoteStream$.value?.getTracks() ?? [];
@@ -15951,9 +15965,9 @@ var RTCPeerConnectionController = class extends Destroyable {
15951
15965
  try {
15952
15966
  const localStream = this.localStreamController.addTrack(track);
15953
15967
  this.peerConnection.addTrack(track, localStream);
15954
- logger$14.debug(`[RTCPeerConnectionController] ${track.kind} track added:`, track.id);
15968
+ logger$15.debug(`[RTCPeerConnectionController] ${track.kind} track added:`, track.id);
15955
15969
  } catch (error) {
15956
- logger$14.error(`[RTCPeerConnectionController] Failed to add ${track.kind} track:`, error);
15970
+ logger$15.error(`[RTCPeerConnectionController] Failed to add ${track.kind} track:`, error);
15957
15971
  this._errors$.next(error);
15958
15972
  throw error;
15959
15973
  }
@@ -15970,15 +15984,15 @@ var RTCPeerConnectionController = class extends Destroyable {
15970
15984
  }
15971
15985
  const sender = this.peerConnection.getSenders().find((sender$1) => sender$1.track?.id === trackId);
15972
15986
  if (!sender) {
15973
- logger$14.debug(`[RTCPeerConnectionController] track not found: ${trackId}`);
15987
+ logger$15.debug(`[RTCPeerConnectionController] track not found: ${trackId}`);
15974
15988
  return;
15975
15989
  }
15976
15990
  try {
15977
15991
  this.peerConnection.removeTrack(sender);
15978
15992
  this.localStreamController.removeTrack(trackId);
15979
- logger$14.debug(`[RTCPeerConnectionController] ${sender.track?.kind} track removed:`, trackId);
15993
+ logger$15.debug(`[RTCPeerConnectionController] ${sender.track?.kind} track removed:`, trackId);
15980
15994
  } catch (error) {
15981
- logger$14.error(`[RTCPeerConnectionController] Failed to remove ${sender.track?.kind} track:`, error);
15995
+ logger$15.error(`[RTCPeerConnectionController] Failed to remove ${sender.track?.kind} track:`, error);
15982
15996
  this._errors$.next(error);
15983
15997
  throw error;
15984
15998
  }
@@ -16005,7 +16019,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16005
16019
  async replaceAudioTrackWithConstraints(constraints) {
16006
16020
  const senders = this.peerConnection?.getSenders().filter((s) => s.track?.kind === "audio" && s.track.readyState === "live");
16007
16021
  if (!senders || senders.length === 0) {
16008
- logger$14.warn("[RTCPeerConnectionController] No live audio sender to replace");
16022
+ logger$15.warn("[RTCPeerConnectionController] No live audio sender to replace");
16009
16023
  return;
16010
16024
  }
16011
16025
  for (const sender of senders) {
@@ -16023,7 +16037,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16023
16037
  const newTrack = (await this.getUserMedia({ audio: mergedConstraints })).getAudioTracks()[0];
16024
16038
  await sender.replaceTrack(newTrack);
16025
16039
  this.localStreamController.addTrack(newTrack);
16026
- logger$14.debug(`[RTCPeerConnectionController] Audio track replaced for server-pushed params. New track: ${newTrack.id}`);
16040
+ logger$15.debug(`[RTCPeerConnectionController] Audio track replaced for server-pushed params. New track: ${newTrack.id}`);
16027
16041
  }
16028
16042
  }
16029
16043
  /**
@@ -16031,7 +16045,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16031
16045
  * Completes all observables to prevent memory leaks.
16032
16046
  */
16033
16047
  destroy() {
16034
- logger$14.debug(`[RTCPeerConnectionController] Destroying RTCPeerConnectionController. ${this.propose}`);
16048
+ logger$15.debug(`[RTCPeerConnectionController] Destroying RTCPeerConnectionController. ${this.propose}`);
16035
16049
  this.removeConnectionTimer();
16036
16050
  this._iceGatheringController?.destroy();
16037
16051
  this.localStreamController.destroy();
@@ -16055,7 +16069,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16055
16069
  }
16056
16070
  stopRemoteTracks() {
16057
16071
  this._remoteStream$.value?.getTracks().forEach((track) => {
16058
- logger$14.debug(`[RTCPeerConnectionController] Stopping remote track: ${track.kind}`);
16072
+ logger$15.debug(`[RTCPeerConnectionController] Stopping remote track: ${track.kind}`);
16059
16073
  track.stop();
16060
16074
  });
16061
16075
  }
@@ -16072,7 +16086,7 @@ var RTCPeerConnectionController = class extends Destroyable {
16072
16086
  ...params,
16073
16087
  sdp: finalRemote
16074
16088
  };
16075
- logger$14.debug("[RTCPeerConnectionController] Setting remote description:", answer);
16089
+ logger$15.debug("[RTCPeerConnectionController] Setting remote description:", answer);
16076
16090
  return this.peerConnection.setRemoteDescription(answer);
16077
16091
  }
16078
16092
  };
@@ -16110,8 +16124,8 @@ function isVertoPingInnerParams(value) {
16110
16124
 
16111
16125
  //#endregion
16112
16126
  //#region src/managers/VertoManager.ts
16113
- var import_cjs$12 = require_cjs();
16114
- const logger$13 = getLogger();
16127
+ var import_cjs$13 = require_cjs();
16128
+ const logger$14 = getLogger();
16115
16129
  var VertoManager = class extends Destroyable {
16116
16130
  constructor(callSession) {
16117
16131
  super();
@@ -16137,6 +16151,7 @@ var WebRTCVertoManager = class extends VertoManager {
16137
16151
  this._screenShareTimeoutMs = 5e4;
16138
16152
  this._nodeId$ = this.createBehaviorSubject(options.nodeId ?? null);
16139
16153
  this.onError = options.onError;
16154
+ this.onModifyFailed = options.onModifyFailed;
16140
16155
  this.initSubscriptions();
16141
16156
  this.initMainPeerConnection();
16142
16157
  }
@@ -16149,7 +16164,7 @@ var WebRTCVertoManager = class extends VertoManager {
16149
16164
  try {
16150
16165
  await this.executeVerto(vertoModifyMessage);
16151
16166
  } catch (error) {
16152
- logger$13.warn("[WebRTCManager] Call might already be disconnected, error sending Verto hold:", error);
16167
+ logger$14.warn("[WebRTCManager] Call might already be disconnected, error sending Verto hold:", error);
16153
16168
  throw error;
16154
16169
  }
16155
16170
  }
@@ -16162,7 +16177,7 @@ var WebRTCVertoManager = class extends VertoManager {
16162
16177
  try {
16163
16178
  await this.executeVerto(vertoModifyMessage);
16164
16179
  } catch (error) {
16165
- logger$13.warn("[WebRTCManager] Call might already be disconnected, error sending Verto unhold:", error);
16180
+ logger$14.warn("[WebRTCManager] Call might already be disconnected, error sending Verto unhold:", error);
16166
16181
  throw error;
16167
16182
  }
16168
16183
  }
@@ -16202,7 +16217,7 @@ var WebRTCVertoManager = class extends VertoManager {
16202
16217
  return rtcPeerConnection;
16203
16218
  }
16204
16219
  get signalingStatus$() {
16205
- return this.cachedObservable("signalingStatus$", () => (0, import_cjs$12.merge)(this._signalingStatus$.pipe(filterNull()), this.mainPeerConnection.connectionState$.pipe((0, import_cjs$12.filter)((connectionState) => [
16220
+ return this.cachedObservable("signalingStatus$", () => (0, import_cjs$13.merge)(this._signalingStatus$.pipe(filterNull()), this.mainPeerConnection.connectionState$.pipe((0, import_cjs$13.filter)((connectionState) => [
16206
16221
  "connected",
16207
16222
  "disconnected",
16208
16223
  "failed"
@@ -16215,7 +16230,7 @@ var WebRTCVertoManager = class extends VertoManager {
16215
16230
  if (event.member_id) this.setSelfIdIfNull(event.member_id);
16216
16231
  });
16217
16232
  this.subscribeTo(this.vertoMedia$, (event) => {
16218
- logger$13.debug("[WebRTCManager] Received Verto media event (early media SDP):", event);
16233
+ logger$14.debug("[WebRTCManager] Received Verto media event (early media SDP):", event);
16219
16234
  this._signalingStatus$.next("ringing");
16220
16235
  const { sdp, callID } = event;
16221
16236
  this._rtcPeerConnectionsMap.get(callID)?.updateAnswerStatus({
@@ -16224,7 +16239,7 @@ var WebRTCVertoManager = class extends VertoManager {
16224
16239
  });
16225
16240
  });
16226
16241
  this.subscribeTo(this.vertoAnswer$, (event) => {
16227
- logger$13.debug("[WebRTCManager] Received Verto answer event:", event);
16242
+ logger$14.debug("[WebRTCManager] Received Verto answer event:", event);
16228
16243
  this._signalingStatus$.next("connecting");
16229
16244
  const { sdp, callID } = event;
16230
16245
  this._rtcPeerConnectionsMap.get(callID)?.updateAnswerStatus({
@@ -16233,7 +16248,7 @@ var WebRTCVertoManager = class extends VertoManager {
16233
16248
  });
16234
16249
  });
16235
16250
  this.subscribeTo(this.vertoMediaParams$, (event) => {
16236
- logger$13.debug("[WebRTCManager] Received Verto mediaParams event:", event);
16251
+ logger$14.debug("[WebRTCManager] Received Verto mediaParams event:", event);
16237
16252
  const { mediaParams, callID } = event;
16238
16253
  const rtcPeerConnController = this._rtcPeerConnectionsMap.get(callID);
16239
16254
  const { audio, video } = mediaParams;
@@ -16247,13 +16262,13 @@ var WebRTCVertoManager = class extends VertoManager {
16247
16262
  timestamp: Date.now()
16248
16263
  });
16249
16264
  } catch (error) {
16250
- logger$13.warn("[WebRTCManager] Error applying server-pushed media params:", error);
16265
+ logger$14.warn("[WebRTCManager] Error applying server-pushed media params:", error);
16251
16266
  this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
16252
16267
  }
16253
16268
  })();
16254
16269
  });
16255
16270
  this.subscribeTo(this.vertoPing$, (vertoPing) => {
16256
- this.attachManager.attach(this.webRtcCallSession);
16271
+ this.attachManager.attach(this.buildAttachableCall());
16257
16272
  this.sendVertoPong(vertoPing);
16258
16273
  });
16259
16274
  }
@@ -16269,13 +16284,13 @@ var WebRTCVertoManager = class extends VertoManager {
16269
16284
  */
16270
16285
  setNodeIdIfNull(nodeId) {
16271
16286
  if (!this._nodeId$.value && nodeId) {
16272
- logger$13.debug(`[WebRTCManager] Early node_id set: ${nodeId}`);
16287
+ logger$14.debug(`[WebRTCManager] Early node_id set: ${nodeId}`);
16273
16288
  this._nodeId$.next(nodeId);
16274
16289
  }
16275
16290
  }
16276
16291
  setSelfIdIfNull(selfId) {
16277
16292
  if (!this._selfId$.value && selfId) {
16278
- logger$13.debug(`[WebRTCManager] Early selfId set: ${selfId}`);
16293
+ logger$14.debug(`[WebRTCManager] Early selfId set: ${selfId}`);
16279
16294
  this._selfId$.next(selfId);
16280
16295
  }
16281
16296
  }
@@ -16284,7 +16299,7 @@ var WebRTCVertoManager = class extends VertoManager {
16284
16299
  const vertoPongMessage = VertoPong({ ...vertoPing });
16285
16300
  await this.executeVerto(vertoPongMessage);
16286
16301
  } catch (error) {
16287
- logger$13.warn("[WebRTCManager] Call might disconnect, error sending Verto pong:", error);
16302
+ logger$14.warn("[WebRTCManager] Call might disconnect, error sending Verto pong:", error);
16288
16303
  this.onError?.(new VertoPongError(error));
16289
16304
  }
16290
16305
  }
@@ -16294,7 +16309,7 @@ var WebRTCVertoManager = class extends VertoManager {
16294
16309
  if (audio) await this.mainPeerConnection.updateSendersConstraints("audio", audio);
16295
16310
  if (video) await this.mainPeerConnection.updateSendersConstraints("video", video);
16296
16311
  } catch (error) {
16297
- logger$13.warn("[WebRTCManager] Error updating media constraints:", error);
16312
+ logger$14.warn("[WebRTCManager] Error updating media constraints:", error);
16298
16313
  this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
16299
16314
  throw error;
16300
16315
  }
@@ -16302,6 +16317,15 @@ var WebRTCVertoManager = class extends VertoManager {
16302
16317
  get selfId() {
16303
16318
  return this._selfId$.value;
16304
16319
  }
16320
+ /** Build an AttachableCall from the current call state. */
16321
+ buildAttachableCall(idOverride) {
16322
+ return {
16323
+ nodeId: this.nodeId ?? void 0,
16324
+ id: idOverride ?? this.webRtcCallSession.id,
16325
+ to: this.webRtcCallSession.to,
16326
+ mediaDirections: this.webRtcCallSession.mediaDirections
16327
+ };
16328
+ }
16305
16329
  /**
16306
16330
  * Request a video keyframe via RTCP PLI/FIR.
16307
16331
  *
@@ -16315,20 +16339,20 @@ var WebRTCVertoManager = class extends VertoManager {
16315
16339
  try {
16316
16340
  const pc = this.mainPeerConnection.peerConnection;
16317
16341
  if (!pc) {
16318
- logger$13.warn("[WebRTCManager] No peer connection for keyframe request");
16342
+ logger$14.warn("[WebRTCManager] No peer connection for keyframe request");
16319
16343
  return;
16320
16344
  }
16321
16345
  const videoReceiver = pc.getReceivers().find((r) => r.track.kind === "video");
16322
16346
  if (!videoReceiver) {
16323
- logger$13.warn("[WebRTCManager] No video receiver for keyframe request");
16347
+ logger$14.warn("[WebRTCManager] No video receiver for keyframe request");
16324
16348
  return;
16325
16349
  }
16326
16350
  if (typeof videoReceiver.requestKeyFrame === "function") {
16327
16351
  videoReceiver.requestKeyFrame();
16328
- logger$13.debug("[WebRTCManager] Keyframe requested via RTCRtpReceiver.requestKeyFrame()");
16329
- } else logger$13.debug("[WebRTCManager] requestKeyFrame() not supported, skipping");
16352
+ logger$14.debug("[WebRTCManager] Keyframe requested via RTCRtpReceiver.requestKeyFrame()");
16353
+ } else logger$14.debug("[WebRTCManager] requestKeyFrame() not supported, skipping");
16330
16354
  } catch (error) {
16331
- logger$13.warn("[WebRTCManager] Keyframe request failed (non-fatal):", error);
16355
+ logger$14.warn("[WebRTCManager] Keyframe request failed (non-fatal):", error);
16332
16356
  }
16333
16357
  }
16334
16358
  /**
@@ -16346,13 +16370,13 @@ var WebRTCVertoManager = class extends VertoManager {
16346
16370
  try {
16347
16371
  const controller = this.mainPeerConnection;
16348
16372
  if (!controller.peerConnection) {
16349
- logger$13.warn("[WebRTCManager] No peer connection for ICE restart");
16373
+ logger$14.warn("[WebRTCManager] No peer connection for ICE restart");
16350
16374
  return;
16351
16375
  }
16352
16376
  await controller.triggerIceRestart(relayOnly);
16353
- logger$13.info(`[WebRTCManager] ICE restart initiated${relayOnly ? " (relay-only)" : ""}`);
16377
+ logger$14.info(`[WebRTCManager] ICE restart initiated${relayOnly ? " (relay-only)" : ""}`);
16354
16378
  } catch (error) {
16355
- logger$13.error("[WebRTCManager] ICE restart failed:", error);
16379
+ logger$14.error("[WebRTCManager] ICE restart failed:", error);
16356
16380
  throw error;
16357
16381
  }
16358
16382
  }
@@ -16370,13 +16394,13 @@ var WebRTCVertoManager = class extends VertoManager {
16370
16394
  const entries = Array.from(this._rtcPeerConnectionsMap.entries());
16371
16395
  for (const [id, controller] of entries) try {
16372
16396
  if (!controller.peerConnection) {
16373
- logger$13.debug(`[WebRTCManager] No peer connection for leg ${id}, skipping ICE restart`);
16397
+ logger$14.debug(`[WebRTCManager] No peer connection for leg ${id}, skipping ICE restart`);
16374
16398
  continue;
16375
16399
  }
16376
16400
  await controller.triggerIceRestart(relayOnly);
16377
- logger$13.info(`[WebRTCManager] ICE restart initiated for leg ${id}${relayOnly ? " (relay-only)" : ""}`);
16401
+ logger$14.info(`[WebRTCManager] ICE restart initiated for leg ${id}${relayOnly ? " (relay-only)" : ""}`);
16378
16402
  } catch (error) {
16379
- logger$13.warn(`[WebRTCManager] ICE restart failed for leg ${id}:`, error);
16403
+ logger$14.warn(`[WebRTCManager] ICE restart failed for leg ${id}:`, error);
16380
16404
  }
16381
16405
  }
16382
16406
  /**
@@ -16388,7 +16412,7 @@ var WebRTCVertoManager = class extends VertoManager {
16388
16412
  requestKeyframeAll() {
16389
16413
  for (const [id, controller] of this._rtcPeerConnectionsMap) {
16390
16414
  if (controller.isScreenShare) {
16391
- logger$13.debug(`[WebRTCManager] Skipping keyframe for send-only screen share leg ${id}`);
16415
+ logger$14.debug(`[WebRTCManager] Skipping keyframe for send-only screen share leg ${id}`);
16392
16416
  continue;
16393
16417
  }
16394
16418
  try {
@@ -16398,33 +16422,33 @@ var WebRTCVertoManager = class extends VertoManager {
16398
16422
  if (!videoReceiver) continue;
16399
16423
  if (typeof videoReceiver.requestKeyFrame === "function") {
16400
16424
  videoReceiver.requestKeyFrame();
16401
- logger$13.debug(`[WebRTCManager] Keyframe requested for leg ${id}`);
16425
+ logger$14.debug(`[WebRTCManager] Keyframe requested for leg ${id}`);
16402
16426
  }
16403
16427
  } catch (error) {
16404
- logger$13.warn(`[WebRTCManager] Keyframe request failed for leg ${id} (non-fatal):`, error);
16428
+ logger$14.warn(`[WebRTCManager] Keyframe request failed for leg ${id} (non-fatal):`, error);
16405
16429
  }
16406
16430
  }
16407
16431
  }
16408
16432
  get callJoinedEvent$() {
16409
- return this.webRtcCallSession.callEvent$.pipe((0, import_cjs$12.filter)(isCallJoinedPayload), (0, import_cjs$12.takeUntil)(this.destroyed$));
16433
+ return this.webRtcCallSession.callEvent$.pipe((0, import_cjs$13.filter)(isCallJoinedPayload), (0, import_cjs$13.takeUntil)(this.destroyed$));
16410
16434
  }
16411
16435
  get vertoMedia$() {
16412
- return this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoMediaInnerParams, "params"), (0, import_cjs$12.takeUntil)(this.destroyed$));
16436
+ return this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoMediaInnerParams, "params"), (0, import_cjs$13.takeUntil)(this.destroyed$));
16413
16437
  }
16414
16438
  get vertoAnswer$() {
16415
- return this.cachedObservable("vertoAnswer$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoAnswerInnerParams, "params"), (0, import_cjs$12.takeUntil)(this.destroyed$)));
16439
+ return this.cachedObservable("vertoAnswer$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoAnswerInnerParams, "params"), (0, import_cjs$13.takeUntil)(this.destroyed$)));
16416
16440
  }
16417
16441
  get vertoMediaParams$() {
16418
- return this.cachedObservable("vertoMediaParams$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoMediaParamsInnerParams, "params"), (0, import_cjs$12.takeUntil)(this.destroyed$)));
16442
+ return this.cachedObservable("vertoMediaParams$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoMediaParamsInnerParams, "params"), (0, import_cjs$13.takeUntil)(this.destroyed$)));
16419
16443
  }
16420
16444
  get vertoBye$() {
16421
- return this.cachedObservable("vertoBye$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoByeMessage, "params"), (0, import_cjs$12.takeUntil)(this.destroyed$)));
16445
+ return this.cachedObservable("vertoBye$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoByeMessage, "params"), (0, import_cjs$13.takeUntil)(this.destroyed$)));
16422
16446
  }
16423
16447
  get vertoAttach$() {
16424
- return this.cachedObservable("vertoAttach$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoAttachMessage, "params"), (0, import_cjs$12.takeUntil)(this.destroyed$)));
16448
+ return this.cachedObservable("vertoAttach$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoAttachMessage, "params"), (0, import_cjs$13.takeUntil)(this.destroyed$)));
16425
16449
  }
16426
16450
  get vertoPing$() {
16427
- return this.cachedObservable("vertoPing$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoPingInnerParams, "params"), (0, import_cjs$12.takeUntil)(this.destroyed$)));
16451
+ return this.cachedObservable("vertoPing$", () => this.webRtcCallSession.webrtcMessages$.pipe(filterAs(isVertoPingInnerParams, "params"), (0, import_cjs$13.takeUntil)(this.destroyed$)));
16428
16452
  }
16429
16453
  async executeVerto(message, optionals = {}) {
16430
16454
  const webrtcVertoMessage = WebrtcVerto({
@@ -16449,7 +16473,7 @@ var WebRTCVertoManager = class extends VertoManager {
16449
16473
  }
16450
16474
  async sendLocalDescription(message, rtcPeerConnController) {
16451
16475
  const vertoMethod = message.method;
16452
- const optionalsParams = this.getSendLocalSDPOptionalParams(rtcPeerConnController, vertoMethod);
16476
+ const optionalsParams = this.getSendLocalSDPOptionalParams(rtcPeerConnController, message);
16453
16477
  try {
16454
16478
  const response = await this.executeVerto(message, optionalsParams);
16455
16479
  switch (vertoMethod) {
@@ -16462,8 +16486,9 @@ var WebRTCVertoManager = class extends VertoManager {
16462
16486
  default:
16463
16487
  }
16464
16488
  } catch (error) {
16465
- logger$13.error(`[WebRTCManager] Error sending Verto ${vertoMethod}:`, error);
16489
+ logger$14.error(`[WebRTCManager] Error sending Verto ${vertoMethod}:`, error);
16466
16490
  this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
16491
+ if (vertoMethod === "verto.modify") this.onModifyFailed?.();
16467
16492
  }
16468
16493
  }
16469
16494
  async processModifyResponse(response, rtcPeerConnController) {
@@ -16476,7 +16501,7 @@ var WebRTCVertoManager = class extends VertoManager {
16476
16501
  sdp
16477
16502
  });
16478
16503
  } catch (error) {
16479
- logger$13.warn("[WebRTCManager] Error processing modify response:", error);
16504
+ logger$14.warn("[WebRTCManager] Error processing modify response:", error);
16480
16505
  const modifyError = error instanceof Error ? error : new Error(String(error), { cause: error });
16481
16506
  this.onError?.(modifyError);
16482
16507
  }
@@ -16488,19 +16513,24 @@ var WebRTCVertoManager = class extends VertoManager {
16488
16513
  this._nodeId$.next(getValueFrom(response, "result.node_id") ?? null);
16489
16514
  const memberId = getValueFrom(response, "result.result.result.memberID") ?? null;
16490
16515
  const callId = getValueFrom(response, "result.result.result.callID") ?? null;
16491
- logger$13.debug("[WebRTCManager] Verto invite response:", {
16516
+ logger$14.debug("[WebRTCManager] Verto invite response:", {
16492
16517
  callId,
16493
16518
  memberId,
16494
16519
  response
16495
16520
  });
16496
16521
  this._selfId$.next(memberId);
16497
16522
  rtcPeerConnController.setMemberId(memberId);
16498
- if (callId) this.webRtcCallSession.addCallId(callId);
16499
- this.attachManager.attach(this.webRtcCallSession);
16500
- logger$13.info("[WebRTCManager] Verto invite successful");
16501
- logger$13.debug(`[WebRTCManager] nodeid: ${this._nodeId$.value}, selfId: ${this._selfId$.value}`);
16523
+ if (callId) {
16524
+ this.webRtcCallSession.addCallId(callId);
16525
+ this.attachManager.attach(this.buildAttachableCall(callId));
16526
+ } else logger$14.warn("[WebRTCManager] Cannot attach call, missing callId:", {
16527
+ nodeId: this.nodeId,
16528
+ callId
16529
+ });
16530
+ logger$14.info("[WebRTCManager] Verto invite successful");
16531
+ logger$14.debug(`[WebRTCManager] nodeid: ${this._nodeId$.value}, selfId: ${this._selfId$.value}`);
16502
16532
  } else {
16503
- logger$13.error("[WebRTCManager] Verto invite failed:", response);
16533
+ logger$14.error("[WebRTCManager] Verto invite failed:", response);
16504
16534
  const inviteError = response.error ? new JSONRPCError(response.error.code, response.error.message, response.error.data) : /* @__PURE__ */ new Error("Verto invite failed: unexpected response");
16505
16535
  this.onError?.(inviteError);
16506
16536
  }
@@ -16545,17 +16575,17 @@ var WebRTCVertoManager = class extends VertoManager {
16545
16575
  if (options.initOffer) this.handleInboundAnswer(rtcPeerConnController);
16546
16576
  }
16547
16577
  async handleInboundAnswer(rtcPeerConnController) {
16548
- logger$13.debug("[WebRTCManager] Waiting for inbound call to be accepted or rejected");
16549
- const vertoByeOrAccepted = await (0, import_cjs$12.firstValueFrom)((0, import_cjs$12.race)(this.vertoBye$, this.webRtcCallSession.answered$).pipe((0, import_cjs$12.takeUntil)(this.destroyed$))).catch(() => null);
16578
+ logger$14.debug("[WebRTCManager] Waiting for inbound call to be accepted or rejected");
16579
+ const vertoByeOrAccepted = await (0, import_cjs$13.firstValueFrom)((0, import_cjs$13.race)(this.vertoBye$, this.webRtcCallSession.answered$).pipe((0, import_cjs$13.takeUntil)(this.destroyed$))).catch(() => null);
16550
16580
  if (vertoByeOrAccepted === null) {
16551
- logger$13.debug("[WebRTCManager] Inbound answer handler aborted (destroyed).");
16581
+ logger$14.debug("[WebRTCManager] Inbound answer handler aborted (destroyed).");
16552
16582
  return;
16553
16583
  }
16554
16584
  if (isVertoByeMessage(vertoByeOrAccepted)) {
16555
- logger$13.info("[WebRTCManager] Inbound call ended by remote before answer.");
16585
+ logger$14.info("[WebRTCManager] Inbound call ended by remote before answer.");
16556
16586
  this.callSession?.destroy();
16557
16587
  } else if (!vertoByeOrAccepted) {
16558
- logger$13.info("[WebRTCManager] Inbound call rejected by user.");
16588
+ logger$14.info("[WebRTCManager] Inbound call rejected by user.");
16559
16589
  try {
16560
16590
  await this.bye("USER_BUSY");
16561
16591
  } finally {
@@ -16563,21 +16593,22 @@ var WebRTCVertoManager = class extends VertoManager {
16563
16593
  this.callSession?.destroy();
16564
16594
  }
16565
16595
  } else {
16566
- logger$13.debug("[WebRTCManager] Inbound call accepted, creating SDP answer");
16596
+ logger$14.debug("[WebRTCManager] Inbound call accepted, creating SDP answer");
16567
16597
  const answerOptions = this.webRtcCallSession.answerMediaOptions;
16568
16598
  try {
16569
16599
  await rtcPeerConnController.acceptInbound(answerOptions);
16570
16600
  } catch (error) {
16571
- logger$13.error("[WebRTCManager] Error creating inbound answer:", error);
16601
+ logger$14.error("[WebRTCManager] Error creating inbound answer:", error);
16572
16602
  this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
16573
16603
  }
16574
16604
  }
16575
16605
  }
16576
16606
  setupVertoAttachHandler() {
16577
16607
  this.subscribeTo(this.vertoAttach$, async (vertoAttach) => {
16578
- logger$13.debug("[WebRTCManager] Received Verto attach event for existing call:", vertoAttach);
16608
+ logger$14.debug("[WebRTCManager] Received Verto attach event for existing call:", vertoAttach);
16579
16609
  const { callID } = vertoAttach;
16580
16610
  await this.attachManager.attach({
16611
+ nodeId: this.nodeId ?? void 0,
16581
16612
  id: callID,
16582
16613
  to: vertoAttach.callee_id_number,
16583
16614
  mediaDirections: {
@@ -16588,12 +16619,12 @@ var WebRTCVertoManager = class extends VertoManager {
16588
16619
  });
16589
16620
  }
16590
16621
  initObservables(rtcPeerConnController) {
16591
- this.mediaDirections$ = rtcPeerConnController.connectionState$.pipe((0, import_cjs$12.filter)((state) => state === "connected"), (0, import_cjs$12.map)(() => rtcPeerConnController.mediaDirections), (0, import_cjs$12.startWith)(rtcPeerConnController.mediaDirections), (0, import_cjs$12.takeUntil)(this.destroyed$));
16592
- this.localStream$ = rtcPeerConnController.localStream$.pipe(filterNull(), (0, import_cjs$12.takeUntil)(this.destroyed$));
16593
- this.remoteStream$ = rtcPeerConnController.remoteStream$.pipe(filterNull(), (0, import_cjs$12.takeUntil)(this.destroyed$));
16622
+ this.mediaDirections$ = rtcPeerConnController.connectionState$.pipe((0, import_cjs$13.filter)((state) => state === "connected"), (0, import_cjs$13.map)(() => rtcPeerConnController.mediaDirections), (0, import_cjs$13.startWith)(rtcPeerConnController.mediaDirections), (0, import_cjs$13.takeUntil)(this.destroyed$));
16623
+ this.localStream$ = rtcPeerConnController.localStream$.pipe(filterNull(), (0, import_cjs$13.takeUntil)(this.destroyed$));
16624
+ this.remoteStream$ = rtcPeerConnController.remoteStream$.pipe(filterNull(), (0, import_cjs$13.takeUntil)(this.destroyed$));
16594
16625
  }
16595
16626
  setupLocalDescriptionHandler(rtcPeerConnController) {
16596
- this.subscribeTo(rtcPeerConnController.localDescription$.pipe((0, import_cjs$12.filter)((description) => description !== null), (0, import_cjs$12.takeUntil)(this.destroyed$)), (description) => {
16627
+ this.subscribeTo(rtcPeerConnController.localDescription$.pipe((0, import_cjs$13.filter)((description) => description !== null), (0, import_cjs$13.takeUntil)(this.destroyed$)), (description) => {
16597
16628
  const { type, sdp } = description;
16598
16629
  const dialogParams = this.dialogParams(rtcPeerConnController);
16599
16630
  const initial = !rtcPeerConnController.firstSDPExchangeCompleted;
@@ -16622,11 +16653,11 @@ var WebRTCVertoManager = class extends VertoManager {
16622
16653
  setupVertoByeHandler() {
16623
16654
  this.subscribeTo(this.vertoBye$, () => {
16624
16655
  this._signalingStatus$.next("disconnected");
16625
- this.attachManager.detach(this.webRtcCallSession);
16656
+ this.attachManager.detach(this.buildAttachableCall());
16626
16657
  this.callSession?.destroy();
16627
16658
  });
16628
16659
  }
16629
- getSendLocalSDPOptionalParams(rtcPeerConnController, vertoMethod) {
16660
+ getSendLocalSDPOptionalParams(rtcPeerConnController, vertoMessage) {
16630
16661
  let subscribe = void 0;
16631
16662
  if (!rtcPeerConnController.firstSDPExchangeCompleted) {
16632
16663
  subscribe = [];
@@ -16634,7 +16665,7 @@ var WebRTCVertoManager = class extends VertoManager {
16634
16665
  else if (rtcPeerConnController.isAdditionalDevice) subscribe.push(...PreferencesContainer.instance.inviteSubscribeAdditionalDevice);
16635
16666
  else if (rtcPeerConnController.isScreenShare) subscribe.push(...PreferencesContainer.instance.inviteSubscribeScreenshare);
16636
16667
  }
16637
- const isInvite = vertoMethod === "verto.invite";
16668
+ const isInvite = isVertoInviteMessage(vertoMessage);
16638
16669
  const isReattach = isInvite && this.webRtcCallSession.options.reattach;
16639
16670
  return {
16640
16671
  callID: rtcPeerConnController.id,
@@ -16643,13 +16674,13 @@ var WebRTCVertoManager = class extends VertoManager {
16643
16674
  };
16644
16675
  }
16645
16676
  async sendLocalDescriptionOnceAccepted(vertoMessageRequest, rtcPeerConnectionController) {
16646
- logger$13.debug("[WebRTCManager] Waiting for call to be accepted or ended before sending answer");
16647
- const vertoByeOrAccepted = await (0, import_cjs$12.firstValueFrom)((0, import_cjs$12.race)(this.vertoBye$, this.webRtcCallSession.answered$));
16677
+ logger$14.debug("[WebRTCManager] Waiting for call to be accepted or ended before sending answer");
16678
+ const vertoByeOrAccepted = await (0, import_cjs$13.firstValueFrom)((0, import_cjs$13.race)(this.vertoBye$, this.webRtcCallSession.answered$));
16648
16679
  if (isVertoByeMessage(vertoByeOrAccepted)) {
16649
- logger$13.info("[WebRTCManager] Call ended before answer was sent.");
16680
+ logger$14.info("[WebRTCManager] Call ended before answer was sent.");
16650
16681
  this.callSession?.destroy();
16651
16682
  } else if (!vertoByeOrAccepted) {
16652
- logger$13.info("[WebRTCManager] Call was not accepted, sending verto.bye.");
16683
+ logger$14.info("[WebRTCManager] Call was not accepted, sending verto.bye.");
16653
16684
  try {
16654
16685
  await this.bye("USER_BUSY");
16655
16686
  } finally {
@@ -16657,14 +16688,14 @@ var WebRTCVertoManager = class extends VertoManager {
16657
16688
  this.callSession?.destroy();
16658
16689
  }
16659
16690
  } else {
16660
- logger$13.debug("[WebRTCManager] Call accepted, sending answer");
16691
+ logger$14.debug("[WebRTCManager] Call accepted, sending answer");
16661
16692
  try {
16662
16693
  this._signalingStatus$.next("connecting");
16663
16694
  await this.sendLocalDescription(vertoMessageRequest, rtcPeerConnectionController);
16664
16695
  await rtcPeerConnectionController.updateAnswerStatus({ status: "sent" });
16665
- await this.attachManager.attach(this.webRtcCallSession);
16696
+ await this.attachManager.attach(this.buildAttachableCall());
16666
16697
  } catch (error) {
16667
- logger$13.error("[WebRTCManager] Error sending Verto answer:", error);
16698
+ logger$14.error("[WebRTCManager] Error sending Verto answer:", error);
16668
16699
  this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
16669
16700
  await rtcPeerConnectionController.updateAnswerStatus({ status: "failed" });
16670
16701
  }
@@ -16753,12 +16784,12 @@ var WebRTCVertoManager = class extends VertoManager {
16753
16784
  this.subscribeTo(rtcPeerConnController.errors$, (error) => {
16754
16785
  this.onError?.(error);
16755
16786
  });
16756
- await (0, import_cjs$12.firstValueFrom)(rtcPeerConnController.connectionState$.pipe((0, import_cjs$12.filter)((state) => state === "connected"), (0, import_cjs$12.take)(1), (0, import_cjs$12.timeout)(this._screenShareTimeoutMs)));
16787
+ await (0, import_cjs$13.firstValueFrom)(rtcPeerConnController.connectionState$.pipe((0, import_cjs$13.filter)((state) => state === "connected"), (0, import_cjs$13.take)(1), (0, import_cjs$13.timeout)(this._screenShareTimeoutMs)));
16757
16788
  this._screenShareStatus$.next("started");
16758
- logger$13.info("[WebRTCManager] Screen share started successfully.");
16789
+ logger$14.info("[WebRTCManager] Screen share started successfully.");
16759
16790
  return rtcPeerConnController.id;
16760
16791
  } catch (error) {
16761
- logger$13.warn("[WebRTCManager] Error initializing additional peer connection:", error);
16792
+ logger$14.warn("[WebRTCManager] Error initializing additional peer connection:", error);
16762
16793
  this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));
16763
16794
  if (rtcPeerConnController) rtcPeerConnController.destroy();
16764
16795
  this._screenShareStatus$.next("none");
@@ -16777,9 +16808,9 @@ var WebRTCVertoManager = class extends VertoManager {
16777
16808
  if (removeTrack) return this.mainPeerConnection.stopTrackSender(removeTrack, { updateTransceiverDirection: true });
16778
16809
  }
16779
16810
  async removeScreenMedia() {
16780
- if (!["starting", "started"].includes(this._screenShareStatus$.value)) logger$13.warn("[WebRTCManager] No active screen share to stop.");
16811
+ if (!["starting", "started"].includes(this._screenShareStatus$.value)) logger$14.warn("[WebRTCManager] No active screen share to stop.");
16781
16812
  if (!this._screenShareId) {
16782
- logger$13.debug("[WebRTCManager] No screen share peer connection found.");
16813
+ logger$14.debug("[WebRTCManager] No screen share peer connection found.");
16783
16814
  return;
16784
16815
  }
16785
16816
  this._screenShareStatus$.next("stopping");
@@ -16808,12 +16839,12 @@ var WebRTCVertoManager = class extends VertoManager {
16808
16839
  dialogParams: this.dialogParams(rtcPeerConnController)
16809
16840
  }));
16810
16841
  } catch (error) {
16811
- logger$13.warn("[WebRTCManager] Call might already be disconnected, error sending Verto bye:", error);
16842
+ logger$14.warn("[WebRTCManager] Call might already be disconnected, error sending Verto bye:", error);
16812
16843
  throw error;
16813
16844
  }
16814
16845
  }
16815
16846
  async bye(cause) {
16816
- this.attachManager.detach(this.webRtcCallSession);
16847
+ this.attachManager.detach(this.buildAttachableCall());
16817
16848
  const rtcPeerConnController = this._rtcPeerConnectionsMap.get(this.webRtcCallSession.id);
16818
16849
  if (rtcPeerConnController) await this.executeVertoBye(rtcPeerConnController, cause);
16819
16850
  }
@@ -16826,7 +16857,7 @@ var WebRTCVertoManager = class extends VertoManager {
16826
16857
  try {
16827
16858
  await this.executeVerto(vertoInfoMessage);
16828
16859
  } catch (error) {
16829
- logger$13.warn("[WebRTCManager] Error sending DTMF digits:", error);
16860
+ logger$14.warn("[WebRTCManager] Error sending DTMF digits:", error);
16830
16861
  throw error;
16831
16862
  }
16832
16863
  }
@@ -16837,10 +16868,10 @@ var WebRTCVertoManager = class extends VertoManager {
16837
16868
  action: "transfer"
16838
16869
  });
16839
16870
  try {
16840
- logger$13.debug("[WebRTCManager] Transferring call with options:", options);
16871
+ logger$14.debug("[WebRTCManager] Transferring call with options:", options);
16841
16872
  await this.executeVerto(message);
16842
16873
  } catch (error) {
16843
- logger$13.error("[WebRTCManager] Error transferring call:", error);
16874
+ logger$14.error("[WebRTCManager] Error transferring call:", error);
16844
16875
  throw error;
16845
16876
  }
16846
16877
  }
@@ -16856,8 +16887,8 @@ var WebRTCVertoManager = class extends VertoManager {
16856
16887
 
16857
16888
  //#endregion
16858
16889
  //#region src/controllers/RTCStatsMonitor.ts
16859
- var import_cjs$11 = require_cjs();
16860
- const logger$12 = getLogger();
16890
+ var import_cjs$12 = require_cjs();
16891
+ const logger$13 = getLogger();
16861
16892
  const DEFAULT_POLLING_INTERVAL_MS = 1e3;
16862
16893
  const DEFAULT_BASELINE_SAMPLES = 10;
16863
16894
  const DEFAULT_NO_AUDIO_PACKET_THRESHOLD_MS = 2e3;
@@ -16919,7 +16950,7 @@ var RTCStatsMonitor = class extends Destroyable {
16919
16950
  }
16920
16951
  /** Simple boolean health indicator. */
16921
16952
  get isNetworkHealthy$() {
16922
- return this.cachedObservable("isNetworkHealthy$", () => this._networkIssues$.pipe((0, import_cjs$11.map)((issues) => issues.length === 0), (0, import_cjs$11.distinctUntilChanged)(), (0, import_cjs$11.takeUntil)(this.destroyed$)));
16953
+ return this.cachedObservable("isNetworkHealthy$", () => this._networkIssues$.pipe((0, import_cjs$12.map)((issues) => issues.length === 0), (0, import_cjs$12.distinctUntilChanged)(), (0, import_cjs$12.takeUntil)(this.destroyed$)));
16923
16954
  }
16924
16955
  /** Whether the network is currently healthy. */
16925
16956
  get isNetworkHealthy() {
@@ -16935,7 +16966,7 @@ var RTCStatsMonitor = class extends Destroyable {
16935
16966
  }
16936
16967
  /** Emits individual critical issues for the recovery pipeline. */
16937
16968
  get criticalIssue$() {
16938
- return this.cachedObservable("criticalIssue$", () => this._networkIssues$.pipe((0, import_cjs$11.mergeMap)((issues) => (0, import_cjs$11.from)(issues.filter((i) => i.severity === "critical"))), (0, import_cjs$11.takeUntil)(this.destroyed$)));
16969
+ return this.cachedObservable("criticalIssue$", () => this._networkIssues$.pipe((0, import_cjs$12.mergeMap)((issues) => (0, import_cjs$12.from)(issues.filter((i) => i.severity === "critical"))), (0, import_cjs$12.takeUntil)(this.destroyed$)));
16939
16970
  }
16940
16971
  /** Emits each raw stats sample extracted from the peer connection. */
16941
16972
  get sample$() {
@@ -16947,32 +16978,32 @@ var RTCStatsMonitor = class extends Destroyable {
16947
16978
  const now = Date.now();
16948
16979
  this.lastAudioPacketChangeTime = now;
16949
16980
  this.lastVideoPacketChangeTime = now;
16950
- logger$12.debug("[RTCStatsMonitor] Starting stats monitoring");
16951
- this.subscribeTo((0, import_cjs$11.interval)(this.pollingIntervalMs).pipe((0, import_cjs$11.filter)(() => this.running), (0, import_cjs$11.switchMap)(() => (0, import_cjs$11.from)(this.peerConnection.getStats()).pipe((0, import_cjs$11.catchError)((err) => {
16952
- logger$12.warn("[RTCStatsMonitor] Failed to get stats:", err);
16953
- return import_cjs$11.EMPTY;
16954
- }))), (0, import_cjs$11.filter)(() => this.running), (0, import_cjs$11.map)((report) => this.extractSample(report))), (sample$1) => this._sample$.next(sample$1));
16955
- this.subscribeTo(this._sample$.pipe((0, import_cjs$11.take)(this.baselineSampleCount), (0, import_cjs$11.toArray)(), (0, import_cjs$11.map)((samples) => ({
16981
+ logger$13.debug("[RTCStatsMonitor] Starting stats monitoring");
16982
+ this.subscribeTo((0, import_cjs$12.interval)(this.pollingIntervalMs).pipe((0, import_cjs$12.filter)(() => this.running), (0, import_cjs$12.switchMap)(() => (0, import_cjs$12.from)(this.peerConnection.getStats()).pipe((0, import_cjs$12.catchError)((err) => {
16983
+ logger$13.warn("[RTCStatsMonitor] Failed to get stats:", err);
16984
+ return import_cjs$12.EMPTY;
16985
+ }))), (0, import_cjs$12.filter)(() => this.running), (0, import_cjs$12.map)((report) => this.extractSample(report))), (sample$1) => this._sample$.next(sample$1));
16986
+ this.subscribeTo(this._sample$.pipe((0, import_cjs$12.take)(this.baselineSampleCount), (0, import_cjs$12.toArray)(), (0, import_cjs$12.map)((samples) => ({
16956
16987
  rtt: samples.reduce((s, b) => s + b.roundTripTime, 0) / samples.length,
16957
16988
  jitter: samples.reduce((s, b) => s + b.audioJitter, 0) / samples.length,
16958
16989
  ready: true
16959
16990
  }))), (baseline) => {
16960
- logger$12.debug(`[RTCStatsMonitor] Baseline established: rtt=${baseline.rtt.toFixed(1)}ms, jitter=${baseline.jitter.toFixed(1)}ms`);
16991
+ logger$13.debug(`[RTCStatsMonitor] Baseline established: rtt=${baseline.rtt.toFixed(1)}ms, jitter=${baseline.jitter.toFixed(1)}ms`);
16961
16992
  this._baseline$.next(baseline);
16962
16993
  });
16963
- this.subscribeTo(this._sample$.pipe((0, import_cjs$11.scan)((acc, sample$1) => ({
16994
+ this.subscribeTo(this._sample$.pipe((0, import_cjs$12.scan)((acc, sample$1) => ({
16964
16995
  prev: acc.current,
16965
16996
  current: sample$1
16966
16997
  }), {
16967
16998
  prev: null,
16968
16999
  current: null
16969
- }), (0, import_cjs$11.filter)((pair) => pair.current !== null)), ({ prev, current }) => {
17000
+ }), (0, import_cjs$12.filter)((pair) => pair.current !== null)), ({ prev, current }) => {
16970
17001
  const now$1 = current.timestamp;
16971
17002
  this.updatePacketTracking(current, now$1);
16972
17003
  const issues = this.detectIssues(current, prev, now$1);
16973
17004
  this._networkIssues$.next(issues);
16974
17005
  });
16975
- this.subscribeTo(this._sample$.pipe((0, import_cjs$11.scan)((history, sample$1) => {
17006
+ this.subscribeTo(this._sample$.pipe((0, import_cjs$12.scan)((history, sample$1) => {
16976
17007
  const cutoff = sample$1.timestamp - this.historyWindowSeconds * 1e3;
16977
17008
  const metrics = {
16978
17009
  timestamp: sample$1.timestamp,
@@ -16994,10 +17025,10 @@ var RTCStatsMonitor = class extends Destroyable {
16994
17025
  stop() {
16995
17026
  if (!this.running) return;
16996
17027
  this.running = false;
16997
- logger$12.debug("[RTCStatsMonitor] Stopping stats monitoring");
17028
+ logger$13.debug("[RTCStatsMonitor] Stopping stats monitoring");
16998
17029
  }
16999
17030
  destroy() {
17000
- logger$12.debug("[RTCStatsMonitor] Destroying RTCStatsMonitor");
17031
+ logger$13.debug("[RTCStatsMonitor] Destroying RTCStatsMonitor");
17001
17032
  this.stop();
17002
17033
  super.destroy();
17003
17034
  }
@@ -17125,8 +17156,8 @@ var RTCStatsMonitor = class extends Destroyable {
17125
17156
 
17126
17157
  //#endregion
17127
17158
  //#region src/managers/CallRecoveryManager.ts
17128
- var import_cjs$10 = require_cjs();
17129
- const logger$11 = getLogger();
17159
+ var import_cjs$11 = require_cjs();
17160
+ const logger$12 = getLogger();
17130
17161
  const DEFAULT_DEBOUNCE_TIME_MS = 2e3;
17131
17162
  const DEFAULT_COOLDOWN_MS = 1e4;
17132
17163
  const DEFAULT_ICE_GRACE_PERIOD_MS = 3e3;
@@ -17162,7 +17193,7 @@ const DEGRADATION_ONLY_ISSUES = new Set([
17162
17193
  * A state machine tracks the pipeline: IDLE -> DEBOUNCING -> RECOVERING -> COOLDOWN.
17163
17194
  */
17164
17195
  var CallRecoveryManager = class extends Destroyable {
17165
- constructor(callbacks, config = {}) {
17196
+ constructor(callbacks, inputs, config = {}) {
17166
17197
  super();
17167
17198
  this._recoveryState$ = this.createBehaviorSubject("idle");
17168
17199
  this._recoveryEvent$ = this.createSubject();
@@ -17176,6 +17207,7 @@ var CallRecoveryManager = class extends Destroyable {
17176
17207
  this._cooldownUntil = 0;
17177
17208
  this._pipelineStop$ = this.createSubject();
17178
17209
  this._callbacks = callbacks;
17210
+ this._inputs = inputs;
17179
17211
  this._config = {
17180
17212
  debounceTimeMs: config.debounceTimeMs ?? DEFAULT_DEBOUNCE_TIME_MS,
17181
17213
  cooldownMs: config.cooldownMs ?? DEFAULT_COOLDOWN_MS,
@@ -17195,16 +17227,16 @@ var CallRecoveryManager = class extends Destroyable {
17195
17227
  this.initDegradationRecoveryPipeline();
17196
17228
  }
17197
17229
  get recoveryState$() {
17198
- return this._recoveryState$.asObservable().pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
17230
+ return this._recoveryState$.asObservable().pipe((0, import_cjs$11.takeUntil)(this._destroyed$));
17199
17231
  }
17200
17232
  get recoveryState() {
17201
17233
  return this._recoveryState$.value;
17202
17234
  }
17203
17235
  get recoveryEvent$() {
17204
- return this._recoveryEvent$.asObservable().pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
17236
+ return this._recoveryEvent$.asObservable().pipe((0, import_cjs$11.takeUntil)(this._destroyed$));
17205
17237
  }
17206
17238
  get bandwidthConstrained$() {
17207
- return this._bandwidthConstrained$.asObservable().pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
17239
+ return this._bandwidthConstrained$.asObservable().pipe((0, import_cjs$11.takeUntil)(this._destroyed$));
17208
17240
  }
17209
17241
  get bandwidthConstrained() {
17210
17242
  return this._bandwidthConstrained$.value;
@@ -17222,10 +17254,10 @@ var CallRecoveryManager = class extends Destroyable {
17222
17254
  */
17223
17255
  async requestIceRestart() {
17224
17256
  if (this._recoveryState$.value === "recovering") {
17225
- logger$11.info("CallRecoveryManager: manual ICE restart skipped — recovery already in progress");
17257
+ logger$12.info("CallRecoveryManager: manual ICE restart skipped — recovery already in progress");
17226
17258
  return;
17227
17259
  }
17228
- logger$11.info("CallRecoveryManager: manual ICE restart requested");
17260
+ logger$12.info("CallRecoveryManager: manual ICE restart requested");
17229
17261
  this.transitionTo("recovering");
17230
17262
  await this.executeIceRestart(false);
17231
17263
  this.startCooldown();
@@ -17241,7 +17273,7 @@ var CallRecoveryManager = class extends Destroyable {
17241
17273
  * WebSocket reconnect or call state recovers to 'connected'.
17242
17274
  */
17243
17275
  reset() {
17244
- logger$11.info("CallRecoveryManager: resetting counters");
17276
+ logger$12.info("CallRecoveryManager: resetting counters");
17245
17277
  this._attemptCount = 0;
17246
17278
  this._keyframeBurstCount = 0;
17247
17279
  this._keyframeBurstStart = 0;
@@ -17250,6 +17282,22 @@ var CallRecoveryManager = class extends Destroyable {
17250
17282
  this.transitionTo("idle");
17251
17283
  }
17252
17284
  /**
17285
+ * Notify the recovery manager that a verto.modify (ICE restart SDP exchange)
17286
+ * failed at the signaling layer. Resets cooldown and pushes a new trigger
17287
+ * so recovery can re-attempt.
17288
+ */
17289
+ notifyModifyFailed() {
17290
+ if (this._recoveryState$.value === "cooldown" || this._recoveryState$.value === "idle") {
17291
+ logger$12.info("CallRecoveryManager: verto.modify failed — re-entering recovery");
17292
+ this._cooldownUntil = 0;
17293
+ this.transitionTo("idle");
17294
+ this.pushTrigger({
17295
+ source: "network",
17296
+ detail: "modify_failed_during_recovery"
17297
+ });
17298
+ }
17299
+ }
17300
+ /**
17253
17301
  * Feed bandwidth information for graceful degradation (Section 22).
17254
17302
  * Call this from the stats monitor with current available outgoing bitrate.
17255
17303
  */
@@ -17264,7 +17312,7 @@ var CallRecoveryManager = class extends Destroyable {
17264
17312
  reason: `bandwidth ${bitrateKbps}kbps below threshold ${this._config.degradationBitrateThreshold}kbps`,
17265
17313
  timestamp: Date.now()
17266
17314
  });
17267
- logger$11.warn(`CallRecoveryManager: disabling video — bandwidth ${bitrateKbps}kbps < ${this._config.degradationBitrateThreshold}kbps`);
17315
+ logger$12.warn(`CallRecoveryManager: disabling video — bandwidth ${bitrateKbps}kbps < ${this._config.degradationBitrateThreshold}kbps`);
17268
17316
  } else if (wasConstrained && bitrateKbps >= this._config.degradationRecoveryThreshold) {
17269
17317
  this._bandwidthConstrained$.next(false);
17270
17318
  this._callbacks.enableVideo();
@@ -17273,7 +17321,7 @@ var CallRecoveryManager = class extends Destroyable {
17273
17321
  reason: `bandwidth ${bitrateKbps}kbps recovered above ${this._config.degradationRecoveryThreshold}kbps`,
17274
17322
  timestamp: Date.now()
17275
17323
  });
17276
- logger$11.info(`CallRecoveryManager: restoring video — bandwidth ${bitrateKbps}kbps >= ${this._config.degradationRecoveryThreshold}kbps`);
17324
+ logger$12.info(`CallRecoveryManager: restoring video — bandwidth ${bitrateKbps}kbps >= ${this._config.degradationRecoveryThreshold}kbps`);
17277
17325
  }
17278
17326
  }
17279
17327
  /**
@@ -17292,14 +17340,14 @@ var CallRecoveryManager = class extends Destroyable {
17292
17340
  handleWebSocketReconnect() {
17293
17341
  const pcState = this._callbacks.getPeerConnectionState();
17294
17342
  if (pcState === "connected" || pcState === "completed") {
17295
- logger$11.info("CallRecoveryManager: signal-only reconnect — peer connection still alive");
17343
+ logger$12.info("CallRecoveryManager: signal-only reconnect — peer connection still alive");
17296
17344
  this.emitEvent({
17297
17345
  action: "signal_reconnect",
17298
17346
  reason: "WebSocket reconnected, peer connection still connected",
17299
17347
  timestamp: Date.now()
17300
17348
  });
17301
17349
  } else {
17302
- logger$11.info("CallRecoveryManager: full reconnect — peer connection also down");
17350
+ logger$12.info("CallRecoveryManager: full reconnect — peer connection also down");
17303
17351
  this.emitEvent({
17304
17352
  action: "full_reconnect",
17305
17353
  reason: "WebSocket reconnected, peer connection not connected — ICE restart needed",
@@ -17318,12 +17366,12 @@ var CallRecoveryManager = class extends Destroyable {
17318
17366
  super.destroy();
17319
17367
  }
17320
17368
  initPipeline() {
17321
- this.subscribeTo(this._trigger$.pipe((0, import_cjs$10.tap)(() => {
17369
+ this.subscribeTo(this._trigger$.pipe((0, import_cjs$11.tap)(() => {
17322
17370
  if (this._recoveryState$.value === "idle") this.transitionTo("debouncing");
17323
- }), (0, import_cjs$10.debounceTime)(this._config.debounceTimeMs), (0, import_cjs$10.filter)(() => this.passGateChecks()), (0, import_cjs$10.exhaustMap)((trigger) => this.executeTieredRecovery(trigger)), (0, import_cjs$10.takeUntil)((0, import_cjs$10.merge)(this._destroyed$, this._pipelineStop$))), {
17371
+ }), (0, import_cjs$11.debounceTime)(this._config.debounceTimeMs), (0, import_cjs$11.withLatestFrom)(this._inputs.signalingReady$), (0, import_cjs$11.filter)(([, signalingReady]) => this.passGateChecks(signalingReady)), (0, import_cjs$11.map)(([trigger]) => trigger), (0, import_cjs$11.exhaustMap)((trigger) => this.executeTieredRecovery(trigger)), (0, import_cjs$11.takeUntil)((0, import_cjs$11.merge)(this._destroyed$, this._pipelineStop$))), {
17324
17372
  next: () => {},
17325
17373
  error: (err) => {
17326
- logger$11.error("CallRecoveryManager: pipeline error", err);
17374
+ logger$12.error("CallRecoveryManager: pipeline error", err);
17327
17375
  this.transitionTo("idle");
17328
17376
  }
17329
17377
  });
@@ -17339,10 +17387,10 @@ var CallRecoveryManager = class extends Destroyable {
17339
17387
  initDegradationRecoveryPipeline() {
17340
17388
  if (!this._config.enableAutoDegradation) return;
17341
17389
  const delayMs = this._config.packetLossRecoveryDelaySec * 1e3;
17342
- this.subscribeTo((0, import_cjs$10.combineLatest)([this._bandwidthConstrained$, this._hasPacketLoss$]).pipe((0, import_cjs$10.switchMap)(([constrained, hasPacketLoss]) => {
17343
- if (constrained && !hasPacketLoss) return (0, import_cjs$10.timer)(delayMs);
17344
- return import_cjs$10.EMPTY;
17345
- }), (0, import_cjs$10.takeUntil)(this._destroyed$)), () => {
17390
+ this.subscribeTo((0, import_cjs$11.combineLatest)([this._bandwidthConstrained$, this._hasPacketLoss$]).pipe((0, import_cjs$11.switchMap)(([constrained, hasPacketLoss]) => {
17391
+ if (constrained && !hasPacketLoss) return (0, import_cjs$11.timer)(delayMs);
17392
+ return import_cjs$11.EMPTY;
17393
+ }), (0, import_cjs$11.takeUntil)(this._destroyed$)), () => {
17346
17394
  this._bandwidthConstrained$.next(false);
17347
17395
  this._callbacks.enableVideo();
17348
17396
  this.emitEvent({
@@ -17350,27 +17398,27 @@ var CallRecoveryManager = class extends Destroyable {
17350
17398
  reason: `no packet loss for ${this._config.packetLossRecoveryDelaySec}s — restoring video`,
17351
17399
  timestamp: Date.now()
17352
17400
  });
17353
- logger$11.info(`CallRecoveryManager: restoring video — no packet loss for ${this._config.packetLossRecoveryDelaySec}s`);
17401
+ logger$12.info(`CallRecoveryManager: restoring video — no packet loss for ${this._config.packetLossRecoveryDelaySec}s`);
17354
17402
  });
17355
17403
  }
17356
- passGateChecks() {
17404
+ passGateChecks(signalingReady) {
17357
17405
  if (this._callbacks.isNegotiating()) {
17358
- logger$11.debug("CallRecoveryManager: gate blocked — negotiation in progress");
17406
+ logger$12.debug("CallRecoveryManager: gate blocked — negotiation in progress");
17359
17407
  this.transitionTo("idle");
17360
17408
  return false;
17361
17409
  }
17362
- if (!this._callbacks.isWebSocketConnected()) {
17363
- logger$11.debug("CallRecoveryManager: gate blocked — WebSocket not connected");
17410
+ if (!signalingReady) {
17411
+ logger$12.debug("CallRecoveryManager: gate blocked — signaling not ready");
17364
17412
  this.transitionTo("idle");
17365
17413
  return false;
17366
17414
  }
17367
17415
  if (!this._callbacks.isCallConnected()) {
17368
- logger$11.debug("CallRecoveryManager: gate blocked — call not connected");
17416
+ logger$12.debug("CallRecoveryManager: gate blocked — call not connected");
17369
17417
  this.transitionTo("idle");
17370
17418
  return false;
17371
17419
  }
17372
17420
  if (this.isCooldownActive()) {
17373
- logger$11.debug("CallRecoveryManager: gate blocked — cooldown active");
17421
+ logger$12.debug("CallRecoveryManager: gate blocked — cooldown active");
17374
17422
  this.transitionTo("cooldown");
17375
17423
  return false;
17376
17424
  }
@@ -17381,17 +17429,17 @@ var CallRecoveryManager = class extends Destroyable {
17381
17429
  }
17382
17430
  executeTieredRecovery(trigger) {
17383
17431
  this.transitionTo("recovering");
17384
- logger$11.info(`CallRecoveryManager: starting tiered recovery — source=${trigger.source} detail=${trigger.detail}`);
17385
- return (0, import_cjs$10.from)(this.runTiers(trigger)).pipe((0, import_cjs$10.tap)(() => this.startCooldown()), (0, import_cjs$10.catchError)((err) => {
17386
- logger$11.error("CallRecoveryManager: tiered recovery failed", err);
17432
+ logger$12.info(`CallRecoveryManager: starting tiered recovery — source=${trigger.source} detail=${trigger.detail}`);
17433
+ return (0, import_cjs$11.from)(this.runTiers(trigger)).pipe((0, import_cjs$11.tap)(() => this.startCooldown()), (0, import_cjs$11.catchError)((err) => {
17434
+ logger$12.error("CallRecoveryManager: tiered recovery failed", err);
17387
17435
  this.startCooldown();
17388
- return import_cjs$10.EMPTY;
17436
+ return import_cjs$11.EMPTY;
17389
17437
  }));
17390
17438
  }
17391
17439
  async runTiers(trigger) {
17392
17440
  this.executeKeyframe(trigger.detail);
17393
17441
  if (trigger.issueType && DEGRADATION_ONLY_ISSUES.has(trigger.issueType)) {
17394
- logger$11.debug(`CallRecoveryManager: degradation-only issue (${trigger.issueType}) — Tier 1 only, skipping ICE restart`);
17442
+ logger$12.debug(`CallRecoveryManager: degradation-only issue (${trigger.issueType}) — Tier 1 only, skipping ICE restart`);
17395
17443
  return;
17396
17444
  }
17397
17445
  if (this._attemptCount < this._config.maxAttempts) {
@@ -17408,13 +17456,13 @@ var CallRecoveryManager = class extends Destroyable {
17408
17456
  maxAttempts: this._config.maxAttempts,
17409
17457
  timestamp: Date.now()
17410
17458
  });
17411
- logger$11.warn("CallRecoveryManager: max recovery attempts reached");
17459
+ logger$12.warn("CallRecoveryManager: max recovery attempts reached");
17412
17460
  }
17413
17461
  }
17414
17462
  executeKeyframe(reason) {
17415
17463
  const now = Date.now();
17416
17464
  if (now < this._keyframeCooldownUntil) {
17417
- logger$11.debug("CallRecoveryManager: keyframe request skipped — cooldown active");
17465
+ logger$12.debug("CallRecoveryManager: keyframe request skipped — cooldown active");
17418
17466
  return;
17419
17467
  }
17420
17468
  if (now - this._keyframeBurstStart > this._config.keyframeBurstWindowMs) {
@@ -17423,7 +17471,7 @@ var CallRecoveryManager = class extends Destroyable {
17423
17471
  }
17424
17472
  if (this._keyframeBurstCount >= this._config.keyframeMaxBurst) {
17425
17473
  this._keyframeCooldownUntil = now + this._config.keyframeCooldownMs;
17426
- logger$11.debug(`CallRecoveryManager: keyframe burst limit reached (${this._config.keyframeMaxBurst}), cooldown until ${this._keyframeCooldownUntil}`);
17474
+ logger$12.debug(`CallRecoveryManager: keyframe burst limit reached (${this._config.keyframeMaxBurst}), cooldown until ${this._keyframeCooldownUntil}`);
17427
17475
  return;
17428
17476
  }
17429
17477
  this._keyframeBurstCount += 1;
@@ -17433,12 +17481,12 @@ var CallRecoveryManager = class extends Destroyable {
17433
17481
  reason,
17434
17482
  timestamp: now
17435
17483
  });
17436
- logger$11.debug(`CallRecoveryManager: keyframe requested (burst ${this._keyframeBurstCount}/${this._config.keyframeMaxBurst})`);
17484
+ logger$12.debug(`CallRecoveryManager: keyframe requested (burst ${this._keyframeBurstCount}/${this._config.keyframeMaxBurst})`);
17437
17485
  }
17438
17486
  async executeIceRestart(relayOnly) {
17439
17487
  this._attemptCount += 1;
17440
17488
  const tier = relayOnly ? "Tier 3 (relay-only)" : "Tier 2 (standard)";
17441
- logger$11.info(`CallRecoveryManager: ${tier} ICE restart — attempt ${this._attemptCount}/${this._config.maxAttempts}`);
17489
+ logger$12.info(`CallRecoveryManager: ${tier} ICE restart — attempt ${this._attemptCount}/${this._config.maxAttempts}`);
17442
17490
  this.emitEvent({
17443
17491
  action: "reinvite_started",
17444
17492
  reason: `${tier} ICE restart`,
@@ -17455,7 +17503,7 @@ var CallRecoveryManager = class extends Destroyable {
17455
17503
  maxAttempts: this._config.maxAttempts,
17456
17504
  timestamp: Date.now()
17457
17505
  });
17458
- logger$11.info(`CallRecoveryManager: ${tier} ICE restart succeeded`);
17506
+ logger$12.info(`CallRecoveryManager: ${tier} ICE restart succeeded`);
17459
17507
  this._attemptCount = 0;
17460
17508
  return true;
17461
17509
  }
@@ -17466,7 +17514,7 @@ var CallRecoveryManager = class extends Destroyable {
17466
17514
  maxAttempts: this._config.maxAttempts,
17467
17515
  timestamp: Date.now()
17468
17516
  });
17469
- logger$11.warn(`CallRecoveryManager: ${tier} ICE restart failed`);
17517
+ logger$12.warn(`CallRecoveryManager: ${tier} ICE restart failed`);
17470
17518
  return false;
17471
17519
  } catch {
17472
17520
  this.emitEvent({
@@ -17476,7 +17524,7 @@ var CallRecoveryManager = class extends Destroyable {
17476
17524
  maxAttempts: this._config.maxAttempts,
17477
17525
  timestamp: Date.now()
17478
17526
  });
17479
- logger$11.warn(`CallRecoveryManager: ${tier} ICE restart timed out`);
17527
+ logger$12.warn(`CallRecoveryManager: ${tier} ICE restart timed out`);
17480
17528
  return false;
17481
17529
  }
17482
17530
  }
@@ -17497,7 +17545,7 @@ var CallRecoveryManager = class extends Destroyable {
17497
17545
  transitionTo(state) {
17498
17546
  const prev = this._recoveryState$.value;
17499
17547
  if (prev !== state) {
17500
- logger$11.debug(`CallRecoveryManager: state ${prev} -> ${state}`);
17548
+ logger$12.debug(`CallRecoveryManager: state ${prev} -> ${state}`);
17501
17549
  this._recoveryState$.next(state);
17502
17550
  }
17503
17551
  }
@@ -17505,7 +17553,7 @@ var CallRecoveryManager = class extends Destroyable {
17505
17553
  this._cooldownUntil = Date.now() + this._config.cooldownMs;
17506
17554
  this.transitionTo("cooldown");
17507
17555
  if (this._cooldownSubscription) this._cooldownSubscription.unsubscribe();
17508
- this._cooldownSubscription = (0, import_cjs$10.timer)(this._config.cooldownMs).pipe((0, import_cjs$10.take)(1), (0, import_cjs$10.takeUntil)(this._destroyed$), (0, import_cjs$10.filter)(() => this._recoveryState$.value === "cooldown")).subscribe(() => this.transitionTo("idle"));
17556
+ this._cooldownSubscription = (0, import_cjs$11.timer)(this._config.cooldownMs).pipe((0, import_cjs$11.take)(1), (0, import_cjs$11.takeUntil)(this._destroyed$), (0, import_cjs$11.filter)(() => this._recoveryState$.value === "cooldown")).subscribe(() => this.transitionTo("idle"));
17509
17557
  }
17510
17558
  emitEvent(event) {
17511
17559
  this._recoveryEvent$.next(event);
@@ -17599,8 +17647,8 @@ function mosToQualityLevel(mos) {
17599
17647
 
17600
17648
  //#endregion
17601
17649
  //#region src/core/entities/Call.ts
17602
- var import_cjs$9 = require_cjs();
17603
- const logger$10 = getLogger();
17650
+ var import_cjs$10 = require_cjs();
17651
+ const logger$11 = getLogger();
17604
17652
  /**
17605
17653
  * Ratio between the critical and warning RTT spike multipliers.
17606
17654
  * Warning threshold = baseline * warningMultiplier (default 3x)
@@ -17618,7 +17666,7 @@ const fromDestinationParams = (destination) => {
17618
17666
  });
17619
17667
  return params;
17620
17668
  } catch (error) {
17621
- logger$10.warn(`Failed to parse destination URI: ${destination}`, error);
17669
+ logger$11.warn(`Failed to parse destination URI: ${destination}`, error);
17622
17670
  return {};
17623
17671
  }
17624
17672
  };
@@ -17674,10 +17722,13 @@ var WebRTCCall = class extends Destroyable {
17674
17722
  const { deviceController, networkChange$ } = initialization;
17675
17723
  this._networkChange$ = networkChange$;
17676
17724
  this.participantFactory = new ParticipantFactory(this.executeMethod.bind(this), this.vertoManager, deviceController);
17677
- this.subscribeTo((0, import_cjs$9.merge)(this._status$.asObservable(), this.vertoManager.signalingStatus$).pipe((0, import_cjs$9.distinctUntilChanged)(), (0, import_cjs$9.takeUntil)(this._destroyed$)), (status) => {
17725
+ this.subscribeTo((0, import_cjs$10.merge)(this._status$.asObservable(), this.vertoManager.signalingStatus$).pipe((0, import_cjs$10.distinctUntilChanged)(), (0, import_cjs$10.takeUntil)(this._destroyed$)), (status) => {
17678
17726
  this._lastMergedStatus = status;
17679
17727
  if (status === "connected" && !this._statsMonitor) this.initResilienceSubsystems();
17680
- else if (status === "disconnected" || status === "destroyed" || status === "failed") this.stopResilienceSubsystems();
17728
+ else if (status === "disconnected") {
17729
+ this._statsMonitor?.destroy();
17730
+ this._statsMonitor = void 0;
17731
+ } else if (status === "destroyed" || status === "failed") this.stopResilienceSubsystems();
17681
17732
  });
17682
17733
  }
17683
17734
  /** Observable stream of errors from media, signaling, and peer connection layers. */
@@ -17696,13 +17747,17 @@ var WebRTCCall = class extends Destroyable {
17696
17747
  this.destroy();
17697
17748
  }
17698
17749
  }
17750
+ /** Notify the recovery manager that a verto.modify signaling exchange failed. */
17751
+ notifyModifyFailed() {
17752
+ this._recoveryManager?.notifyModifyFailed();
17753
+ }
17699
17754
  /** Whether this call is `'inbound'` or `'outbound'`. */
17700
17755
  get direction() {
17701
17756
  return this.options.initOffer ? "inbound" : "outbound";
17702
17757
  }
17703
17758
  /** Observable of the address associated with this call. */
17704
17759
  get address$() {
17705
- return this.deferEmission((0, import_cjs$9.from)([this.address])).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
17760
+ return this.deferEmission((0, import_cjs$10.from)([this.address])).pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
17706
17761
  }
17707
17762
  /** Display name of the caller. */
17708
17763
  get fromName() {
@@ -17781,7 +17836,7 @@ var WebRTCCall = class extends Destroyable {
17781
17836
  }
17782
17837
  /** Observable of layout layer positions for all participants. */
17783
17838
  get layoutLayers$() {
17784
- return this.deferEmission(this.callEventsManager.layoutLayers$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
17839
+ return this.deferEmission(this.callEventsManager.layoutLayers$).pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
17785
17840
  }
17786
17841
  /** Current snapshot of layout layers. */
17787
17842
  get layoutLayers() {
@@ -17809,7 +17864,7 @@ var WebRTCCall = class extends Destroyable {
17809
17864
  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);
17810
17865
  return response;
17811
17866
  } catch (error) {
17812
- logger$10.error(`[Call] Error executing method ${method} with params`, params, error);
17867
+ logger$11.error(`[Call] Error executing method ${method} with params`, params, error);
17813
17868
  throw error;
17814
17869
  }
17815
17870
  }
@@ -17836,45 +17891,45 @@ var WebRTCCall = class extends Destroyable {
17836
17891
  }
17837
17892
  /** Observable of the current call status (e.g. `'ringing'`, `'connected'`). */
17838
17893
  get status$() {
17839
- return this.publicCachedObservable("status$", () => (0, import_cjs$9.merge)(this._status$.asObservable(), this.vertoManager.signalingStatus$).pipe((0, import_cjs$9.distinctUntilChanged)(), (0, import_cjs$9.tap)((status) => {
17894
+ return this.publicCachedObservable("status$", () => (0, import_cjs$10.merge)(this._status$.asObservable(), this.vertoManager.signalingStatus$).pipe((0, import_cjs$10.distinctUntilChanged)(), (0, import_cjs$10.tap)((status) => {
17840
17895
  this._lastMergedStatus = status;
17841
17896
  })));
17842
17897
  }
17843
17898
  /** Observable of the participants list, emits on join/leave/update. */
17844
17899
  get participants$() {
17845
- return this.deferEmission(this.callEventsManager.participants$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
17900
+ return this.deferEmission(this.callEventsManager.participants$).pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
17846
17901
  }
17847
17902
  /** Observable of the local (self) participant. */
17848
17903
  get self$() {
17849
- return this.deferEmission(this.callEventsManager.self$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
17904
+ return this.deferEmission(this.callEventsManager.self$).pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
17850
17905
  }
17851
17906
  /** Observable indicating whether the call is being recorded. */
17852
17907
  get recording$() {
17853
- return this.deferEmission(this.callEventsManager.recording$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
17908
+ return this.deferEmission(this.callEventsManager.recording$).pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
17854
17909
  }
17855
17910
  /** Observable indicating whether the call is being streamed. */
17856
17911
  get streaming$() {
17857
- return this.deferEmission(this.callEventsManager.streaming$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
17912
+ return this.deferEmission(this.callEventsManager.streaming$).pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
17858
17913
  }
17859
17914
  /** Observable indicating whether raise-hand priority is active. */
17860
17915
  get raiseHandPriority$() {
17861
- return this.deferEmission(this.callEventsManager.raiseHandPriority$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
17916
+ return this.deferEmission(this.callEventsManager.raiseHandPriority$).pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
17862
17917
  }
17863
17918
  /** Observable indicating whether the call room is locked. */
17864
17919
  get locked$() {
17865
- return this.deferEmission(this.callEventsManager.locked$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
17920
+ return this.deferEmission(this.callEventsManager.locked$).pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
17866
17921
  }
17867
17922
  /** Observable of custom metadata associated with the call. */
17868
17923
  get meta$() {
17869
- return this.deferEmission(this.callEventsManager.meta$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
17924
+ return this.deferEmission(this.callEventsManager.meta$).pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
17870
17925
  }
17871
17926
  /** Observable of the call's capability flags. */
17872
17927
  get capabilities$() {
17873
- return this.deferEmission(this.callEventsManager.capabilities$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
17928
+ return this.deferEmission(this.callEventsManager.capabilities$).pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
17874
17929
  }
17875
17930
  /** Observable of the current layout name. */
17876
17931
  get layout$() {
17877
- return this.deferEmission(this.callEventsManager.layout$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
17932
+ return this.deferEmission(this.callEventsManager.layout$).pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
17878
17933
  }
17879
17934
  /** Current call status. */
17880
17935
  get status() {
@@ -17906,7 +17961,7 @@ var WebRTCCall = class extends Destroyable {
17906
17961
  }
17907
17962
  /** Observable of available layout names. */
17908
17963
  get layouts$() {
17909
- return this.deferEmission(this.callEventsManager.layouts$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
17964
+ return this.deferEmission(this.callEventsManager.layouts$).pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
17910
17965
  }
17911
17966
  /** Current snapshot of available layout names. */
17912
17967
  get layouts() {
@@ -17914,7 +17969,7 @@ var WebRTCCall = class extends Destroyable {
17914
17969
  }
17915
17970
  /** Observable of the local media stream (camera/microphone). */
17916
17971
  get localStream$() {
17917
- return this.deferEmission(this.vertoManager.localStream$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
17972
+ return this.deferEmission(this.vertoManager.localStream$).pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
17918
17973
  }
17919
17974
  /** Current local media stream, or `null` if not available. */
17920
17975
  get localStream() {
@@ -17922,7 +17977,7 @@ var WebRTCCall = class extends Destroyable {
17922
17977
  }
17923
17978
  /** Observable of the remote media stream from the far end. */
17924
17979
  get remoteStream$() {
17925
- return this.deferEmission(this.vertoManager.remoteStream$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
17980
+ return this.deferEmission(this.vertoManager.remoteStream$).pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
17926
17981
  }
17927
17982
  /** Current remote media stream, or `null` if not available. */
17928
17983
  get remoteStream() {
@@ -18012,9 +18067,9 @@ var WebRTCCall = class extends Destroyable {
18012
18067
  */
18013
18068
  initResilienceSubsystems() {
18014
18069
  const pc = this.rtcPeerConnection;
18015
- logger$10.debug(`[Call] initResilienceSubsystems: pc=${pc ? "exists" : "undefined"}, connectionState=${pc?.connectionState}`);
18070
+ logger$11.debug(`[Call] initResilienceSubsystems: pc=${pc ? "exists" : "undefined"}, connectionState=${pc?.connectionState}`);
18016
18071
  if (!pc) {
18017
- logger$10.warn("[Call] No peer connection available, skipping resilience init");
18072
+ logger$11.warn("[Call] No peer connection available, skipping resilience init");
18018
18073
  return;
18019
18074
  }
18020
18075
  try {
@@ -18049,21 +18104,20 @@ var WebRTCCall = class extends Destroyable {
18049
18104
  disableVideo: () => {
18050
18105
  try {
18051
18106
  this.vertoManager.muteMainVideoInputDevice();
18052
- logger$10.debug("[Call] Recovery manager disabled video");
18107
+ logger$11.debug("[Call] Recovery manager disabled video");
18053
18108
  } catch {
18054
- logger$10.debug("[Call] Recovery manager failed to disable video");
18109
+ logger$11.debug("[Call] Recovery manager failed to disable video");
18055
18110
  }
18056
18111
  },
18057
18112
  enableVideo: () => {
18058
18113
  this.vertoManager.unmuteMainVideoInputDevice().catch(() => {
18059
- logger$10.debug("[Call] Recovery manager failed to enable video");
18114
+ logger$11.debug("[Call] Recovery manager failed to enable video");
18060
18115
  });
18061
18116
  },
18062
18117
  isNegotiating: () => this.vertoManager.mainPeerConnection.isNegotiating,
18063
- isWebSocketConnected: () => this._lastMergedStatus !== "disconnected",
18064
18118
  isCallConnected: () => this._lastMergedStatus === "connected",
18065
18119
  getPeerConnectionState: () => pc.connectionState
18066
- }, {
18120
+ }, { signalingReady$: this.clientSession.authenticated$ }, {
18067
18121
  debounceTimeMs: prefs.recoveryDebounceTime,
18068
18122
  cooldownMs: prefs.recoveryCooldown,
18069
18123
  iceGracePeriodMs: prefs.iceDisconnectedGracePeriod,
@@ -18106,6 +18160,15 @@ var WebRTCCall = class extends Destroyable {
18106
18160
  });
18107
18161
  this.subscribeTo(this._recoveryManager.recoveryEvent$, (event) => {
18108
18162
  this._recoveryEvent$.next(event);
18163
+ if (event.action === "max_attempts_reached") {
18164
+ logger$11.warn("[Call] All recovery attempts exhausted, terminating call");
18165
+ this.emitError({
18166
+ kind: "network",
18167
+ fatal: true,
18168
+ error: /* @__PURE__ */ new Error("Call recovery failed: all attempts exhausted"),
18169
+ callId: this.id
18170
+ });
18171
+ }
18109
18172
  });
18110
18173
  this.subscribeTo(this._recoveryManager.bandwidthConstrained$, (constrained) => {
18111
18174
  this._bandwidthConstrained$.next(constrained);
@@ -18117,14 +18180,14 @@ var WebRTCCall = class extends Destroyable {
18117
18180
  });
18118
18181
  else if (event.type === "online") this._recoveryManager?.handleWebSocketReconnect();
18119
18182
  });
18120
- this.subscribeTo(this.clientSession.authenticated$.pipe((0, import_cjs$9.skip)(1), (0, import_cjs$9.filter)(Boolean)), () => {
18121
- logger$10.debug("[Call] WebSocket reconnected — notifying recovery manager");
18183
+ this.subscribeTo(this.clientSession.authenticated$.pipe((0, import_cjs$10.skip)(1), (0, import_cjs$10.filter)(Boolean)), () => {
18184
+ logger$11.debug("[Call] WebSocket reconnected — notifying recovery manager");
18122
18185
  this._recoveryManager?.handleWebSocketReconnect();
18123
18186
  });
18124
18187
  this._statsMonitor.start();
18125
- logger$10.debug("[Call] Resilience subsystems initialized for call", this.id);
18188
+ logger$11.debug("[Call] Resilience subsystems initialized for call", this.id);
18126
18189
  } catch (error) {
18127
- logger$10.warn("[Call] Failed to initialize resilience subsystems:", error);
18190
+ logger$11.warn("[Call] Failed to initialize resilience subsystems:", error);
18128
18191
  }
18129
18192
  }
18130
18193
  /**
@@ -18146,14 +18209,14 @@ var WebRTCCall = class extends Destroyable {
18146
18209
  }
18147
18210
  /** Observable of the current audio/video send/receive directions. */
18148
18211
  get mediaDirections$() {
18149
- return this.deferEmission(this.vertoManager.mediaDirections$).pipe((0, import_cjs$9.takeUntil)(this._destroyed$));
18212
+ return this.deferEmission(this.vertoManager.mediaDirections$).pipe((0, import_cjs$10.takeUntil)(this._destroyed$));
18150
18213
  }
18151
18214
  /** Current audio/video send/receive directions. */
18152
18215
  get mediaDirections() {
18153
18216
  return this.vertoManager.mediaDirections;
18154
18217
  }
18155
18218
  get participantsId$() {
18156
- return this.cachedObservable("participantsId$", () => this.participants$.pipe((0, import_cjs$9.map)((participants) => participants.map((participant) => participant.id))));
18219
+ return this.cachedObservable("participantsId$", () => this.participants$.pipe((0, import_cjs$10.map)((participants) => participants.map((participant) => participant.id))));
18157
18220
  }
18158
18221
  /**
18159
18222
  * Executes a raw JSON-RPC request on the client session.
@@ -18186,48 +18249,48 @@ var WebRTCCall = class extends Destroyable {
18186
18249
  }
18187
18250
  isCallSessionEvent(event) {
18188
18251
  try {
18189
- logger$10.debug("[Call] Checking if event is for this call session:", event);
18252
+ logger$11.debug("[Call] Checking if event is for this call session:", event);
18190
18253
  const callId = getValueFrom(event, "params.params.callID") ?? getValueFrom(event, "params.call_id");
18191
18254
  const roomSessionId = getValueFrom(event, "params.room_session_id");
18192
- logger$10.debug(`[Call] Extracted session identifiers callID: ${callId} and roomSessionID: ${roomSessionId} from event:`);
18255
+ logger$11.debug(`[Call] Extracted session identifiers callID: ${callId} and roomSessionID: ${roomSessionId} from event:`);
18193
18256
  return callId === this.id || !!callId && this.callEventsManager.isCallIdValid(callId) || !!roomSessionId && this.callEventsManager.isRoomSessionIdValid(roomSessionId);
18194
18257
  } catch (error) {
18195
- logger$10.error("[Call] Error checking if event is for this call session:", error);
18258
+ logger$11.error("[Call] Error checking if event is for this call session:", error);
18196
18259
  return false;
18197
18260
  }
18198
18261
  }
18199
18262
  get callSessionEvents$() {
18200
- return this.cachedObservable("callSessionEvents$", () => this.clientSession.signalingEvent$.pipe((0, import_cjs$9.filter)((event) => this.isCallSessionEvent(event)), (0, import_cjs$9.tap)((event) => {
18201
- logger$10.debug("[Call] Received call session event:", event);
18202
- }), (0, import_cjs$9.takeUntil)(this.destroyed$), (0, import_cjs$9.share)()));
18263
+ return this.cachedObservable("callSessionEvents$", () => this.clientSession.signalingEvent$.pipe((0, import_cjs$10.filter)((event) => this.isCallSessionEvent(event)), (0, import_cjs$10.tap)((event) => {
18264
+ logger$11.debug("[Call] Received call session event:", event);
18265
+ }), (0, import_cjs$10.takeUntil)(this.destroyed$), (0, import_cjs$10.share)()));
18203
18266
  }
18204
18267
  /** Observable of call-updated events. */
18205
18268
  get callUpdated$() {
18206
- return this.publicCachedObservable("callUpdated$", () => this.callSessionEvents$.pipe(filterAs(isCallUpdatedMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
18269
+ return this.publicCachedObservable("callUpdated$", () => this.callSessionEvents$.pipe(filterAs(isCallUpdatedMetadata, "params"), (0, import_cjs$10.takeUntil)(this.destroyed$)));
18207
18270
  }
18208
18271
  /** Observable of member-joined events, emitted when a remote participant joins the call. */
18209
18272
  get memberJoined$() {
18210
- return this.publicCachedObservable("memberJoined$", () => this.callSessionEvents$.pipe(filterAs(isMemberJoinedMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
18273
+ return this.publicCachedObservable("memberJoined$", () => this.callSessionEvents$.pipe(filterAs(isMemberJoinedMetadata, "params"), (0, import_cjs$10.takeUntil)(this.destroyed$)));
18211
18274
  }
18212
18275
  /** Observable of member-left events, emitted when a participant leaves the call. */
18213
18276
  get memberLeft$() {
18214
- return this.publicCachedObservable("memberLeft$", () => this.callSessionEvents$.pipe(filterAs(isMemberLeftMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
18277
+ return this.publicCachedObservable("memberLeft$", () => this.callSessionEvents$.pipe(filterAs(isMemberLeftMetadata, "params"), (0, import_cjs$10.takeUntil)(this.destroyed$)));
18215
18278
  }
18216
18279
  /** Observable of member-updated events (mute, volume, etc.). */
18217
18280
  get memberUpdated$() {
18218
- return this.publicCachedObservable("memberUpdated$", () => this.callSessionEvents$.pipe(filterAs(isMemberUpdatedMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
18281
+ return this.publicCachedObservable("memberUpdated$", () => this.callSessionEvents$.pipe(filterAs(isMemberUpdatedMetadata, "params"), (0, import_cjs$10.takeUntil)(this.destroyed$)));
18219
18282
  }
18220
18283
  /** Observable of member-talking events (speech start/stop). */
18221
18284
  get memberTalking$() {
18222
- return this.publicCachedObservable("memberTalking$", () => this.callSessionEvents$.pipe(filterAs(isMemberTalkingMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
18285
+ return this.publicCachedObservable("memberTalking$", () => this.callSessionEvents$.pipe(filterAs(isMemberTalkingMetadata, "params"), (0, import_cjs$10.takeUntil)(this.destroyed$)));
18223
18286
  }
18224
18287
  /** Observable of call state-change events. */
18225
18288
  get callStates$() {
18226
- return this.publicCachedObservable("callStates$", () => this.callSessionEvents$.pipe(filterAs(isCallStateMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
18289
+ return this.publicCachedObservable("callStates$", () => this.callSessionEvents$.pipe(filterAs(isCallStateMetadata, "params"), (0, import_cjs$10.takeUntil)(this.destroyed$)));
18227
18290
  }
18228
18291
  /** Observable of layout-changed events. */
18229
18292
  get layoutUpdates$() {
18230
- return this.publicCachedObservable("layoutUpdates$", () => this.callSessionEvents$.pipe(filterAs(isLayoutChangedMetadata, "params"), (0, import_cjs$9.takeUntil)(this.destroyed$)));
18293
+ return this.publicCachedObservable("layoutUpdates$", () => this.callSessionEvents$.pipe(filterAs(isLayoutChangedMetadata, "params"), (0, import_cjs$10.takeUntil)(this.destroyed$)));
18231
18294
  }
18232
18295
  /** Underlying `RTCPeerConnection`, for advanced use cases. */
18233
18296
  get rtcPeerConnection() {
@@ -18235,7 +18298,7 @@ var WebRTCCall = class extends Destroyable {
18235
18298
  }
18236
18299
  /** Observable of raw signaling events as plain objects. */
18237
18300
  get signalingEvent$() {
18238
- return this.publicCachedObservable("signalingEvent$", () => this.callEvent$.pipe((0, import_cjs$9.map)((event) => JSON.parse(JSON.stringify(event)))));
18301
+ return this.publicCachedObservable("signalingEvent$", () => this.callEvent$.pipe((0, import_cjs$10.map)((event) => JSON.parse(JSON.stringify(event)))));
18239
18302
  }
18240
18303
  /**
18241
18304
  * Subscribe to a custom signaling event type on this call.
@@ -18263,16 +18326,16 @@ var WebRTCCall = class extends Destroyable {
18263
18326
  subscribe(eventType) {
18264
18327
  const cached = this._customSubscriptions.get(eventType);
18265
18328
  if (cached) return cached;
18266
- const filtered$ = this.callSessionEvents$.pipe((0, import_cjs$9.filter)((event) => event.event_type === eventType), (0, import_cjs$9.map)((event) => JSON.parse(JSON.stringify(event))), (0, import_cjs$9.takeUntil)(this._destroyed$));
18329
+ const filtered$ = this.callSessionEvents$.pipe((0, import_cjs$10.filter)((event) => event.event_type === eventType), (0, import_cjs$10.map)((event) => JSON.parse(JSON.stringify(event))), (0, import_cjs$10.takeUntil)(this._destroyed$));
18267
18330
  this._customSubscriptions.set(eventType, filtered$);
18268
18331
  this._sendVertoSubscribe(eventType);
18269
18332
  return filtered$;
18270
18333
  }
18271
18334
  get webrtcMessages$() {
18272
- return this.cachedObservable("webrtcMessages$", () => this.callSessionEvents$.pipe(filterAs(isWebrtcMessageMetadata, "params"), (0, import_cjs$9.tap)((event) => logger$10.debug("[Call] Event is a WebRTC message event:", event)), (0, import_cjs$9.takeUntil)(this.destroyed$), (0, import_cjs$9.share)()));
18335
+ return this.cachedObservable("webrtcMessages$", () => this.callSessionEvents$.pipe(filterAs(isWebrtcMessageMetadata, "params"), (0, import_cjs$10.tap)((event) => logger$11.debug("[Call] Event is a WebRTC message event:", event)), (0, import_cjs$10.takeUntil)(this.destroyed$), (0, import_cjs$10.share)()));
18273
18336
  }
18274
18337
  get callEvent$() {
18275
- return this.cachedObservable("callEvent$", () => this.callSessionEvents$.pipe(filterAs(isSignalwireCallMetadata, "params"), (0, import_cjs$9.tap)((event) => logger$10.debug("[Call] Event is a call event:", event)), (0, import_cjs$9.takeUntil)(this.destroyed$), (0, import_cjs$9.share)()));
18338
+ return this.cachedObservable("callEvent$", () => this.callSessionEvents$.pipe(filterAs(isSignalwireCallMetadata, "params"), (0, import_cjs$10.tap)((event) => logger$11.debug("[Call] Event is a call event:", event)), (0, import_cjs$10.takeUntil)(this.destroyed$), (0, import_cjs$10.share)()));
18276
18339
  }
18277
18340
  get layoutEvent$() {
18278
18341
  return this.cachedObservable("layoutEvent$", () => this.callEvent$.pipe(filterAs(isLayoutChangedMetadata, "params")));
@@ -18365,7 +18428,7 @@ var WebRTCCall = class extends Destroyable {
18365
18428
  */
18366
18429
  async setLayout(layout, positions) {
18367
18430
  if (!this.layouts.includes(layout)) throw new InvalidParams(`Layout ${layout} is not available in the current call layouts: ${this.layouts.join(", ")}`);
18368
- const selfId = await (0, import_cjs$9.firstValueFrom)(this.selfId$.pipe((0, import_cjs$9.filter)((id) => id !== null)));
18431
+ const selfId = await (0, import_cjs$10.firstValueFrom)(this.selfId$.pipe((0, import_cjs$10.filter)((id) => id !== null)));
18369
18432
  await this.executeMethod(selfId, "call.layout.set", {
18370
18433
  layout,
18371
18434
  positions
@@ -18406,10 +18469,10 @@ var WebRTCCall = class extends Destroyable {
18406
18469
  message
18407
18470
  };
18408
18471
  this.clientSession.execute(WebrtcVerto(params)).catch((error) => {
18409
- logger$10.warn(`[Call] verto.subscribe for '${eventType}' failed (non-fatal):`, error);
18472
+ logger$11.warn(`[Call] verto.subscribe for '${eventType}' failed (non-fatal):`, error);
18410
18473
  });
18411
18474
  } catch (error) {
18412
- logger$10.warn(`[Call] Failed to send verto.subscribe for '${eventType}':`, error);
18475
+ logger$11.warn(`[Call] Failed to send verto.subscribe for '${eventType}':`, error);
18413
18476
  }
18414
18477
  }
18415
18478
  };
@@ -18431,6 +18494,7 @@ function inferCallErrorKind(error) {
18431
18494
  function isFatalError(error) {
18432
18495
  if (error instanceof VertoPongError) return false;
18433
18496
  if (error instanceof MediaTrackError) return false;
18497
+ if (error instanceof RPCTimeoutError) return false;
18434
18498
  return true;
18435
18499
  }
18436
18500
  /**
@@ -18462,6 +18526,9 @@ var CallFactory = class {
18462
18526
  callId: callInstance.id
18463
18527
  };
18464
18528
  callInstance.emitError(callError);
18529
+ },
18530
+ onModifyFailed: () => {
18531
+ callInstance.notifyModifyFailed();
18465
18532
  }
18466
18533
  }),
18467
18534
  callEventsManager: new CallEventsManager(callInstance)
@@ -18475,8 +18542,8 @@ var CallFactory = class {
18475
18542
 
18476
18543
  //#endregion
18477
18544
  //#region src/behaviors/Collection.ts
18478
- var import_cjs$8 = require_cjs();
18479
- const logger$9 = getLogger();
18545
+ var import_cjs$9 = require_cjs();
18546
+ const logger$10 = getLogger();
18480
18547
  var Fetcher = class {
18481
18548
  constructor(endpoint, params, http) {
18482
18549
  this.endpoint = endpoint;
@@ -18500,7 +18567,7 @@ var Fetcher = class {
18500
18567
  this.hasMore = !!this.nextUrl;
18501
18568
  return result.data.filter(this.filter).map(this.mapper);
18502
18569
  }
18503
- logger$9.error("Failed to fetch entity");
18570
+ logger$10.error("Failed to fetch entity");
18504
18571
  return [];
18505
18572
  }
18506
18573
  async id(v) {
@@ -18541,10 +18608,10 @@ var EntityCollection = class extends Destroyable {
18541
18608
  this.values$.next(Array.from(this.collectionData.values()));
18542
18609
  };
18543
18610
  this._hasMore$ = this.createBehaviorSubject(true);
18544
- this._destroy$ = new import_cjs$8.Subject();
18611
+ this._destroy$ = new import_cjs$9.Subject();
18545
18612
  this.updateSubscription = this.update$.subscribe(this.upsertData);
18546
18613
  this.loading$.next(false);
18547
- this.hasMore$ = (0, import_cjs$8.defer)(() => (0, import_cjs$8.from)(this.init())).pipe((0, import_cjs$8.switchMap)(() => this._hasMore$), (0, import_cjs$8.distinctUntilChanged)(), (0, import_cjs$8.shareReplay)(1), (0, import_cjs$8.takeUntil)(this._destroy$));
18614
+ this.hasMore$ = (0, import_cjs$9.defer)(() => (0, import_cjs$9.from)(this.init())).pipe((0, import_cjs$9.switchMap)(() => this._hasMore$), (0, import_cjs$9.distinctUntilChanged)(), (0, import_cjs$9.shareReplay)(1), (0, import_cjs$9.takeUntil)(this._destroy$));
18548
18615
  }
18549
18616
  get loading() {
18550
18617
  return this.loading$.value;
@@ -18553,7 +18620,7 @@ var EntityCollection = class extends Destroyable {
18553
18620
  return this.fetchController.hasMore ?? true;
18554
18621
  }
18555
18622
  get updated$() {
18556
- return this.cachedObservable("updated$", () => this.loading$.pipe((0, import_cjs$8.distinctUntilChanged)(), (0, import_cjs$8.skip)(1), (0, import_cjs$8.filter)((loading) => !loading), (0, import_cjs$8.map)(() => void 0), (0, import_cjs$8.takeUntil)(this._destroy$)));
18623
+ return this.cachedObservable("updated$", () => this.loading$.pipe((0, import_cjs$9.distinctUntilChanged)(), (0, import_cjs$9.skip)(1), (0, import_cjs$9.filter)((loading) => !loading), (0, import_cjs$9.map)(() => void 0), (0, import_cjs$9.takeUntil)(this._destroy$)));
18557
18624
  }
18558
18625
  get values() {
18559
18626
  return Array.from(this.collectionData.values());
@@ -18572,7 +18639,7 @@ var EntityCollection = class extends Destroyable {
18572
18639
  this._hasMore$.next(this.fetchController.hasMore ?? false);
18573
18640
  this.loading$.next(false);
18574
18641
  } catch (error) {
18575
- logger$9.error(`Failed to fetch initial collection data`, error);
18642
+ logger$10.error(`Failed to fetch initial collection data`, error);
18576
18643
  this._hasMore$.next(this.fetchController.hasMore ?? false);
18577
18644
  this.loading$.next(false);
18578
18645
  this.onError?.(new CollectionFetchError("fetchMore", error));
@@ -18586,14 +18653,14 @@ var EntityCollection = class extends Destroyable {
18586
18653
  if (data) this.upsertData(data);
18587
18654
  return data;
18588
18655
  } catch (error) {
18589
- logger$9.error(`Failed to fetch data for (${String(key)}:${String(value)}) :`, error);
18656
+ logger$10.error(`Failed to fetch data for (${String(key)}:${String(value)}) :`, error);
18590
18657
  this.loading$.next(false);
18591
18658
  this.onError?.(new CollectionFetchError(`tryFetch(${String(key)})`, error));
18592
18659
  }
18593
18660
  }
18594
18661
  get$(id) {
18595
18662
  if (!this.observablesRegistry.has(id)) {
18596
- this.observablesRegistry.set(id, new import_cjs$8.ReplaySubject(1));
18663
+ this.observablesRegistry.set(id, new import_cjs$9.ReplaySubject(1));
18597
18664
  const data = this.collectionData.get(id);
18598
18665
  if (data) this.observablesRegistry.get(id)?.next(data);
18599
18666
  else this.tryFetch("id", id);
@@ -18617,9 +18684,9 @@ var EntityCollection = class extends Destroyable {
18617
18684
  }
18618
18685
  };
18619
18686
  var EntityCollectionTransformed = class {
18620
- constructor(originalCollection, filter$16 = (i) => !!i, mapper = (item) => item) {
18687
+ constructor(originalCollection, filter$17 = (i) => !!i, mapper = (item) => item) {
18621
18688
  this.originalCollection = originalCollection;
18622
- this.filter = filter$16;
18689
+ this.filter = filter$17;
18623
18690
  this.mapper = mapper;
18624
18691
  }
18625
18692
  get loading$() {
@@ -18638,15 +18705,15 @@ var EntityCollectionTransformed = class {
18638
18705
  return this.originalCollection.values.filter(this.filter).map(this.mapper);
18639
18706
  }
18640
18707
  get values$() {
18641
- return this._values$ ??= this.originalCollection.values$.pipe((0, import_cjs$8.map)((values) => values.filter(this.filter).map(this.mapper)));
18708
+ return this._values$ ??= this.originalCollection.values$.pipe((0, import_cjs$9.map)((values) => values.filter(this.filter).map(this.mapper)));
18642
18709
  }
18643
18710
  get$(id) {
18644
18711
  const original$ = this.originalCollection.get$(id);
18645
- return !original$ ? original$ : original$.pipe((0, import_cjs$8.pipe)((0, import_cjs$8.filter)(this.filter), (0, import_cjs$8.map)(this.mapper)));
18712
+ return !original$ ? original$ : original$.pipe((0, import_cjs$9.pipe)((0, import_cjs$9.filter)(this.filter), (0, import_cjs$9.map)(this.mapper)));
18646
18713
  }
18647
18714
  async find$(key, value) {
18648
18715
  const original$ = await this.originalCollection.find$(key, value);
18649
- return !original$ ? original$ : original$.pipe((0, import_cjs$8.pipe)((0, import_cjs$8.filter)(this.filter), (0, import_cjs$8.map)(this.mapper)));
18716
+ return !original$ ? original$ : original$.pipe((0, import_cjs$9.pipe)((0, import_cjs$9.filter)(this.filter), (0, import_cjs$9.map)(this.mapper)));
18650
18717
  }
18651
18718
  loadMore() {
18652
18719
  this.originalCollection.loadMore();
@@ -18658,7 +18725,7 @@ var EntityCollectionTransformed = class {
18658
18725
 
18659
18726
  //#endregion
18660
18727
  //#region src/core/entities/Address.ts
18661
- var import_cjs$7 = require_cjs();
18728
+ var import_cjs$8 = require_cjs();
18662
18729
  /**
18663
18730
  * Represents a contact or room in the directory.
18664
18731
  *
@@ -18676,8 +18743,8 @@ var Address = class extends Destroyable {
18676
18743
  if (this._conversationMessages.hasMore) this._conversationMessages.loadMore();
18677
18744
  return this._conversationMessages;
18678
18745
  };
18679
- this.textMessages$ = (0, import_cjs$7.defer)(this.initConversationMessages).pipe((0, import_cjs$7.map)(() => this.textMessage), (0, import_cjs$7.shareReplay)(1), (0, import_cjs$7.takeUntil)(this.destroyed$));
18680
- this.history$ = (0, import_cjs$7.defer)(this.initConversationMessages).pipe((0, import_cjs$7.map)(() => this.history), (0, import_cjs$7.shareReplay)(1), (0, import_cjs$7.takeUntil)(this.destroyed$));
18746
+ this.textMessages$ = (0, import_cjs$8.defer)(this.initConversationMessages).pipe((0, import_cjs$8.map)(() => this.textMessage), (0, import_cjs$8.shareReplay)(1), (0, import_cjs$8.takeUntil)(this.destroyed$));
18747
+ this.history$ = (0, import_cjs$8.defer)(this.initConversationMessages).pipe((0, import_cjs$8.map)(() => this.history), (0, import_cjs$8.shareReplay)(1), (0, import_cjs$8.takeUntil)(this.destroyed$));
18681
18748
  this._state$ = this.createBehaviorSubject(null);
18682
18749
  }
18683
18750
  /** @internal */
@@ -18712,7 +18779,7 @@ var Address = class extends Destroyable {
18712
18779
  }
18713
18780
  /** Observable of the human-readable display name. */
18714
18781
  get displayName$() {
18715
- return this.cachedObservable("displayName$", () => this._state$.pipe(filterNull(), (0, import_cjs$7.map)((state) => state.display_name), (0, import_cjs$7.takeUntil)(this.destroyed$)));
18782
+ return this.cachedObservable("displayName$", () => this._state$.pipe(filterNull(), (0, import_cjs$8.map)((state) => state.display_name), (0, import_cjs$8.takeUntil)(this.destroyed$)));
18716
18783
  }
18717
18784
  /** Human-readable display name. */
18718
18785
  get displayName() {
@@ -18721,7 +18788,7 @@ var Address = class extends Destroyable {
18721
18788
  }
18722
18789
  /** Observable of the preview image URL. */
18723
18790
  get previewUrl$() {
18724
- return this.cachedObservable("previewUrl$", () => this._state$.pipe(filterNull(), (0, import_cjs$7.map)((state) => state.preview_url), (0, import_cjs$7.takeUntil)(this.destroyed$)));
18791
+ return this.cachedObservable("previewUrl$", () => this._state$.pipe(filterNull(), (0, import_cjs$8.map)((state) => state.preview_url), (0, import_cjs$8.takeUntil)(this.destroyed$)));
18725
18792
  }
18726
18793
  /** Preview image URL. */
18727
18794
  get previewUrl() {
@@ -18730,7 +18797,7 @@ var Address = class extends Destroyable {
18730
18797
  }
18731
18798
  /** Observable of the cover image URL. */
18732
18799
  get coverUrl$() {
18733
- return this.cachedObservable("coverUrl$", () => this._state$.pipe(filterNull(), (0, import_cjs$7.shareReplay)(1), (0, import_cjs$7.map)((state) => state.cover_url), (0, import_cjs$7.takeUntil)(this.destroyed$)));
18800
+ return this.cachedObservable("coverUrl$", () => this._state$.pipe(filterNull(), (0, import_cjs$8.shareReplay)(1), (0, import_cjs$8.map)((state) => state.cover_url), (0, import_cjs$8.takeUntil)(this.destroyed$)));
18734
18801
  }
18735
18802
  /** Cover image URL. */
18736
18803
  get coverUrl() {
@@ -18739,7 +18806,7 @@ var Address = class extends Destroyable {
18739
18806
  }
18740
18807
  /** Observable of the underlying resource ID. */
18741
18808
  get resourceId$() {
18742
- return this.cachedObservable("resourceId$", () => this._state$.pipe(filterNull(), (0, import_cjs$7.shareReplay)(1), (0, import_cjs$7.map)((state) => state.resource_id), (0, import_cjs$7.takeUntil)(this.destroyed$)));
18809
+ return this.cachedObservable("resourceId$", () => this._state$.pipe(filterNull(), (0, import_cjs$8.shareReplay)(1), (0, import_cjs$8.map)((state) => state.resource_id), (0, import_cjs$8.takeUntil)(this.destroyed$)));
18743
18810
  }
18744
18811
  /** Underlying resource ID. */
18745
18812
  get resourceId() {
@@ -18748,7 +18815,7 @@ var Address = class extends Destroyable {
18748
18815
  }
18749
18816
  /** Observable of the resource type (e.g. `'room'`, `'subscriber'`). */
18750
18817
  get type$() {
18751
- return this.cachedObservable("type$", () => this._state$.pipe(filterNull(), (0, import_cjs$7.shareReplay)(1), (0, import_cjs$7.map)((state) => state.type), (0, import_cjs$7.takeUntil)(this.destroyed$)));
18818
+ return this.cachedObservable("type$", () => this._state$.pipe(filterNull(), (0, import_cjs$8.shareReplay)(1), (0, import_cjs$8.map)((state) => state.type), (0, import_cjs$8.takeUntil)(this.destroyed$)));
18752
18819
  }
18753
18820
  /** Resource type (e.g. `'room'`, `'subscriber'`). */
18754
18821
  get type() {
@@ -18757,7 +18824,7 @@ var Address = class extends Destroyable {
18757
18824
  }
18758
18825
  /** Observable of available communication channels (audio, video, messaging). */
18759
18826
  get channels$() {
18760
- return this.cachedObservable("channels$", () => this._state$.pipe(filterNull(), (0, import_cjs$7.shareReplay)(1), (0, import_cjs$7.map)((state) => state.channels), (0, import_cjs$7.takeUntil)(this.destroyed$)));
18827
+ return this.cachedObservable("channels$", () => this._state$.pipe(filterNull(), (0, import_cjs$8.shareReplay)(1), (0, import_cjs$8.map)((state) => state.channels), (0, import_cjs$8.takeUntil)(this.destroyed$)));
18761
18828
  }
18762
18829
  /** Available communication channels. */
18763
18830
  get channels() {
@@ -18771,7 +18838,7 @@ var Address = class extends Destroyable {
18771
18838
  }
18772
18839
  /** Observable indicating whether the address (room) is locked. */
18773
18840
  get locked$() {
18774
- return this.cachedObservable("locked$", () => this._state$.pipe(filterNull(), (0, import_cjs$7.shareReplay)(1), (0, import_cjs$7.map)((state) => state.locked), (0, import_cjs$7.takeUntil)(this.destroyed$)));
18841
+ return this.cachedObservable("locked$", () => this._state$.pipe(filterNull(), (0, import_cjs$8.shareReplay)(1), (0, import_cjs$8.map)((state) => state.locked), (0, import_cjs$8.takeUntil)(this.destroyed$)));
18775
18842
  }
18776
18843
  /**
18777
18844
  * Sends a text message to this address.
@@ -18837,14 +18904,14 @@ var Address = class extends Destroyable {
18837
18904
 
18838
18905
  //#endregion
18839
18906
  //#region src/core/utils.ts
18840
- var import_cjs$6 = require_cjs();
18841
- const logger$8 = getLogger();
18907
+ var import_cjs$7 = require_cjs();
18908
+ const logger$9 = getLogger();
18842
18909
  const isRPCConnectResult = (e) => {
18843
- logger$8.debug("isRPCConnectResult check:", e);
18910
+ logger$9.debug("isRPCConnectResult check:", e);
18844
18911
  if (!e || typeof e !== "object") return false;
18845
18912
  const result = e;
18846
18913
  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";
18847
- logger$8.debug("isRPCConnectResult check result:", is);
18914
+ logger$9.debug("isRPCConnectResult check result:", is);
18848
18915
  return is;
18849
18916
  };
18850
18917
  var PendingRPC = class PendingRPC {
@@ -18853,7 +18920,7 @@ var PendingRPC = class PendingRPC {
18853
18920
  }
18854
18921
  constructor(request, responses$, options) {
18855
18922
  this.id = v4_default();
18856
- logger$8.debug(`[PendingRPC(${this.id}) request:${request.id}: method:${request.method}] Creating PendingRPC`);
18923
+ logger$9.debug(`[PendingRPC(${this.id}) request:${request.id}: method:${request.method}] Creating PendingRPC`);
18857
18924
  this.request = request;
18858
18925
  const timeoutMs = options?.timeoutMs ?? PendingRPC.defaultTimeoutMs;
18859
18926
  const signal = options?.signal;
@@ -18863,38 +18930,38 @@ var PendingRPC = class PendingRPC {
18863
18930
  return;
18864
18931
  }
18865
18932
  let isSettled = false;
18866
- const subscription = (0, import_cjs$6.race)(responses$.pipe((0, import_cjs$6.filter)((result) => result.id === request.id), (0, import_cjs$6.take)(1)), new import_cjs$6.Observable((subscriber) => {
18867
- const timer$2 = setTimeout(() => {
18933
+ const subscription = (0, import_cjs$7.race)(responses$.pipe((0, import_cjs$7.filter)((result) => result.id === request.id), (0, import_cjs$7.take)(1)), new import_cjs$7.Observable((subscriber) => {
18934
+ const timer$3 = setTimeout(() => {
18868
18935
  subscriber.error(new RPCTimeoutError(request.id, timeoutMs));
18869
18936
  }, timeoutMs);
18870
- return () => clearTimeout(timer$2);
18871
- }), signal ? new import_cjs$6.Observable((subscriber) => {
18937
+ return () => clearTimeout(timer$3);
18938
+ }), signal ? new import_cjs$7.Observable((subscriber) => {
18872
18939
  const abortHandler = () => {
18873
18940
  subscriber.error(new DOMException("The operation was aborted", "AbortError"));
18874
18941
  };
18875
18942
  signal.addEventListener("abort", abortHandler);
18876
18943
  return () => signal.removeEventListener("abort", abortHandler);
18877
- }) : import_cjs$6.NEVER).subscribe({
18944
+ }) : import_cjs$7.NEVER).subscribe({
18878
18945
  next: (response) => {
18879
18946
  isSettled = true;
18880
18947
  if (response.error) {
18881
18948
  const rpcError = new JSONRPCError(response.error.code, response.error.message, response.error.data, void 0, request.id);
18882
- logger$8.debug(`[PendingRPC(${this.id}) request:${request.id}] Rejecting promise with RPC error:`, rpcError);
18949
+ logger$9.debug(`[PendingRPC(${this.id}) request:${request.id}] Rejecting promise with RPC error:`, rpcError);
18883
18950
  reject(rpcError);
18884
18951
  } else {
18885
- logger$8.debug(`[PendingRPC(${this.id}) request:${request.id}] Resolving promise with response:`, response);
18952
+ logger$9.debug(`[PendingRPC(${this.id}) request:${request.id}] Resolving promise with response:`, response);
18886
18953
  resolve(response);
18887
18954
  }
18888
18955
  subscription.unsubscribe();
18889
18956
  },
18890
18957
  error: (error) => {
18891
- logger$8.debug(`[PendingRPC(${this.id}) request:${request.id}] Rejecting promise with error:`, error);
18958
+ logger$9.debug(`[PendingRPC(${this.id}) request:${request.id}] Rejecting promise with error:`, error);
18892
18959
  isSettled = true;
18893
18960
  reject(error);
18894
18961
  subscription.unsubscribe();
18895
18962
  },
18896
18963
  complete: () => {
18897
- logger$8.debug(`[PendingRPC(${this.id}) request:${request.id}] Observable completed`);
18964
+ logger$9.debug(`[PendingRPC(${this.id}) request:${request.id}] Observable completed`);
18898
18965
  if (!isSettled) reject(new RPCTimeoutError(request.id, timeoutMs));
18899
18966
  subscription.unsubscribe();
18900
18967
  }
@@ -18914,8 +18981,8 @@ var PendingRPC = class PendingRPC {
18914
18981
 
18915
18982
  //#endregion
18916
18983
  //#region src/managers/ClientSessionManager.ts
18917
- var import_cjs$5 = require_cjs();
18918
- const logger$7 = getLogger();
18984
+ var import_cjs$6 = require_cjs();
18985
+ const logger$8 = getLogger();
18919
18986
  const getAddressSearchURI = (options) => {
18920
18987
  const to = options.to?.split("?")[0];
18921
18988
  const from$9 = options.from?.startsWith("subscriber://") ? options.from.replace("subscriber://", "") : options.from;
@@ -18950,10 +19017,10 @@ var ClientSessionManager = class extends Destroyable {
18950
19017
  this._iceServers$ = this.createBehaviorSubject([]);
18951
19018
  attachManager.setSession(this);
18952
19019
  this.callFactory = new CallFactory(this, deviceController, attachManager, webRTCApiProvider, networkChange$);
18953
- this.initialized$ = (0, import_cjs$5.defer)(() => (0, import_cjs$5.from)(this.init())).pipe((0, import_cjs$5.shareReplay)(1), (0, import_cjs$5.takeUntil)(this.destroyed$));
19020
+ this.initialized$ = (0, import_cjs$6.defer)(() => (0, import_cjs$6.from)(this.init())).pipe((0, import_cjs$6.shareReplay)(1), (0, import_cjs$6.takeUntil)(this.destroyed$));
18954
19021
  }
18955
19022
  get incomingCalls$() {
18956
- return this.cachedObservable("incomingCalls$", () => this.calls$.pipe((0, import_cjs$5.map)((calls) => calls.filter((call) => call.direction === "inbound"))));
19023
+ return this.cachedObservable("incomingCalls$", () => this.calls$.pipe((0, import_cjs$6.map)((calls) => calls.filter((call) => call.direction === "inbound"))));
18957
19024
  }
18958
19025
  get incomingCalls() {
18959
19026
  return Object.values(this._calls$.value).filter((call) => call.direction === "inbound");
@@ -18965,7 +19032,7 @@ var ClientSessionManager = class extends Destroyable {
18965
19032
  return this._subscriberInfo$.value;
18966
19033
  }
18967
19034
  get calls$() {
18968
- return this.cachedObservable("calls$", () => this._calls$.pipe((0, import_cjs$5.map)((calls) => Object.values(calls))));
19035
+ return this.cachedObservable("calls$", () => this._calls$.pipe((0, import_cjs$6.map)((calls) => Object.values(calls))));
18969
19036
  }
18970
19037
  get calls() {
18971
19038
  return Object.values(this._calls$.value);
@@ -19009,7 +19076,7 @@ var ClientSessionManager = class extends Destroyable {
19009
19076
  try {
19010
19077
  return await this.transport.execute(request, options);
19011
19078
  } catch (error) {
19012
- logger$7.debug("[Session] Execute Error", error);
19079
+ logger$8.debug("[Session] Execute Error", error);
19013
19080
  this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
19014
19081
  throw error;
19015
19082
  }
@@ -19023,40 +19090,40 @@ var ClientSessionManager = class extends Destroyable {
19023
19090
  return true;
19024
19091
  }
19025
19092
  setupMessageHandlers() {
19026
- logger$7.debug("[Session] Setting up message handlers");
19093
+ logger$8.debug("[Session] Setting up message handlers");
19027
19094
  this.subscribeTo(this.authStateEvent$, async (authStateEvent) => {
19028
- logger$7.debug("[Session] Authorization state event received:", authStateEvent);
19095
+ logger$8.debug("[Session] Authorization state event received:", authStateEvent);
19029
19096
  try {
19030
19097
  await this.updateAuthorizationStateInStorage(authStateEvent.authorization_state);
19031
19098
  } catch (error) {
19032
- logger$7.error("[Session] Failed to handle authorization state update:", error);
19099
+ logger$8.error("[Session] Failed to handle authorization state update:", error);
19033
19100
  this._errors$.next(new AuthStateHandlerError(error));
19034
19101
  }
19035
19102
  });
19036
- this.subscribeTo(this.transport.connectionStatus$.pipe((0, import_cjs$5.filter)((status) => status === "connected"), (0, import_cjs$5.exhaustMap)(() => {
19037
- logger$7.debug("[Session] Connection established, initiating authentication");
19038
- return (0, import_cjs$5.from)(this.authenticate()).pipe((0, import_cjs$5.catchError)((error) => {
19103
+ this.subscribeTo(this.transport.connectionStatus$.pipe((0, import_cjs$6.filter)((status) => status === "connected"), (0, import_cjs$6.exhaustMap)(() => {
19104
+ logger$8.debug("[Session] Connection established, initiating authentication");
19105
+ return (0, import_cjs$6.from)(this.authenticate()).pipe((0, import_cjs$6.catchError)((error) => {
19039
19106
  this.handleAuthenticationError(error).catch((err) => {
19040
- logger$7.error("[Session] Error handling authentication failure:", err);
19107
+ logger$8.error("[Session] Error handling authentication failure:", err);
19041
19108
  });
19042
- return import_cjs$5.EMPTY;
19109
+ return import_cjs$6.EMPTY;
19043
19110
  }));
19044
19111
  })), void 0);
19045
19112
  this.subscribeTo(this.vertoInvite$, async (invite) => {
19046
- logger$7.debug("[Session] Verto invite received:", invite);
19113
+ logger$8.debug("[Session] Verto invite received:", invite);
19047
19114
  try {
19048
19115
  await this.createInboundCall(invite);
19049
19116
  } catch (error) {
19050
- logger$7.error("[Session] Error handling Verto invite:", error);
19117
+ logger$8.error("[Session] Error handling Verto invite:", error);
19051
19118
  this._errors$.next(new VertoInviteHandlerError(error));
19052
19119
  }
19053
19120
  });
19054
19121
  this.subscribeTo(this.vertoAttach$, async (attach) => {
19055
- logger$7.debug("[Session] Verto attach received:", attach);
19122
+ logger$8.debug("[Session] Verto attach received:", attach);
19056
19123
  try {
19057
19124
  await this.handleVertoAttach(attach);
19058
19125
  } catch (error) {
19059
- logger$7.error("[Session] Error handling Verto attach:", error);
19126
+ logger$8.error("[Session] Error handling Verto attach:", error);
19060
19127
  this._errors$.next(new VertoAttachHandlerError(error));
19061
19128
  }
19062
19129
  });
@@ -19066,49 +19133,49 @@ var ClientSessionManager = class extends Destroyable {
19066
19133
  const storedState = await this.storage.getItem(this.authorizationStateKey);
19067
19134
  this.authorizationState$.next(storedState ?? void 0);
19068
19135
  } catch (error) {
19069
- logger$7.error("Failed to retrieve authorization state from storage:", error);
19136
+ logger$8.error("Failed to retrieve authorization state from storage:", error);
19070
19137
  this.authorizationState$.next(void 0);
19071
19138
  }
19072
19139
  }
19073
19140
  async updateAuthorizationStateInStorage(authorizationState) {
19074
19141
  if (!authorizationState) {
19075
- logger$7.debug("[Session] Removing authorization state from storage");
19142
+ logger$8.debug("[Session] Removing authorization state from storage");
19076
19143
  try {
19077
19144
  await this.storage.removeItem(this.authorizationStateKey);
19078
19145
  this.authorizationState$.next(void 0);
19079
19146
  } catch (error) {
19080
- logger$7.error("Failed to remove authorization state from storage:", error);
19147
+ logger$8.error("Failed to remove authorization state from storage:", error);
19081
19148
  throw error;
19082
19149
  }
19083
19150
  return;
19084
19151
  }
19085
19152
  try {
19086
- logger$7.debug("[Session] Updating authorization state in storage");
19153
+ logger$8.debug("[Session] Updating authorization state in storage");
19087
19154
  await this.storage.setItem(this.authorizationStateKey, authorizationState);
19088
19155
  this.authorizationState$.next(authorizationState);
19089
19156
  } catch (error) {
19090
- logger$7.error("Failed to retrieve authorization state from storage:", error);
19157
+ logger$8.error("Failed to retrieve authorization state from storage:", error);
19091
19158
  throw error;
19092
19159
  }
19093
19160
  }
19094
19161
  get authStateEvent$() {
19095
- return this.cachedObservable("authStateEvent$", () => this.signalingEvent$.pipe((0, import_cjs$5.tap)((msg) => {
19096
- logger$7.debug("[Session] Received incoming message:", msg);
19097
- }), filterAs(isSignalwireAuthorizationStateMetadata, "params"), (0, import_cjs$5.tap)((event) => {
19098
- logger$7.debug("[Session] Authorization state event received:", event.authorization_state);
19162
+ return this.cachedObservable("authStateEvent$", () => this.signalingEvent$.pipe((0, import_cjs$6.tap)((msg) => {
19163
+ logger$8.debug("[Session] Received incoming message:", msg);
19164
+ }), filterAs(isSignalwireAuthorizationStateMetadata, "params"), (0, import_cjs$6.tap)((event) => {
19165
+ logger$8.debug("[Session] Authorization state event received:", event.authorization_state);
19099
19166
  })));
19100
19167
  }
19101
19168
  get signalingEvent$() {
19102
- return this.cachedObservable("signalingEvent$", () => this.transport.incomingEvent$.pipe(filterAs(isSignalwireRequest, "params"), (0, import_cjs$5.share)()));
19169
+ return this.cachedObservable("signalingEvent$", () => this.transport.incomingEvent$.pipe(filterAs(isSignalwireRequest, "params"), (0, import_cjs$6.share)()));
19103
19170
  }
19104
19171
  get vertoInvite$() {
19105
- return this.cachedObservable("vertoInvite$", () => this.signalingEvent$.pipe((0, import_cjs$5.filter)(isWebrtcMessageMetadata), (0, import_cjs$5.filter)((event) => isVertoInviteMessage(event.params)), (0, import_cjs$5.map)((event) => ({
19172
+ return this.cachedObservable("vertoInvite$", () => this.signalingEvent$.pipe((0, import_cjs$6.filter)(isWebrtcMessageMetadata), (0, import_cjs$6.filter)((event) => isVertoInviteMessage(event.params)), (0, import_cjs$6.map)((event) => ({
19106
19173
  node_id: event.node_id,
19107
19174
  ...event.params.params
19108
19175
  }))));
19109
19176
  }
19110
19177
  get vertoAttach$() {
19111
- return this.cachedObservable("vertoAttach$", () => this.signalingEvent$.pipe((0, import_cjs$5.filter)(isWebrtcMessageMetadata), (0, import_cjs$5.filter)((event) => isVertoAttachMessage(event.params)), (0, import_cjs$5.map)((event) => ({
19178
+ return this.cachedObservable("vertoAttach$", () => this.signalingEvent$.pipe((0, import_cjs$6.filter)(isWebrtcMessageMetadata), (0, import_cjs$6.filter)((event) => isVertoAttachMessage(event.params)), (0, import_cjs$6.map)((event) => ({
19112
19179
  node_id: event.node_id,
19113
19180
  ...event.params.params
19114
19181
  }))));
@@ -19128,20 +19195,20 @@ var ClientSessionManager = class extends Destroyable {
19128
19195
  return { jwt_token: credential.token };
19129
19196
  }
19130
19197
  async connect() {
19131
- await (0, import_cjs$5.firstValueFrom)(this.initialized$);
19198
+ await (0, import_cjs$6.firstValueFrom)(this.initialized$);
19132
19199
  await this.transport.connect();
19133
- await (0, import_cjs$5.firstValueFrom)(this.authenticated$.pipe((0, import_cjs$5.takeUntil)(this.destroyed$), (0, import_cjs$5.filter)(Boolean), (0, import_cjs$5.take)(1), (0, import_cjs$5.timeout)({ first: 15e3 })));
19200
+ await (0, import_cjs$6.firstValueFrom)(this.authenticated$.pipe((0, import_cjs$6.takeUntil)(this.destroyed$), (0, import_cjs$6.filter)(Boolean), (0, import_cjs$6.take)(1), (0, import_cjs$6.timeout)({ first: 15e3 })));
19134
19201
  }
19135
19202
  async handleAuthenticationError(error) {
19136
- logger$7.error("Authentication error:", error);
19203
+ logger$8.error("Authentication error:", error);
19137
19204
  const isRecoverableAuthError = error instanceof JSONRPCError && (error.code === RPC_ERROR_REQUESTER_VALIDATION_FAILED || error.code === RPC_ERROR_INVALID_PARAMS || error.code === RPC_ERROR_AUTHENTICATION_FAILED);
19138
- const hasStoredState = await (0, import_cjs$5.firstValueFrom)(this.authorizationState$.pipe((0, import_cjs$5.take)(1))) !== void 0;
19205
+ const hasStoredState = await (0, import_cjs$6.firstValueFrom)(this.authorizationState$.pipe((0, import_cjs$6.take)(1))) !== void 0;
19139
19206
  if (isRecoverableAuthError && hasStoredState) {
19140
- logger$7.debug("[Session] Recoverable auth error — cleaning up stored state and reconnecting fresh");
19207
+ logger$8.debug("[Session] Recoverable auth error — cleaning up stored state and reconnecting fresh");
19141
19208
  try {
19142
19209
  await this.cleanupStoredConnectionParams();
19143
19210
  } catch (cleanupError) {
19144
- logger$7.error("Failed to cleanup stored connection params:", cleanupError);
19211
+ logger$8.error("Failed to cleanup stored connection params:", cleanupError);
19145
19212
  } finally {
19146
19213
  this.transport.reconnect();
19147
19214
  }
@@ -19156,44 +19223,44 @@ var ClientSessionManager = class extends Destroyable {
19156
19223
  try {
19157
19224
  await this.storage.setItem(this.authorizationStateKey, authorization_state);
19158
19225
  } catch (error) {
19159
- logger$7.error("Failed to update authorization state in storage:", error);
19226
+ logger$8.error("Failed to update authorization state in storage:", error);
19160
19227
  this._errors$.next(new AuthStateHandlerError(error));
19161
19228
  }
19162
19229
  }
19163
19230
  async reauthenticate(token, dpopToken, options) {
19164
- logger$7.debug("[Session] Re-authenticating session");
19231
+ logger$8.debug("[Session] Re-authenticating session");
19165
19232
  try {
19166
19233
  let resolvedDpopToken = dpopToken;
19167
19234
  if (!resolvedDpopToken && this.dpopManager?.initialized) try {
19168
19235
  resolvedDpopToken = await this.dpopManager.createRpcProof({ method: "signalwire.reauthenticate" });
19169
19236
  } catch (error) {
19170
19237
  if (this._clientBound) throw error;
19171
- logger$7.warn("[Session] Failed to create DPoP proof for reauthenticate:", error);
19238
+ logger$8.warn("[Session] Failed to create DPoP proof for reauthenticate:", error);
19172
19239
  }
19173
19240
  const request = RPCReauthenticate({
19174
19241
  project: this._authorization$.value?.project_id ?? "",
19175
19242
  jwt_token: token,
19176
19243
  ...resolvedDpopToken ? { dpop_token: resolvedDpopToken } : {}
19177
19244
  });
19178
- await (0, import_cjs$5.lastValueFrom)((0, import_cjs$5.from)(this.transport.execute(request)).pipe(throwOnRPCError(), (0, import_cjs$5.take)(1), (0, import_cjs$5.catchError)((err) => {
19179
- logger$7.error("[Session] Re-authentication RPC failed:", err);
19245
+ await (0, import_cjs$6.lastValueFrom)((0, import_cjs$6.from)(this.transport.execute(request)).pipe(throwOnRPCError(), (0, import_cjs$6.take)(1), (0, import_cjs$6.catchError)((err) => {
19246
+ logger$8.error("[Session] Re-authentication RPC failed:", err);
19180
19247
  throw err;
19181
19248
  })));
19182
19249
  if (options?.clientBound) this._clientBound = true;
19183
- logger$7.debug("[Session] Re-authentication successful, updating stored auth state");
19250
+ logger$8.debug("[Session] Re-authentication successful, updating stored auth state");
19184
19251
  } catch (error) {
19185
- logger$7.error("[Session] Re-authentication failed:", error);
19252
+ logger$8.error("[Session] Re-authentication failed:", error);
19186
19253
  this._errors$.next(new AuthStateHandlerError(error));
19187
19254
  throw error;
19188
19255
  }
19189
19256
  }
19190
19257
  async authenticate() {
19191
- logger$7.debug("[Session] Starting authentication process");
19192
- const persistedParams = await (0, import_cjs$5.firstValueFrom)((0, import_cjs$5.combineLatest)({
19258
+ logger$8.debug("[Session] Starting authentication process");
19259
+ const persistedParams = await (0, import_cjs$6.firstValueFrom)((0, import_cjs$6.combineLatest)({
19193
19260
  protocol: this.transport.protocol$,
19194
19261
  authorization_state: this.authorizationState$
19195
- }).pipe((0, import_cjs$5.take)(1)));
19196
- logger$7.debug("[Session] Persisted params:\n", {
19262
+ }).pipe((0, import_cjs$6.take)(1)));
19263
+ logger$8.debug("[Session] Persisted params:\n", {
19197
19264
  protocol: persistedParams.protocol,
19198
19265
  authStateLength: persistedParams.authorization_state?.length
19199
19266
  });
@@ -19201,16 +19268,16 @@ var ClientSessionManager = class extends Destroyable {
19201
19268
  const storedToken = this.getCredential().token;
19202
19269
  const isReconnect = hasReconnectState && storedToken;
19203
19270
  let dpopToken;
19204
- if (isReconnect) logger$7.debug("[Session] Reconnecting with stored jwt_token + authorization_state");
19271
+ if (isReconnect) logger$8.debug("[Session] Reconnecting with stored jwt_token + authorization_state");
19205
19272
  else if (this.onBeforeReconnect && this._clientBound) {
19206
- logger$7.debug("[Session] Refreshing credentials before fresh connect");
19273
+ logger$8.debug("[Session] Refreshing credentials before fresh connect");
19207
19274
  await this.onBeforeReconnect();
19208
19275
  }
19209
19276
  if ((!isReconnect || this._clientBound) && this.dpopManager?.initialized) try {
19210
19277
  dpopToken = await this.dpopManager.createRpcProof({ method: "signalwire.connect" });
19211
19278
  } catch (error) {
19212
19279
  if (this._clientBound) throw error;
19213
- logger$7.warn("[Session] Failed to create DPoP proof for connect, proceeding without:", error);
19280
+ logger$8.warn("[Session] Failed to create DPoP proof for connect, proceeding without:", error);
19214
19281
  }
19215
19282
  const rpcConnectRequest = RPCConnect({
19216
19283
  authentication: isReconnect ? { jwt_token: storedToken } : this.authentication,
@@ -19226,13 +19293,13 @@ var ClientSessionManager = class extends Destroyable {
19226
19293
  protocol: persistedParams.protocol
19227
19294
  } : {}
19228
19295
  });
19229
- const response = await (0, import_cjs$5.lastValueFrom)((0, import_cjs$5.from)(this.transport.execute(rpcConnectRequest)).pipe(throwOnRPCError(), (0, import_cjs$5.map)((res) => res.result), (0, import_cjs$5.filter)(isRPCConnectResult), (0, import_cjs$5.tap)(() => {
19230
- logger$7.debug("[Session] Response passed filter, processing authentication result");
19231
- }), (0, import_cjs$5.take)(1), (0, import_cjs$5.catchError)((err) => {
19232
- logger$7.error("[Session] Authentication RPC failed:", err);
19296
+ const response = await (0, import_cjs$6.lastValueFrom)((0, import_cjs$6.from)(this.transport.execute(rpcConnectRequest)).pipe(throwOnRPCError(), (0, import_cjs$6.map)((res) => res.result), (0, import_cjs$6.filter)(isRPCConnectResult), (0, import_cjs$6.tap)(() => {
19297
+ logger$8.debug("[Session] Response passed filter, processing authentication result");
19298
+ }), (0, import_cjs$6.take)(1), (0, import_cjs$6.catchError)((err) => {
19299
+ logger$8.error("[Session] Authentication RPC failed:", err);
19233
19300
  throw err;
19234
19301
  })));
19235
- logger$7.debug("[Session] Processing authentication result:", {
19302
+ logger$8.debug("[Session] Processing authentication result:", {
19236
19303
  hasProtocol: !!response.protocol,
19237
19304
  hasAuthorization: !!response.authorization,
19238
19305
  hasIceServers: !!response.ice_servers
@@ -19241,7 +19308,7 @@ var ClientSessionManager = class extends Destroyable {
19241
19308
  this._authorization$.next(response.authorization);
19242
19309
  this._iceServers$.next(response.ice_servers ?? []);
19243
19310
  this._authenticated$.next(true);
19244
- logger$7.debug("[Session] Authentication completed successfully");
19311
+ logger$8.debug("[Session] Authentication completed successfully");
19245
19312
  }
19246
19313
  async disconnect() {
19247
19314
  this.transport.disconnect();
@@ -19260,7 +19327,7 @@ var ClientSessionManager = class extends Destroyable {
19260
19327
  displayDirection: invite.display_direction,
19261
19328
  userVariables: invite.userVariables
19262
19329
  });
19263
- await (0, import_cjs$5.firstValueFrom)(callSession.status$);
19330
+ await (0, import_cjs$6.firstValueFrom)(callSession.status$);
19264
19331
  this._calls$.next({
19265
19332
  [`${callSession.id}`]: callSession,
19266
19333
  ...this._calls$.value
@@ -19278,11 +19345,11 @@ var ClientSessionManager = class extends Destroyable {
19278
19345
  async handleVertoAttach(attach) {
19279
19346
  const { callID } = attach;
19280
19347
  if (callID in this._calls$.value) {
19281
- logger$7.debug(`[Session] Verto attach for existing call ${callID}, deferring to per-call handler`);
19348
+ logger$8.debug(`[Session] Verto attach for existing call ${callID}, deferring to per-call handler`);
19282
19349
  return;
19283
19350
  }
19284
19351
  const storedOptions = this.attachManager.consumePendingAttachment(callID);
19285
- logger$7.debug(`[Session] Creating reattached call for callID: ${callID}`);
19352
+ logger$8.debug(`[Session] Creating reattached call for callID: ${callID}`);
19286
19353
  const callSession = await this.createCall({
19287
19354
  nodeId: attach.node_id,
19288
19355
  callId: callID,
@@ -19293,7 +19360,7 @@ var ClientSessionManager = class extends Destroyable {
19293
19360
  reattach: true,
19294
19361
  ...storedOptions
19295
19362
  });
19296
- await (0, import_cjs$5.firstValueFrom)(callSession.status$);
19363
+ await (0, import_cjs$6.firstValueFrom)(callSession.status$);
19297
19364
  this._calls$.next({
19298
19365
  [`${callSession.id}`]: callSession,
19299
19366
  ...this._calls$.value
@@ -19307,16 +19374,16 @@ var ClientSessionManager = class extends Destroyable {
19307
19374
  to: destinationURI,
19308
19375
  ...options
19309
19376
  });
19310
- await (0, import_cjs$5.firstValueFrom)((0, import_cjs$5.race)(callSession.selfId$.pipe((0, import_cjs$5.filter)((id) => Boolean(id)), (0, import_cjs$5.take)(1), (0, import_cjs$5.timeout)(this.callCreateTimeout)), callSession.errors$.pipe((0, import_cjs$5.take)(1), (0, import_cjs$5.switchMap)((callError) => (0, import_cjs$5.throwError)(() => callError.error)))));
19377
+ await (0, import_cjs$6.firstValueFrom)((0, import_cjs$6.race)(callSession.selfId$.pipe((0, import_cjs$6.filter)((id) => Boolean(id)), (0, import_cjs$6.take)(1), (0, import_cjs$6.timeout)(this.callCreateTimeout)), callSession.errors$.pipe((0, import_cjs$6.take)(1), (0, import_cjs$6.switchMap)((callError) => (0, import_cjs$6.throwError)(() => callError.error)))));
19311
19378
  this._calls$.next({
19312
19379
  [`${callSession.id}`]: callSession,
19313
19380
  ...this._calls$.value
19314
19381
  });
19315
19382
  return callSession;
19316
19383
  } catch (error) {
19317
- logger$7.error("[Session] Error creating outbound call:", error);
19384
+ logger$8.error("[Session] Error creating outbound call:", error);
19318
19385
  callSession?.destroy();
19319
- const callError = new CallCreateError(error instanceof import_cjs$5.TimeoutError ? "Call create timeout" : "Call creation failed", error, "outbound");
19386
+ const callError = new CallCreateError(error instanceof import_cjs$6.TimeoutError ? "Call create timeout" : "Call creation failed", error, "outbound");
19320
19387
  this._errors$.next(callError);
19321
19388
  throw callError;
19322
19389
  }
@@ -19332,16 +19399,16 @@ var ClientSessionManager = class extends Destroyable {
19332
19399
  address = this._directory.get(addressId);
19333
19400
  if (!address) throw new DependencyError(`Address ID: ${addressId} not found`);
19334
19401
  } catch {
19335
- logger$7.warn(`[Session] Directory lookup failed for ${addressURI}, proceeding with raw URI`);
19402
+ logger$8.warn(`[Session] Directory lookup failed for ${addressURI}, proceeding with raw URI`);
19336
19403
  }
19337
19404
  const callSession = this.callFactory.createCall(address, { ...options });
19338
- this.subscribeTo(callSession.status$.pipe((0, import_cjs$5.filter)((status) => status === "destroyed"), (0, import_cjs$5.take)(1)), () => {
19405
+ this.subscribeTo(callSession.status$.pipe((0, import_cjs$6.filter)((status) => status === "destroyed"), (0, import_cjs$6.take)(1)), () => {
19339
19406
  const { [`${callSession.id}`]: _, ...remainingCalls } = this._calls$.value;
19340
19407
  this._calls$.next(remainingCalls);
19341
19408
  });
19342
19409
  return callSession;
19343
19410
  } catch (error) {
19344
- logger$7.error("[Session] Error creating call session:", error);
19411
+ logger$8.error("[Session] Error creating call session:", error);
19345
19412
  throw new CallCreateError("Call create error", error, options.initOffer ? "inbound" : "outbound");
19346
19413
  }
19347
19414
  }
@@ -19389,8 +19456,8 @@ const isString = (obj) => typeof obj === "string";
19389
19456
 
19390
19457
  //#endregion
19391
19458
  //#region src/managers/ConversationsManager.ts
19392
- var import_cjs$4 = require_cjs();
19393
- const logger$6 = getLogger();
19459
+ var import_cjs$5 = require_cjs();
19460
+ const logger$7 = getLogger();
19394
19461
  var ConversationMessagesFetcher = class extends Fetcher {
19395
19462
  constructor(groupId, http) {
19396
19463
  super(`/api/fabric/conversations/${groupId}/messages`, "page_size=100", http);
@@ -19430,13 +19497,13 @@ var ConversationsManager = class {
19430
19497
  }
19431
19498
  throw new ConversationError("Join Failed - Unexpected response");
19432
19499
  } catch (error) {
19433
- logger$6.error("[ConversationsManager] Failed to join conversation:", error);
19500
+ logger$7.error("[ConversationsManager] Failed to join conversation:", error);
19434
19501
  throw error;
19435
19502
  }
19436
19503
  }
19437
19504
  async getConversationMessageCollection(addressId) {
19438
19505
  const groupId = this.groupIds.get(addressId) ?? await this.join(addressId);
19439
- return Promise.resolve(new ConversationMessageCollection(groupId, this.clientSession.signalingEvent$.pipe(filterAs(isConversationMessageMetadata, "params"), (0, import_cjs$4.tap)((event) => logger$6.debug("[ConversationsManager ] Conversation Event:", event)), (0, import_cjs$4.map)((params) => ({ ...params }))), this.http, this.onError));
19506
+ return Promise.resolve(new ConversationMessageCollection(groupId, this.clientSession.signalingEvent$.pipe(filterAs(isConversationMessageMetadata, "params"), (0, import_cjs$5.tap)((event) => logger$7.debug("[ConversationsManager ] Conversation Event:", event)), (0, import_cjs$5.map)((params) => ({ ...params }))), this.http, this.onError));
19440
19507
  }
19441
19508
  async sendText(text, destinationAddressId) {
19442
19509
  const groupId = this.groupIds.get(destinationAddressId) ?? await this.join(destinationAddressId);
@@ -19453,12 +19520,222 @@ var ConversationsManager = class {
19453
19520
  })).ok) return;
19454
19521
  throw new ConversationError("Send Text Failed - Unexpected response");
19455
19522
  } catch (error) {
19456
- logger$6.error("[ConversationsManager] Failed to send text message:", error);
19523
+ logger$7.error("[ConversationsManager] Failed to send text message:", error);
19457
19524
  throw error;
19458
19525
  }
19459
19526
  }
19460
19527
  };
19461
19528
 
19529
+ //#endregion
19530
+ //#region src/managers/DeviceTokenManager.ts
19531
+ var import_cjs$4 = require_cjs();
19532
+ const logger$6 = getLogger();
19533
+ /**
19534
+ * Resolves the token expiry timestamp (epoch seconds) using a 3-tier priority chain:
19535
+ * 1. `data.expires_at` — server-provided absolute timestamp
19536
+ * 2. `data.expires_in` — server-provided relative lifetime
19537
+ * 3. Fallback to `DEVICE_TOKEN_DEFAULT_EXPIRE_IN` with a warning
19538
+ */
19539
+ function resolveExpiresAt(data) {
19540
+ if (data.expires_at) return data.expires_at;
19541
+ if (data.expires_in) return Math.floor(Date.now() / 1e3) + data.expires_in;
19542
+ logger$6.warn("[DeviceToken] Could not determine token expiry, using default");
19543
+ return Math.floor(Date.now() / 1e3) + DEVICE_TOKEN_DEFAULT_EXPIRE_IN;
19544
+ }
19545
+ /**
19546
+ * Resolves the token TTL in seconds from a fresh response.
19547
+ * Called at token receive time so `expires_at - now` reflects the original lifetime.
19548
+ *
19549
+ * 1. `data.expires_in` — server-provided TTL directly
19550
+ * 2. `data.expires_at - now` — derive TTL from absolute timestamp
19551
+ * 3. Fallback to `DEVICE_TOKEN_DEFAULT_EXPIRE_IN`
19552
+ */
19553
+ function resolveExpireIn(data) {
19554
+ if (data.expires_in) return data.expires_in;
19555
+ if (data.expires_at) return Math.max(data.expires_at - Math.floor(Date.now() / 1e3), 1);
19556
+ return DEVICE_TOKEN_DEFAULT_EXPIRE_IN;
19557
+ }
19558
+ /**
19559
+ * Manages the Client Bound SAT lifecycle: activation, token exchange,
19560
+ * reauthentication, and automatic refresh scheduling.
19561
+ *
19562
+ * Extends {@link Destroyable} for automatic RxJS subscription and subject cleanup.
19563
+ * Uses a reactive pipeline (`BehaviorSubject` + `switchMap(timer())`) instead of
19564
+ * raw `setTimeout` for refresh scheduling.
19565
+ */
19566
+ var DeviceTokenManager = class extends Destroyable {
19567
+ constructor(dpopManager, http, errorHandler, getCredential) {
19568
+ super();
19569
+ this.dpopManager = dpopManager;
19570
+ this.http = http;
19571
+ this.errorHandler = errorHandler;
19572
+ this.getCredential = getCredential;
19573
+ this._currentToken$ = this.createBehaviorSubject(null);
19574
+ this._refreshInProgress = false;
19575
+ this._effectiveExpireIn = DEVICE_TOKEN_DEFAULT_EXPIRE_IN;
19576
+ this.subscribeTo(this._currentToken$.pipe((0, import_cjs$4.filter)(Boolean), (0, import_cjs$4.switchMap)((tokenData) => {
19577
+ const expiresAt = resolveExpiresAt(tokenData);
19578
+ const refreshIn = Math.max(expiresAt * 1e3 - Date.now() - DEVICE_TOKEN_REFRESH_BUFFER_MS, 1e3);
19579
+ logger$6.debug(`[DeviceToken] Scheduling Client Bound SAT refresh in ${refreshIn}ms`);
19580
+ return (0, import_cjs$4.timer)(refreshIn);
19581
+ })), () => {
19582
+ this.executeRefresh();
19583
+ });
19584
+ }
19585
+ /** Current token TTL in milliseconds. Used to extend cached credential expiry on refresh. */
19586
+ get effectiveExpireIn() {
19587
+ return this._effectiveExpireIn;
19588
+ }
19589
+ /**
19590
+ * Activates the Client Bound SAT flow when the subscriber's token has
19591
+ * `sat:refresh` scope.
19592
+ *
19593
+ * Steps:
19594
+ * 1. Check subscriber's `sat_claims` for `sat:refresh` scope
19595
+ * 2. Call `/api/fabric/subscriber/devices/token` with a DPoP proof
19596
+ * 3. Reauthenticate the session with the Client Bound SAT + DPoP proof
19597
+ * 4. Emit token to trigger the reactive refresh pipeline
19598
+ */
19599
+ async activate(subscriber, session, updateCredential) {
19600
+ const { satClaims } = subscriber;
19601
+ if (!satClaims?.scope?.includes(SAT_REFRESH_SCOPE)) {
19602
+ logger$6.debug("[DeviceToken] No sat:refresh scope, skipping Client Bound SAT activation");
19603
+ return;
19604
+ }
19605
+ this._session = session;
19606
+ this._updateCredential = updateCredential;
19607
+ try {
19608
+ const tokenData = await this.obtainToken();
19609
+ if (!tokenData.expires_at && !tokenData.expires_in && satClaims.expires_at) tokenData.expires_at = satClaims.expires_at;
19610
+ this._effectiveExpireIn = resolveExpireIn(tokenData);
19611
+ const rpcProof = await this.dpopManager.createRpcProof({ method: "signalwire.reauthenticate" });
19612
+ await session.reauthenticate(tokenData.token, rpcProof, { clientBound: true });
19613
+ updateCredential({ token: tokenData.token });
19614
+ logger$6.info("[DeviceToken] Client Bound SAT activated successfully");
19615
+ this._currentToken$.next(tokenData);
19616
+ } catch (error) {
19617
+ logger$6.error("[DeviceToken] Failed to activate Client Bound SAT:", error);
19618
+ this.errorHandler(new DPoPInitError(error, "Failed to activate Client Bound SAT"));
19619
+ const credential = this.getCredential();
19620
+ const expiresAt = satClaims.expires_at ?? (credential.expiry_at ? credential.expiry_at / 1e3 : Date.now() / 1e3 + DEVICE_TOKEN_DEFAULT_EXPIRE_IN / 1e3);
19621
+ this._currentToken$.next({
19622
+ token: credential.token ?? "",
19623
+ expires_at: expiresAt
19624
+ });
19625
+ }
19626
+ }
19627
+ /**
19628
+ * Obtains a Client Bound SAT from `/api/fabric/subscriber/devices/token`.
19629
+ * Returns the full {@link DeviceTokenResponse} including expiry metadata.
19630
+ */
19631
+ async obtainToken() {
19632
+ const dpopProof = await this.dpopManager.createHttpProof({
19633
+ method: "POST",
19634
+ uri: DEVICE_TOKEN_ENDPOINT
19635
+ });
19636
+ const response = await this.http.request({
19637
+ url: DEVICE_TOKEN_ENDPOINT,
19638
+ ...POST_PARAMS,
19639
+ body: JSON.stringify({
19640
+ dpop_token: dpopProof,
19641
+ expire_in: DEVICE_TOKEN_DEFAULT_EXPIRE_IN
19642
+ })
19643
+ });
19644
+ if (!response.ok || !response.body) throw new DeviceTokenError(`Failed to obtain device token: ${response.status} ${response.statusText}`);
19645
+ const data = JSON.parse(response.body);
19646
+ if (!data.token) throw new DeviceTokenError("Device token response missing token field");
19647
+ return data;
19648
+ }
19649
+ /**
19650
+ * Refreshes the Client Bound SAT via `/api/fabric/subscriber/devices/refresh`.
19651
+ *
19652
+ * Creates a fresh DPoP proof, calls the refresh endpoint, reauthenticates
19653
+ * the WebSocket session, and returns the new token data (scheduling is
19654
+ * handled by the reactive pipeline).
19655
+ */
19656
+ async refreshToken(session, currentToken, updateCredential) {
19657
+ logger$6.debug("[DeviceToken] Refreshing Client Bound SAT");
19658
+ const dpopProof = await this.dpopManager.createHttpProof({
19659
+ method: "POST",
19660
+ uri: DEVICE_REFRESH_ENDPOINT,
19661
+ accessToken: currentToken
19662
+ });
19663
+ const response = await this.http.request({
19664
+ url: DEVICE_REFRESH_ENDPOINT,
19665
+ ...POST_PARAMS,
19666
+ body: JSON.stringify({
19667
+ dpop_token: dpopProof,
19668
+ expire_in: this._effectiveExpireIn
19669
+ })
19670
+ });
19671
+ if (!response.ok || !response.body) throw new TokenRefreshError(`Failed to refresh device token: ${response.status} ${response.statusText}`);
19672
+ const data = JSON.parse(response.body);
19673
+ if (!data.token) throw new TokenRefreshError("Device token refresh response missing token field");
19674
+ if (!data.expires_at && !data.expires_in) data.expires_in = this._effectiveExpireIn;
19675
+ this._effectiveExpireIn = resolveExpireIn(data);
19676
+ const rpcProof = await this.dpopManager.createRpcProof({ method: "signalwire.reauthenticate" });
19677
+ await session.reauthenticate(data.token, rpcProof);
19678
+ updateCredential({ token: data.token });
19679
+ logger$6.info("[DeviceToken] Client Bound SAT refreshed successfully");
19680
+ return data;
19681
+ }
19682
+ /**
19683
+ * Executes a refresh with retry and exponential backoff.
19684
+ * On success, emits to `_currentToken$` to schedule the next refresh.
19685
+ * On all retries exhausted, emits to `errorHandler`.
19686
+ */
19687
+ async executeRefresh() {
19688
+ if (this._refreshInProgress) {
19689
+ logger$6.debug("[DeviceToken] Refresh already in progress, skipping");
19690
+ return;
19691
+ }
19692
+ const session = this._session;
19693
+ const updateCredential = this._updateCredential;
19694
+ if (!session || !updateCredential) {
19695
+ logger$6.warn("[DeviceToken] Cannot refresh: session or updateCredential not set");
19696
+ return;
19697
+ }
19698
+ if (!session.authenticated) {
19699
+ logger$6.debug("[DeviceToken] Session not authenticated, deferring refresh");
19700
+ return;
19701
+ }
19702
+ this._refreshInProgress = true;
19703
+ try {
19704
+ const currentToken = this.getCredential().token;
19705
+ if (!currentToken) throw new TokenRefreshError("No current token available for refresh");
19706
+ const newTokenData = await this.retryRefresh(session, currentToken, updateCredential);
19707
+ this._currentToken$.next(newTokenData);
19708
+ } catch (error) {
19709
+ logger$6.error("[DeviceToken] Automatic Client Bound SAT refresh failed:", error);
19710
+ this.errorHandler(error instanceof TokenRefreshError ? error : new TokenRefreshError("Automatic token refresh failed", error));
19711
+ } finally {
19712
+ this._refreshInProgress = false;
19713
+ }
19714
+ }
19715
+ /**
19716
+ * Retries `refreshToken()` up to `DEVICE_TOKEN_REFRESH_MAX_RETRIES` times
19717
+ * with exponential backoff (1s, 2s, 4s).
19718
+ */
19719
+ async retryRefresh(session, currentToken, updateCredential) {
19720
+ let lastError;
19721
+ for (let attempt = 0; attempt < DEVICE_TOKEN_REFRESH_MAX_RETRIES; attempt++) try {
19722
+ return await this.refreshToken(session, currentToken, updateCredential);
19723
+ } catch (error) {
19724
+ lastError = error;
19725
+ if (attempt < DEVICE_TOKEN_REFRESH_MAX_RETRIES - 1) {
19726
+ const delay$1 = DEVICE_TOKEN_REFRESH_RETRY_BASE_MS * Math.pow(2, attempt);
19727
+ logger$6.warn(`[DeviceToken] Refresh attempt ${attempt + 1} failed, retrying in ${delay$1}ms`);
19728
+ await new Promise((resolve) => setTimeout(resolve, delay$1));
19729
+ }
19730
+ }
19731
+ throw lastError instanceof Error ? lastError : new TokenRefreshError("All refresh retries exhausted", lastError);
19732
+ }
19733
+ /** Cleans up the manager, cancelling the reactive pipeline and all subscriptions. */
19734
+ destroy() {
19735
+ super.destroy();
19736
+ }
19737
+ };
19738
+
19462
19739
  //#endregion
19463
19740
  //#region src/managers/DiagnosticsCollector.ts
19464
19741
  const logger$5 = getLogger();
@@ -20392,13 +20669,43 @@ var SignalWire = class extends Destroyable {
20392
20669
  this._errors$.next(error);
20393
20670
  });
20394
20671
  await this._clientSession.connect();
20395
- this.subscribeTo(this._clientSession.authenticated$.pipe((0, import_cjs.skip)(1), (0, import_cjs.filter)(Boolean)), () => {
20396
- logger$1.debug("[SignalWire] Re-registering subscriber after reconnect");
20397
- this.register().then(() => {
20672
+ if (this._dpopManager?.initialized) {
20673
+ if (this._refreshTimerId) {
20674
+ clearTimeout(this._refreshTimerId);
20675
+ this._refreshTimerId = void 0;
20676
+ logger$1.debug("[SignalWire] Developer refresh disabled — Client Bound SAT activation starting");
20677
+ }
20678
+ this._deviceTokenManager = new DeviceTokenManager(this._dpopManager, this._deps.http, (error) => this._errors$.next(error), () => this._deps.credential);
20679
+ await this._deviceTokenManager.activate(this._deps.subscriber, this._clientSession, (cred) => {
20680
+ this._deps.credential = {
20681
+ ...this._deps.credential,
20682
+ ...cred
20683
+ };
20684
+ });
20685
+ }
20686
+ this.subscribeTo(this._clientSession.authenticated$.pipe((0, import_cjs.skip)(1), (0, import_cjs.filter)(Boolean)), async () => {
20687
+ try {
20688
+ if (this._deviceTokenManager) {
20689
+ await this._deviceTokenManager.activate(this._deps.subscriber, this._clientSession, (cred) => {
20690
+ this._deps.credential = {
20691
+ ...this._deps.credential,
20692
+ ...cred
20693
+ };
20694
+ });
20695
+ logger$1.debug("[SignalWire] Client Bound SAT re-activated after reconnect");
20696
+ }
20697
+ } catch (error) {
20698
+ logger$1.error("[SignalWire] Client Bound SAT re-activation failed (non-fatal):", error);
20699
+ this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
20700
+ }
20701
+ try {
20702
+ logger$1.debug("[SignalWire] Re-registering subscriber after reconnect");
20703
+ await this.register();
20398
20704
  logger$1.debug("[SignalWire] Subscriber re-registered successfully after reconnect");
20399
- }).catch((error) => {
20705
+ } catch (error) {
20400
20706
  logger$1.error("[SignalWire] Re-registration failed after reconnect:", error);
20401
- });
20707
+ this._errors$.next(error instanceof Error ? error : new Error(String(error), { cause: error }));
20708
+ }
20402
20709
  });
20403
20710
  const conversationManager = new ConversationsManager(this._clientSession, this._deps.http, () => this._deps.getSubscriberFromAddressId(), errorHandler);
20404
20711
  const directory = new DirectoryManager(this._deps.http, this._clientSession, conversationManager, errorHandler);