@signalwire/js 4.0.0-beta.1 → 4.0.0-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,56 +1,10 @@
1
- import { n as JSONRPCRequest, r as JSONRPCResponse, t as EventChannel } from "./base-aVtoG8Wk.mjs";
1
+ import { a as JSONRPCSuccessResponse, i as JSONRPCResponse, n as JSONRPCErrorResponse, r as JSONRPCRequest, t as EventChannel } from "./base-CQPEW1lJ.mjs";
2
2
  import * as rxjs0 from "rxjs";
3
3
  import { BehaviorSubject, Observable, Observer, ReplaySubject, Subject, Subscription } from "rxjs";
4
4
  import { URL as URL$1 } from "node:url";
5
5
 
6
- //#region src/behaviors/Destroyable.d.ts
7
- declare abstract class Destroyable {
8
- protected subscriptions: Subscription[];
9
- protected subjects: Subject<unknown>[];
10
- protected _destroyed$: Subject<void>;
11
- destroy(): void;
12
- protected subscribeTo<T>(observable: Observable<T>, observerOrNext: Partial<Observer<T>> | ((value: T) => void) | undefined): void;
13
- protected createSubject<T>(): Subject<T>;
14
- protected createReplaySubject<T>(bufferSize?: number, windowTime?: number): ReplaySubject<T>;
15
- protected createBehaviorSubject<T>(initialValue: T): BehaviorSubject<T>;
16
- get $(): Observable<this>;
17
- /**
18
- * Observable that emits when the instance is destroyed
19
- */
20
- get destroyed$(): Observable<void>;
21
- }
22
- //#endregion
23
- //#region src/core/types/media.types.d.ts
24
- /** WebRTC transceiver direction for a single media kind. */
25
- type MediaDirection = RTCRtpTransceiverDirection;
26
- /** Audio and video directions "inactive" | "recvonly" | "sendonly" | "sendrecv" | "stopped" */
27
- interface MediaDirections {
28
- /** Audio direction */
29
- audio: MediaDirection;
30
- /** Video direction */
31
- video: MediaDirection;
32
- }
33
- /** Options controlling which media tracks to send and receive. */
34
- interface MediaOptions {
35
- /** Enable audio input. */
36
- audio?: boolean;
37
- /** Enable video input. */
38
- video?: boolean;
39
- /** Custom constraints for the audio input track. */
40
- inputAudioDeviceConstraints?: MediaTrackConstraints;
41
- /** Custom constraints for the video input track. */
42
- inputVideoDeviceConstraints?: MediaTrackConstraints;
43
- /** Pre-existing audio stream to use instead of `getUserMedia`. */
44
- inputAudioStream?: MediaStream;
45
- /** Pre-existing video stream to use instead of `getUserMedia`. */
46
- inputVideoStream?: MediaStream;
47
- /** Whether to receive remote audio. */
48
- receiveAudio?: boolean;
49
- /** Whether to receive remote video. */
50
- receiveVideo?: boolean;
51
- }
52
- //#endregion
53
6
  //#region src/core/types/common.types.d.ts
7
+ /** JSON-compatible value type for serializable data structures. */
54
8
  interface JSONSerializable {
55
9
  [key: string]: JSONSerializable | string | number | boolean | null | undefined | JSONSerializable[];
56
10
  }
@@ -99,6 +53,7 @@ interface HTTPResponse<T extends HttpBody = string> {
99
53
  /** Final URL after any redirects */
100
54
  url: string;
101
55
  }
56
+ /** Browser-compatible WebSocket client interface. */
102
57
  interface WebSocketClient {
103
58
  addEventListener: WebSocket['addEventListener'];
104
59
  removeEventListener: WebSocket['removeEventListener'];
@@ -106,6 +61,7 @@ interface WebSocketClient {
106
61
  close: WebSocket['close'];
107
62
  readyState: WebSocket['readyState'];
108
63
  }
64
+ /** Node.js WebSocket client interface with event listener overloads. */
109
65
  interface NodeSocketClient extends WebSocketClient {
110
66
  addEventListener(method: 'open' | 'close' | 'error' | 'message', cb: (event: unknown) => void, options?: unknown): void;
111
67
  removeEventListener(method: 'open' | 'close' | 'error' | 'message', cb: (event: unknown) => void): void;
@@ -122,24 +78,52 @@ interface NodeSocketAdapter {
122
78
  }
123
79
  /** Browser-compatible WebSocket constructor type. */
124
80
  type WebSocketAdapter = new (url: string | URL, protocols?: string | string[]) => WebSocketClient;
125
- /** Authentication credentials for the SDK. */
81
+ /**
82
+ * Authentication credentials for the SDK.
83
+ *
84
+ * At least one of `token` or `authorizationState` must be provided.
85
+ */
126
86
  interface SDKCredential {
127
- /** JWT subscriber access token. */
87
+ /** JWT subscriber access token (SAT). */
128
88
  token?: string;
129
89
  /** Pre-authorized session state (alternative to token). */
130
90
  authorizationState?: string;
131
- /** Token expiry timestamp in milliseconds since epoch. */
91
+ /** Token expiry timestamp in milliseconds since epoch. When set, the SDK attempts credential refresh before expiry. */
132
92
  expiry_at?: number;
133
93
  }
134
94
  /** Types of addressable resources in the fabric. */
135
95
  type ResourceType = 'app' | 'call' | 'room' | 'subscriber';
136
96
  //#endregion
137
97
  //#region src/dependencies/interfaces.d.ts
98
+ /** Persistence scope: browser `localStorage` or `sessionStorage`. */
138
99
  type StorageScope = 'local' | 'session';
100
+ /** Key-value storage interface for persisting SDK preferences and state. */
139
101
  interface Storage {
140
102
  setItem(key: string, value: string | null, scope: StorageScope): Promise<void>;
141
103
  getItem(key: string, scope: StorageScope): Promise<string | null>;
142
104
  removeItem(key: string, scope: StorageScope): Promise<void>;
105
+ /** Clears all keys in the given scope. Implementations may scope the clear to SDK keys only. */
106
+ clear(scope: StorageScope): Promise<void>;
107
+ }
108
+ /**
109
+ * Context provided by the SDK when calling {@link CredentialProvider.authenticate}.
110
+ *
111
+ * Contains optional parameters the SDK generates internally (e.g., DPoP fingerprint)
112
+ * that the implementor can forward to their server-side token endpoint.
113
+ */
114
+ interface AuthenticateContext {
115
+ /**
116
+ * JWK Thumbprint (RFC 7638) of the SDK's ephemeral DPoP key pair.
117
+ *
118
+ * When present, the implementor should forward this value as the `fingerprint`
119
+ * parameter to the server-side SAT issuance endpoint alongside `scope: "sat:refresh"`.
120
+ * This enables the server to bind the SAT to the SDK's key pair, allowing
121
+ * automatic Client Bound SAT refresh without developer intervention.
122
+ *
123
+ * When absent (e.g., Web Crypto API not available), the implementor should
124
+ * proceed without DPoP binding.
125
+ */
126
+ fingerprint?: string;
143
127
  }
144
128
  /**
145
129
  * Provides authentication credentials to the SDK.
@@ -160,12 +144,14 @@ interface CredentialProvider {
160
144
  * Implementor responsibilities:
161
145
  * - Resolve with a valid {@link SDKCredential} on success.
162
146
  * - Reject (throw) on failure — this will cause client initialization to fail.
147
+ * - When `context.fingerprint` is provided, forward it to the server-side token
148
+ * endpoint with `scope: "sat:refresh"` to enable automatic token refresh.
163
149
  *
164
150
  * SDK behavior:
165
151
  * - Awaits this method before establishing the WebSocket connection.
166
152
  * - On rejection, propagates the error to the caller of `SignalWire()`.
167
153
  */
168
- authenticate(): Promise<SDKCredential>;
154
+ authenticate(context?: AuthenticateContext): Promise<SDKCredential>;
169
155
  /**
170
156
  * Obtains fresh credentials before the current ones expire. Optional.
171
157
  *
@@ -178,10 +164,57 @@ interface CredentialProvider {
178
164
  * - Scheduled automatically before expiry; implementors do not need to manage timing.
179
165
  * - On rejection, the refresh schedule stops and the session continues with the
180
166
  * current credentials until they expire.
181
- * - When not provided, the SDK uses the initial credentials for the entire session lifetime.
167
+ * - When not provided and the SAT includes a `sat:refresh` scope, the SDK
168
+ * automatically refreshes via Client Bound SAT (DPoP) without developer intervention.
169
+ * - When not provided and no refresh scope is present, the SDK uses the initial
170
+ * credentials for the entire session lifetime.
182
171
  */
183
172
  refresh?: () => Promise<SDKCredential>;
184
173
  }
174
+ /**
175
+ * Provides custom WebRTC API implementations for non-standard environments.
176
+ *
177
+ * Use this when the standard browser WebRTC APIs are not available or need
178
+ * to be replaced (e.g., Citrix HDX, React Native, Electron).
179
+ *
180
+ * @example
181
+ * ```typescript
182
+ * import { SignalWire, type WebRTCApiProvider } from '@signalwire/js';
183
+ *
184
+ * const provider: WebRTCApiProvider = {
185
+ * RTCPeerConnection: CustomRTCPeerConnection,
186
+ * mediaDevices: {
187
+ * getUserMedia: (constraints) => customGetUserMedia(constraints),
188
+ * enumerateDevices: () => customEnumerateDevices(),
189
+ * addEventListener: (type, listener) => { ... },
190
+ * removeEventListener: (type, listener) => { ... },
191
+ * }
192
+ * };
193
+ *
194
+ * const client = new SignalWire(credentialProvider, { webRTCApiProvider: provider });
195
+ * ```
196
+ */
197
+ interface WebRTCApiProvider {
198
+ /** Custom RTCPeerConnection constructor. */
199
+ RTCPeerConnection: typeof RTCPeerConnection;
200
+ /** Custom media device access. Only the methods used by the SDK are required. */
201
+ mediaDevices: WebRTCMediaDevices;
202
+ }
203
+ /**
204
+ * Subset of the `MediaDevices` interface actually used by the SDK.
205
+ *
206
+ * Implementations only need to provide these methods — the full browser
207
+ * `MediaDevices` type is intentionally not required so that React Native
208
+ * and other non-browser environments can conform without polyfilling
209
+ * unused APIs.
210
+ */
211
+ interface WebRTCMediaDevices {
212
+ getUserMedia(constraints: MediaStreamConstraints): Promise<MediaStream>;
213
+ getDisplayMedia?(options: DisplayMediaStreamOptions): Promise<MediaStream>;
214
+ enumerateDevices(): Promise<MediaDeviceInfo[]>;
215
+ addEventListener(type: string, listener: EventListenerOrEventListenerObject): void;
216
+ removeEventListener(type: string, listener: EventListenerOrEventListenerObject): void;
217
+ }
185
218
  //#endregion
186
219
  //#region src/managers/StorageManager.d.ts
187
220
  declare class StorageManager {
@@ -216,6 +249,82 @@ declare class StorageManager {
216
249
  * @throws Error from underlying storage implementation
217
250
  */
218
251
  removeItem(key: string, scope?: StorageScope): Promise<void>;
252
+ /**
253
+ * Clears all SDK keys from both 'local' and 'session' scopes.
254
+ * @throws StorageWriteError if clearing fails
255
+ */
256
+ clearAll(): Promise<void>;
257
+ }
258
+ //#endregion
259
+ //#region src/behaviors/Destroyable.d.ts
260
+ declare abstract class Destroyable {
261
+ protected subscriptions: Subscription[];
262
+ protected subjects: Subject<unknown>[];
263
+ protected _destroyed$: Subject<void>;
264
+ private _observableCache?;
265
+ destroy(): void;
266
+ protected cachedObservable<T>(key: string, factory: () => Observable<T>): Observable<T>;
267
+ /**
268
+ * Like `cachedObservable`, but defers emissions to the microtask queue
269
+ * via `observeOn(asapScheduler)`.
270
+ *
271
+ * Use ONLY for public-facing observable getters that external consumers
272
+ * subscribe to. Prevents a class of bugs where `BehaviorSubject` or
273
+ * `ReplaySubject` replays synchronously during `subscribe()`, before
274
+ * the subscription variable is assigned in the caller's scope.
275
+ *
276
+ * Do NOT use for observables consumed internally by the SDK — internal
277
+ * code using `subscribeTo()`, `firstValueFrom()`, or `withLatestFrom()`
278
+ * depends on synchronous emission delivery.
279
+ */
280
+ protected publicCachedObservable<T>(key: string, factory: () => Observable<T>): Observable<T>;
281
+ /**
282
+ * Wraps an observable so emissions are deferred to the microtask queue.
283
+ *
284
+ * Use ONLY for public-facing getters that expose a subject via
285
+ * `.asObservable()` without going through `cachedObservable`.
286
+ *
287
+ * Do NOT use for observables consumed internally by the SDK.
288
+ */
289
+ protected deferEmission<T>(observable: Observable<T>): Observable<T>;
290
+ protected subscribeTo<T>(observable: Observable<T>, observerOrNext: Partial<Observer<T>> | ((value: T) => void) | undefined): void;
291
+ protected createSubject<T>(): Subject<T>;
292
+ protected createReplaySubject<T>(bufferSize?: number, windowTime?: number): ReplaySubject<T>;
293
+ protected createBehaviorSubject<T>(initialValue: T): BehaviorSubject<T>;
294
+ /**
295
+ * Observable that emits when the instance is destroyed
296
+ */
297
+ get destroyed$(): Observable<void>;
298
+ }
299
+ //#endregion
300
+ //#region src/core/types/media.types.d.ts
301
+ /** WebRTC transceiver direction for a single media kind. */
302
+ type MediaDirection = RTCRtpTransceiverDirection;
303
+ /** Audio and video directions "inactive" | "recvonly" | "sendonly" | "sendrecv" | "stopped" */
304
+ interface MediaDirections {
305
+ /** Audio direction */
306
+ audio: MediaDirection;
307
+ /** Video direction */
308
+ video: MediaDirection;
309
+ }
310
+ /** Options controlling which media tracks to send and receive. */
311
+ interface MediaOptions {
312
+ /** Enable audio input. Defaults to `true` when not specified. */
313
+ audio?: boolean;
314
+ /** Enable video input. Defaults to `false` when not specified. */
315
+ video?: boolean;
316
+ /** Custom constraints for the audio input track. */
317
+ inputAudioDeviceConstraints?: MediaTrackConstraints;
318
+ /** Custom constraints for the video input track. */
319
+ inputVideoDeviceConstraints?: MediaTrackConstraints;
320
+ /** Pre-existing audio stream to use instead of `getUserMedia`. */
321
+ inputAudioStream?: MediaStream;
322
+ /** Pre-existing video stream to use instead of `getUserMedia`. */
323
+ inputVideoStream?: MediaStream;
324
+ /** Whether to receive remote audio. */
325
+ receiveAudio?: boolean;
326
+ /** Whether to receive remote video. */
327
+ receiveVideo?: boolean;
219
328
  }
220
329
  //#endregion
221
330
  //#region src/containers/PreferencesContainer.d.ts
@@ -295,6 +404,108 @@ declare class ClientPreferences {
295
404
  /** Custom user variables attached to calls. */
296
405
  get userVariables(): Record<string, unknown>;
297
406
  set userVariables(value: Record<string, unknown>);
407
+ /** Stats polling interval in milliseconds. */
408
+ get statsPollingInterval(): number;
409
+ set statsPollingInterval(value: number);
410
+ /** Number of baseline samples for stats monitoring. */
411
+ get statsBaselineSamples(): number;
412
+ set statsBaselineSamples(value: number);
413
+ /** Duration in ms with no inbound packets before a critical issue is emitted. */
414
+ get statsNoPacketThreshold(): number;
415
+ set statsNoPacketThreshold(value: number);
416
+ /** Multiplier for RTT spike detection relative to baseline. */
417
+ get statsRttSpikeMultiplier(): number;
418
+ set statsRttSpikeMultiplier(value: number);
419
+ /** Packet loss fraction threshold (0-1) for issue detection. */
420
+ get statsPacketLossThreshold(): number;
421
+ set statsPacketLossThreshold(value: number);
422
+ /** Multiplier for jitter spike detection relative to baseline. */
423
+ get statsJitterSpikeMultiplier(): number;
424
+ set statsJitterSpikeMultiplier(value: number);
425
+ /** Number of seconds of metrics history to retain. */
426
+ get statsHistorySize(): number;
427
+ set statsHistorySize(value: number);
428
+ /** Maximum keyframe requests in a burst window. */
429
+ get keyframeMaxBurst(): number;
430
+ set keyframeMaxBurst(value: number);
431
+ /** Keyframe burst window duration in milliseconds. */
432
+ get keyframeBurstWindow(): number;
433
+ set keyframeBurstWindow(value: number);
434
+ /** Cooldown period in ms after keyframe burst limit is reached. */
435
+ get keyframeCooldown(): number;
436
+ set keyframeCooldown(value: number);
437
+ /** Minimum time in ms between re-INVITE attempts. */
438
+ get reinviteDebounceTime(): number;
439
+ set reinviteDebounceTime(value: number);
440
+ /** Maximum re-INVITE attempts per call. */
441
+ get reinviteMaxAttempts(): number;
442
+ set reinviteMaxAttempts(value: number);
443
+ /** Timeout in ms for a single re-INVITE attempt. */
444
+ get reinviteTimeout(): number;
445
+ set reinviteTimeout(value: number);
446
+ /** Recovery signal debounce window in seconds. */
447
+ get recoveryDebounceTime(): number;
448
+ set recoveryDebounceTime(seconds: number);
449
+ /** Cooldown period between recovery attempts in seconds. */
450
+ get recoveryCooldown(): number;
451
+ set recoveryCooldown(seconds: number);
452
+ /** Grace period before treating ICE 'disconnected' as failure, in seconds. */
453
+ get iceDisconnectedGracePeriod(): number;
454
+ set iceDisconnectedGracePeriod(seconds: number);
455
+ /** Timeout for a single ICE restart attempt in seconds. */
456
+ get iceRestartTimeout(): number;
457
+ set iceRestartTimeout(seconds: number);
458
+ /** Maximum recovery attempts before giving up. */
459
+ get maxRecoveryAttempts(): number;
460
+ set maxRecoveryAttempts(value: number);
461
+ /** Whether relay-only escalation is enabled as a last-resort recovery tier. */
462
+ get enableRelayFallback(): boolean;
463
+ set enableRelayFallback(value: boolean);
464
+ /** Whether browser network change detection (online/offline) is enabled. */
465
+ get enableNetworkChangeDetection(): boolean;
466
+ set enableNetworkChangeDetection(value: boolean);
467
+ /** Whether server-sent media-timeout hangups are intercepted for recovery. */
468
+ get enableServerHangupInterception(): boolean;
469
+ set enableServerHangupInterception(value: boolean);
470
+ /** Whether device selections are persisted to storage. */
471
+ get persistDeviceSelection(): boolean;
472
+ set persistDeviceSelection(value: boolean);
473
+ /** Whether device changes are auto-applied to active calls. */
474
+ get syncDevicesToActiveCalls(): boolean;
475
+ set syncDevicesToActiveCalls(value: boolean);
476
+ /** Whether to auto-mute video when the tab becomes hidden. */
477
+ get autoMuteVideoOnHidden(): boolean;
478
+ set autoMuteVideoOnHidden(value: boolean);
479
+ /** Whether to re-enumerate devices when the page becomes visible. */
480
+ get refreshDevicesOnVisible(): boolean;
481
+ set refreshDevicesOnVisible(value: boolean);
482
+ /** Whether to check peer connection health when the page becomes visible. */
483
+ get checkConnectionOnVisible(): boolean;
484
+ set checkConnectionOnVisible(value: boolean);
485
+ /** Default audio track constraints applied when no explicit constraints are provided. */
486
+ get defaultAudioConstraints(): MediaTrackConstraints | undefined;
487
+ set defaultAudioConstraints(value: MediaTrackConstraints | undefined);
488
+ /** Default video track constraints applied when video is enabled without explicit constraints. */
489
+ get defaultVideoConstraints(): MediaTrackConstraints | undefined;
490
+ set defaultVideoConstraints(value: MediaTrackConstraints | undefined);
491
+ /** Whether stereo Opus is enabled globally. */
492
+ get stereoAudio(): boolean;
493
+ set stereoAudio(value: boolean);
494
+ /** Whether automatic video degradation on low bandwidth is enabled. */
495
+ get enableAutoDegradation(): boolean;
496
+ set enableAutoDegradation(value: boolean);
497
+ /** Bitrate in kbps below which video is automatically disabled. */
498
+ get degradationBitrateThreshold(): number;
499
+ set degradationBitrateThreshold(value: number);
500
+ /** Bitrate in kbps above which video is automatically re-enabled. */
501
+ get degradationRecoveryThreshold(): number;
502
+ set degradationRecoveryThreshold(value: number);
503
+ /** Preferred video codecs in priority order. */
504
+ get preferredVideoCodecs(): string[];
505
+ set preferredVideoCodecs(value: string[]);
506
+ /** Preferred audio codecs in priority order. */
507
+ get preferredAudioCodecs(): string[];
508
+ set preferredAudioCodecs(value: string[]);
298
509
  /** Saves current preferences to storage (fire-and-forget). */
299
510
  private _saveToStorage;
300
511
  /** Loads preferences from storage and applies them to the container. */
@@ -311,11 +522,13 @@ interface HTTPRequestControllerOptions {
311
522
  }
312
523
  declare class HTTPRequestController {
313
524
  private baseURL;
314
- private credential;
525
+ private readonly getCredential;
315
526
  private static readonly defaultMaxRetries;
316
527
  private static readonly defaultRetryDelayMinMs;
317
528
  private static readonly defaultRetryDelayMaxMs;
318
529
  private static readonly defaultRequestTimeoutMs;
530
+ /** Sensitive field names to mask in debug logs. */
531
+ private static readonly SENSITIVE_BODY_FIELDS;
319
532
  private readonly maxRetries;
320
533
  private readonly retryDelayMin;
321
534
  private readonly retryDelayMax;
@@ -323,7 +536,7 @@ declare class HTTPRequestController {
323
536
  private _responses$;
324
537
  private _errors$;
325
538
  private _status$;
326
- constructor(baseURL: string, credential: SDKCredential, options?: HTTPRequestControllerOptions);
539
+ constructor(baseURL: string, getCredential: () => SDKCredential, options?: HTTPRequestControllerOptions);
327
540
  get status$(): Observable<HTTPRequestStatus>;
328
541
  get status(): HTTPRequestStatus;
329
542
  get responses$(): Observable<HTTPResponse>;
@@ -333,6 +546,10 @@ declare class HTTPRequestController {
333
546
  private executeRequest;
334
547
  private buildURL;
335
548
  private buildHeaders;
549
+ /**
550
+ * Sanitizes a request body for debug logging by masking sensitive fields.
551
+ */
552
+ private sanitizeBody;
336
553
  private convertResponse;
337
554
  }
338
555
  //#endregion
@@ -351,44 +568,105 @@ declare abstract class Fetchable<T = unknown> extends Destroyable {
351
568
  * Pure address-related types (no implementation dependencies)
352
569
  * Types that reference model implementations are in interfaces.ts
353
570
  */
571
+ /** Raw address response from the SignalWire Fabric API. */
354
572
  interface GetAddressResponse {
573
+ /** Unique address identifier. */
355
574
  id: string;
575
+ /** Human-readable display name. */
356
576
  display_name: string;
577
+ /** Resource name (used as a URI for dialing). */
357
578
  name: string;
579
+ /** URL for an avatar or preview image. */
358
580
  preview_url?: string;
581
+ /** URL for a cover image. */
359
582
  cover_url?: string;
583
+ /** Underlying resource identifier. */
360
584
  resource_id: string;
585
+ /** Type of the underlying resource. */
361
586
  type: ResourceType;
587
+ /** Available communication channels for this address. */
362
588
  channels: {
589
+ /** Audio-only channel URI. */
363
590
  audio?: string;
591
+ /** Messaging channel URI. */
364
592
  messaging?: string;
593
+ /** Video channel URI. */
365
594
  video?: string;
366
595
  };
596
+ /** Whether the address resource is currently locked. */
367
597
  locked: boolean;
598
+ /** ISO 8601 timestamp when the address was created. */
368
599
  created_at: string;
369
600
  }
370
601
  //#endregion
602
+ //#region src/core/types/crypto.types.d.ts
603
+ /** Parameters for creating an HTTP DPoP proof (for Prime API endpoints). */
604
+ interface DPoPHttpProofParams {
605
+ /** HTTP method (e.g., "POST"). */
606
+ readonly method: string;
607
+ /** Request URI — should be the full URL per RFC 9449 (e.g., "https://fabric.signalwire.com/api/..."). */
608
+ readonly uri: string;
609
+ /** Access token to bind via `ath` claim (SHA-256 hash). Used for resource endpoints, not token endpoints. */
610
+ readonly accessToken?: string;
611
+ }
612
+ /** Parameters for creating an RPC DPoP proof (for switchblade WebSocket methods). */
613
+ interface DPoPRpcProofParams {
614
+ /** RPC method name (e.g., "signalwire.connect" or "signalwire.reauthenticate"). */
615
+ readonly method: string;
616
+ }
617
+ /** SAT claims returned by /api/fabric/subscriber/info. */
618
+ interface SATClaims {
619
+ /** Token scopes (e.g., ["sat:refresh"]). */
620
+ scope?: string[];
621
+ /** Confirmation claim binding the token to a key. */
622
+ cnf?: {
623
+ jkt: string;
624
+ };
625
+ /** Token expiry timestamp in seconds since epoch. */
626
+ expires_at?: number;
627
+ }
628
+ //#endregion
371
629
  //#region src/core/types/subscriber.types.d.ts
630
+ /** Raw subscriber profile response from the SignalWire Fabric API. */
372
631
  interface GetSubscriberInfoResponse {
632
+ /** Unique subscriber identifier. */
373
633
  id: string;
634
+ /** Subscriber's email address. */
374
635
  email: string;
636
+ /** Subscriber's first name. */
375
637
  first_name?: string;
638
+ /** Subscriber's last name. */
376
639
  last_name?: string;
640
+ /** Subscriber's display name. */
377
641
  display_name?: string;
642
+ /** Subscriber's job title. */
378
643
  job_title?: string;
644
+ /** Subscriber's time zone offset. */
379
645
  time_zone?: number;
646
+ /** Subscriber's country. */
380
647
  country?: string;
648
+ /** Subscriber's region or state. */
381
649
  region?: string;
650
+ /** Subscriber's company name. */
382
651
  company_name?: string;
652
+ /** Key for push notification delivery. */
383
653
  push_notification_key: string;
654
+ /** Application-level settings for this subscriber. */
384
655
  app_settings?: {
656
+ /** Display name configured at the application level. */
385
657
  display_name: string;
658
+ /** Permission scopes granted to this subscriber. */
386
659
  scopes: string[];
387
660
  };
661
+ /** Fabric addresses associated with this subscriber. */
388
662
  fabric_addresses: GetAddressResponse[];
663
+ /** Filtered SAT claims (scope, cnf, expires_at) returned when the token has special capabilities. */
664
+ sat_claims?: SATClaims;
389
665
  }
390
666
  //#endregion
391
667
  //#region src/core/entities/Subscriber.d.ts
668
+ /** Subscriber online presence state. */
669
+ type SubscriberPresence = 'online' | 'offline' | 'busy';
392
670
  /**
393
671
  * Authenticated subscriber profile.
394
672
  *
@@ -425,40 +703,92 @@ declare class Subscriber extends Fetchable<GetSubscriberInfoResponse> {
425
703
  };
426
704
  /** Fabric addresses associated with this subscriber. */
427
705
  addresses: GetAddressResponse[];
706
+ /** Filtered SAT claims when the token has special capabilities (e.g., refresh scope). */
707
+ satClaims?: SATClaims;
428
708
  constructor(http: HTTPRequestController);
429
709
  protected populateInstance(data: GetSubscriberInfoResponse): void;
430
710
  }
431
711
  //#endregion
432
712
  //#region src/core/types/call.types.d.ts
713
+ /** SDP role for the peer connection negotiation. */
433
714
  type RTCPeerConnectionType = 'offer' | 'answer';
715
+ /** Purpose of the peer connection (primary call, screen share, or additional device). */
434
716
  type RTCPeerConnectionPropose = 'main' | 'screenshare' | 'additional-device';
717
+ /** States during call connection establishment. */
435
718
  type CallConnectStates = 'connecting' | 'connected';
719
+ /** Lifecycle states of the signaling protocol for a call. */
436
720
  type SignalingCallStates = 'created' | 'ringing' | 'answered' | 'ending' | 'ended';
721
+ /** Whether the call is inbound (received) or outbound (initiated). */
437
722
  type CallDirection = 'inbound' | 'outbound';
723
+ /** Playback state of media being played into a call. */
438
724
  type CallPlayState = 'playing' | 'paused' | 'finished';
725
+ /** Common parameters shared by all call device types. */
439
726
  interface CallDeviceCommonParams {
727
+ /** Optional SIP headers to include in the call setup. */
440
728
  headers?: unknown[];
441
729
  }
730
+ /** Parameters for a WebRTC or SIP call device. */
442
731
  interface CallDeviceWebRTCOrSIPParams extends CallDeviceCommonParams {
732
+ /** Source address or URI for the call. */
443
733
  from: string;
734
+ /** Destination address or URI for the call. */
444
735
  to: string;
445
736
  }
737
+ /** Parameters for a phone (PSTN) call device. */
446
738
  interface CallDevicePhoneParams extends CallDeviceCommonParams {
739
+ /** Caller phone number (E.164 format). */
447
740
  from_number: string;
741
+ /** Destination phone number (E.164 format). */
448
742
  to_number: string;
449
743
  }
744
+ /** A WebRTC or SIP call device descriptor. */
450
745
  interface CallDeviceWebRTCOrSIP {
746
+ /** Transport type for the device. */
451
747
  type: 'webrtc' | 'sip';
748
+ /** Connection parameters for the device. */
452
749
  params: CallDeviceWebRTCOrSIPParams;
453
750
  }
751
+ /** A phone (PSTN) call device descriptor. */
454
752
  interface CallDevicePhone {
753
+ /** Transport type for the device. */
455
754
  type: 'phone';
755
+ /** Connection parameters for the device. */
456
756
  params: CallDevicePhoneParams;
457
757
  }
758
+ /** Discriminated union of call device types (WebRTC, SIP, or phone). */
458
759
  type CallDevice = CallDeviceWebRTCOrSIP | CallDevicePhone;
760
+ /**
761
+ * Feature capability string that controls what actions a participant can perform.
762
+ *
763
+ * Capabilities are organized into categories:
764
+ * - **self.\*** — Actions the local participant can perform on themselves (mute, deaf, volume, position, meta).
765
+ * - **member.\*** — Actions that can be performed on other participants.
766
+ * - **layout.\*** — Layout management for the video canvas.
767
+ * - **digit.\*** — DTMF digit sending.
768
+ * - **vmuted.\*** — Visibility control for muted video participants.
769
+ * - **lock.\*** — Room lock/unlock control.
770
+ * - **device** / **screenshare** — Device and screen share capabilities.
771
+ * - **end** — Permission to end the call or room.
772
+ */
773
+ type Capability = 'self' | 'self.mute' | 'self.mute.audio' | 'self.mute.audio.on' | 'self.mute.audio.off' | 'self.mute.video' | 'self.mute.video.on' | 'self.mute.video.off' | 'self.deaf' | 'self.deaf.on' | 'self.deaf.off' | 'self.microphone' | 'self.microphone.volume.set' | 'self.microphone.sensitivity.set' | 'self.speaker' | 'self.speaker.volume.set' | 'self.position.set' | 'self.meta' | 'self.audioflags.set' | 'member' | 'member.mute' | 'member.mute.audio' | 'member.mute.audio.on' | 'member.mute.audio.off' | 'member.mute.video' | 'member.mute.video.on' | 'member.mute.video.off' | 'member.deaf' | 'member.deaf.on' | 'member.deaf.off' | 'member.microphone' | 'member.microphone.volume.set' | 'member.microphone.sensitivity.set' | 'member.speaker' | 'member.speaker.volume.set' | 'member.position.set' | 'member.meta' | 'member.audioflags.set' | 'layout' | 'layout.set' | 'digit' | 'digit.send' | 'vmuted' | 'vmuted.hide' | 'vmuted.hide.on' | 'vmuted.hide.off' | 'lock' | 'lock.on' | 'lock.off' | 'device' | 'screenshare' | 'end';
774
+ /**
775
+ * Position of a participant's video within the layout canvas.
776
+ *
777
+ * - `'auto'` — Automatically positioned by the layout engine.
778
+ * - `` `reserved-${number}` `` — A reserved slot in the layout (e.g., `'reserved-0'`).
779
+ * - `` `standard-${number}` `` — A standard slot in the layout (e.g., `'standard-1'`).
780
+ * - `'off-canvas'` — Participant is not visible in the layout.
781
+ * - `'playback'` — Playback position for media streams.
782
+ * - `'full-screen'` — Participant occupies the entire canvas.
783
+ */
459
784
  type VideoPosition = 'auto' | `reserved-${number}` | `standard-${number}` | 'off-canvas' | 'playback' | 'full-screen';
460
785
  //#endregion
461
786
  //#region src/core/RPCMessages/types/common.d.ts
787
+ interface MemberTarget {
788
+ member_id: string;
789
+ call_id: string;
790
+ node_id: string;
791
+ }
462
792
  interface Member {
463
793
  room_session_id: string;
464
794
  room_id: string;
@@ -535,56 +865,10 @@ interface ConversationDetails {
535
865
  start_time: number;
536
866
  end_time?: number;
537
867
  }
538
- interface PartialDialogParams {
539
- callID: string;
540
- }
541
- interface AudioMediaParams {
542
- autoGainControl: boolean;
543
- echoCancellation: boolean;
544
- noiseSuppression: boolean;
545
- }
546
- interface FrameRateConstraint {
547
- min: number;
548
- ideal: number;
549
- max: number;
550
- }
551
- interface AspectRatioConstraint {
552
- exact: number;
553
- }
554
- interface DimensionConstraint {
555
- min: number;
556
- ideal: number;
557
- }
558
- interface VideoAdvancedConstraint {
559
- width: DimensionConstraint;
560
- height: DimensionConstraint;
561
- frameRate: FrameRateConstraint;
562
- }
563
- interface VideoMediaParams {
564
- frameRate: FrameRateConstraint;
565
- aspectRatio: AspectRatioConstraint;
566
- width: DimensionConstraint;
567
- height: DimensionConstraint;
568
- advanced: VideoAdvancedConstraint[];
569
- resizeMode: string;
570
- }
571
- interface MediaParams {
572
- audio?: AudioMediaParams;
573
- video?: VideoMediaParams;
574
- }
575
868
  //#endregion
576
869
  //#region src/core/RPCMessages/types/verto.d.ts
577
- interface VertoAnswerParams {
578
- callID: string;
579
- sdp: string;
580
- }
581
- interface VertoMediaParamsParams {
582
- callID: string;
583
- mediaParams: MediaParams;
584
- }
585
- interface VertoPingParams {
586
- callID: string;
587
- dialogParams: PartialDialogParams;
870
+ interface VertoParams {
871
+ userVariables?: Record<string, unknown>;
588
872
  }
589
873
  //#endregion
590
874
  //#region src/core/RPCMessages/types/events.d.ts
@@ -595,7 +879,7 @@ interface WebrtcMessagePayload {
595
879
  jsonrpc: '2.0';
596
880
  id: number;
597
881
  method: string;
598
- params: VertoAnswerParams | VertoMediaParamsParams | VertoPingParams;
882
+ params: VertoParams;
599
883
  }
600
884
  interface CallJoinedPayload {
601
885
  room_session: RoomSession;
@@ -646,6 +930,11 @@ interface CallUpdatedPayload {
646
930
  room_id: string;
647
931
  room_session_id: string;
648
932
  }
933
+ interface RoomUpdatedPayload {
934
+ room_session: RoomSession;
935
+ room_id: string;
936
+ room_session_id: string;
937
+ }
649
938
  interface CallStatePayload {
650
939
  call_id: string;
651
940
  node_id: string;
@@ -692,7 +981,6 @@ interface ConversationMessagePayload {
692
981
  conversation_name: string;
693
982
  user_name: string;
694
983
  }
695
- type ConversationMessageUpdatedPayload = ConversationMessagePayload;
696
984
  //#endregion
697
985
  //#region src/behaviors/types/collection.types.d.ts
698
986
  interface Entity {
@@ -722,16 +1010,17 @@ declare class EntityCollection<T extends Entity = Entity> extends Destroyable im
722
1010
  private fetchController;
723
1011
  private update$;
724
1012
  private readonly onError?;
725
- loading$: rxjs0.BehaviorSubject<boolean>;
726
- values$: ReplaySubject<T[]>;
727
1013
  hasMore$: Observable<boolean>;
728
1014
  private collectionData;
729
1015
  private observablesRegistry;
730
- private updateSubscription;
731
1016
  private upsertData;
732
- private _destroy$;
1017
+ private _loading$;
1018
+ private _values$;
1019
+ private _hasMore$;
733
1020
  constructor(fetchController: FetchController<T>, update$: Observable<Partial<T>>, onError?: ((error: Error) => void) | undefined);
1021
+ get loading$(): Observable<boolean>;
734
1022
  get loading(): boolean;
1023
+ get values$(): Observable<T[]>;
735
1024
  get hasMore(): boolean;
736
1025
  get updated$(): Observable<void>;
737
1026
  get values(): T[];
@@ -747,6 +1036,7 @@ declare class EntityCollectionTransformed<O extends Entity = Entity, T extends E
747
1036
  private originalCollection;
748
1037
  private filter;
749
1038
  private mapper;
1039
+ private _values$?;
750
1040
  constructor(originalCollection: EntityCollection<O>, filter?: (i: unknown) => i is O, mapper?: (item: O) => T);
751
1041
  get loading$(): Observable<boolean>;
752
1042
  get loading(): boolean;
@@ -760,25 +1050,407 @@ declare class EntityCollectionTransformed<O extends Entity = Entity, T extends E
760
1050
  destroy(): void;
761
1051
  }
762
1052
  //#endregion
1053
+ //#region src/core/entities/types/participant.types.d.ts
1054
+ /** Options for selecting a media device. */
1055
+ interface SelectDeviceOptions {
1056
+ savePreference?: boolean;
1057
+ }
1058
+ //#endregion
1059
+ //#region src/controllers/RTCStatsMonitor.d.ts
1060
+ interface NetworkIssue {
1061
+ type: 'no_inbound_audio' | 'no_inbound_video' | 'high_rtt' | 'high_packet_loss' | 'high_jitter' | 'ice_disconnected';
1062
+ severity: 'warning' | 'critical';
1063
+ timestamp: number;
1064
+ value?: number;
1065
+ threshold?: number;
1066
+ }
1067
+ interface NetworkMetrics {
1068
+ timestamp: number;
1069
+ audio: {
1070
+ packetsReceived: number;
1071
+ packetsLost: number;
1072
+ jitter: number;
1073
+ };
1074
+ video: {
1075
+ packetsReceived: number;
1076
+ packetsLost: number;
1077
+ };
1078
+ roundTripTime: number;
1079
+ availableOutgoingBitrate?: number;
1080
+ }
1081
+ //#endregion
763
1082
  //#region src/managers/types/verto-manager.types.d.ts
764
1083
  type ScreenShareStatus = 'none' | 'starting' | 'started' | 'stopping';
765
- type SignalingStatus = 'trying' | 'ringing' | 'connecting' | 'connected' | 'disconnected' | 'failed';
1084
+ type SignalingStatus = Extract<CallStatus, 'trying' | 'ringing' | 'connecting' | 'connected' | 'disconnected' | 'failed'>;
766
1085
  interface TransferOptions {
767
1086
  destination: string;
768
1087
  }
769
1088
  //#endregion
1089
+ //#region src/core/errors.d.ts
1090
+ declare class UnexpectedError extends Error {
1091
+ at?: string | undefined;
1092
+ constructor(at?: string | undefined, options?: ErrorOptions);
1093
+ }
1094
+ declare class InvalidCredentialsError extends Error {
1095
+ reason: string;
1096
+ constructor(reason?: string, options?: ErrorOptions);
1097
+ }
1098
+ /**
1099
+ * Semantic category of a call-lifecycle error.
1100
+ *
1101
+ * - `'media'` – RTCPeerConnection / media device failure
1102
+ * - `'signaling'` – Verto / JSON-RPC protocol error
1103
+ * - `'timeout'` – Call setup timed out waiting for a response
1104
+ * - `'rejected'` – Remote side rejected the call
1105
+ * - `'network'` – Transport lost during an active call
1106
+ * - `'internal'` – Unexpected / unknown error
1107
+ */
1108
+ type CallErrorKind = 'media' | 'signaling' | 'timeout' | 'rejected' | 'network' | 'internal';
1109
+ /**
1110
+ * Structured error emitted on `call.errors$`.
1111
+ *
1112
+ * Provides actionable metadata so consumers can react without
1113
+ * resorting to `instanceof` checks on raw `Error` objects.
1114
+ */
1115
+ interface CallError {
1116
+ /** Semantic category of the error. */
1117
+ readonly kind: CallErrorKind;
1118
+ /**
1119
+ * Whether the error terminates the call.
1120
+ * When `true`, the call will automatically transition to `'failed'`
1121
+ * and be destroyed — no further action is needed from the consumer.
1122
+ */
1123
+ readonly fatal: boolean;
1124
+ /** The underlying error. */
1125
+ readonly error: Error;
1126
+ /** ID of the call that produced this error. */
1127
+ readonly callId: string;
1128
+ }
1129
+ declare class CallCreateError extends Error {
1130
+ message: string;
1131
+ error: unknown;
1132
+ direction: 'inbound' | 'outbound';
1133
+ constructor(message: string, error?: unknown, direction?: 'inbound' | 'outbound', options?: ErrorOptions);
1134
+ }
1135
+ declare class VertoPongError extends Error {
1136
+ originalError: unknown;
1137
+ constructor(originalError: unknown);
1138
+ }
1139
+ declare class MessageParseError extends Error {
1140
+ originalError: unknown;
1141
+ constructor(originalError: unknown);
1142
+ }
1143
+ declare class CollectionFetchError extends Error {
1144
+ operation: string;
1145
+ originalError: unknown;
1146
+ constructor(operation: string, originalError: unknown);
1147
+ }
1148
+ declare class MediaTrackError extends Error {
1149
+ operation: string;
1150
+ kind: string;
1151
+ originalError: unknown;
1152
+ constructor(operation: string, kind: string, originalError: unknown);
1153
+ }
1154
+ declare class DPoPInitError extends Error {
1155
+ originalError: unknown;
1156
+ constructor(originalError: unknown, message?: string);
1157
+ }
1158
+ /**
1159
+ * Error thrown when a recovery attempt fails.
1160
+ *
1161
+ * Carries the recovery action and attempt number for diagnostic purposes.
1162
+ */
1163
+ declare class RecoveryError extends Error {
1164
+ action: string;
1165
+ attempt: number;
1166
+ originalError?: unknown | undefined;
1167
+ constructor(action: string, attempt: number, originalError?: unknown | undefined);
1168
+ }
1169
+ /**
1170
+ * Error thrown when getUserMedia fails with OverconstrainedError
1171
+ * and all fallback levels have been exhausted.
1172
+ */
1173
+ declare class OverconstrainedFallbackError extends Error {
1174
+ deviceKind: string;
1175
+ originalError?: unknown | undefined;
1176
+ constructor(deviceKind: string, originalError?: unknown | undefined);
1177
+ }
1178
+ /**
1179
+ * Error thrown when the preflight connectivity test fails.
1180
+ */
1181
+ declare class PreflightError extends Error {
1182
+ phase: string;
1183
+ originalError?: unknown | undefined;
1184
+ constructor(phase: string, originalError?: unknown | undefined);
1185
+ }
1186
+ declare class DeviceTokenError extends Error {
1187
+ originalError?: unknown | undefined;
1188
+ constructor(message: string, originalError?: unknown | undefined);
1189
+ }
1190
+ declare class TokenRefreshError extends Error {
1191
+ originalError?: unknown | undefined;
1192
+ constructor(message: string, originalError?: unknown | undefined);
1193
+ }
1194
+ //#endregion
1195
+ //#region src/core/types/resilience.types.d.ts
1196
+ /**
1197
+ * Types for SDK resilience, recovery, diagnostics, and quality monitoring.
1198
+ *
1199
+ * These types support:
1200
+ * - WebRTC stats monitoring (Section 1)
1201
+ * - Tiered recovery system (Section 2)
1202
+ * - Device recovery events (Section 5)
1203
+ * - Tab visibility handling (Section 4)
1204
+ * - Audio/video constraint management (Section 16)
1205
+ * - Network resilience & recovery pipeline (Section 19)
1206
+ * - Preflight connectivity test (Section 20)
1207
+ * - Call quality score (Section 21)
1208
+ * - Graceful degradation (Section 22)
1209
+ * - Platform capability detection (Section 24)
1210
+ * - Structured diagnostic log export (Section 26)
1211
+ */
1212
+ /** Simplified quality level for UI indicators, derived from MOS score. */
1213
+ type QualityLevel = 'excellent' | 'good' | 'fair' | 'poor' | 'critical';
1214
+ /**
1215
+ * Extended call status that includes the 'recovering' state.
1216
+ *
1217
+ * Used when the SDK is attempting to recover a call after a network
1218
+ * disruption or media failure.
1219
+ */
1220
+ type ResilienceCallStatus = 'new' | 'trying' | 'ringing' | 'connecting' | 'connected' | 'recovering' | 'disconnecting' | 'disconnected' | 'failed' | 'destroyed';
1221
+ type NetworkMetrics$1 = NetworkMetrics;
1222
+ /** Event emitted when a recovery action is taken on a call. */
1223
+ interface RecoveryEvent {
1224
+ /** The recovery action that was taken. */
1225
+ readonly action: 'keyframe_requested' | 'reinvite_started' | 'reinvite_succeeded' | 'reinvite_failed' | 'reinvite_timeout' | 'max_attempts_reached' | 'call_recovering' | 'call_recovered' | 'call_recovery_failed' | 'signal_reconnect' | 'full_reconnect' | 'video_disabled' | 'video_restored';
1226
+ /** Human-readable description of why recovery was triggered. */
1227
+ readonly reason: string;
1228
+ /** Current attempt number (for multi-attempt recoveries). */
1229
+ readonly attempt?: number;
1230
+ /** Maximum number of attempts allowed. */
1231
+ readonly maxAttempts?: number;
1232
+ /** Timestamp when the event occurred (epoch ms). */
1233
+ readonly timestamp: number;
1234
+ }
1235
+ /** State of the recovery pipeline state machine (Section 19.7). */
1236
+ type RecoveryState = 'idle' | 'debouncing' | 'recovering' | 'cooldown';
1237
+ /** Event emitted when the SDK auto-switches a device. */
1238
+ interface DeviceRecoveryEvent {
1239
+ /** The kind of device that was switched. */
1240
+ readonly kind: 'audioinput' | 'audiooutput' | 'videoinput';
1241
+ /** The device that was previously selected (null if none). */
1242
+ readonly previousDevice: MediaDeviceInfo | null;
1243
+ /** The device that was selected as a replacement (null if none available). */
1244
+ readonly newDevice: MediaDeviceInfo | null;
1245
+ /** The reason for the device switch. */
1246
+ readonly reason: 'device_disconnected' | 'device_reconnected' | 'session_restored' | 'fallback_to_default' | 'default_changed' | 'ambiguous_match';
1247
+ }
1248
+ /**
1249
+ * Serializable subset of MediaDeviceInfo for persistence.
1250
+ *
1251
+ * The browser's MediaDeviceInfo interface is not serializable.
1252
+ * This stores the fields needed for device recovery across sessions.
1253
+ */
1254
+ interface StoredDevicePreference {
1255
+ /** The device ID. */
1256
+ readonly deviceId: string;
1257
+ /** The human-readable label. */
1258
+ readonly label: string;
1259
+ /** The device kind. */
1260
+ readonly kind: MediaDeviceKind;
1261
+ /** The group ID (identifies the physical device). */
1262
+ readonly groupId: string;
1263
+ }
1264
+ /** Result of a media permissions request (Section 5.10). */
1265
+ interface PermissionResult {
1266
+ /** Whether audio permission was granted. */
1267
+ readonly audio: boolean;
1268
+ /** Whether video permission was granted. */
1269
+ readonly video: boolean;
1270
+ /** The audio device the user selected in the browser picker, if any. */
1271
+ readonly selectedAudioDevice?: MediaDeviceInfo;
1272
+ /** The video device the user selected in the browser picker, if any. */
1273
+ readonly selectedVideoDevice?: MediaDeviceInfo;
1274
+ }
1275
+ /** Event emitted when getUserMedia falls back to looser constraints. */
1276
+ interface ConstraintFallbackEvent {
1277
+ /** The kind of input device. */
1278
+ readonly kind: 'audioinput' | 'videoinput';
1279
+ /** The device that was originally requested. */
1280
+ readonly requestedDevice: MediaDeviceInfo | null;
1281
+ /** The device that the browser actually provided. */
1282
+ readonly actualDevice: MediaDeviceInfo | null;
1283
+ /** The constraint level that succeeded. */
1284
+ readonly fallbackLevel: 'exact' | 'preferred' | 'default';
1285
+ }
1286
+ /** Browser/platform WebRTC capability flags. */
1287
+ interface PlatformCapabilities {
1288
+ /** Whether screen sharing is supported. */
1289
+ readonly screenShare: boolean;
1290
+ /** Whether screen share can include system audio (Chrome-only). */
1291
+ readonly screenShareAudio: boolean;
1292
+ /** Whether simulcast is supported. */
1293
+ readonly simulcast: boolean;
1294
+ /** Whether insertable streams / encoded transforms are available. */
1295
+ readonly insertableStreams: boolean;
1296
+ /** Whether setSinkId (audio output selection) is supported. */
1297
+ readonly audioOutputSelection: boolean;
1298
+ /** List of supported video codecs. */
1299
+ readonly videoCodecs: readonly string[];
1300
+ /** List of supported audio codecs. */
1301
+ readonly audioCodecs: readonly string[];
1302
+ /** Whether the browser supports WebRTC at all. */
1303
+ readonly webrtc: boolean;
1304
+ /** Whether getUserMedia is available. */
1305
+ readonly getUserMedia: boolean;
1306
+ /** Whether getDisplayMedia is available. */
1307
+ readonly getDisplayMedia: boolean;
1308
+ }
1309
+ /** Options for the preflight connectivity test. */
1310
+ interface PreflightOptions {
1311
+ /** How long to run the media test in seconds (default: 10). */
1312
+ readonly duration?: number;
1313
+ /** Skip the media/bandwidth test, only test signaling + TURN + devices. */
1314
+ readonly skipMediaTest?: boolean;
1315
+ /** Test a specific audio device instead of the currently selected one. */
1316
+ readonly audioDevice?: MediaDeviceInfo;
1317
+ /** Test a specific video device instead of the currently selected one. */
1318
+ readonly videoDevice?: MediaDeviceInfo;
1319
+ }
1320
+ /** Results of a preflight connectivity test. */
1321
+ interface PreflightResult {
1322
+ /** Overall pass/fail. */
1323
+ readonly ok: boolean;
1324
+ /** Signaling server reachability. */
1325
+ readonly signaling: {
1326
+ readonly reachable: boolean;
1327
+ readonly rttMs: number;
1328
+ };
1329
+ /** ICE/TURN connectivity. */
1330
+ readonly connectivity: {
1331
+ /** 'direct' = host/srflx worked, 'relay' = only TURN relay, 'failed' = nothing. */
1332
+ readonly type: 'direct' | 'relay' | 'failed';
1333
+ /** Whether TURN servers are reachable. */
1334
+ readonly turnReachable: boolean;
1335
+ /** Whether STUN servers are reachable. */
1336
+ readonly stunReachable: boolean;
1337
+ /** RTT to media server in ms. */
1338
+ readonly rttMs: number;
1339
+ };
1340
+ /** Bandwidth estimation (null if skipMediaTest). */
1341
+ readonly bandwidth: {
1342
+ readonly uploadKbps: number;
1343
+ readonly downloadKbps: number;
1344
+ } | null;
1345
+ /** Device test results. */
1346
+ readonly devices: {
1347
+ readonly audioInput: {
1348
+ readonly working: boolean;
1349
+ readonly device: MediaDeviceInfo | null;
1350
+ };
1351
+ readonly videoInput: {
1352
+ readonly working: boolean;
1353
+ readonly device: MediaDeviceInfo | null;
1354
+ };
1355
+ readonly audioOutput: {
1356
+ readonly available: boolean;
1357
+ readonly device: MediaDeviceInfo | null;
1358
+ };
1359
+ };
1360
+ /** Human-readable warnings. */
1361
+ readonly warnings: readonly string[];
1362
+ }
1363
+ /** Event emitted when audio constraints change on a call. */
1364
+ interface AudioConstraintsEvent {
1365
+ /** The new constraints applied. */
1366
+ readonly constraints: MediaTrackConstraints;
1367
+ /** How the constraints were applied. */
1368
+ readonly method: 'applyConstraints' | 'trackReplacement';
1369
+ /** Timestamp when the event occurred (epoch ms). */
1370
+ readonly timestamp: number;
1371
+ }
1372
+ /** Event emitted when server-pushed media params are applied. */
1373
+ interface MediaParamsEvent {
1374
+ /** Audio constraints pushed by the server, if any. */
1375
+ readonly audio?: MediaTrackConstraints;
1376
+ /** Video constraints pushed by the server, if any. */
1377
+ readonly video?: MediaTrackConstraints;
1378
+ /** Timestamp when the event occurred (epoch ms). */
1379
+ readonly timestamp: number;
1380
+ }
1381
+ /** Structured diagnostic bundle for a session. */
1382
+ interface SessionDiagnostics {
1383
+ /** SDK version. */
1384
+ readonly sdkVersion: string;
1385
+ /** Browser/platform user agent string. */
1386
+ readonly userAgent: string;
1387
+ /** Platform capabilities detected at construction time. */
1388
+ readonly capabilities: PlatformCapabilities;
1389
+ /** Timeline of significant events during the session. */
1390
+ readonly events: readonly DiagnosticEvent[];
1391
+ /** Quality summary per call. */
1392
+ readonly calls: readonly CallDiagnosticSummary[];
1393
+ /** Device changes that occurred during the session. */
1394
+ readonly deviceChanges: readonly DeviceRecoveryEvent[];
1395
+ /** Current device list snapshot. */
1396
+ readonly devices: {
1397
+ readonly audioInput: readonly MediaDeviceInfo[];
1398
+ readonly audioOutput: readonly MediaDeviceInfo[];
1399
+ readonly videoInput: readonly MediaDeviceInfo[];
1400
+ };
1401
+ }
1402
+ /** A single diagnostic event in the session timeline. */
1403
+ interface DiagnosticEvent {
1404
+ /** Timestamp when the event occurred (epoch ms). */
1405
+ readonly timestamp: number;
1406
+ /** Category of the event. */
1407
+ readonly category: 'connection' | 'call' | 'device' | 'recovery' | 'error';
1408
+ /** Event description string. */
1409
+ readonly event: string;
1410
+ /** Additional details about the event. */
1411
+ readonly details?: Readonly<Record<string, unknown>>;
1412
+ }
1413
+ /** Quality summary for a single call in the diagnostic bundle. */
1414
+ interface CallDiagnosticSummary {
1415
+ /** Unique call ID. */
1416
+ readonly callId: string;
1417
+ /** Whether the call was inbound or outbound. */
1418
+ readonly direction: 'inbound' | 'outbound';
1419
+ /** The destination dialed, if outbound. */
1420
+ readonly destination?: string;
1421
+ /** Total call duration in seconds. */
1422
+ readonly duration: number;
1423
+ /** Final call status. */
1424
+ readonly status: string;
1425
+ /** Average MOS quality score over the call. */
1426
+ readonly avgQualityScore: number;
1427
+ /** Worst (minimum) MOS quality score during the call. */
1428
+ readonly minQualityScore: number;
1429
+ /** Number of recovery attempts made during the call. */
1430
+ readonly recoveryAttempts: number;
1431
+ /** ICE candidate types that were used. */
1432
+ readonly iceCandidateTypes: readonly string[];
1433
+ /** Final network metrics snapshot at call end. */
1434
+ readonly finalMetrics: NetworkMetrics$1;
1435
+ }
1436
+ //#endregion
770
1437
  //#region src/core/RPCMessages/RPCConnect.d.ts
771
1438
  interface Authorization {
772
1439
  jti: string;
773
1440
  project_id: string;
1441
+ data_zone?: string;
1442
+ scope?: string[];
774
1443
  fabric_subscriber: {
775
1444
  version: number;
776
1445
  expires_at: number;
777
1446
  subscriber_id: string;
778
- application_id: string;
1447
+ application_id: string | null;
779
1448
  project_id: string;
780
1449
  space_id: string;
781
1450
  };
1451
+ cnf?: {
1452
+ jkt: string;
1453
+ };
782
1454
  }
783
1455
  //#endregion
784
1456
  //#region src/core/utils.d.ts
@@ -905,40 +1577,107 @@ declare class SelfCapabilities extends Destroyable {
905
1577
  get state(): CallCapabilitiesState;
906
1578
  }
907
1579
  //#endregion
908
- //#region src/core/entities/types/participant.types.d.ts
909
- interface SelectDeviceOptions {
910
- savePreference?: boolean;
911
- }
912
- //#endregion
913
1580
  //#region src/interfaces/DeviceController.d.ts
914
1581
  /**
915
- * Device interface for media device management
916
- * Provides access to media devices and device selection
1582
+ * Interface for media device management.
1583
+ *
1584
+ * Provides reactive access to available media devices, device selection,
1585
+ * and monitoring for device changes (connect/disconnect).
917
1586
  */
918
1587
  interface DeviceController {
1588
+ /** Observable list of available audio input (microphone) devices. */
919
1589
  readonly audioInputDevices$: Observable<MediaDeviceInfo[]>;
1590
+ /** Observable list of available audio output (speaker) devices. */
920
1591
  readonly audioOutputDevices$: Observable<MediaDeviceInfo[]>;
1592
+ /** Observable list of available video input (camera) devices. */
921
1593
  readonly videoInputDevices$: Observable<MediaDeviceInfo[]>;
1594
+ /** Observable of the currently selected audio input device, or `null` if none. */
922
1595
  readonly selectedAudioInputDevice$: Observable<MediaDeviceInfo | null>;
1596
+ /** Observable of the currently selected audio output device, or `null` if none. */
923
1597
  readonly selectedAudioOutputDevice$: Observable<MediaDeviceInfo | null>;
1598
+ /** Observable of the currently selected video input device, or `null` if none. */
924
1599
  readonly selectedVideoInputDevice$: Observable<MediaDeviceInfo | null>;
1600
+ /** Currently selected audio input device, or `null` if none. */
925
1601
  readonly selectedAudioInputDevice: MediaDeviceInfo | null;
1602
+ /** Currently selected audio output device, or `null` if none. */
926
1603
  readonly selectedAudioOutputDevice: MediaDeviceInfo | null;
1604
+ /** Currently selected video input device, or `null` if none. */
927
1605
  readonly selectedVideoInputDevice: MediaDeviceInfo | null;
1606
+ /** Current snapshot of available audio input devices. */
928
1607
  readonly audioInputDevices: MediaDeviceInfo[];
1608
+ /** Current snapshot of available audio output devices. */
929
1609
  readonly audioOutputDevices: MediaDeviceInfo[];
1610
+ /** Current snapshot of available video input devices. */
930
1611
  readonly videoInputDevices: MediaDeviceInfo[];
931
- readonly selectedAudioInputDeviceConstraints: MediaTrackConstraints;
932
- readonly selectedVideoInputDeviceConstraints: MediaTrackConstraints;
1612
+ /** Media track constraints for the selected audio input device. Returns `false` when disabled. */
1613
+ readonly selectedAudioInputDeviceConstraints: MediaTrackConstraints | boolean;
1614
+ /** Media track constraints for the selected video input device. Returns `false` when disabled. */
1615
+ readonly selectedVideoInputDeviceConstraints: MediaTrackConstraints | boolean;
1616
+ /**
1617
+ * Converts a {@link MediaDeviceInfo} to track constraints suitable for `getUserMedia`.
1618
+ * @param deviceInfo - The device to convert, or `null` for default constraints.
1619
+ */
933
1620
  deviceInfoToConstraints(deviceInfo: MediaDeviceInfo | null): MediaTrackConstraints;
1621
+ /**
1622
+ * Sets the preferred audio input device for future calls.
1623
+ * @param device - The device to select, or `null` to use the system default.
1624
+ */
934
1625
  selectAudioInputDevice(device: MediaDeviceInfo | null): void;
1626
+ /**
1627
+ * Sets the preferred video input device for future calls.
1628
+ * @param device - The device to select, or `null` to use the system default.
1629
+ */
935
1630
  selectVideoInputDevice(device: MediaDeviceInfo | null): void;
1631
+ /**
1632
+ * Sets the preferred audio output device for future calls.
1633
+ * @param device - The device to select, or `null` to use the system default.
1634
+ */
936
1635
  selectAudioOutputDevice(device: MediaDeviceInfo | null): void;
1636
+ /** Starts monitoring for media device changes (connect/disconnect). */
937
1637
  enableDeviceMonitoring(): void;
1638
+ /** Stops monitoring for media device changes. */
938
1639
  disableDeviceMonitoring(): void;
1640
+ /**
1641
+ * Returns the capabilities of a media device.
1642
+ * @param deviceInfo - The device to query.
1643
+ * @returns The device capabilities, or `null` if unavailable.
1644
+ */
939
1645
  getDeviceCapabilities(deviceInfo: MediaDeviceInfo): Promise<MediaTrackCapabilities | null>;
1646
+ /**
1647
+ * Checks whether a device is still available and usable.
1648
+ * @param deviceInfo - The device to validate, or `null`.
1649
+ * @returns `true` if the device is valid and available. Returns `false` for `null`, audio output devices, or unavailable devices.
1650
+ */
940
1651
  isValidDevice(deviceInfo: MediaDeviceInfo | null): Promise<boolean>;
1652
+ /** Observable stream of errors from device enumeration and monitoring. */
941
1653
  readonly errors$: Observable<Error>;
1654
+ /**
1655
+ * Observable that emits when the SDK auto-switches a device due to
1656
+ * disconnect, reconnect, or recovery.
1657
+ */
1658
+ readonly deviceRecovered$: Observable<DeviceRecoveryEvent>;
1659
+ /** Disables audio input (receive-only mode). No track will be acquired. */
1660
+ disableAudioInput(): void;
1661
+ /** Re-enables audio input, restoring the last selection or auto-selecting. */
1662
+ enableAudioInput(): void;
1663
+ /** Disables video input (receive-only mode). No track will be acquired. */
1664
+ disableVideoInput(): void;
1665
+ /** Re-enables video input, restoring the last selection or auto-selecting. */
1666
+ enableVideoInput(): void;
1667
+ /** Observable that emits `true` when video input is disabled (receive-only). */
1668
+ readonly videoInputDisabled$: Observable<boolean>;
1669
+ /** Observable that emits `true` when audio input is disabled (receive-only). */
1670
+ readonly audioInputDisabled$: Observable<boolean>;
1671
+ /** Whether video input is currently disabled. */
1672
+ readonly videoInputDisabled: boolean;
1673
+ /** Whether audio input is currently disabled. */
1674
+ readonly audioInputDisabled: boolean;
1675
+ /** Injects the storage manager for device persistence. */
1676
+ setStorageManager(storageManager: StorageManager): void;
1677
+ /** Clears all device state (history, selections, persisted prefs) and re-enumerates. */
1678
+ clearDeviceState(): Promise<void>;
1679
+ /** Force a device re-enumeration. */
1680
+ enumerateDevices(): Promise<void>;
942
1681
  }
943
1682
  //#endregion
944
1683
  //#region src/interfaces/VertoManager.d.ts
@@ -969,7 +1708,7 @@ interface VertoManager {
969
1708
  * Callback type for executing call methods
970
1709
  * Injected to avoid circular dependency with Call class
971
1710
  */
972
- type ExecuteMethod = <T extends JSONRPCResponse = JSONRPCResponse>(target: string, method: string, args: Record<string, unknown>) => Promise<T>;
1711
+ type ExecuteMethod = <T extends JSONRPCResponse = JSONRPCResponse>(target: string | MemberTarget, method: string, args: Record<string, unknown>) => Promise<T>;
973
1712
  type ParticipantState = Member & {
974
1713
  position: LayoutLayer;
975
1714
  };
@@ -990,45 +1729,45 @@ declare class Participant extends Destroyable implements CallParticipant {
990
1729
  /** @internal */
991
1730
  upnext(data: Partial<ParticipantState>): void;
992
1731
  /** Observable of the participant's display name. */
993
- get name$(): Observable<string>;
1732
+ get name$(): Observable<string | undefined>;
994
1733
  /** Observable of the participant type (e.g. `'member'`, `'screen'`). */
995
- get type$(): Observable<string>;
1734
+ get type$(): Observable<string | undefined>;
996
1735
  /** Observable indicating whether the participant has raised their hand. */
997
- get handraised$(): Observable<boolean>;
1736
+ get handraised$(): Observable<boolean | undefined>;
998
1737
  /** Observable indicating whether the participant is visible in the layout. */
999
- get visible$(): Observable<boolean>;
1738
+ get visible$(): Observable<boolean | undefined>;
1000
1739
  /** Observable indicating whether the participant's audio is muted. */
1001
- get audioMuted$(): Observable<boolean>;
1740
+ get audioMuted$(): Observable<boolean | undefined>;
1002
1741
  /** Observable indicating whether the participant's video is muted. */
1003
- get videoMuted$(): Observable<boolean>;
1742
+ get videoMuted$(): Observable<boolean | undefined>;
1004
1743
  /** Observable indicating whether the participant is deafened. */
1005
- get deaf$(): Observable<boolean>;
1744
+ get deaf$(): Observable<boolean | undefined>;
1006
1745
  /** Observable of the participant's microphone input volume. */
1007
- get inputVolume$(): Observable<number>;
1746
+ get inputVolume$(): Observable<number | undefined>;
1008
1747
  /** Observable of the participant's speaker output volume. */
1009
- get outputVolume$(): Observable<number>;
1748
+ get outputVolume$(): Observable<number | undefined>;
1010
1749
  /** Observable of the microphone input sensitivity level. */
1011
- get inputSensitivity$(): Observable<number>;
1750
+ get inputSensitivity$(): Observable<number | undefined>;
1012
1751
  /** Observable indicating whether echo cancellation is enabled. */
1013
- get echoCancellation$(): Observable<boolean>;
1752
+ get echoCancellation$(): Observable<boolean | undefined>;
1014
1753
  /** Observable indicating whether auto-gain control is enabled. */
1015
- get autoGain$(): Observable<boolean>;
1754
+ get autoGain$(): Observable<boolean | undefined>;
1016
1755
  /** Observable indicating whether noise suppression is enabled. */
1017
- get noiseSuppression$(): Observable<boolean>;
1756
+ get noiseSuppression$(): Observable<boolean | undefined>;
1018
1757
  /** Observable indicating whether low-bitrate mode is active. */
1019
- get lowbitrate$(): Observable<boolean>;
1758
+ get lowbitrate$(): Observable<boolean | undefined>;
1020
1759
  /** Observable indicating whether noise reduction is active. */
1021
- get denoise$(): Observable<boolean>;
1760
+ get denoise$(): Observable<boolean | undefined>;
1022
1761
  /** Observable of custom metadata for this participant. */
1023
- get meta$(): Observable<Record<string, unknown>>;
1762
+ get meta$(): Observable<Record<string, unknown> | undefined>;
1024
1763
  /** Observable of the participant's subscriber ID. */
1025
- get subscriberId$(): Observable<string>;
1764
+ get subscriberId$(): Observable<string | undefined>;
1026
1765
  /** Observable of the participant's address ID. */
1027
- get addressId$(): Observable<string>;
1766
+ get addressId$(): Observable<string | undefined>;
1028
1767
  /** Observable of the server node ID for this participant. */
1029
- get nodeId$(): Observable<string>;
1768
+ get nodeId$(): Observable<string | undefined>;
1030
1769
  /** Observable indicating whether the participant is currently speaking. */
1031
- get isTalking$(): Observable<boolean>;
1770
+ get isTalking$(): Observable<boolean | undefined>;
1032
1771
  /** Whether the participant is currently speaking. */
1033
1772
  get isTalking(): boolean;
1034
1773
  /** Observable of the participant's layout position. */
@@ -1041,22 +1780,39 @@ declare class Participant extends Destroyable implements CallParticipant {
1041
1780
  get name(): string | undefined;
1042
1781
  /** Participant type (e.g. `'member'`, `'screen'`). */
1043
1782
  get type(): string | undefined;
1783
+ /** Whether the participant has raised their hand. */
1044
1784
  get handraised(): boolean;
1785
+ /** Whether the participant is visible in the layout. */
1045
1786
  get visible(): boolean;
1787
+ /** Whether the participant's audio is muted. */
1046
1788
  get audioMuted(): boolean;
1789
+ /** Whether the participant's video is muted. */
1047
1790
  get videoMuted(): boolean;
1791
+ /** Whether the participant is deafened (incoming audio muted). */
1048
1792
  get deaf(): boolean;
1793
+ /** Current microphone input volume level, or `undefined` if not set. */
1049
1794
  get inputVolume(): number | undefined;
1795
+ /** Current speaker output volume level, or `undefined` if not set. */
1050
1796
  get outputVolume(): number | undefined;
1797
+ /** Current microphone input sensitivity level, or `undefined` if not set. */
1051
1798
  get inputSensitivity(): number | undefined;
1799
+ /** Whether echo cancellation is enabled. */
1052
1800
  get echoCancellation(): boolean;
1801
+ /** Whether automatic gain control is enabled. */
1053
1802
  get autoGain(): boolean;
1803
+ /** Whether noise suppression is enabled. */
1054
1804
  get noiseSuppression(): boolean;
1805
+ /** Whether low-bitrate mode is active. */
1055
1806
  get lowbitrate(): boolean;
1807
+ /** Whether noise reduction (denoise) is active. */
1056
1808
  get denoise(): boolean;
1809
+ /** Custom metadata for this participant, or `undefined` if not set. */
1057
1810
  get meta(): Record<string, unknown> | undefined;
1811
+ /** Subscriber ID of this participant, or `undefined` if not available. */
1058
1812
  get subscriberId(): string | undefined;
1813
+ /** Address ID of this participant, or `undefined` if not available. */
1059
1814
  get addressId(): string | undefined;
1815
+ /** Server node ID for this participant, or `undefined` if not available. */
1060
1816
  get nodeId(): string | undefined;
1061
1817
  /** @internal */
1062
1818
  get value(): Partial<Member>;
@@ -1085,18 +1841,38 @@ declare class Participant extends Destroyable implements CallParticipant {
1085
1841
  toggleLowbitrate(): Promise<void>;
1086
1842
  /** Sets the microphone input sensitivity level. */
1087
1843
  setAudioInputSensitivity(value: number): Promise<void>;
1088
- /** Sets the microphone input volume level. */
1844
+ /**
1845
+ * Sets the microphone input volume level.
1846
+ * @param value - Volume level (0-100).
1847
+ */
1089
1848
  setAudioInputVolume(value: number): Promise<void>;
1090
- /** Sets the speaker output volume level. */
1849
+ /**
1850
+ * Sets the speaker output volume level.
1851
+ * @param value - Volume level (0-100).
1852
+ */
1091
1853
  setAudioOutputVolume(value: number): Promise<void>;
1092
- /** Sets the participant's position in the video layout. */
1854
+ /**
1855
+ * Sets the participant's position in the video layout.
1856
+ * @param value - The {@link VideoPosition} to assign (e.g. `'auto'`, `'reserved-0'`).
1857
+ */
1093
1858
  setPosition(value: VideoPosition): Promise<void>;
1094
1859
  /** Removes this participant from the call. */
1095
1860
  remove(): Promise<void>;
1096
1861
  /** Ends the call for this participant. */
1097
1862
  end(): Promise<void>;
1863
+ /**
1864
+ * Replaces custom metadata for this participant.
1865
+ * @param _meta - Metadata object to set.
1866
+ * @throws {UnimplementedError} Not yet implemented.
1867
+ */
1098
1868
  setMeta(_meta: Record<string, unknown>): Promise<void>;
1869
+ /**
1870
+ * Merges values into custom metadata (unlike {@link setMeta} which replaces).
1871
+ * @param _meta - Metadata to merge.
1872
+ * @throws {UnimplementedError} Not yet implemented.
1873
+ */
1099
1874
  updateMeta(_meta: Record<string, unknown>): Promise<void>;
1875
+ /** Destroys the participant, releasing all subscriptions and references. */
1100
1876
  destroy(): void;
1101
1877
  }
1102
1878
  /**
@@ -1112,8 +1888,29 @@ declare class SelfParticipant extends Participant implements CallSelfParticipant
1112
1888
  * Contains all capability flags as both observables and values.
1113
1889
  */
1114
1890
  readonly capabilities: SelfCapabilities;
1891
+ /**
1892
+ * Studio audio mode state. When enabled, all audio processing
1893
+ * (echo cancellation, noise suppression, auto gain control) is disabled
1894
+ * to provide raw/unprocessed audio for musicians, podcasters, etc.
1895
+ */
1896
+ private _studioAudio$;
1897
+ /** @internal */
1115
1898
  constructor(id: string, executeMethod: ExecuteMethod, vertoManager: VertoManager, deviceController: DeviceController);
1116
1899
  destroy(): void;
1900
+ /** Observable indicating whether studio audio (raw/unprocessed audio) mode is enabled. */
1901
+ get studioAudio$(): Observable<boolean>;
1902
+ /** Whether studio audio (raw/unprocessed audio) mode is currently enabled. */
1903
+ get studioAudio(): boolean;
1904
+ /**
1905
+ * Enables studio audio mode by disabling all audio processing.
1906
+ * Sets echoCancellation, noiseSuppression, and autoGainControl to false.
1907
+ */
1908
+ enableStudioAudio(): Promise<void>;
1909
+ /**
1910
+ * Disables studio audio mode by restoring all audio processing to enabled.
1911
+ * Sets echoCancellation, noiseSuppression, and autoGainControl to true.
1912
+ */
1913
+ disableStudioAudio(): Promise<void>;
1117
1914
  /** Starts sharing the local screen. */
1118
1915
  startScreenShare(): Promise<void>;
1119
1916
  /** Observable of the current screen share status. */
@@ -1159,9 +1956,24 @@ declare class SelfParticipant extends Participant implements CallSelfParticipant
1159
1956
  setVideoInputDeviceConstraints(constraints: MediaTrackConstraints): Promise<void>;
1160
1957
  /** Selects the audio output device. Optionally saves as a preference. */
1161
1958
  selectAudioOutputDevice(device: MediaDeviceInfo, options?: SelectDeviceOptions): void;
1959
+ /**
1960
+ * Exits studio audio mode without restoring defaults.
1961
+ * Called internally before individual audio flag toggles.
1962
+ */
1963
+ private exitStudioModeIfActive;
1964
+ /** Toggles echo cancellation. Exits studio mode if active. */
1965
+ toggleEchoCancellation(): Promise<void>;
1966
+ /** Toggles automatic gain control. Exits studio mode if active. */
1967
+ toggleAudioInputAutoGain(): Promise<void>;
1968
+ /** Toggles noise suppression. Exits studio mode if active. */
1969
+ toggleNoiseSuppression(): Promise<void>;
1970
+ /** Mutes local audio. Falls back to local device mute if the server RPC fails. */
1162
1971
  mute(): Promise<void>;
1972
+ /** Unmutes local audio. Falls back to local device unmute if the server RPC fails. */
1163
1973
  unmute(): Promise<void>;
1974
+ /** Mutes local video. Falls back to local device mute if the server RPC fails. */
1164
1975
  muteVideo(): Promise<void>;
1976
+ /** Unmutes local video. Falls back to local device unmute if the server RPC fails. */
1165
1977
  unmuteVideo(): Promise<void>;
1166
1978
  }
1167
1979
  /** Type guard that checks if a participant is the local {@link SelfParticipant}. */
@@ -1174,26 +1986,26 @@ declare const isSelfParticipant: (participant: Participant) => participant is Se
1174
1986
  */
1175
1987
  interface CallParticipant {
1176
1988
  readonly id: string;
1177
- readonly name$: Observable<string>;
1178
- readonly type$: Observable<string>;
1179
- readonly handraised$: Observable<boolean>;
1180
- readonly visible$: Observable<boolean>;
1181
- readonly audioMuted$: Observable<boolean>;
1182
- readonly videoMuted$: Observable<boolean>;
1183
- readonly deaf$: Observable<boolean>;
1184
- readonly inputVolume$: Observable<number>;
1185
- readonly outputVolume$: Observable<number>;
1186
- readonly inputSensitivity$: Observable<number>;
1187
- readonly echoCancellation$: Observable<boolean>;
1188
- readonly autoGain$: Observable<boolean>;
1189
- readonly noiseSuppression$: Observable<boolean>;
1190
- readonly lowbitrate$: Observable<boolean>;
1191
- readonly denoise$: Observable<boolean>;
1192
- readonly meta$: Observable<Record<string, unknown>>;
1193
- readonly subscriberId$: Observable<string>;
1194
- readonly addressId$: Observable<string>;
1195
- readonly nodeId$: Observable<string>;
1196
- readonly isTalking$: Observable<boolean>;
1989
+ readonly name$: Observable<string | undefined>;
1990
+ readonly type$: Observable<string | undefined>;
1991
+ readonly handraised$: Observable<boolean | undefined>;
1992
+ readonly visible$: Observable<boolean | undefined>;
1993
+ readonly audioMuted$: Observable<boolean | undefined>;
1994
+ readonly videoMuted$: Observable<boolean | undefined>;
1995
+ readonly deaf$: Observable<boolean | undefined>;
1996
+ readonly inputVolume$: Observable<number | undefined>;
1997
+ readonly outputVolume$: Observable<number | undefined>;
1998
+ readonly inputSensitivity$: Observable<number | undefined>;
1999
+ readonly echoCancellation$: Observable<boolean | undefined>;
2000
+ readonly autoGain$: Observable<boolean | undefined>;
2001
+ readonly noiseSuppression$: Observable<boolean | undefined>;
2002
+ readonly lowbitrate$: Observable<boolean | undefined>;
2003
+ readonly denoise$: Observable<boolean | undefined>;
2004
+ readonly meta$: Observable<Record<string, unknown> | undefined>;
2005
+ readonly subscriberId$: Observable<string | undefined>;
2006
+ readonly addressId$: Observable<string | undefined>;
2007
+ readonly nodeId$: Observable<string | undefined>;
2008
+ readonly isTalking$: Observable<boolean | undefined>;
1197
2009
  readonly position$: Observable<LayoutLayer | undefined>;
1198
2010
  readonly name: string | undefined;
1199
2011
  readonly type: string | undefined;
@@ -1243,13 +2055,34 @@ interface CallParticipant {
1243
2055
  * Extends CallParticipant with methods for controlling the local participant
1244
2056
  */
1245
2057
  interface CallSelfParticipant extends CallParticipant {
1246
- readonly screenShareStatus$: Observable<string>;
1247
- readonly screenShareStatus: string;
2058
+ readonly screenShareStatus$: Observable<ScreenShareStatus>;
2059
+ readonly screenShareStatus: ScreenShareStatus;
2060
+ readonly studioAudio$: Observable<boolean>;
2061
+ readonly studioAudio: boolean;
2062
+ enableStudioAudio(): Promise<void>;
2063
+ disableStudioAudio(): Promise<void>;
1248
2064
  startScreenShare(): Promise<void>;
1249
2065
  stopScreenShare(): Promise<void>;
1250
- selectAudioInputDevice(device: MediaDeviceInfo): void;
1251
- selectVideoInputDevice(device: MediaDeviceInfo): void;
1252
- selectAudioOutputDevice(device: MediaDeviceInfo): void;
2066
+ selectAudioInputDevice(device: MediaDeviceInfo, options?: SelectDeviceOptions): void;
2067
+ selectVideoInputDevice(device: MediaDeviceInfo, options?: SelectDeviceOptions): void;
2068
+ selectAudioOutputDevice(device: MediaDeviceInfo, options?: SelectDeviceOptions): void;
2069
+ addAdditionalDevice(options: MediaOptions): Promise<void>;
2070
+ removeAdditionalDevice(id: string): Promise<void>;
2071
+ addAudioInputDevice(options?: {
2072
+ constraints?: MediaTrackConstraints;
2073
+ stream?: MediaStream;
2074
+ }): Promise<void>;
2075
+ addVideoInputDevice(options?: {
2076
+ constraints?: MediaTrackConstraints;
2077
+ stream?: MediaStream;
2078
+ }): Promise<void>;
2079
+ addInputDevices(options?: MediaOptions): Promise<void>;
2080
+ setAudioInputDeviceConstraints(constraints: MediaTrackConstraints): Promise<void>;
2081
+ setVideoInputDeviceConstraints(constraints: MediaTrackConstraints): Promise<void>;
2082
+ setInputDevicesConstraints(constraints: {
2083
+ audio: MediaTrackConstraints;
2084
+ video: MediaTrackConstraints;
2085
+ }): Promise<void>;
1253
2086
  }
1254
2087
  /**
1255
2088
  * Minimal interface for a collection with pagination
@@ -1271,7 +2104,7 @@ interface CallAddress {
1271
2104
  readonly textMessages$: Observable<CallTextMessageCollection | undefined>;
1272
2105
  }
1273
2106
  /** Lifecycle status of a call. */
1274
- type CallStatus = 'new' | 'trying' | 'ringing' | 'connecting' | 'connected' | 'disconnecting' | 'disconnected' | 'failed' | 'destroyed';
2107
+ type CallStatus = 'new' | 'trying' | 'ringing' | 'connecting' | 'connected' | 'recovering' | 'disconnecting' | 'disconnected' | 'failed' | 'destroyed';
1275
2108
  /** Configuration options for creating a call. */
1276
2109
  interface CallOptions extends MediaOptions {
1277
2110
  /** Target server node ID. */
@@ -1294,6 +2127,12 @@ interface CallOptions extends MediaOptions {
1294
2127
  readonly displayDirection?: string;
1295
2128
  /** Custom user variables sent with the call invite. */
1296
2129
  readonly userVariables?: Record<string, unknown>;
2130
+ /** Preferred video codecs for this call (overrides global preferences). */
2131
+ readonly preferredVideoCodecs?: string[];
2132
+ /** Preferred audio codecs for this call (overrides global preferences). */
2133
+ readonly preferredAudioCodecs?: string[];
2134
+ /** Enable stereo Opus for this call (overrides global preferences). */
2135
+ readonly stereo?: boolean;
1297
2136
  }
1298
2137
  /** Observable state of a call (status, recording, participants, etc.). */
1299
2138
  interface CallState {
@@ -1322,29 +2161,49 @@ interface CallState {
1322
2161
  * and control actions (hangup, mute, transfer, etc.).
1323
2162
  */
1324
2163
  interface Call extends CallState {
1325
- readonly capabilities$: Observable<string[]>;
1326
- readonly capabilities: string[];
2164
+ readonly capabilities$: Observable<Capability[]>;
2165
+ readonly capabilities: Capability[];
1327
2166
  readonly mediaDirections$: Observable<MediaDirections>;
1328
2167
  readonly mediaDirections: MediaDirections;
1329
2168
  readonly self$: Observable<CallSelfParticipant | null>;
1330
2169
  readonly self: CallSelfParticipant | null;
1331
2170
  readonly to?: string;
1332
- readonly direction: 'inbound' | 'outbound';
2171
+ readonly direction: CallDirection;
1333
2172
  readonly layouts$: Observable<string[]>;
1334
2173
  readonly layouts: string[];
1335
2174
  readonly layout$: Observable<string>;
1336
2175
  readonly layout?: string;
1337
2176
  readonly layoutLayers$: Observable<LayoutLayer[]>;
1338
2177
  readonly layoutLayers: LayoutLayer[];
1339
- readonly localStream$: Observable<MediaStream | null>;
2178
+ /** Observable that emits only non-null MediaStreams (waits until the stream exists). */
2179
+ readonly localStream$: Observable<MediaStream>;
2180
+ /** Sync getter — returns null before the stream is created. */
1340
2181
  readonly localStream: MediaStream | null;
1341
- readonly remoteStream$: Observable<MediaStream | null>;
2182
+ /** Observable that emits only non-null MediaStreams (waits until the stream exists). */
2183
+ readonly remoteStream$: Observable<MediaStream>;
1342
2184
  readonly remoteStream: MediaStream | null;
1343
2185
  readonly rtcPeerConnection: RTCPeerConnection | undefined;
1344
- readonly errors$: Observable<Error>;
2186
+ readonly errors$: Observable<CallError>;
1345
2187
  readonly signalingEvent$: Observable<Record<string, unknown>>;
1346
2188
  readonly address?: CallAddress;
1347
2189
  readonly address$: Observable<CallAddress | undefined>;
2190
+ userVariables?: Record<string, unknown>;
2191
+ readonly userVariables$: Observable<Record<string, unknown>>;
2192
+ readonly networkIssues$: Observable<NetworkIssue[]>;
2193
+ readonly networkIssues: NetworkIssue[];
2194
+ readonly isNetworkHealthy$: Observable<boolean>;
2195
+ readonly isNetworkHealthy: boolean;
2196
+ readonly networkMetrics$: Observable<NetworkMetrics[]>;
2197
+ readonly networkMetrics: NetworkMetrics[];
2198
+ readonly qualityScore$: Observable<number>;
2199
+ readonly qualityLevel$: Observable<QualityLevel>;
2200
+ readonly recoveryState$: Observable<RecoveryState>;
2201
+ readonly recoveryEvent$: Observable<RecoveryEvent>;
2202
+ readonly bandwidthConstrained$: Observable<boolean>;
2203
+ readonly mediaParamsUpdated$: Observable<MediaParamsEvent>;
2204
+ requestKeyframe(): void;
2205
+ requestIceRestart(): Promise<void>;
2206
+ subscribe(eventType: string): Observable<Record<string, unknown>>;
1348
2207
  hangup(): Promise<void>;
1349
2208
  toggleLock(): Promise<void>;
1350
2209
  toggleHold(): Promise<void>;
@@ -1354,10 +2213,11 @@ interface Call extends CallState {
1354
2213
  transfer(options: TransferOptions): Promise<void>;
1355
2214
  toggleIncomingVideo(): Promise<void>;
1356
2215
  toggleIncomingAudio(): Promise<void>;
1357
- answer(): void;
2216
+ answer(options?: MediaOptions): void;
1358
2217
  reject(): void;
1359
2218
  sendDigits(digits: string): Promise<void>;
1360
2219
  executeMethod<T extends JSONRPCResponse = JSONRPCResponse>(target: string, method: string, args: Record<string, unknown>): Promise<T>;
2220
+ execute<T extends JSONRPCResponse = JSONRPCResponse>(request: JSONRPCRequest, options?: PendingRPCOptions): Promise<T>;
1361
2221
  }
1362
2222
  /**
1363
2223
  * Extended Call interface with internal management capabilities
@@ -1373,6 +2233,7 @@ interface CallManager extends Call {
1373
2233
  readonly nodeId$: Observable<string | null>;
1374
2234
  readonly nodeId: string | null;
1375
2235
  readonly answered$: Observable<boolean>;
2236
+ readonly answerMediaOptions?: MediaOptions;
1376
2237
  readonly callUpdated$: Observable<CallUpdatedPayload>;
1377
2238
  readonly memberJoined$: Observable<MemberJoinedPayload>;
1378
2239
  readonly memberLeft$: Observable<MemberLeftPayload>;
@@ -1384,7 +2245,6 @@ interface CallManager extends Call {
1384
2245
  addCallId(callId: string): void;
1385
2246
  /** @internal */
1386
2247
  createParticipant(memberId: string, selfId?: string | null): Participant | SelfParticipant;
1387
- execute<T extends JSONRPCResponse = JSONRPCResponse>(request: JSONRPCRequest, options?: PendingRPCOptions): Promise<T>;
1388
2248
  destroy(): void;
1389
2249
  }
1390
2250
  //#endregion
@@ -1395,7 +2255,7 @@ interface CallManager extends Call {
1395
2255
  * This interface breaks the circular dependency between Address and Directory
1396
2256
  * by providing a minimal contract that Address needs from the Directory.
1397
2257
  *
1398
- * @typeParam TAddress - The Address type, defaults to never to enforce explicit typing
2258
+ * @template TAddress - The Address type, defaults to never to enforce explicit typing
1399
2259
  *
1400
2260
  * @remarks
1401
2261
  * Uses a generic type parameter to maintain type safety while avoiding
@@ -1416,7 +2276,7 @@ interface AddressProvider<TAddress = never> {
1416
2276
  * Address history entry from conversation messages
1417
2277
  * Contains a reference to the sender address as an observable
1418
2278
  *
1419
- * @typeParam TAddress - The Address type, provided by the implementation
2279
+ * @template TAddress - The Address type, provided by the implementation
1420
2280
  *
1421
2281
  * @remarks
1422
2282
  * Uses a generic type parameter to maintain type safety while avoiding
@@ -1434,7 +2294,7 @@ interface AddressHistory<TAddress = never> {
1434
2294
  * Text message from conversation
1435
2295
  * Contains a reference to the sender address as an observable
1436
2296
  *
1437
- * @typeParam TAddress - The Address type, provided by the implementation
2297
+ * @template TAddress - The Address type, provided by the implementation
1438
2298
  *
1439
2299
  * @remarks
1440
2300
  * Uses a generic type parameter to maintain type safety while avoiding
@@ -1577,11 +2437,35 @@ declare class Address extends Destroyable {
1577
2437
  get locked(): boolean;
1578
2438
  /** Observable indicating whether the address (room) is locked. */
1579
2439
  get locked$(): Observable<boolean>;
1580
- /** Sends a text message to this address. */
2440
+ /**
2441
+ * Sends a text message to this address.
2442
+ *
2443
+ * @param text - The message text to send.
2444
+ *
2445
+ * @example
2446
+ * ```ts
2447
+ * await address.sendText('Hello!');
2448
+ * ```
2449
+ */
1581
2450
  sendText(text: string): Promise<void>;
1582
- /** Collection of text messages for this address, with pagination support. */
2451
+ /**
2452
+ * Collection of text messages for this address, with pagination support.
2453
+ *
2454
+ * Returns `undefined` until {@link textMessages$} has been subscribed to (lazy-loaded).
2455
+ * Filters to `'chat'` subtype messages from the conversation.
2456
+ *
2457
+ * @see {@link textMessages$} to trigger lazy loading.
2458
+ * @see {@link sendText} to send a new message.
2459
+ */
1583
2460
  get textMessage(): EntityCollectionTransformed<GetConversationMessageResponse, TextMessage<Address>> | undefined;
1584
- /** Collection of call history entries for this address, with pagination support. */
2461
+ /**
2462
+ * Collection of call history entries for this address, with pagination support.
2463
+ *
2464
+ * Returns `undefined` until {@link history$} has been subscribed to (lazy-loaded).
2465
+ * Filters to `'log'` subtype messages including kind, status, start/end times.
2466
+ *
2467
+ * @see {@link history$} to trigger lazy loading.
2468
+ */
1585
2469
  get history(): EntityCollectionTransformed<GetConversationMessageResponse, AddressHistory<Address>> | undefined;
1586
2470
  /** Observable of active call states for this address. @throws {UnimplementedError} Requires presence support. */
1587
2471
  get activity$(): Observable<CallState[]>;
@@ -1594,10 +2478,19 @@ interface AttachableCall {
1594
2478
  id: string;
1595
2479
  to?: string;
1596
2480
  mediaDirections: MediaDirections;
2481
+ nodeId?: string;
1597
2482
  }
1598
2483
  interface OutboundCallProvider {
1599
2484
  createOutboundCall(destination: string | Address, options?: CallOptions): Promise<Call>;
1600
2485
  }
2486
+ interface Attachment {
2487
+ destination: string;
2488
+ mediaDirections: MediaDirections;
2489
+ audioInputDevice: MediaDeviceInfo | null;
2490
+ videoInputDevice: MediaDeviceInfo | null;
2491
+ nodeId?: string;
2492
+ attachedAt: number;
2493
+ }
1601
2494
  declare class AttachManager {
1602
2495
  private readonly storage;
1603
2496
  private readonly deviceController;
@@ -1612,8 +2505,32 @@ declare class AttachManager {
1612
2505
  attach(call: AttachableCall): Promise<void>;
1613
2506
  detach(call: AttachableCall): Promise<void>;
1614
2507
  flush(): Promise<void>;
2508
+ /**
2509
+ * Reattach to previously active calls by sending verto.invite with
2510
+ * reattaching: true.
2511
+ *
2512
+ * NOTE: This currently fails with INVALID_CALL_REFERENCE because the
2513
+ * server's jsock UUID check rejects the new connection's UUID. A
2514
+ * server-side fix is needed: when reattaching: true is explicitly set
2515
+ * in dialogParams, FreeSWITCH's attempt_reattach() should update the
2516
+ * call's jsock reference to the new connection's UUID instead of
2517
+ * rejecting. Once that fix is deployed, this will work for both
2518
+ * page reloads and WebSocket reconnects.
2519
+ *
2520
+ * Failed reattach attempts are handled gracefully — the stale call
2521
+ * reference is cleaned up from storage.
2522
+ */
1615
2523
  reattachCalls(): Promise<void>;
1616
- private buildCallOptions;
2524
+ /**
2525
+ * Build CallOptions from stored attachment data for a call being reattached.
2526
+ * Also used by the session-level verto.attach handler.
2527
+ */
2528
+ buildCallOptions(attachment: Attachment): CallOptions;
2529
+ /**
2530
+ * Consume stored attachment data for a pending call (used by session-level
2531
+ * verto.attach handler as a future path when server supports it).
2532
+ */
2533
+ consumePendingAttachment(_callId: string): CallOptions | undefined;
1617
2534
  private detachExpired;
1618
2535
  }
1619
2536
  //#endregion
@@ -1628,6 +2545,16 @@ declare class TransportManager extends Destroyable {
1628
2545
  private isConnected;
1629
2546
  private ackEvent;
1630
2547
  private replySignalwirePing;
2548
+ /**
2549
+ * Filter that drops events from a previous session after reconnect.
2550
+ *
2551
+ * Compares the event's `event_channel` against the current protocol.
2552
+ * Events whose channel doesn't contain the current protocol are from
2553
+ * a stale session and are discarded. Events without an event_channel
2554
+ * (auth state events, RPC responses) always pass through.
2555
+ */
2556
+ private discardStaleEvents;
2557
+ private _currentProtocol;
1631
2558
  private _outgoingMessages$;
1632
2559
  private _webSocketConnections;
1633
2560
  private _jsonRPCMessage$;
@@ -1648,6 +2575,101 @@ declare class TransportManager extends Destroyable {
1648
2575
  private _init;
1649
2576
  }
1650
2577
  //#endregion
2578
+ //#region src/controllers/CryptoController.d.ts
2579
+ /**
2580
+ * Controls DPoP (Demonstrating Proof-of-Possession) cryptographic operations.
2581
+ *
2582
+ * Generates an RSA-2048 key pair where the private key is non-extractable,
2583
+ * computes the JWK Thumbprint (RFC 7638) as the fingerprint, and creates
2584
+ * signed DPoP proof JWTs for both HTTP API requests and WebSocket RPC calls.
2585
+ *
2586
+ * The key pair is persisted in IndexedDB so the same fingerprint survives
2587
+ * page reloads. This keeps the Client Bound SAT and stored authorization_state
2588
+ * valid across reloads without needing to re-authenticate.
2589
+ *
2590
+ * @example
2591
+ * ```typescript
2592
+ * const crypto = new CryptoController();
2593
+ * await crypto.init();
2594
+ *
2595
+ * // Get fingerprint for SAT issuance
2596
+ * const fingerprint = crypto.fingerprint;
2597
+ *
2598
+ * // Create proof for HTTP endpoint
2599
+ * const httpProof = await crypto.createHttpProof({
2600
+ * method: 'POST',
2601
+ * uri: '/api/fabric/subscriber/devices/token'
2602
+ * });
2603
+ *
2604
+ * // Create proof for RPC call
2605
+ * const rpcProof = await crypto.createRpcProof({
2606
+ * method: 'signalwire.connect'
2607
+ * });
2608
+ * ```
2609
+ */
2610
+ declare class CryptoController {
2611
+ private _keyPair;
2612
+ private _publicJwk;
2613
+ private _fingerprint;
2614
+ private _initialized;
2615
+ /**
2616
+ * Initializes the DPoP key pair. Loads an existing key from IndexedDB
2617
+ * if available, otherwise generates a new one and persists it.
2618
+ *
2619
+ * The private key is non-extractable — IndexedDB stores the CryptoKey
2620
+ * handle via the structured clone algorithm without exposing key material.
2621
+ *
2622
+ * @returns The JWK Thumbprint (fingerprint) for the key.
2623
+ */
2624
+ init(): Promise<string>;
2625
+ /**
2626
+ * The JWK Thumbprint (RFC 7638) of the public key.
2627
+ * Used as the `fingerprint` parameter when requesting scoped SATs.
2628
+ *
2629
+ * @throws {DPoPInitError} If {@link init} has not been called.
2630
+ */
2631
+ get fingerprint(): string;
2632
+ /**
2633
+ * Whether the controller has been initialized with a key pair.
2634
+ */
2635
+ get initialized(): boolean;
2636
+ /**
2637
+ * Creates a DPoP proof JWT for an HTTP API request.
2638
+ *
2639
+ * Used for Prime API endpoints like `/api/fabric/subscriber/devices/token`
2640
+ * and `/api/fabric/subscriber/devices/refresh`.
2641
+ *
2642
+ * @param params - HTTP method and URI for the proof.
2643
+ * @returns Signed DPoP proof JWT string.
2644
+ */
2645
+ createHttpProof(params: DPoPHttpProofParams): Promise<string>;
2646
+ /**
2647
+ * Creates a DPoP proof JWT for a WebSocket RPC call.
2648
+ *
2649
+ * Used for switchblade RPC methods like `signalwire.connect` and
2650
+ * `signalwire.reauthenticate`.
2651
+ *
2652
+ * @param params - RPC method name for the proof.
2653
+ * @returns Signed DPoP proof JWT string.
2654
+ */
2655
+ createRpcProof(params: DPoPRpcProofParams): Promise<string>;
2656
+ /**
2657
+ * Releases the key pair references and removes the persisted key from IndexedDB.
2658
+ * After calling destroy, the controller must be re-initialized to be used again.
2659
+ */
2660
+ destroy(): void;
2661
+ private get publicJwk();
2662
+ private get privateKey();
2663
+ private signProof;
2664
+ }
2665
+ //#endregion
2666
+ //#region src/controllers/NetworkMonitor.d.ts
2667
+ interface NetworkChangeEvent {
2668
+ type: 'online' | 'offline' | 'connection_change';
2669
+ timestamp: number;
2670
+ networkType?: string;
2671
+ }
2672
+ //#endregion
1651
2673
  //#region src/core/entities/Directory.d.ts
1652
2674
  /**
1653
2675
  * Directory interface for managing addresses
@@ -1721,30 +2743,93 @@ interface ClientSession {
1721
2743
  * Used by VertoManager to configure RTCPeerConnection
1722
2744
  */
1723
2745
  readonly iceServers: RTCIceServer[] | undefined;
2746
+ /**
2747
+ * Emits true when the session is authenticated, false when not.
2748
+ * Used by Call to detect WebSocket reconnections (skip(1) + filter(true)
2749
+ * indicates a re-authentication after the initial connect).
2750
+ */
2751
+ readonly authenticated$: Observable<boolean>;
2752
+ }
2753
+ //#endregion
2754
+ //#region src/interfaces/SessionState.d.ts
2755
+ /**
2756
+ * Extended session interface that adds call management and authentication
2757
+ * state on top of the narrow ClientSession contract.
2758
+ *
2759
+ * Accessible via `client.session`. Call and CallFactory continue to depend
2760
+ * only on the narrow ClientSession interface.
2761
+ */
2762
+ interface SessionState extends ClientSession {
2763
+ /**
2764
+ * Observable stream of currently active inbound calls.
2765
+ * Filters `calls$` to only include calls with `direction === 'inbound'`.
2766
+ */
2767
+ readonly incomingCalls$: Observable<Call[]>;
2768
+ /**
2769
+ * Current snapshot of active inbound calls.
2770
+ */
2771
+ readonly incomingCalls: Call[];
2772
+ /**
2773
+ * Observable stream of all currently active calls (both inbound and outbound).
2774
+ */
2775
+ readonly calls$: Observable<Call[]>;
2776
+ /**
2777
+ * Current snapshot of all active calls.
2778
+ */
2779
+ readonly calls: Call[];
2780
+ /**
2781
+ * Observable that emits `true` once the session has been authenticated,
2782
+ * and `false` after disconnect.
2783
+ */
2784
+ readonly authenticated$: Observable<boolean>;
2785
+ /**
2786
+ * Current authentication state.
2787
+ * Returns `true` if the session is currently authenticated.
2788
+ */
2789
+ readonly authenticated: boolean;
1724
2790
  }
1725
2791
  //#endregion
1726
2792
  //#region src/managers/ClientSessionManager.d.ts
1727
- declare class ClientSessionManager extends Destroyable implements ClientSession {
1728
- private credential;
2793
+ /**
2794
+ * Discriminated union for session authentication state.
2795
+ * clientBound is tracked separately via _wasClientBound (sticky flag)
2796
+ * to avoid dual sources of truth.
2797
+ */
2798
+ type SessionAuthState = {
2799
+ kind: 'unauthenticated';
2800
+ } | {
2801
+ kind: 'authenticated';
2802
+ };
2803
+ declare class ClientSessionManager extends Destroyable implements SessionState {
2804
+ private readonly getCredential;
1729
2805
  private readonly transport;
1730
2806
  private readonly storage;
1731
2807
  private readonly authorizationStateKey;
1732
2808
  private readonly attachManager;
2809
+ private readonly dpopManager?;
1733
2810
  private callFactory;
1734
2811
  private callCreateTimeout;
1735
2812
  private readonly agent;
1736
2813
  private readonly eventAcks;
1737
2814
  initialized$: Observable<boolean>;
1738
- authorization$: rxjs0.Subject<Authorization>;
1739
2815
  private authorizationState$;
1740
2816
  private connectVersion;
2817
+ /**
2818
+ * Optional hook called before a fresh connect on reconnect.
2819
+ * Used by SignalWire to refresh expired credentials before re-authenticating.
2820
+ * @internal
2821
+ */
2822
+ onBeforeReconnect?: () => Promise<void>;
2823
+ private _authorization$;
1741
2824
  private _errors$;
1742
2825
  private _directory?;
1743
- private _authenticated$;
2826
+ private _authState$;
2827
+ /** Sticky flag — once true, stays true for the session lifetime. */
2828
+ private _wasClientBound;
1744
2829
  private _subscriberInfo$;
1745
2830
  private _calls$;
1746
2831
  private _iceServers$;
1747
- constructor(credential: SDKCredential, transport: TransportManager, storage: StorageManager, authorizationStateKey: string, deviceController: DeviceController, attachManager: AttachManager);
2832
+ constructor(getCredential: () => SDKCredential, transport: TransportManager, storage: StorageManager, authorizationStateKey: string, deviceController: DeviceController, attachManager: AttachManager, webRTCApiProvider: WebRTCApiProvider, dpopManager?: CryptoController | undefined, networkChange$?: Observable<NetworkChangeEvent>);
1748
2833
  get incomingCalls$(): Observable<Call[]>;
1749
2834
  get incomingCalls(): Call[];
1750
2835
  get subscriberInfo$(): Observable<Address | null>;
@@ -1752,9 +2837,20 @@ declare class ClientSessionManager extends Destroyable implements ClientSession
1752
2837
  get calls$(): Observable<Call[]>;
1753
2838
  get calls(): Call[];
1754
2839
  get iceServers(): RTCIceServer[] | undefined;
2840
+ get authorization$(): Observable<Authorization | undefined>;
2841
+ get authorization(): Authorization | undefined;
1755
2842
  get errors$(): Observable<Error>;
1756
2843
  get authenticated$(): Observable<boolean>;
1757
2844
  get authenticated(): boolean;
2845
+ /**
2846
+ * Whether this session is client-bound (using a Client Bound SAT).
2847
+ * When client-bound, DPoP proof creation failures are treated as
2848
+ * authentication errors rather than silently degraded.
2849
+ * @internal
2850
+ */
2851
+ get clientBound(): boolean;
2852
+ /** @internal Current auth state for debugging/testing. */
2853
+ get authState(): SessionAuthState;
1758
2854
  /**
1759
2855
  * Set the directory instance
1760
2856
  * Called by SignalWire after directory is created
@@ -1768,85 +2864,158 @@ declare class ClientSessionManager extends Destroyable implements ClientSession
1768
2864
  private loadAuthorizationStateFromStorage;
1769
2865
  private updateAuthorizationStateInStorage;
1770
2866
  private get authStateEvent$();
1771
- get signalingEvent$(): Observable<{
2867
+ get signalingEvent$(): Observable<(Omit<{
1772
2868
  event_type: "webrtc.message";
1773
- event_channel: string;
2869
+ event_channel: EventChannel;
1774
2870
  timestamp: number;
2871
+ project_id?: string;
2872
+ node_id?: string;
2873
+ is_author?: boolean;
2874
+ params: WebrtcMessagePayload;
2875
+ }, "event_channel" | "project_id" | "node_id"> & {
2876
+ event_channel: string;
1775
2877
  project_id: string;
1776
2878
  node_id: string;
1777
- params: WebrtcMessagePayload;
1778
- } | {
2879
+ }) | {
1779
2880
  event_type: "signalwire.authorization.state";
1780
2881
  params: SignalwireAuthorizationStatePayload;
1781
- } | {
2882
+ } | (Omit<{
1782
2883
  event_type: "call.joined";
1783
- event_channel: string;
2884
+ event_channel: EventChannel;
1784
2885
  timestamp: number;
2886
+ project_id?: string;
2887
+ node_id?: string;
2888
+ is_author?: boolean;
1785
2889
  params: CallJoinedPayload;
1786
- } | {
1787
- event_type: "call.left";
2890
+ }, "event_channel"> & {
1788
2891
  event_channel: string;
2892
+ }) | (Omit<{
2893
+ event_type: "call.left";
2894
+ event_channel: EventChannel;
1789
2895
  timestamp: number;
2896
+ project_id?: string;
2897
+ node_id?: string;
2898
+ is_author?: boolean;
1790
2899
  params: CallLeftPayload;
1791
- } | {
1792
- event_type: "call.updated";
2900
+ }, "event_channel"> & {
1793
2901
  event_channel: string;
2902
+ }) | (Omit<{
2903
+ event_type: "call.updated";
2904
+ event_channel: EventChannel;
1794
2905
  timestamp: number;
2906
+ project_id?: string;
2907
+ node_id?: string;
2908
+ is_author?: boolean;
1795
2909
  params: CallUpdatedPayload;
1796
- } | {
1797
- event_type: "call.state";
2910
+ }, "event_channel"> & {
1798
2911
  event_channel: string;
2912
+ }) | (Omit<{
2913
+ event_type: "call.state";
2914
+ event_channel: EventChannel;
1799
2915
  timestamp: number;
2916
+ project_id?: string;
2917
+ node_id?: string;
2918
+ is_author?: boolean;
1800
2919
  params: CallStatePayload;
1801
- } | {
1802
- event_type: "call.play";
2920
+ }, "event_channel"> & {
1803
2921
  event_channel: string;
2922
+ }) | (Omit<{
2923
+ event_type: "call.play";
2924
+ event_channel: EventChannel;
1804
2925
  timestamp: number;
2926
+ project_id?: string;
2927
+ node_id?: string;
2928
+ is_author?: boolean;
1805
2929
  params: CallPlayPayload;
1806
- } | {
1807
- event_type: "call.connect";
2930
+ }, "event_channel"> & {
1808
2931
  event_channel: string;
2932
+ }) | (Omit<{
2933
+ event_type: "call.connect";
2934
+ event_channel: EventChannel;
1809
2935
  timestamp: number;
2936
+ project_id?: string;
2937
+ node_id?: string;
2938
+ is_author?: boolean;
1810
2939
  params: CallConnectPayload;
1811
- } | {
2940
+ }, "event_channel"> & {
2941
+ event_channel: string;
2942
+ }) | (Omit<{
2943
+ event_type: "room.updated";
2944
+ event_channel: EventChannel;
2945
+ timestamp: number;
2946
+ project_id?: string;
2947
+ node_id?: string;
2948
+ is_author?: boolean;
2949
+ params: RoomUpdatedPayload;
2950
+ }, "event_channel"> & {
2951
+ event_channel: string;
2952
+ }) | Omit<{
1812
2953
  event_type: "member.updated";
1813
2954
  event_channel: EventChannel;
1814
2955
  timestamp: number;
2956
+ project_id?: string;
2957
+ node_id?: string;
2958
+ is_author?: boolean;
1815
2959
  params: MemberUpdatedPayload;
1816
- } | {
2960
+ }, never> | Omit<{
1817
2961
  event_type: "member.joined";
1818
2962
  event_channel: EventChannel;
1819
2963
  timestamp: number;
2964
+ project_id?: string;
2965
+ node_id?: string;
2966
+ is_author?: boolean;
1820
2967
  params: MemberJoinedPayload;
1821
- } | {
2968
+ }, never> | Omit<{
1822
2969
  event_type: "member.left";
1823
2970
  event_channel: EventChannel;
1824
2971
  timestamp: number;
2972
+ project_id?: string;
2973
+ node_id?: string;
2974
+ is_author?: boolean;
1825
2975
  params: MemberLeftPayload;
1826
- } | {
2976
+ }, never> | Omit<{
1827
2977
  event_type: "member.talking";
1828
2978
  event_channel: EventChannel;
1829
2979
  timestamp: number;
2980
+ project_id?: string;
2981
+ node_id?: string;
2982
+ is_author?: boolean;
1830
2983
  params: MemberTalkingPayload;
1831
- } | {
2984
+ }, never> | Omit<{
1832
2985
  event_type: "layout.changed";
1833
2986
  event_channel: EventChannel;
1834
2987
  timestamp: number;
2988
+ project_id?: string;
2989
+ node_id?: string;
2990
+ is_author?: boolean;
1835
2991
  params: LayoutChangedPayload;
1836
- } | {
2992
+ }, never> | (Omit<{
1837
2993
  event_type: "conversation.message";
2994
+ event_channel: EventChannel;
2995
+ timestamp: number;
2996
+ project_id?: string;
2997
+ node_id?: string;
2998
+ is_author?: boolean;
2999
+ params: ConversationMessagePayload;
3000
+ }, "event_channel" | "timestamp" | "is_author"> & {
1838
3001
  event_channel: string;
1839
3002
  timestamp: string;
1840
3003
  is_author: boolean;
1841
- params: ConversationMessagePayload;
1842
- } | {
3004
+ }) | (Omit<{
1843
3005
  event_type: "conversation.message.updated";
3006
+ event_channel: EventChannel;
3007
+ timestamp: number;
3008
+ project_id?: string;
3009
+ node_id?: string;
3010
+ is_author?: boolean;
3011
+ params: ConversationMessagePayload;
3012
+ }, "event_channel" | "timestamp" | "is_author"> & {
1844
3013
  event_channel: string;
1845
3014
  timestamp: string;
1846
3015
  is_author: boolean;
1847
- params: ConversationMessageUpdatedPayload;
1848
- }>;
3016
+ })>;
1849
3017
  private get vertoInvite$();
3018
+ private get vertoAttach$();
1850
3019
  private get contexts();
1851
3020
  private get eventing();
1852
3021
  private get topics();
@@ -1855,96 +3024,182 @@ declare class ClientSessionManager extends Destroyable implements ClientSession
1855
3024
  private handleAuthenticationError;
1856
3025
  cleanupStoredConnectionParams(): Promise<void>;
1857
3026
  protected updateAuthState(authorization_state: string): Promise<void>;
3027
+ reauthenticate(token: string, dpopToken?: string, options?: {
3028
+ clientBound?: boolean;
3029
+ }): Promise<void>;
1858
3030
  private authenticate;
1859
3031
  disconnect(): Promise<void>;
1860
3032
  private createInboundCall;
3033
+ /**
3034
+ * Handle a server-pushed verto.attach event at the session level.
3035
+ *
3036
+ * On page reload the server detects the reconnected session and pushes
3037
+ * verto.attach for any active calls. If a call object already exists
3038
+ * (network blip, no reload), the per-call handler in VertoManager deals
3039
+ * with it. This method only creates a new call object when no existing
3040
+ * one matches the callID.
3041
+ */
3042
+ private handleVertoAttach;
1861
3043
  createOutboundCall(destination: string | Address, options?: CallOptions): Promise<Call>;
1862
3044
  private createCall;
1863
3045
  destroy(): void;
1864
3046
  }
1865
- declare class ClientSessionWrapper {
3047
+ declare class ClientSessionWrapper implements SessionState {
1866
3048
  private clientSessionManager;
1867
3049
  constructor(clientSessionManager: ClientSessionManager);
1868
3050
  get authenticated$(): Observable<boolean>;
1869
3051
  get authenticated(): boolean;
1870
- get signalingEvent$(): Observable<{
3052
+ get signalingEvent$(): Observable<(Omit<{
1871
3053
  event_type: "webrtc.message";
1872
- event_channel: string;
3054
+ event_channel: EventChannel;
1873
3055
  timestamp: number;
3056
+ project_id?: string;
3057
+ node_id?: string;
3058
+ is_author?: boolean;
3059
+ params: WebrtcMessagePayload;
3060
+ }, "event_channel" | "project_id" | "node_id"> & {
3061
+ event_channel: string;
1874
3062
  project_id: string;
1875
3063
  node_id: string;
1876
- params: WebrtcMessagePayload;
1877
- } | {
3064
+ }) | {
1878
3065
  event_type: "signalwire.authorization.state";
1879
3066
  params: SignalwireAuthorizationStatePayload;
1880
- } | {
3067
+ } | (Omit<{
1881
3068
  event_type: "call.joined";
1882
- event_channel: string;
3069
+ event_channel: EventChannel;
1883
3070
  timestamp: number;
3071
+ project_id?: string;
3072
+ node_id?: string;
3073
+ is_author?: boolean;
1884
3074
  params: CallJoinedPayload;
1885
- } | {
1886
- event_type: "call.left";
3075
+ }, "event_channel"> & {
1887
3076
  event_channel: string;
3077
+ }) | (Omit<{
3078
+ event_type: "call.left";
3079
+ event_channel: EventChannel;
1888
3080
  timestamp: number;
3081
+ project_id?: string;
3082
+ node_id?: string;
3083
+ is_author?: boolean;
1889
3084
  params: CallLeftPayload;
1890
- } | {
1891
- event_type: "call.updated";
3085
+ }, "event_channel"> & {
1892
3086
  event_channel: string;
3087
+ }) | (Omit<{
3088
+ event_type: "call.updated";
3089
+ event_channel: EventChannel;
1893
3090
  timestamp: number;
3091
+ project_id?: string;
3092
+ node_id?: string;
3093
+ is_author?: boolean;
1894
3094
  params: CallUpdatedPayload;
1895
- } | {
1896
- event_type: "call.state";
3095
+ }, "event_channel"> & {
1897
3096
  event_channel: string;
3097
+ }) | (Omit<{
3098
+ event_type: "call.state";
3099
+ event_channel: EventChannel;
1898
3100
  timestamp: number;
3101
+ project_id?: string;
3102
+ node_id?: string;
3103
+ is_author?: boolean;
1899
3104
  params: CallStatePayload;
1900
- } | {
1901
- event_type: "call.play";
3105
+ }, "event_channel"> & {
1902
3106
  event_channel: string;
3107
+ }) | (Omit<{
3108
+ event_type: "call.play";
3109
+ event_channel: EventChannel;
1903
3110
  timestamp: number;
3111
+ project_id?: string;
3112
+ node_id?: string;
3113
+ is_author?: boolean;
1904
3114
  params: CallPlayPayload;
1905
- } | {
1906
- event_type: "call.connect";
3115
+ }, "event_channel"> & {
1907
3116
  event_channel: string;
3117
+ }) | (Omit<{
3118
+ event_type: "call.connect";
3119
+ event_channel: EventChannel;
1908
3120
  timestamp: number;
3121
+ project_id?: string;
3122
+ node_id?: string;
3123
+ is_author?: boolean;
1909
3124
  params: CallConnectPayload;
1910
- } | {
3125
+ }, "event_channel"> & {
3126
+ event_channel: string;
3127
+ }) | (Omit<{
3128
+ event_type: "room.updated";
3129
+ event_channel: EventChannel;
3130
+ timestamp: number;
3131
+ project_id?: string;
3132
+ node_id?: string;
3133
+ is_author?: boolean;
3134
+ params: RoomUpdatedPayload;
3135
+ }, "event_channel"> & {
3136
+ event_channel: string;
3137
+ }) | Omit<{
1911
3138
  event_type: "member.updated";
1912
3139
  event_channel: EventChannel;
1913
3140
  timestamp: number;
3141
+ project_id?: string;
3142
+ node_id?: string;
3143
+ is_author?: boolean;
1914
3144
  params: MemberUpdatedPayload;
1915
- } | {
3145
+ }, never> | Omit<{
1916
3146
  event_type: "member.joined";
1917
3147
  event_channel: EventChannel;
1918
3148
  timestamp: number;
3149
+ project_id?: string;
3150
+ node_id?: string;
3151
+ is_author?: boolean;
1919
3152
  params: MemberJoinedPayload;
1920
- } | {
3153
+ }, never> | Omit<{
1921
3154
  event_type: "member.left";
1922
3155
  event_channel: EventChannel;
1923
3156
  timestamp: number;
3157
+ project_id?: string;
3158
+ node_id?: string;
3159
+ is_author?: boolean;
1924
3160
  params: MemberLeftPayload;
1925
- } | {
3161
+ }, never> | Omit<{
1926
3162
  event_type: "member.talking";
1927
3163
  event_channel: EventChannel;
1928
3164
  timestamp: number;
3165
+ project_id?: string;
3166
+ node_id?: string;
3167
+ is_author?: boolean;
1929
3168
  params: MemberTalkingPayload;
1930
- } | {
3169
+ }, never> | Omit<{
1931
3170
  event_type: "layout.changed";
1932
3171
  event_channel: EventChannel;
1933
3172
  timestamp: number;
3173
+ project_id?: string;
3174
+ node_id?: string;
3175
+ is_author?: boolean;
1934
3176
  params: LayoutChangedPayload;
1935
- } | {
3177
+ }, never> | (Omit<{
1936
3178
  event_type: "conversation.message";
3179
+ event_channel: EventChannel;
3180
+ timestamp: number;
3181
+ project_id?: string;
3182
+ node_id?: string;
3183
+ is_author?: boolean;
3184
+ params: ConversationMessagePayload;
3185
+ }, "event_channel" | "timestamp" | "is_author"> & {
1937
3186
  event_channel: string;
1938
3187
  timestamp: string;
1939
3188
  is_author: boolean;
1940
- params: ConversationMessagePayload;
1941
- } | {
3189
+ }) | (Omit<{
1942
3190
  event_type: "conversation.message.updated";
3191
+ event_channel: EventChannel;
3192
+ timestamp: number;
3193
+ project_id?: string;
3194
+ node_id?: string;
3195
+ is_author?: boolean;
3196
+ params: ConversationMessagePayload;
3197
+ }, "event_channel" | "timestamp" | "is_author"> & {
1943
3198
  event_channel: string;
1944
3199
  timestamp: string;
1945
3200
  is_author: boolean;
1946
- params: ConversationMessageUpdatedPayload;
1947
- }>;
3201
+ })>;
3202
+ get iceServers(): RTCIceServer[] | undefined;
1948
3203
  execute<T extends JSONRPCResponse = JSONRPCResponse>(request: JSONRPCRequest, options?: PendingRPCOptions): Promise<T>;
1949
3204
  get incomingCalls$(): Observable<Call[]>;
1950
3205
  get incomingCalls(): Call[];
@@ -1952,6 +3207,35 @@ declare class ClientSessionWrapper {
1952
3207
  get calls(): Call[];
1953
3208
  }
1954
3209
  //#endregion
3210
+ //#region src/utils/logger.d.ts
3211
+ /** Log level names supported by the SDK. */
3212
+ type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent';
3213
+ /**
3214
+ * Logger interface that consumers can implement to replace the built-in logger.
3215
+ * All methods accept variadic arguments matching the browser console API.
3216
+ */
3217
+ interface SDKLogger {
3218
+ error(...args: unknown[]): void;
3219
+ warn(...args: unknown[]): void;
3220
+ info(...args: unknown[]): void;
3221
+ debug(...args: unknown[]): void;
3222
+ trace(...args: unknown[]): void;
3223
+ }
3224
+ /** Debug options that control verbose SDK logging. */
3225
+ interface DebugOptions {
3226
+ /** Log all WebSocket send/recv traffic to the console. */
3227
+ logWsTraffic?: boolean;
3228
+ }
3229
+ /** Replace the built-in logger with a custom implementation. Pass `null` to restore defaults. */
3230
+ declare const setLogger: (logger: SDKLogger | null) => void;
3231
+ /** Configure debug options (e.g., `{ logWsTraffic: true }`). */
3232
+ declare const setDebugOptions: (options: DebugOptions | null) => void;
3233
+ /**
3234
+ * Set the log level for the built-in logger.
3235
+ * Has no effect when a custom logger is set via `setLogger()`.
3236
+ */
3237
+ declare const setLogLevel: (level: LogLevel) => void;
3238
+ //#endregion
1955
3239
  //#region src/clients/SignalWire.d.ts
1956
3240
  /** Options for constructing a {@link SignalWire}. */
1957
3241
  interface SignalWireOptions {
@@ -1959,21 +3243,62 @@ interface SignalWireOptions {
1959
3243
  skipConnection?: boolean;
1960
3244
  /** Skip automatic subscriber registration on construction. */
1961
3245
  skipRegister?: boolean;
1962
- /** Skip reconnecting to previously attached calls. */
1963
- skipReconnect?: boolean;
1964
3246
  /** Skip monitoring media device changes. */
1965
3247
  skipDeviceMonitoring?: boolean;
1966
3248
  /** Whether to reconnect to previously attached calls. */
1967
3249
  reconnectAttachedCalls?: boolean;
1968
3250
  /** Whether to save preferences. */
1969
3251
  savePreferences?: boolean;
3252
+ /**
3253
+ * Persist the session across page reloads.
3254
+ *
3255
+ * When `true`, credential, authorization state, and protocol are stored in
3256
+ * `localStorage` (survives reload). The DPoP key pair is persisted in
3257
+ * IndexedDB. On reload, the SDK restores the session from cache
3258
+ * without calling `credentialProvider.authenticate()`.
3259
+ *
3260
+ * When `false` (default), session data lives in `sessionStorage` and is
3261
+ * lost on reload.
3262
+ *
3263
+ * Call {@link SignalWire.destroy | destroy()} to clear all persisted state
3264
+ * (explicit logout).
3265
+ */
3266
+ persistSession?: boolean;
1970
3267
  /** Custom storage implementation for persistence. */
1971
3268
  storageImplementation?: Storage;
1972
3269
  /** Custom WebSocket constructor */
1973
3270
  webSocketConstructor?: WebSocketAdapter | NodeSocketAdapter;
3271
+ /** Custom WebRTC API provider */
3272
+ webRTCApiProvider?: WebRTCApiProvider;
3273
+ /**
3274
+ * Custom logger implementation. Must implement the {@link SDKLogger} interface.
3275
+ * Pass `null` to restore the built-in logger.
3276
+ *
3277
+ * **Note:** Logger configuration is global — setting it on one instance affects all instances.
3278
+ */
3279
+ logger?: SDKLogger | null;
3280
+ /**
3281
+ * Log level for the built-in logger.
3282
+ * Default: `'warn'`. Set to `'debug'` for verbose SDK output.
3283
+ * Has no effect when a custom `logger` is provided.
3284
+ *
3285
+ * **Note:** Logger configuration is global — setting it on one instance affects all instances.
3286
+ */
3287
+ logLevel?: LogLevel;
3288
+ /** Debug options for verbose SDK diagnostics (e.g., `{ logWsTraffic: true }`). */
3289
+ debug?: DebugOptions;
1974
3290
  }
1975
3291
  /** Options for {@link SignalWire.dial}. Extends {@link MediaOptions} with dial-specific settings. */
1976
- interface DialOptions extends MediaOptions {}
3292
+ interface DialOptions extends MediaOptions {
3293
+ /** Preferred video codecs for this call (overrides global preferences). */
3294
+ preferredVideoCodecs?: string[];
3295
+ /** Preferred audio codecs for this call (overrides global preferences). */
3296
+ preferredAudioCodecs?: string[];
3297
+ /** Enable stereo Opus for this call (overrides global preferences). */
3298
+ stereo?: boolean;
3299
+ /** Optional node ID for routing the call */
3300
+ nodeId?: string;
3301
+ }
1977
3302
  /**
1978
3303
  * Main entry point for the SignalWire Browser SDK.
1979
3304
  *
@@ -2001,9 +3326,43 @@ declare class SignalWire extends Destroyable implements DeviceController {
2001
3326
  private _errors$;
2002
3327
  private _options;
2003
3328
  private _refreshTimerId?;
3329
+ private _dpopManager?;
3330
+ private _deviceTokenManager?;
3331
+ private _credentialProvider?;
2004
3332
  private _deps;
2005
- constructor(credentialProvider: CredentialProvider, options?: SignalWireOptions);
3333
+ private _networkMonitor?;
3334
+ private _visibilityController?;
3335
+ private _diagnosticsCollector?;
3336
+ private _platformCapabilities?;
3337
+ /**
3338
+ * Creates a new SignalWire client and begins connecting.
3339
+ *
3340
+ * @param credentialProvider - Provider that supplies authentication credentials.
3341
+ * @param options - Configuration options (connection, device monitoring, preferences).
3342
+ */
3343
+ constructor(credentialProvider: CredentialProvider | undefined, options?: SignalWireOptions);
3344
+ /**
3345
+ * Initializes DPoP if not already set up. Returns the fingerprint on success.
3346
+ */
3347
+ private initDPoP;
3348
+ /**
3349
+ * Resolves credentials using cache-first strategy when persistSession is enabled.
3350
+ *
3351
+ * 1. If persistSession → check localStorage for cached credential
3352
+ * 2. If cached and not expired → use it (skip provider.authenticate())
3353
+ * 3. If no cache or expired → call provider.authenticate()
3354
+ * 4. If no provider AND no cache → throw
3355
+ */
3356
+ private resolveCredentials;
2006
3357
  private validateCredentials;
3358
+ /**
3359
+ * Schedules credential refresh with exponential backoff retry on failure.
3360
+ * On success, resets attempt counter and schedules the next refresh.
3361
+ * After exhausting retries, emits TokenRefreshError and disconnects.
3362
+ */
3363
+ private scheduleCredentialRefresh;
3364
+ /** Persist credential to localStorage when persistSession is enabled. */
3365
+ private persistCredential;
2007
3366
  private init;
2008
3367
  private handleAttachments;
2009
3368
  /**
@@ -2016,9 +3375,9 @@ declare class SignalWire extends Destroyable implements DeviceController {
2016
3375
  * unexpectedly (e.g. network change, server restart). Reconnection uses an
2017
3376
  * **exponential back-off** strategy:
2018
3377
  *
2019
- * - First retry after `reconnectDelayMin` (default **1 s**).
3378
+ * - First retry after `reconnectDelayMin` (default **0.1 s**).
2020
3379
  * - Each subsequent retry doubles the delay up to `reconnectDelayMax`
2021
- * (default **30 s**).
3380
+ * (default **3 s**).
2022
3381
  * - The delay resets to `reconnectDelayMin` once a connection succeeds.
2023
3382
  * - A per-attempt `connectionTimeout` (default **10 s**) aborts the
2024
3383
  * attempt and schedules the next retry if the server does not respond.
@@ -2088,20 +3447,89 @@ declare class SignalWire extends Destroyable implements DeviceController {
2088
3447
  get ready$(): Observable<boolean>;
2089
3448
  /** Observable stream of errors from transport, authentication, and devices. */
2090
3449
  get errors$(): Observable<Error>;
2091
- /** Disconnects the WebSocket and tears down the session. */
3450
+ /** Platform WebRTC capabilities detected at construction time. */
3451
+ get platformCapabilities(): PlatformCapabilities;
3452
+ /** Observable that emits when the SDK auto-switches a device. */
3453
+ get deviceRecovered$(): Observable<DeviceRecoveryEvent>;
3454
+ /**
3455
+ * Export a structured diagnostic bundle for support/debugging.
3456
+ * Includes connection events, call summaries, and device changes.
3457
+ */
3458
+ exportDiagnostics(): SessionDiagnostics;
3459
+ /**
3460
+ * Initialize resilience subsystems. Non-fatal: any failure is logged and
3461
+ * the SDK continues working without the failing subsystem.
3462
+ */
3463
+ private initResilienceSubsystems;
3464
+ /**
3465
+ * Disconnects the WebSocket and tears down the current session.
3466
+ *
3467
+ * The client can be reconnected by calling {@link connect} again,
3468
+ * which creates a fresh transport and session.
3469
+ */
2092
3470
  disconnect(): Promise<void>;
2093
3471
  private waitAuthentication;
2094
- /** Registers the subscriber as online to receive inbound calls and events. */
3472
+ /**
3473
+ * Registers the subscriber as online to receive inbound calls and events.
3474
+ *
3475
+ * Waits for authentication to complete before sending the registration.
3476
+ * If the initial attempt fails, reauthentication is attempted automatically.
3477
+ *
3478
+ * @throws {InvalidCredentialsError} If registration and reauthentication both fail.
3479
+ */
2095
3480
  register(): Promise<void>;
2096
- /** Unregisters the subscriber, going offline for inbound calls. */
3481
+ /**
3482
+ * Unregisters the subscriber, going offline for inbound calls.
3483
+ *
3484
+ * The WebSocket connection remains open; use {@link disconnect} to fully close it.
3485
+ */
2097
3486
  unregister(): Promise<void>;
2098
3487
  /**
2099
3488
  * Places an outbound call to the given destination.
2100
- * @param destination - Address URI string or {@link Address} instance to call.
2101
- * @param options - Media and dial options (audio/video, constraints).
3489
+ *
3490
+ * Waits for authentication before dialing. Media options are merged from
3491
+ * saved preferences, destination query parameters (e.g. `?channel=video`),
3492
+ * and the provided `options` (highest priority).
3493
+ *
3494
+ * Returns a {@link Call} in `'ringing'` state. Subscribe to {@link Call.status$}
3495
+ * to track progression through `'connected'` → `'disconnected'`.
3496
+ *
3497
+ * @param destination - Address URI string (e.g. `'/public/my-room'`) or {@link Address} instance.
3498
+ * @param options - Media and dial options (audio/video, device constraints). Overrides defaults.
2102
3499
  * @returns The created {@link Call} instance.
3500
+ * @throws {Error} If authentication is not complete or call creation fails.
3501
+ *
3502
+ * @example
3503
+ * ```ts
3504
+ * const call = await client.dial('/public/conference', {
3505
+ * audio: true,
3506
+ * video: true,
3507
+ * });
3508
+ * call.status$.subscribe(status => console.log('Call:', status));
3509
+ * ```
2103
3510
  */
2104
3511
  dial(destination: string | Address, options?: DialOptions): Promise<Call>;
3512
+ /**
3513
+ * Runs a multi-phase connectivity test against the given destination.
3514
+ *
3515
+ * The test checks:
3516
+ * 1. **Signaling** -- WebSocket connected, RTT measurement
3517
+ * 2. **Devices** -- getUserMedia succeeds with selected (or specified) devices
3518
+ * 3. **ICE/TURN** -- gathers ICE candidates to verify STUN/TURN reachability
3519
+ * 4. **Media/bandwidth** (unless `skipMediaTest`) -- dials the destination,
3520
+ * collects getStats() for `duration` seconds, computes bandwidth estimates
3521
+ *
3522
+ * @param destination - A destination to dial for the media test (e.g. `'/private/network-test'`).
3523
+ * @param options - Preflight options (duration, skipMediaTest, device overrides).
3524
+ * @returns A {@link PreflightResult} describing connectivity health.
3525
+ *
3526
+ * @example
3527
+ * ```ts
3528
+ * const result = await client.preflight('/private/network-test', { duration: 5 });
3529
+ * if (!result.ok) console.warn('Connectivity issues:', result.warnings);
3530
+ * ```
3531
+ */
3532
+ preflight(destination: string, options?: PreflightOptions): Promise<PreflightResult>;
2105
3533
  /** The underlying client session for advanced RPC operations. */
2106
3534
  get session(): ClientSessionWrapper;
2107
3535
  /** Observable list of available audio input (microphone) devices. */
@@ -2128,10 +3556,10 @@ declare class SignalWire extends Destroyable implements DeviceController {
2128
3556
  get selectedAudioOutputDevice(): MediaDeviceInfo | null;
2129
3557
  /** Currently selected video input device, or `null` if none. */
2130
3558
  get selectedVideoInputDevice(): MediaDeviceInfo | null;
2131
- /** Media track constraints for the selected audio input device. */
2132
- get selectedAudioInputDeviceConstraints(): MediaTrackConstraints;
2133
- /** Media track constraints for the selected video input device. */
2134
- get selectedVideoInputDeviceConstraints(): MediaTrackConstraints;
3559
+ /** Media track constraints for the selected audio input device. Returns `false` when disabled. */
3560
+ get selectedAudioInputDeviceConstraints(): MediaTrackConstraints | boolean;
3561
+ /** Media track constraints for the selected video input device. Returns `false` when disabled. */
3562
+ get selectedVideoInputDeviceConstraints(): MediaTrackConstraints | boolean;
2135
3563
  /** Converts a `MediaDeviceInfo` to track constraints suitable for `getUserMedia`. */
2136
3564
  deviceInfoToConstraints(deviceInfo: MediaDeviceInfo | null): MediaTrackConstraints;
2137
3565
  /** Sets the preferred audio input device. */
@@ -2144,8 +3572,60 @@ declare class SignalWire extends Destroyable implements DeviceController {
2144
3572
  enableDeviceMonitoring(): void;
2145
3573
  /** Stops monitoring for media device changes. */
2146
3574
  disableDeviceMonitoring(): void;
3575
+ /**
3576
+ * Returns the capabilities of a media device.
3577
+ * @param deviceInfo - The device to query.
3578
+ * @returns The device capabilities, or `null` if unavailable.
3579
+ */
2147
3580
  getDeviceCapabilities(deviceInfo: MediaDeviceInfo): Promise<MediaTrackCapabilities | null>;
3581
+ /**
3582
+ * Checks whether a device is still available and usable.
3583
+ * @param deviceInfo - The device to validate, or `null`.
3584
+ * @returns `true` if the device is valid and available. Returns `false` for `null`, audio output devices, or unavailable devices.
3585
+ */
2148
3586
  isValidDevice(deviceInfo: MediaDeviceInfo | null): Promise<boolean>;
3587
+ /** Injects a storage manager into the device controller for persistence. */
3588
+ setStorageManager(storageManager: StorageManager): void;
3589
+ /** Clears all device state and re-enumerates. */
3590
+ clearDeviceState(): Promise<void>;
3591
+ /** Forces a device re-enumeration. */
3592
+ enumerateDevices(): Promise<void>;
3593
+ /** Disables audio input (receive-only mode). No audio track will be acquired. */
3594
+ disableAudioInput(): void;
3595
+ /** Re-enables audio input, restoring the last selection or auto-selecting. */
3596
+ enableAudioInput(): void;
3597
+ /** Disables video input (receive-only mode). No video track will be acquired. */
3598
+ disableVideoInput(): void;
3599
+ /** Re-enables video input, restoring the last selection or auto-selecting. */
3600
+ enableVideoInput(): void;
3601
+ /** Observable that emits `true` when video input is disabled (receive-only). */
3602
+ get videoInputDisabled$(): Observable<boolean>;
3603
+ /** Observable that emits `true` when audio input is disabled (receive-only). */
3604
+ get audioInputDisabled$(): Observable<boolean>;
3605
+ /** Whether video input is currently disabled. */
3606
+ get videoInputDisabled(): boolean;
3607
+ /** Whether audio input is currently disabled. */
3608
+ get audioInputDisabled(): boolean;
3609
+ /**
3610
+ * Triggers the browser's media permission dialog and captures the user's device selections.
3611
+ *
3612
+ * @param options - Which permissions to request.
3613
+ * @param options.audio - Whether to request audio permission.
3614
+ * @param options.video - Whether to request video permission.
3615
+ * @returns The permission result with selected devices.
3616
+ */
3617
+ requestMediaPermissions(options?: {
3618
+ audio?: boolean;
3619
+ video?: boolean;
3620
+ }): Promise<PermissionResult>;
3621
+ /**
3622
+ * Clears all SDK-persisted state and resets to defaults.
3623
+ *
3624
+ * This clears device preferences, device history, authorization state,
3625
+ * attached call IDs, and all SDK storage keys, then re-enumerates devices.
3626
+ */
3627
+ resetToDefaults(): Promise<void>;
3628
+ /** Destroys the client, clearing timers and releasing all resources. */
2149
3629
  destroy(): void;
2150
3630
  }
2151
3631
  //#endregion
@@ -2188,38 +3668,9 @@ declare class StaticCredentialProvider implements CredentialProvider {
2188
3668
  authenticate(): Promise<SDKCredential>;
2189
3669
  }
2190
3670
  //#endregion
2191
- //#region src/core/errors.d.ts
2192
- declare class CallCreateError extends Error {
2193
- message: string;
2194
- error: unknown;
2195
- constructor(message: string, error?: unknown, options?: ErrorOptions);
2196
- }
2197
- declare class VertoPongError extends Error {
2198
- originalError: unknown;
2199
- constructor(originalError: unknown);
2200
- }
2201
- declare class MessageParseError extends Error {
2202
- originalError: unknown;
2203
- constructor(originalError: unknown);
2204
- }
2205
- declare class CollectionFetchError extends Error {
2206
- operation: string;
2207
- originalError: unknown;
2208
- constructor(operation: string, originalError: unknown);
2209
- }
2210
- declare class MediaTrackError extends Error {
2211
- operation: string;
2212
- kind: string;
2213
- originalError: unknown;
2214
- constructor(operation: string, kind: string, originalError: unknown);
2215
- }
2216
- //#endregion
2217
3671
  //#region src/controllers/RTCPeerConnectionController.d.ts
2218
3672
  interface RTCPeerConnectionControllerOptions extends MediaOptions {
2219
3673
  callId?: string;
2220
- WebRTCPeerConnectionConstructor?: typeof RTCPeerConnection;
2221
- getUserMedia?: (constraints: MediaStreamConstraints) => Promise<MediaStream>;
2222
- getDisplayMedia?: (options: DisplayMediaStreamOptions) => Promise<MediaStream>;
2223
3674
  rtcConfiguration?: RTCConfiguration;
2224
3675
  simulcast?: boolean;
2225
3676
  sfu?: boolean;
@@ -2230,6 +3681,13 @@ interface RTCPeerConnectionControllerOptions extends MediaOptions {
2230
3681
  relayOnly?: boolean;
2231
3682
  iceCandidateTimeout?: number;
2232
3683
  iceGatheringTimeout?: number;
3684
+ webRTCApiProvider?: WebRTCApiProvider;
3685
+ /** Per-call preferred video codecs (overrides global preferences). */
3686
+ preferredVideoCodecs?: string[];
3687
+ /** Per-call preferred audio codecs (overrides global preferences). */
3688
+ preferredAudioCodecs?: string[];
3689
+ /** Per-call stereo Opus setting (overrides global preferences). */
3690
+ stereo?: boolean;
2233
3691
  }
2234
3692
  type RTCPeerConnectionControllerOptionsPartial = Partial<RTCPeerConnectionControllerOptions>;
2235
3693
  interface UpdateSDPStatusParams {
@@ -2269,6 +3727,7 @@ declare class RTCPeerConnectionController extends Destroyable {
2269
3727
  private _initialized$;
2270
3728
  private _remoteDescription$;
2271
3729
  private _remoteStream$;
3730
+ private _remoteOfferMediaDirections;
2272
3731
  constructor(options?: RTCPeerConnectionControllerOptionsPartial, remoteSessionDescription?: string, deviceController?: DeviceController);
2273
3732
  private get iceGatheringController();
2274
3733
  private get shouldEmitLocalDescription();
@@ -2336,6 +3795,12 @@ declare class RTCPeerConnectionController extends Destroyable {
2336
3795
  status,
2337
3796
  sdp
2338
3797
  }: UpdateSDPStatusParams): Promise<void>;
3798
+ /**
3799
+ * Accept an inbound call by creating the SDP answer.
3800
+ * Optionally override media options before the answer is generated.
3801
+ * Must be called after initialization for inbound (answer-type) connections.
3802
+ */
3803
+ acceptInbound(mediaOverrides?: MediaOptions): Promise<void>;
2339
3804
  private handleOfferReceived;
2340
3805
  private readyToConnect;
2341
3806
  private setRemoteDescriptionBefore;
@@ -2351,6 +3816,22 @@ declare class RTCPeerConnectionController extends Destroyable {
2351
3816
  private setupEventListeners;
2352
3817
  private negotiationEnded;
2353
3818
  restarIce(): void;
3819
+ /**
3820
+ * Trigger an ICE restart through the existing negotiation pipeline.
3821
+ *
3822
+ * This creates an offer with iceRestart: true and goes through the full
3823
+ * SDP pipeline (setLocalDescription → ICE gathering → localDescription$ emission).
3824
+ * The caller should NOT send the SDP manually — the existing
3825
+ * setupLocalDescriptionHandler in VertoManager will pick up the emission
3826
+ * from localDescription$ and send it as a verto.modify.
3827
+ *
3828
+ * Unlike calling pc.createOffer/setLocalDescription directly, this method:
3829
+ * - Sets _isNegotiating$ so ICEGatheringController arms its timers
3830
+ * - Waits for ICE gathering to complete before localDescription$ emits
3831
+ * - Goes through setLocalDescriptionBefore() for any SDP munging
3832
+ */
3833
+ triggerIceRestart(relayOnly?: boolean): Promise<void>;
3834
+ private restoreIceTransportPolicy;
2354
3835
  /**
2355
3836
  * Setup track handling for remote tracks.
2356
3837
  */
@@ -2377,6 +3858,13 @@ declare class RTCPeerConnectionController extends Destroyable {
2377
3858
  */
2378
3859
  setLocalTrack(track: MediaStreamTrack): void;
2379
3860
  updateSendersConstraints(kind: 'audio' | 'video', constraints?: MediaTrackConstraints): Promise<void>;
3861
+ /**
3862
+ * Replace the current audio track with a new one using the given constraints.
3863
+ * Used for server-pushed audio constraint changes where applyConstraints
3864
+ * fails on iOS Safari. Stops the current track, acquires a new one via
3865
+ * getUserMedia, and replaces the sender track.
3866
+ */
3867
+ replaceAudioTrackWithConstraints(constraints: MediaTrackConstraints): Promise<void>;
2380
3868
  /**
2381
3869
  * Clean up resources and close the peer connection.
2382
3870
  * Completes all observables to prevent memory leaks.
@@ -2415,10 +3903,19 @@ interface WebRTCVerto extends VertoManager {
2415
3903
  unhold(): Promise<void>;
2416
3904
  destroy(): void;
2417
3905
  transfer(options: TransferOptions): Promise<void>;
3906
+ /** Request a video keyframe via verto.modify. */
3907
+ requestKeyframe?: () => void;
3908
+ /** Request an ICE restart via verto.modify with iceRestart offer. */
3909
+ requestIceRestart?: (relayOnly?: boolean) => Promise<void>;
3910
+ /** Request an ICE restart on all active peer connections (multi-leg). */
3911
+ requestIceRestartAll?: (relayOnly?: boolean) => Promise<void>;
3912
+ /** Request keyframes on all video-receiving legs (skips send-only screen share). */
3913
+ requestKeyframeAll?: () => void;
2418
3914
  }
2419
3915
  //#endregion
2420
3916
  //#region src/managers/CallEventsManager.d.ts
2421
3917
  interface WebRTCCallEventManagerOptions {}
3918
+ /** @internal */
2422
3919
  declare class CallEventsManager extends Destroyable {
2423
3920
  protected webRtcCallSession: CallManager;
2424
3921
  protected options: WebRTCCallEventManagerOptions;
@@ -2426,15 +3923,13 @@ declare class CallEventsManager extends Destroyable {
2426
3923
  private originCallId?;
2427
3924
  private callIds;
2428
3925
  private roomSessionIds;
2429
- private _status$;
2430
3926
  private _participants$;
2431
3927
  private _self$;
2432
3928
  private _sessionState$;
2433
3929
  constructor(webRtcCallSession: CallManager, options?: WebRTCCallEventManagerOptions);
2434
3930
  get participants$(): Observable<CallParticipant[]>;
3931
+ get participants(): CallParticipant[];
2435
3932
  get self$(): Observable<CallSelfParticipant>;
2436
- get status$(): Observable<CallStatus>;
2437
- get status(): CallStatus;
2438
3933
  isRoomSessionIdValid(roomSessionId: string): boolean;
2439
3934
  addCallId(callId: string): void;
2440
3935
  isCallIdValid(callId: string): boolean;
@@ -2446,7 +3941,7 @@ declare class CallEventsManager extends Destroyable {
2446
3941
  get raiseHandPriority$(): Observable<boolean>;
2447
3942
  get locked$(): Observable<boolean>;
2448
3943
  get meta$(): Observable<Record<string, unknown>>;
2449
- get capabilities$(): Observable<string[]>;
3944
+ get capabilities$(): Observable<Capability[]>;
2450
3945
  get layout$(): Observable<string>;
2451
3946
  get layouts$(): Observable<string[]>;
2452
3947
  get layoutLayers$(): Observable<LayoutLayer[]>;
@@ -2459,7 +3954,7 @@ declare class CallEventsManager extends Destroyable {
2459
3954
  get meta(): Record<string, unknown>;
2460
3955
  get layout(): string | undefined;
2461
3956
  get layouts(): string[];
2462
- get capabilities(): string[];
3957
+ get capabilities(): Capability[];
2463
3958
  isSessionEvent(id: string): boolean;
2464
3959
  protected initSubscriptions(): void;
2465
3960
  private updateParticipantPositions;
@@ -2472,6 +3967,27 @@ declare class CallEventsManager extends Destroyable {
2472
3967
  destroy(): void;
2473
3968
  }
2474
3969
  //#endregion
3970
+ //#region src/managers/CallRecoveryManager.d.ts
3971
+ type RecoveryState$1 = 'idle' | 'debouncing' | 'recovering' | 'cooldown';
3972
+ interface RecoveryEvent$1 {
3973
+ action: 'keyframe_requested' | 'reinvite_started' | 'reinvite_succeeded' | 'reinvite_failed' | 'reinvite_timeout' | 'max_attempts_reached' | 'signal_reconnect' | 'full_reconnect' | 'video_disabled' | 'video_restored';
3974
+ reason: string;
3975
+ attempt?: number;
3976
+ maxAttempts?: number;
3977
+ timestamp: number;
3978
+ }
3979
+ //#endregion
3980
+ //#region src/utils/qualityScore.d.ts
3981
+ /**
3982
+ * MOS (Mean Opinion Score) quality computation based on the simplified
3983
+ * ITU-T G.107 E-model.
3984
+ *
3985
+ * Provides a single 1-5 number that applications can use for a
3986
+ * green / yellow / red quality indicator without understanding raw
3987
+ * jitter and packet-loss values.
3988
+ */
3989
+ type QualityLevel$1 = 'excellent' | 'good' | 'fair' | 'poor' | 'critical';
3990
+ //#endregion
2475
3991
  //#region src/core/entities/Call.d.ts
2476
3992
  /**
2477
3993
  * Manager instances returned by initialization callback
@@ -2499,6 +4015,10 @@ interface CallInitialization {
2499
4015
  * Device controller for media device access
2500
4016
  */
2501
4017
  deviceController: DeviceController;
4018
+ /**
4019
+ * Network change events for feeding recovery pipeline
4020
+ */
4021
+ networkChange$?: Observable<NetworkChangeEvent>;
2502
4022
  }
2503
4023
  /**
2504
4024
  * Concrete WebRTC call implementation.
@@ -2515,19 +4035,39 @@ declare class WebRTCCall extends Destroyable implements CallManager {
2515
4035
  readonly id: string;
2516
4036
  /** Destination URI this call was placed to. */
2517
4037
  to?: string;
2518
- protected readonly participantsMap: Map<string, Participant>;
2519
4038
  private vertoManager;
2520
4039
  private callEventsManager;
2521
4040
  private participantFactory;
2522
4041
  private _errors$;
2523
4042
  private _status$;
4043
+ private _lastMergedStatus;
2524
4044
  private _answered$;
4045
+ private _answerMediaOptions?;
2525
4046
  private _holdState;
4047
+ private _userVariables$;
4048
+ private _statsMonitor?;
4049
+ private _recoveryManager?;
4050
+ private _networkChange$?;
4051
+ private _networkIssues$;
4052
+ private _networkMetrics$;
4053
+ private _isNetworkHealthy$;
4054
+ private _qualityScore$;
4055
+ private _qualityLevel$;
4056
+ private _recoveryState$;
4057
+ private _recoveryEvent$;
4058
+ private _bandwidthConstrained$;
4059
+ private _mediaParamsUpdated$;
4060
+ private _customSubscriptions;
2526
4061
  constructor(clientSession: ClientSession, options: CallOptions, initialization: CallInitialization, address?: Address | undefined);
2527
4062
  /** Observable stream of errors from media, signaling, and peer connection layers. */
2528
- get errors$(): Observable<Error>;
2529
- /** @internal Push an error to the call's error stream. */
2530
- emitError(error: Error): void;
4063
+ get errors$(): Observable<CallError>;
4064
+ /**
4065
+ * @internal Push an error to the call's error stream.
4066
+ * Fatal errors automatically transition the call to `'failed'` and destroy it.
4067
+ */
4068
+ emitError(callError: CallError): void;
4069
+ /** Notify the recovery manager that a verto.modify signaling exchange failed. */
4070
+ notifyModifyFailed(): void;
2531
4071
  /** Whether this call is `'inbound'` or `'outbound'`. */
2532
4072
  get direction(): CallDirection;
2533
4073
  /** Observable of the address associated with this call. */
@@ -2545,23 +4085,51 @@ declare class WebRTCCall extends Destroyable implements CallManager {
2545
4085
  /** @internal Registers an additional call ID for event routing. */
2546
4086
  addCallId(callId: string): void;
2547
4087
  /** List of capabilities available in the current call. */
2548
- get capabilities(): string[];
4088
+ get capabilities(): Capability[];
2549
4089
  /** Current snapshot of all participants in the call. */
2550
4090
  get participants(): CallParticipant[];
2551
4091
  /** The local participant, or `null` if not yet joined. */
2552
4092
  get self(): CallSelfParticipant | null;
4093
+ /** Toggles the call lock state, preventing or allowing new participants from joining. */
2553
4094
  toggleLock(): Promise<void>;
4095
+ /**
4096
+ * Toggles the hold state of the call (pauses/resumes local media transmission).
4097
+ *
4098
+ * Distinct from {@link Participant.toggleMute} which mutes individual tracks.
4099
+ */
2554
4100
  toggleHold(): Promise<void>;
4101
+ /** @throws {UnimplementedError} Not yet implemented. Status tracked via {@link recording$}. */
2555
4102
  startRecording(): Promise<void>;
4103
+ /** @throws {UnimplementedError} Not yet implemented. Status tracked via {@link streaming$}. */
2556
4104
  startStreaming(): Promise<void>;
4105
+ /**
4106
+ * Replaces the call's custom metadata.
4107
+ * @param _meta - Metadata object to set.
4108
+ * @throws {UnimplementedError} Not yet implemented.
4109
+ */
2557
4110
  setMeta(_meta: Record<string, unknown>): Promise<void>;
4111
+ /**
4112
+ * Merges values into the call's custom metadata (unlike {@link setMeta} which replaces).
4113
+ * @param _meta - Metadata to merge.
4114
+ * @throws {UnimplementedError} Not yet implemented.
4115
+ */
2558
4116
  updateMeta(_meta: Record<string, unknown>): Promise<void>;
2559
4117
  /** Observable of layout layer positions for all participants. */
2560
4118
  get layoutLayers$(): Observable<LayoutLayer[]>;
2561
4119
  /** Current snapshot of layout layers. */
2562
4120
  get layoutLayers(): LayoutLayer[];
2563
- /** Executes a Verto RPC method targeting a specific participant. */
2564
- executeMethod<T extends JSONRPCResponse = JSONRPCResponse>(target: string, method: string, args: Record<string, unknown>): Promise<T>;
4121
+ /**
4122
+ * Executes a Verto RPC method targeting a specific participant.
4123
+ *
4124
+ * Constructs call context (node_id, call_id, member_id) and sends the RPC request.
4125
+ *
4126
+ * @param target - Target member ID string, or a {@link MemberTarget} object.
4127
+ * @param method - Verto method name (e.g. `'call.mute'`, `'call.member.remove'`).
4128
+ * @param args - Parameters for the RPC method.
4129
+ * @returns The RPC response.
4130
+ * @throws {JSONRPCError} If the RPC call returns an error.
4131
+ */
4132
+ executeMethod<T extends JSONRPCResponse = JSONRPCResponse>(target: string | MemberTarget, method: string, args: Record<string, unknown>): Promise<T>;
2565
4133
  private buildMethodParams;
2566
4134
  /** Observable of the current call status (e.g. `'ringing'`, `'connected'`). */
2567
4135
  get status$(): Observable<CallStatus>;
@@ -2580,7 +4148,7 @@ declare class WebRTCCall extends Destroyable implements CallManager {
2580
4148
  /** Observable of custom metadata associated with the call. */
2581
4149
  get meta$(): Observable<Record<string, unknown>>;
2582
4150
  /** Observable of the call's capability flags. */
2583
- get capabilities$(): Observable<string[]>;
4151
+ get capabilities$(): Observable<Capability[]>;
2584
4152
  /** Observable of the current layout name. */
2585
4153
  get layout$(): Observable<string>;
2586
4154
  /** Current call status. */
@@ -2609,6 +4177,55 @@ declare class WebRTCCall extends Destroyable implements CallManager {
2609
4177
  get remoteStream$(): Observable<MediaStream>;
2610
4178
  /** Current remote media stream, or `null` if not available. */
2611
4179
  get remoteStream(): MediaStream | null;
4180
+ /** Observable of custom user variables associated with the call. */
4181
+ get userVariables$(): Observable<Record<string, unknown>>;
4182
+ /** a copy of the current custom user variables of the call. */
4183
+ get userVariables(): Record<string, unknown>;
4184
+ /** Merge current custom user variables of the call. */
4185
+ set userVariables(variables: Record<string, unknown>);
4186
+ /** Observable of current network health issues (empty array = healthy). */
4187
+ get networkIssues$(): Observable<NetworkIssue[]>;
4188
+ /** Current snapshot of network issues. */
4189
+ get networkIssues(): NetworkIssue[];
4190
+ /** Simple boolean health indicator derived from stats monitor. */
4191
+ get isNetworkHealthy$(): Observable<boolean>;
4192
+ /** Whether the network is currently healthy. */
4193
+ get isNetworkHealthy(): boolean;
4194
+ /** Rolling history of raw network metrics (RTT, jitter, packet loss, bitrate). */
4195
+ get networkMetrics$(): Observable<NetworkMetrics[]>;
4196
+ /** Current snapshot of the metrics rolling window. */
4197
+ get networkMetrics(): NetworkMetrics[];
4198
+ /** Observable of MOS quality score (1-5) computed from stats metrics. */
4199
+ get qualityScore$(): Observable<number>;
4200
+ /** Observable of simplified quality level (excellent/good/fair/poor/critical). */
4201
+ get qualityLevel$(): Observable<QualityLevel$1>;
4202
+ /** Observable of the recovery pipeline state machine. */
4203
+ get recoveryState$(): Observable<RecoveryState$1>;
4204
+ /** Observable of recovery events (keyframe requested, ICE restart, etc.). */
4205
+ get recoveryEvent$(): Observable<RecoveryEvent$1>;
4206
+ /** Observable indicating whether the call is bandwidth-constrained. */
4207
+ get bandwidthConstrained$(): Observable<boolean>;
4208
+ /** Observable that emits when server-pushed media params are applied. */
4209
+ get mediaParamsUpdated$(): Observable<MediaParamsEvent>;
4210
+ /**
4211
+ * @internal Emit a media params update event.
4212
+ * Called by the VertoManager when server-pushed media params are applied.
4213
+ */
4214
+ emitMediaParamsUpdated(event: MediaParamsEvent): void;
4215
+ /** Request a video keyframe via RTCP PLI/FIR. */
4216
+ requestKeyframe(): void;
4217
+ /** Force an ICE restart / re-INVITE. */
4218
+ requestIceRestart(): Promise<void>;
4219
+ /**
4220
+ * @internal Initialize resilience subsystems when the call reaches 'connected'.
4221
+ * Called from within the status subscription to wire stats and recovery.
4222
+ */
4223
+ private initResilienceSubsystems;
4224
+ /**
4225
+ * @internal Stop and destroy resilience subsystems (on disconnect/destroy).
4226
+ * Clears references so they can be re-created on reconnect.
4227
+ */
4228
+ private stopResilienceSubsystems;
2612
4229
  /** @internal */
2613
4230
  createParticipant(memberId: string, selfId?: string | null): Participant | SelfParticipant;
2614
4231
  /** Observable of the current audio/video send/receive directions. */
@@ -2616,7 +4233,16 @@ declare class WebRTCCall extends Destroyable implements CallManager {
2616
4233
  /** Current audio/video send/receive directions. */
2617
4234
  get mediaDirections(): MediaDirections;
2618
4235
  protected get participantsId$(): Observable<string[]>;
2619
- /** Executes a raw JSON-RPC request on the client session. */
4236
+ /**
4237
+ * Executes a raw JSON-RPC request on the client session.
4238
+ *
4239
+ * Lower-level than {@link executeMethod} — allows full control over the RPC request structure.
4240
+ *
4241
+ * @param request - Complete JSON-RPC request object.
4242
+ * @param options - Optional RPC execution options (timeout, etc.).
4243
+ * @returns The RPC response.
4244
+ * @throws {JSONRPCError} If the RPC call returns an error response.
4245
+ */
2620
4246
  execute<T extends JSONRPCResponse = JSONRPCResponse>(request: JSONRPCRequest, options?: PendingRPCOptions): Promise<T>;
2621
4247
  /** Observable of the local participant's member ID. */
2622
4248
  get selfId$(): Observable<string | null>;
@@ -2630,9 +4256,9 @@ declare class WebRTCCall extends Destroyable implements CallManager {
2630
4256
  private get callSessionEvents$();
2631
4257
  /** Observable of call-updated events. */
2632
4258
  get callUpdated$(): Observable<CallUpdatedPayload>;
2633
- /** Observable of member-joined events. */
4259
+ /** Observable of member-joined events, emitted when a remote participant joins the call. */
2634
4260
  get memberJoined$(): Observable<MemberJoinedPayload>;
2635
- /** Observable of member-left events. */
4261
+ /** Observable of member-left events, emitted when a participant leaves the call. */
2636
4262
  get memberLeft$(): Observable<MemberLeftPayload>;
2637
4263
  /** Observable of member-updated events (mute, volume, etc.). */
2638
4264
  get memberUpdated$(): Observable<MemberUpdatedPayload>;
@@ -2646,32 +4272,117 @@ declare class WebRTCCall extends Destroyable implements CallManager {
2646
4272
  get rtcPeerConnection(): RTCPeerConnection | undefined;
2647
4273
  /** Observable of raw signaling events as plain objects. */
2648
4274
  get signalingEvent$(): Observable<Record<string, unknown>>;
2649
- /** Observable of WebRTC-specific signaling messages. */
4275
+ /**
4276
+ * Subscribe to a custom signaling event type on this call.
4277
+ *
4278
+ * Returns a cached observable that filters `callSessionEvents$` for events
4279
+ * whose `event_type` matches the given string. The observable completes
4280
+ * when the call is destroyed.
4281
+ *
4282
+ * Unlike `signalingEvent$` (which only emits known call-level event types),
4283
+ * this method also matches custom/user-defined event types.
4284
+ *
4285
+ * The SDK does not validate event type strings --- the server decides
4286
+ * whether a given type is valid.
4287
+ *
4288
+ * @param eventType - The event type to subscribe to (e.g. `'my.custom.event'`).
4289
+ * @returns An observable that emits matching signaling events.
4290
+ *
4291
+ * @example
4292
+ * ```ts
4293
+ * call.subscribe('my.custom.event').subscribe(event => {
4294
+ * console.log('Custom event:', event);
4295
+ * });
4296
+ * ```
4297
+ */
4298
+ subscribe(eventType: string): Observable<Record<string, unknown>>;
2650
4299
  get webrtcMessages$(): Observable<WebrtcMessagePayload>;
2651
- /** Observable of call-level signaling events. */
2652
- get callEvent$(): Observable<WebrtcMessagePayload | CallJoinedPayload | CallLeftPayload | CallUpdatedPayload | CallStatePayload | CallPlayPayload | CallConnectPayload | MemberUpdatedPayload | MemberJoinedPayload | MemberLeftPayload | MemberTalkingPayload | LayoutChangedPayload | ConversationMessagePayload>;
2653
- /** Observable of layout-changed signaling events. */
4300
+ get callEvent$(): Observable<WebrtcMessagePayload | CallJoinedPayload | CallLeftPayload | CallUpdatedPayload | CallStatePayload | CallPlayPayload | CallConnectPayload | RoomUpdatedPayload | MemberUpdatedPayload | MemberJoinedPayload | MemberLeftPayload | MemberTalkingPayload | LayoutChangedPayload | ConversationMessagePayload>;
2654
4301
  get layoutEvent$(): Observable<LayoutChangedPayload>;
2655
- /** Hangs up the call and releases all resources. */
4302
+ /**
4303
+ * Hangs up the call and releases all resources.
4304
+ *
4305
+ * Sends a Verto `bye` to the server, transitions status to `'disconnecting'`,
4306
+ * then destroys the call. After this, the call instance is no longer usable.
4307
+ *
4308
+ * @example
4309
+ * ```ts
4310
+ * await call.hangup();
4311
+ * ```
4312
+ */
2656
4313
  hangup(): Promise<void>;
2657
- /** Sends DTMF digits (e.g. `'1234#'`) on the call. */
4314
+ /**
4315
+ * Sends DTMF digits on the call.
4316
+ *
4317
+ * @param dtmf - The digit string to send (e.g. `'1234#'`).
4318
+ *
4319
+ * @example
4320
+ * ```ts
4321
+ * await call.sendDigits('1234#');
4322
+ * ```
4323
+ */
2658
4324
  sendDigits(dtmf: string): Promise<void>;
2659
- /** Accepts an inbound call. */
2660
- answer(): void;
2661
- /** Rejects an inbound call. */
4325
+ /** Observable of WebRTC-specific signaling messages. */
4326
+ /** Observable of call-level signaling events. */
4327
+ /** Observable of layout-changed signaling events. */
4328
+ /**
4329
+ * Accepts an inbound call, optionally overriding media options for the answer.
4330
+ *
4331
+ * @param options - Optional media constraints for the answer (audio/video).
4332
+ *
4333
+ * @example
4334
+ * ```ts
4335
+ * // Accept with defaults
4336
+ * call.answer();
4337
+ *
4338
+ * // Accept audio-only
4339
+ * call.answer({ audio: true, video: false });
4340
+ * ```
4341
+ * @see {@link reject} to decline the call instead.
4342
+ * @see {@link answered$} to observe the acceptance state.
4343
+ */
4344
+ answer(options?: MediaOptions): void;
4345
+ /** Media options provided when answering. Used internally by the VertoManager. */
4346
+ get answerMediaOptions(): MediaOptions | undefined;
4347
+ /**
4348
+ * Rejects an inbound call, preventing media negotiation.
4349
+ *
4350
+ * @see {@link answer} to accept the call instead.
4351
+ * @see {@link answered$} to observe the rejection state.
4352
+ */
2662
4353
  reject(): void;
2663
4354
  /** Observable that emits `true` when answered, `false` when rejected. */
2664
4355
  get answered$(): Observable<boolean>;
2665
4356
  /**
2666
4357
  * Sets the call layout and participant positions.
4358
+ *
2667
4359
  * @param layout - Layout name (must be one of {@link layouts}).
2668
- * @param positions - Map of member IDs to video positions.
4360
+ * @param positions - Map of member IDs to {@link VideoPosition} values.
4361
+ * @throws {InvalidParams} If the layout is not in the available {@link layouts}.
4362
+ *
4363
+ * @example
4364
+ * ```ts
4365
+ * await call.setLayout('grid-responsive', {
4366
+ * [participantId]: 'reserved-0',
4367
+ * });
4368
+ * ```
2669
4369
  */
2670
4370
  setLayout(layout: string, positions: Record<string, VideoPosition>): Promise<void>;
2671
- /** Transfers the call to other participants. */
4371
+ /**
4372
+ * Transfers the call to another destination.
4373
+ *
4374
+ * @param options - Transfer configuration including the target destination.
4375
+ * @see {@link status$} to observe the transfer progress.
4376
+ */
2672
4377
  transfer(options: TransferOptions): Promise<void>;
2673
4378
  /** Destroys the call, releasing all resources and subscriptions. */
2674
4379
  destroy(): void;
4380
+ /**
4381
+ * @internal Send a verto.subscribe message to add an event type to the
4382
+ * server's subscription list for this call. Best-effort — failures are
4383
+ * logged but don't prevent the filtered observable from being returned.
4384
+ */
4385
+ private _sendVertoSubscribe;
2675
4386
  }
2676
4387
  //#endregion
2677
4388
  //#region src/index.d.ts
@@ -2686,5 +4397,5 @@ declare const version: string;
2686
4397
  */
2687
4398
  declare const ready: boolean;
2688
4399
  //#endregion
2689
- export { Address, type AddressHistory, type Call, type CallAddress, CallCreateError, type CallOptions, type CallParticipant, type CallSelfParticipant, type CallState, type CallStatus, ClientPreferences, CollectionFetchError, type DialOptions, type Directory, type ExecuteMethod, type LayoutLayer, type MediaDirection, type MediaDirections, type MediaOptions, MediaTrackError, MessageParseError, type NodeSocketAdapter, Participant, type SDKCredential, SelfParticipant, SignalWire, type SignalWireOptions, StaticCredentialProvider, Subscriber, type TextMessage, VertoPongError, WebRTCCall, type WebSocketAdapter, embeddableCall, isSelfParticipant, ready, version };
4400
+ export { Address, type AddressHistory, type AudioConstraintsEvent, type AuthenticateContext, type Call, type CallAddress, type CallCapabilitiesState, CallCreateError, type CallDiagnosticSummary, type CallDirection, type CallError, type CallErrorKind, type NetworkIssue as CallNetworkIssue, type NetworkIssue, type NetworkMetrics as CallNetworkMetrics, type NetworkMetrics, type CallOptions, type CallParticipant, type CallSelfParticipant, type CallState, type CallStatus, type Capability, ClientPreferences, CollectionFetchError, type ConstraintFallbackEvent, type CredentialProvider, DPoPInitError, type DebugOptions, type DeviceController, type DeviceRecoveryEvent, DeviceTokenError, type DiagnosticEvent, type DialOptions, type Directory, type ExecuteMethod, InvalidCredentialsError, type JSONRPCErrorResponse, type JSONRPCRequest, type JSONRPCResponse, type JSONRPCSuccessResponse, type LayoutLayer, type LogLevel, type MediaDirection, type MediaDirections, type MediaOptions, type MediaParamsEvent, MediaTrackError, type MemberCapabilities, MessageParseError, type NodeSocketAdapter, type OnOffCapability, OverconstrainedFallbackError, Participant, type PendingRPCOptions, type PermissionResult, type PlatformCapabilities, PreflightError, type PreflightOptions, type PreflightResult, type QualityLevel, RecoveryError, type RecoveryEvent, type RecoveryState, type ResilienceCallStatus, type SATClaims, type SDKCredential, type SDKLogger, type ScreenShareStatus, type SelectDeviceOptions, SelfCapabilities, SelfParticipant, type SessionDiagnostics, type SessionState, SignalWire, type SignalWireOptions, StaticCredentialProvider, type Storage, type StoredDevicePreference, Subscriber, type SubscriberPresence, type TextMessage, TokenRefreshError, type TransferOptions, UnexpectedError, VertoPongError, type VideoPosition, type WebRTCApiProvider, WebRTCCall, type WebRTCMediaDevices, type WebSocketAdapter, embeddableCall, isSelfParticipant, ready, setDebugOptions, setLogLevel, setLogger, version };
2690
4401
  //# sourceMappingURL=index.d.mts.map