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

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
@@ -84,7 +84,7 @@ type WebSocketAdapter = new (url: string | URL, protocols?: string | string[]) =
84
84
  * At least one of `token` or `authorizationState` must be provided.
85
85
  */
86
86
  interface SDKCredential {
87
- /** JWT subscriber access token (SAT). */
87
+ /** JWT user access token (SAT). */
88
88
  token?: string;
89
89
  /** Pre-authorized session state (alternative to token). */
90
90
  authorizationState?: string;
@@ -134,8 +134,25 @@ interface AuthenticateContext {
134
134
  * - Setting `expiry_at` when the credential has a known expiration so the SDK can schedule refresh.
135
135
  * - Handling errors and never leaking sensitive data through error messages.
136
136
  *
137
- * The SDK owns the credential lifecycle: it calls `authenticate` once during initialization
138
- * and, if `refresh` is provided and `expiry_at` is set, schedules automatic refresh before expiry.
137
+ * ## Refresh precedence
138
+ *
139
+ * The SDK selects exactly one refresh mechanism per session, evaluated at connect
140
+ * time (and re-evaluated on reconnect):
141
+ *
142
+ * | `refresh` provided | SAT carries `sat:refresh` scope | Active mechanism |
143
+ * | ------------------ | -------------------------------- | ------------------------------------ |
144
+ * | yes | yes | Client Bound SAT (DPoP, internal) |
145
+ * | yes | no | Developer-provided `refresh()` |
146
+ * | no | yes | Client Bound SAT (DPoP, internal) |
147
+ * | no | no | None — session ends at `expiry_at` |
148
+ *
149
+ * When the SDK falls back to the developer-provided `refresh()` because the SAT
150
+ * lacked `sat:refresh` scope, a `credential_refresh_fallback` event is emitted on
151
+ * `SignalWire.warnings$` so application code can observe the transition.
152
+ *
153
+ * Mint a SAT via `POST /api/fabric/subscribers/tokens` with `fingerprint` and
154
+ * `scope: ["sat:refresh"]` (both currently optional on that endpoint) to enable
155
+ * the Client Bound SAT path; otherwise provide `refresh()` here.
139
156
  */
140
157
  interface CredentialProvider {
141
158
  /**
@@ -146,6 +163,8 @@ interface CredentialProvider {
146
163
  * - Reject (throw) on failure — this will cause client initialization to fail.
147
164
  * - When `context.fingerprint` is provided, forward it to the server-side token
148
165
  * endpoint with `scope: "sat:refresh"` to enable automatic token refresh.
166
+ * Ignoring `context.fingerprint` causes the SDK to fall back to `refresh()`
167
+ * (if provided) or end the session at expiry.
149
168
  *
150
169
  * SDK behavior:
151
170
  * - Awaits this method before establishing the WebSocket connection.
@@ -160,14 +179,12 @@ interface CredentialProvider {
160
179
  * - Reject (throw) if refresh is not possible — the SDK will stop the refresh schedule.
161
180
  *
162
181
  * SDK behavior:
163
- * - Only called when `expiry_at` was set on the previous credential.
182
+ * - Only called when `expiry_at` was set on the previous credential AND the
183
+ * SAT does not carry `sat:refresh` scope (otherwise the SDK refreshes
184
+ * internally via Client Bound SAT). See the precedence table above.
164
185
  * - Scheduled automatically before expiry; implementors do not need to manage timing.
165
186
  * - On rejection, the refresh schedule stops and the session continues with the
166
187
  * current credentials until they expire.
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.
171
188
  */
172
189
  refresh?: () => Promise<SDKCredential>;
173
190
  }
@@ -325,6 +342,12 @@ interface MediaOptions {
325
342
  receiveAudio?: boolean;
326
343
  /** Whether to receive remote video. */
327
344
  receiveVideo?: boolean;
345
+ /**
346
+ * When local media can't be acquired (permission denied or device
347
+ * unavailable), continue the call in receive-only mode instead of failing.
348
+ * Defaults to `true`. Ignored when the call is not set to receive any media.
349
+ */
350
+ fallbackToReceiveOnly?: boolean;
328
351
  }
329
352
  //#endregion
330
353
  //#region src/containers/PreferencesContainer.d.ts
@@ -520,7 +543,7 @@ interface HTTPRequestControllerOptions {
520
543
  retryDelayMax?: number;
521
544
  requestTimeout?: number;
522
545
  }
523
- declare class HTTPRequestController {
546
+ declare class HTTPRequestController extends Destroyable {
524
547
  private baseURL;
525
548
  private readonly getCredential;
526
549
  private static readonly defaultMaxRetries;
@@ -626,57 +649,57 @@ interface SATClaims {
626
649
  expires_at?: number;
627
650
  }
628
651
  //#endregion
629
- //#region src/core/types/subscriber.types.d.ts
630
- /** Raw subscriber profile response from the SignalWire Fabric API. */
631
- interface GetSubscriberInfoResponse {
632
- /** Unique subscriber identifier. */
652
+ //#region src/core/types/user.types.d.ts
653
+ /** Raw user profile response from the SignalWire Fabric API. */
654
+ interface GetUserInfoResponse {
655
+ /** Unique user identifier. */
633
656
  id: string;
634
- /** Subscriber's email address. */
657
+ /** User's email address. */
635
658
  email: string;
636
- /** Subscriber's first name. */
659
+ /** User's first name. */
637
660
  first_name?: string;
638
- /** Subscriber's last name. */
661
+ /** User's last name. */
639
662
  last_name?: string;
640
- /** Subscriber's display name. */
663
+ /** User's display name. */
641
664
  display_name?: string;
642
- /** Subscriber's job title. */
665
+ /** User's job title. */
643
666
  job_title?: string;
644
- /** Subscriber's time zone offset. */
667
+ /** User's time zone offset. */
645
668
  time_zone?: number;
646
- /** Subscriber's country. */
669
+ /** User's country. */
647
670
  country?: string;
648
- /** Subscriber's region or state. */
671
+ /** User's region or state. */
649
672
  region?: string;
650
- /** Subscriber's company name. */
673
+ /** User's company name. */
651
674
  company_name?: string;
652
675
  /** Key for push notification delivery. */
653
676
  push_notification_key: string;
654
- /** Application-level settings for this subscriber. */
677
+ /** Application-level settings for this user. */
655
678
  app_settings?: {
656
679
  /** Display name configured at the application level. */
657
680
  display_name: string;
658
- /** Permission scopes granted to this subscriber. */
681
+ /** Permission scopes granted to this user. */
659
682
  scopes: string[];
660
683
  };
661
- /** Fabric addresses associated with this subscriber. */
684
+ /** Fabric addresses associated with this user. */
662
685
  fabric_addresses: GetAddressResponse[];
663
686
  /** Filtered SAT claims (scope, cnf, expires_at) returned when the token has special capabilities. */
664
687
  sat_claims?: SATClaims;
665
688
  }
666
689
  //#endregion
667
- //#region src/core/entities/Subscriber.d.ts
668
- /** Subscriber online presence state. */
669
- type SubscriberPresence = 'online' | 'offline' | 'busy';
690
+ //#region src/core/entities/User.d.ts
691
+ /** User online presence state. */
692
+ type UserPresence = 'online' | 'offline' | 'busy';
670
693
  /**
671
- * Authenticated subscriber profile.
694
+ * Authenticated user profile.
672
695
  *
673
696
  * Fetched automatically when a {@link SignalWire} connects.
674
697
  * Contains identity, contact, and organization details.
675
698
  */
676
- declare class Subscriber extends Fetchable<GetSubscriberInfoResponse> {
677
- /** Unique subscriber identifier. */
699
+ declare class User extends Fetchable<GetUserInfoResponse> {
700
+ /** Unique user identifier. */
678
701
  id: string;
679
- /** Subscriber email address. */
702
+ /** User email address. */
680
703
  email: string;
681
704
  /** First name. */
682
705
  firstName?: string;
@@ -701,12 +724,12 @@ declare class Subscriber extends Fetchable<GetSubscriberInfoResponse> {
701
724
  displayName: string;
702
725
  scopes: string[];
703
726
  };
704
- /** Fabric addresses associated with this subscriber. */
727
+ /** Fabric addresses associated with this user. */
705
728
  addresses: GetAddressResponse[];
706
729
  /** Filtered SAT claims when the token has special capabilities (e.g., refresh scope). */
707
730
  satClaims?: SATClaims;
708
731
  constructor(http: HTTPRequestController);
709
- protected populateInstance(data: GetSubscriberInfoResponse): void;
732
+ protected populateInstance(data: GetUserInfoResponse): void;
710
733
  }
711
734
  //#endregion
712
735
  //#region src/core/types/call.types.d.ts
@@ -795,7 +818,7 @@ interface Member {
795
818
  member_id: string;
796
819
  call_id: string;
797
820
  name: string;
798
- type: 'member' | 'screen';
821
+ type: 'member' | 'screen' | 'device' | (string & {});
799
822
  parent_id?: string;
800
823
  requested_position?: string;
801
824
  handraised: boolean;
@@ -803,17 +826,17 @@ interface Member {
803
826
  audio_muted: boolean;
804
827
  video_muted: boolean;
805
828
  deaf: boolean;
806
- input_volume: number;
807
- output_volume: number;
808
- input_sensitivity: number;
829
+ input_volume?: number;
830
+ output_volume?: number;
831
+ input_sensitivity?: number;
809
832
  echo_cancellation: boolean;
810
833
  auto_gain: boolean;
811
834
  noise_suppression: boolean;
812
835
  lowbitrate: boolean;
813
836
  denoise: boolean;
814
- talking: boolean;
815
- isAudience: boolean;
816
- meta: Record<string, unknown>;
837
+ talking?: boolean;
838
+ isAudience?: boolean;
839
+ meta?: Record<string, unknown>;
817
840
  subscriber_id: string;
818
841
  address_id: string;
819
842
  updated?: string[];
@@ -935,6 +958,15 @@ interface RoomUpdatedPayload {
935
958
  room_id: string;
936
959
  room_session_id: string;
937
960
  }
961
+ /**
962
+ * Describes the peer (remote) call referenced from a call.state event.
963
+ *
964
+ * Mirrors the backend (relay.c) `peer` shape.
965
+ */
966
+ interface CallStateRelatedCall {
967
+ call_id?: string;
968
+ node_id?: string;
969
+ }
938
970
  interface CallStatePayload {
939
971
  call_id: string;
940
972
  node_id: string;
@@ -942,10 +974,19 @@ interface CallStatePayload {
942
974
  call_state: SignalingCallStates;
943
975
  direction: CallDirection;
944
976
  device: CallDevice;
945
- start_time: number;
946
- answer_time: number;
947
- end_time: number;
977
+ /**
978
+ * Epoch timestamps for the call lifecycle. Optional because pre-answer
979
+ * states (e.g. `created`, `ringing`) do not have an `answer_time`/`end_time`
980
+ * and the backend reports them as `0` or omits them.
981
+ */
982
+ start_time?: number;
983
+ answer_time?: number;
984
+ end_time?: number;
948
985
  room_session_id: string;
986
+ /** The peer (remote) call this call is connected to, if any. */
987
+ peer?: CallStateRelatedCall;
988
+ /** Application-defined tag associated with the call. */
989
+ tag?: string;
949
990
  }
950
991
  interface CallPlayPayload {
951
992
  control_id: string;
@@ -1132,6 +1173,14 @@ declare class CallCreateError extends Error {
1132
1173
  direction: 'inbound' | 'outbound';
1133
1174
  constructor(message: string, error?: unknown, direction?: 'inbound' | 'outbound', options?: ErrorOptions);
1134
1175
  }
1176
+ declare class CallNotReadyError extends Error {
1177
+ callId: string;
1178
+ constructor(callId: string, options?: ErrorOptions);
1179
+ }
1180
+ declare class ParticipantNotReadyError extends Error {
1181
+ memberId: string;
1182
+ constructor(memberId: string, options?: ErrorOptions);
1183
+ }
1135
1184
  declare class VertoPongError extends Error {
1136
1185
  originalError: unknown;
1137
1186
  constructor(originalError: unknown);
@@ -1151,6 +1200,32 @@ declare class MediaTrackError extends Error {
1151
1200
  originalError: unknown;
1152
1201
  constructor(operation: string, kind: string, originalError: unknown);
1153
1202
  }
1203
+ /**
1204
+ * Failure to acquire local media (camera, microphone, or screen capture)
1205
+ * via `getUserMedia`/`getDisplayMedia`.
1206
+ *
1207
+ * Non-fatal by default: screenshare and additional-device failures never
1208
+ * end the call, and main-connection failures degrade to receive-only when
1209
+ * possible. The wrapping site sets `fatal` to `true` only when the call
1210
+ * cannot continue (receive-only fallback disabled or no receive intent).
1211
+ */
1212
+ declare class MediaAccessError extends Error {
1213
+ /** The SDK operation that failed, e.g. `'acquireLocalMedia'`, `'startScreenShare'`, `'addInputDevice'`. */
1214
+ operation: string;
1215
+ /** The media being acquired: `'audio' | 'video' | 'audiovideo' | 'screen'`. */
1216
+ media: string;
1217
+ /** The raw `getUserMedia`/`getDisplayMedia` error (typically a `DOMException`). */
1218
+ originalError: unknown;
1219
+ /** Whether this failure terminates the call. */
1220
+ readonly fatal: boolean;
1221
+ constructor(/** The SDK operation that failed, e.g. `'acquireLocalMedia'`, `'startScreenShare'`, `'addInputDevice'`. */
1222
+ operation: string, /** The media being acquired: `'audio' | 'video' | 'audiovideo' | 'screen'`. */
1223
+ media: string, /** The raw `getUserMedia`/`getDisplayMedia` error (typically a `DOMException`). */
1224
+ originalError: unknown, /** Whether this failure terminates the call. */
1225
+ fatal?: boolean);
1226
+ /** True when the underlying failure is a permission denial (user or policy). */
1227
+ get denied(): boolean;
1228
+ }
1154
1229
  declare class DPoPInitError extends Error {
1155
1230
  originalError: unknown;
1156
1231
  constructor(originalError: unknown, message?: string);
@@ -1491,6 +1566,8 @@ interface MemberCapabilities {
1491
1566
  readonly meta: boolean;
1492
1567
  readonly remove: boolean;
1493
1568
  readonly audioFlags: boolean;
1569
+ readonly denoise: boolean;
1570
+ readonly lowbitrate: boolean;
1494
1571
  }
1495
1572
  /**
1496
1573
  * Call-level capabilities state
@@ -1720,12 +1797,12 @@ type ParticipantState = Member & {
1720
1797
  * the local participant with additional device control.
1721
1798
  */
1722
1799
  declare class Participant extends Destroyable implements CallParticipant {
1723
- protected executeMethod: ExecuteMethod;
1800
+ private callExecuteMethod;
1724
1801
  protected deviceController: DeviceController;
1725
1802
  /** Unique member ID of this participant. */
1726
1803
  readonly id: string;
1727
1804
  private _state$;
1728
- constructor(id: string, executeMethod: ExecuteMethod, deviceController: DeviceController);
1805
+ constructor(id: string, callExecuteMethod: ExecuteMethod, deviceController: DeviceController);
1729
1806
  /** @internal */
1730
1807
  upnext(data: Partial<ParticipantState>): void;
1731
1808
  /** Observable of the participant's display name. */
@@ -1742,11 +1819,31 @@ declare class Participant extends Destroyable implements CallParticipant {
1742
1819
  get videoMuted$(): Observable<boolean | undefined>;
1743
1820
  /** Observable indicating whether the participant is deafened. */
1744
1821
  get deaf$(): Observable<boolean | undefined>;
1745
- /** Observable of the participant's microphone input volume. */
1822
+ /**
1823
+ * Observable of the participant's **server-side** microphone input volume
1824
+ * as reported by the mix engine. This is gain applied on the bridged audio
1825
+ * leg (FreeSWITCH channel read volume), NOT the local browser mic. For a
1826
+ * local PC mic control, see {@link Call.setLocalMicrophoneGain}.
1827
+ *
1828
+ * @see {@link setAudioInputVolume}
1829
+ */
1746
1830
  get inputVolume$(): Observable<number | undefined>;
1747
- /** Observable of the participant's speaker output volume. */
1831
+ /**
1832
+ * Observable of the participant's **server-side** speaker output volume as
1833
+ * reported by the mix engine (FreeSWITCH channel write volume). NOT the
1834
+ * local HTML `<audio>` element volume — set that on your own element.
1835
+ *
1836
+ * @see {@link setAudioOutputVolume}
1837
+ */
1748
1838
  get outputVolume$(): Observable<number | undefined>;
1749
- /** Observable of the microphone input sensitivity level. */
1839
+ /**
1840
+ * Observable of the **conference-only** microphone energy/gate sensitivity
1841
+ * level for this member. Routes through the conferencing mix engine and has
1842
+ * no effect on 1:1 WebRTC calls. Populated from `member.updated` events for
1843
+ * conference members.
1844
+ *
1845
+ * @see {@link setAudioInputSensitivity}
1846
+ */
1750
1847
  get inputSensitivity$(): Observable<number | undefined>;
1751
1848
  /** Observable indicating whether echo cancellation is enabled. */
1752
1849
  get echoCancellation$(): Observable<boolean | undefined>;
@@ -1760,8 +1857,8 @@ declare class Participant extends Destroyable implements CallParticipant {
1760
1857
  get denoise$(): Observable<boolean | undefined>;
1761
1858
  /** Observable of custom metadata for this participant. */
1762
1859
  get meta$(): Observable<Record<string, unknown> | undefined>;
1763
- /** Observable of the participant's subscriber ID. */
1764
- get subscriberId$(): Observable<string | undefined>;
1860
+ /** Observable of the participant's user ID. */
1861
+ get userId$(): Observable<string | undefined>;
1765
1862
  /** Observable of the participant's address ID. */
1766
1863
  get addressId$(): Observable<string | undefined>;
1767
1864
  /** Observable of the server node ID for this participant. */
@@ -1790,11 +1887,21 @@ declare class Participant extends Destroyable implements CallParticipant {
1790
1887
  get videoMuted(): boolean;
1791
1888
  /** Whether the participant is deafened (incoming audio muted). */
1792
1889
  get deaf(): boolean;
1793
- /** Current microphone input volume level, or `undefined` if not set. */
1890
+ /**
1891
+ * Current **server-side** microphone input volume as reported by the mix
1892
+ * engine, or `undefined` if not set. Not the local PC mic — see
1893
+ * {@link Call.setLocalMicrophoneGain} for browser-side control.
1894
+ */
1794
1895
  get inputVolume(): number | undefined;
1795
- /** Current speaker output volume level, or `undefined` if not set. */
1896
+ /**
1897
+ * Current **server-side** speaker output volume from the mix engine, or
1898
+ * `undefined` if not set. Not the local `<audio>` element volume.
1899
+ */
1796
1900
  get outputVolume(): number | undefined;
1797
- /** Current microphone input sensitivity level, or `undefined` if not set. */
1901
+ /**
1902
+ * Current **conference-only** microphone sensitivity/gate level, or
1903
+ * `undefined` if not set. Applies only to conference members.
1904
+ */
1798
1905
  get inputSensitivity(): number | undefined;
1799
1906
  /** Whether echo cancellation is enabled. */
1800
1907
  get echoCancellation(): boolean;
@@ -1808,14 +1915,40 @@ declare class Participant extends Destroyable implements CallParticipant {
1808
1915
  get denoise(): boolean;
1809
1916
  /** Custom metadata for this participant, or `undefined` if not set. */
1810
1917
  get meta(): Record<string, unknown> | undefined;
1811
- /** Subscriber ID of this participant, or `undefined` if not available. */
1812
- get subscriberId(): string | undefined;
1918
+ /** User ID of this participant, or `undefined` if not available. */
1919
+ get userId(): string | undefined;
1813
1920
  /** Address ID of this participant, or `undefined` if not available. */
1814
1921
  get addressId(): string | undefined;
1815
1922
  /** Server node ID for this participant, or `undefined` if not available. */
1816
1923
  get nodeId(): string | undefined;
1924
+ /** Call ID for this participant's leg, or `undefined` if not available. */
1925
+ get callId(): string | undefined;
1817
1926
  /** @internal */
1818
1927
  get value(): Partial<Member>;
1928
+ /**
1929
+ * Target triple for member RPCs, built from the participant's own state.
1930
+ * The backend locates the member's session by the target `call_id`/`node_id`,
1931
+ * so this must always be the participant's own call context — never the
1932
+ * local call's id (issue #19400).
1933
+ *
1934
+ * Reading it doubles as a readiness probe: it throws until the first full
1935
+ * member event (`member.joined`/`member.updated` or the `call.joined`
1936
+ * roster) arrives, and never regresses afterwards.
1937
+ *
1938
+ * @throws {ParticipantNotReadyError} If the member state has not been
1939
+ * received yet (e.g. a participant first seen via `member.talking`) — an
1940
+ * empty call context can never address the member, so fail fast instead of
1941
+ * sending a doomed RPC.
1942
+ */
1943
+ get target(): MemberTarget;
1944
+ /**
1945
+ * Executes a member RPC against this participant, injecting its own
1946
+ * {@link target} as the target.
1947
+ *
1948
+ * @throws {ParticipantNotReadyError} Via {@link target}, when the
1949
+ * member state has not been received yet.
1950
+ */
1951
+ protected executeMethod(method: string, args: Record<string, unknown>): Promise<JSONRPCResponse>;
1819
1952
  /** Toggles the deafened state (mutes/unmutes incoming audio). */
1820
1953
  toggleDeaf(): Promise<void>;
1821
1954
  /** Toggles the hand-raised state. */
@@ -1838,21 +1971,53 @@ declare class Participant extends Destroyable implements CallParticipant {
1838
1971
  toggleAudioInputAutoGain(): Promise<void>;
1839
1972
  /** Toggles noise suppression on the audio input. */
1840
1973
  toggleNoiseSuppression(): Promise<void>;
1974
+ /** Toggles low-bitrate mode for this participant's media. */
1841
1975
  toggleLowbitrate(): Promise<void>;
1842
- /** Sets the microphone input sensitivity level. */
1976
+ /**
1977
+ * Adjusts the **conference-only** microphone energy gate / sensitivity level
1978
+ * for this member. Routes through the conferencing mix engine
1979
+ * (`signalwire.conferencing member.set_input_sensitivity`) and has no effect
1980
+ * on 1:1 WebRTC calls — for those, use browser audio constraints via
1981
+ * {@link Call.setNoiseSuppression} / {@link Call.setAutoGainControl}.
1982
+ *
1983
+ * This is **not** a local PC mic gain control; it only changes how the
1984
+ * server-side mixer decides to open the mic gate on this participant.
1985
+ *
1986
+ * @param value - Sensitivity level as understood by the conference engine
1987
+ * (integer, larger values are more sensitive).
1988
+ */
1843
1989
  setAudioInputSensitivity(value: number): Promise<void>;
1844
1990
  /**
1845
- * Sets the microphone input volume level.
1991
+ * Sets the **server-side** microphone volume on this participant's bridged
1992
+ * call leg. Applies a multiplier to the audio flowing through the mix
1993
+ * engine (FreeSWITCH channel read volume) — changes what other participants
1994
+ * hear, not what the local browser captures.
1995
+ *
1996
+ * For local PC mic gain, use {@link Call.setLocalMicrophoneGain} instead.
1997
+ *
1846
1998
  * @param value - Volume level (0-100).
1847
1999
  */
1848
2000
  setAudioInputVolume(value: number): Promise<void>;
1849
2001
  /**
1850
- * Sets the speaker output volume level.
2002
+ * Sets the **server-side** speaker volume on this participant's bridged call
2003
+ * leg (FreeSWITCH channel write volume) — what this participant hears from
2004
+ * the mix before it reaches their client.
2005
+ *
2006
+ * For local playback volume (the `<audio>` element the consumer attaches
2007
+ * `remoteStream` to), set `audioElement.volume` directly in the consumer's
2008
+ * code.
2009
+ *
1851
2010
  * @param value - Volume level (0-100).
1852
2011
  */
1853
2012
  setAudioOutputVolume(value: number): Promise<void>;
1854
2013
  /**
1855
2014
  * Sets the participant's position in the video layout.
2015
+ *
2016
+ * Requires the `member.position` capability. The gateway requires a
2017
+ * `targets` array of `{ target, position }` entries (issue #19400). A
2018
+ * resolved promise does not guarantee a visible change: the backend silently
2019
+ * returns `200` (no-op) for non-conference targets.
2020
+ *
1856
2021
  * @param value - The {@link VideoPosition} to assign (e.g. `'auto'`, `'reserved-0'`).
1857
2022
  */
1858
2023
  setPosition(value: VideoPosition): Promise<void>;
@@ -1895,7 +2060,7 @@ declare class SelfParticipant extends Participant implements CallSelfParticipant
1895
2060
  */
1896
2061
  private _studioAudio$;
1897
2062
  /** @internal */
1898
- constructor(id: string, executeMethod: ExecuteMethod, vertoManager: VertoManager, deviceController: DeviceController);
2063
+ constructor(id: string, callExecuteMethod: ExecuteMethod, vertoManager: VertoManager, deviceController: DeviceController);
1899
2064
  destroy(): void;
1900
2065
  /** Observable indicating whether studio audio (raw/unprocessed audio) mode is enabled. */
1901
2066
  get studioAudio$(): Observable<boolean>;
@@ -1911,7 +2076,15 @@ declare class SelfParticipant extends Participant implements CallSelfParticipant
1911
2076
  * Sets echoCancellation, noiseSuppression, and autoGainControl to true.
1912
2077
  */
1913
2078
  disableStudioAudio(): Promise<void>;
1914
- /** Starts sharing the local screen. */
2079
+ /**
2080
+ * Starts sharing the local screen.
2081
+ *
2082
+ * The call is unaffected when acquisition fails.
2083
+ *
2084
+ * @throws The raw `getDisplayMedia` error. A dismissed picker or a
2085
+ * permission denial rejects with a `NotAllowedError` `DOMException` —
2086
+ * inspect `error.name` to tell benign cancels apart from real failures.
2087
+ */
1915
2088
  startScreenShare(): Promise<void>;
1916
2089
  /** Observable of the current screen share status. */
1917
2090
  get screenShareStatus$(): Observable<ScreenShareStatus>;
@@ -1919,7 +2092,14 @@ declare class SelfParticipant extends Participant implements CallSelfParticipant
1919
2092
  get screenShareStatus(): ScreenShareStatus;
1920
2093
  /** Stops the current screen share. */
1921
2094
  stopScreenShare(): Promise<void>;
1922
- /** Adds an additional media input device to the call. */
2095
+ /**
2096
+ * Adds an additional media input device to the call.
2097
+ *
2098
+ * The call is unaffected when acquisition fails.
2099
+ *
2100
+ * @throws The raw `getUserMedia` error (e.g. `NotAllowedError` on
2101
+ * permission denial) — inspect `error.name` to decide how to react.
2102
+ */
1923
2103
  addAdditionalDevice(options: MediaOptions): Promise<void>;
1924
2104
  /** Removes an additional media input device by ID. */
1925
2105
  removeAdditionalDevice(id: string): Promise<void>;
@@ -2002,7 +2182,7 @@ interface CallParticipant {
2002
2182
  readonly lowbitrate$: Observable<boolean | undefined>;
2003
2183
  readonly denoise$: Observable<boolean | undefined>;
2004
2184
  readonly meta$: Observable<Record<string, unknown> | undefined>;
2005
- readonly subscriberId$: Observable<string | undefined>;
2185
+ readonly userId$: Observable<string | undefined>;
2006
2186
  readonly addressId$: Observable<string | undefined>;
2007
2187
  readonly nodeId$: Observable<string | undefined>;
2008
2188
  readonly isTalking$: Observable<boolean | undefined>;
@@ -2023,9 +2203,13 @@ interface CallParticipant {
2023
2203
  readonly lowbitrate: boolean;
2024
2204
  readonly denoise: boolean;
2025
2205
  readonly meta: Record<string, unknown> | undefined;
2026
- readonly subscriberId: string | undefined;
2206
+ readonly userId: string | undefined;
2027
2207
  readonly addressId: string | undefined;
2028
2208
  readonly nodeId: string | undefined;
2209
+ readonly callId: string | undefined;
2210
+ /** The member's own RPC target triple. Throws `ParticipantNotReadyError`
2211
+ * until the member's call context has been received. */
2212
+ readonly target: MemberTarget;
2029
2213
  readonly isTalking: boolean;
2030
2214
  readonly position: LayoutLayer | undefined;
2031
2215
  readonly isAudience: boolean;
@@ -2107,7 +2291,12 @@ interface CallAddress {
2107
2291
  type CallStatus = 'new' | 'trying' | 'ringing' | 'connecting' | 'connected' | 'recovering' | 'disconnecting' | 'disconnected' | 'failed' | 'destroyed';
2108
2292
  /** Configuration options for creating a call. */
2109
2293
  interface CallOptions extends MediaOptions {
2110
- /** Target server node ID. */
2294
+ /**
2295
+ * Optional. Hint to the cluster about which node should host this call.
2296
+ * Used by reattach to pin to the original node; on fresh dials acts as a
2297
+ * steering preference (the server may ignore for placement reasons).
2298
+ * Leave undefined for normal load-balanced placement.
2299
+ */
2111
2300
  readonly nodeId?: string;
2112
2301
  /** Pre-assigned call ID (used for reattach). */
2113
2302
  readonly callId?: string;
@@ -2168,6 +2357,9 @@ interface Call extends CallState {
2168
2357
  readonly self$: Observable<CallSelfParticipant | null>;
2169
2358
  readonly self: CallSelfParticipant | null;
2170
2359
  readonly to?: string;
2360
+ readonly toName?: string;
2361
+ readonly from?: string;
2362
+ readonly fromName?: string;
2171
2363
  readonly direction: CallDirection;
2172
2364
  readonly layouts$: Observable<string[]>;
2173
2365
  readonly layouts: string[];
@@ -2225,9 +2417,6 @@ interface Call extends CallState {
2225
2417
  */
2226
2418
  interface CallManager extends Call {
2227
2419
  readonly options: CallOptions;
2228
- readonly fromName?: string;
2229
- readonly from?: string;
2230
- readonly toName?: string;
2231
2420
  readonly selfId$: Observable<string | null>;
2232
2421
  readonly selfId: string | null;
2233
2422
  readonly nodeId$: Observable<string | null>;
@@ -2497,11 +2686,19 @@ declare class AttachManager {
2497
2686
  private readonly reconnectCallsTimeout;
2498
2687
  private attachKey;
2499
2688
  private session;
2689
+ private writeQueue;
2500
2690
  constructor(storage: StorageManager, deviceController: DeviceController, reconnectCallsTimeout: number, attachKey: string);
2501
2691
  detachAll(): Promise<void>;
2502
2692
  setSession(session: OutboundCallProvider): void;
2503
2693
  private readAttached;
2504
2694
  private writeAttached;
2695
+ /**
2696
+ * Serialize a read-modify-write operation against the attached-calls
2697
+ * storage. The mutator receives the current state and returns the new
2698
+ * state. Concurrent calls queue behind the in-flight one so writes never
2699
+ * interleave.
2700
+ */
2701
+ private mutate;
2505
2702
  attach(call: AttachableCall): Promise<void>;
2506
2703
  detach(call: AttachableCall): Promise<void>;
2507
2704
  flush(): Promise<void>;
@@ -2527,10 +2724,15 @@ declare class AttachManager {
2527
2724
  */
2528
2725
  buildCallOptions(attachment: Attachment): CallOptions;
2529
2726
  /**
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).
2727
+ * Look up stored attachment data for a call id and return CallOptions
2728
+ * suitable for rehydrating a reattached call. Returns undefined when no
2729
+ * matching entry exists in storage.
2730
+ *
2731
+ * Used by the session-level verto.attach handler when the server pushes
2732
+ * an attach event for a call the client doesn't have an object for yet
2733
+ * (e.g. after a reload).
2532
2734
  */
2533
- consumePendingAttachment(_callId: string): CallOptions | undefined;
2735
+ consumePendingAttachment(callId: string): Promise<CallOptions | undefined>;
2534
2736
  private detachExpired;
2535
2737
  }
2536
2738
  //#endregion
@@ -2826,14 +3028,14 @@ declare class ClientSessionManager extends Destroyable implements SessionState {
2826
3028
  private _authState$;
2827
3029
  /** Sticky flag — once true, stays true for the session lifetime. */
2828
3030
  private _wasClientBound;
2829
- private _subscriberInfo$;
3031
+ private _userInfo$;
2830
3032
  private _calls$;
2831
3033
  private _iceServers$;
2832
3034
  constructor(getCredential: () => SDKCredential, transport: TransportManager, storage: StorageManager, authorizationStateKey: string, deviceController: DeviceController, attachManager: AttachManager, webRTCApiProvider: WebRTCApiProvider, dpopManager?: CryptoController | undefined, networkChange$?: Observable<NetworkChangeEvent>);
2833
3035
  get incomingCalls$(): Observable<Call[]>;
2834
3036
  get incomingCalls(): Call[];
2835
- get subscriberInfo$(): Observable<Address | null>;
2836
- get subscriberInfo(): Address | null;
3037
+ get userInfo$(): Observable<Address | null>;
3038
+ get userInfo(): Address | null;
2837
3039
  get calls$(): Observable<Call[]>;
2838
3040
  get calls(): Call[];
2839
3041
  get iceServers(): RTCIceServer[] | undefined;
@@ -3022,7 +3224,34 @@ declare class ClientSessionManager extends Destroyable implements SessionState {
3022
3224
  private get authentication();
3023
3225
  connect(): Promise<void>;
3024
3226
  private handleAuthenticationError;
3227
+ /**
3228
+ * Clear the resume state (authorization_state + protocol) only.
3229
+ *
3230
+ * This is the stale-auth-state recovery helper used by handleAuthError:
3231
+ * the server rejected a reconnect, so the resume state is discarded and a
3232
+ * fresh connect follows. Attach records are deliberately preserved — the
3233
+ * session lives on through the reconnect and reattachCalls() needs the
3234
+ * stored call references afterwards. Do NOT add detachAll() here.
3235
+ *
3236
+ * For public teardown (disconnect/destroy), use {@link teardownSessionState}
3237
+ * instead, which clears the attach records as well.
3238
+ */
3025
3239
  cleanupStoredConnectionParams(): Promise<void>;
3240
+ /**
3241
+ * Public-teardown helper for disconnect()/destroy(). Clears the resume
3242
+ * state (authorization_state + protocol) AND the attach records as one
3243
+ * atomic unit.
3244
+ *
3245
+ * The two stores are coupled: the backend only honors attach records
3246
+ * within the session identified by the resume state, so ending the
3247
+ * session must clear both. Clearing one without the other strands records
3248
+ * no future session can honor (disconnect) or revives a session the
3249
+ * developer explicitly ended (destroy).
3250
+ *
3251
+ * Distinct from {@link cleanupStoredConnectionParams}, which keeps the
3252
+ * attach records for the stale-auth-state recovery path.
3253
+ */
3254
+ teardownSessionState(): Promise<void>;
3026
3255
  protected updateAuthState(authorization_state: string): Promise<void>;
3027
3256
  reauthenticate(token: string, dpopToken?: string, options?: {
3028
3257
  clientBound?: boolean;
@@ -3049,6 +3278,12 @@ declare class ClientSessionWrapper implements SessionState {
3049
3278
  constructor(clientSessionManager: ClientSessionManager);
3050
3279
  get authenticated$(): Observable<boolean>;
3051
3280
  get authenticated(): boolean;
3281
+ /**
3282
+ * Whether the session is using a Client Bound SAT (DPoP). Sticky — set
3283
+ * when the binding is established or restored from a resumed session's
3284
+ * server authorization.
3285
+ */
3286
+ get clientBound(): boolean;
3052
3287
  get signalingEvent$(): Observable<(Omit<{
3053
3288
  event_type: "webrtc.message";
3054
3289
  event_channel: EventChannel;
@@ -3207,6 +3442,60 @@ declare class ClientSessionWrapper implements SessionState {
3207
3442
  get calls(): Call[];
3208
3443
  }
3209
3444
  //#endregion
3445
+ //#region src/core/types/warnings.types.d.ts
3446
+ /**
3447
+ * Non-fatal warning emitted via {@link SignalWire.warnings$ | client.warnings$}.
3448
+ *
3449
+ * Use to detect SDK behaviors that affect session liveness or developer-facing
3450
+ * contracts but do not warrant disconnection. Discriminated by `code`.
3451
+ *
3452
+ * Existing consumers of `errors$` are NOT notified — `warnings$` is a separate
3453
+ * channel so application code can react to warnings without triggering
3454
+ * error-handling code paths (e.g., disconnect cascades, user-facing toasts).
3455
+ */
3456
+ type SDKWarning = CredentialRefreshFallbackWarning | CredentialNoRefreshHandlerWarning;
3457
+ /**
3458
+ * Diagnostic detail for {@link CredentialRefreshFallbackWarning}. Stable
3459
+ * values, but treat unknown strings as "fell back for an unspecified cause" —
3460
+ * do not branch on this value for control flow. New values may be added in
3461
+ * future releases.
3462
+ */
3463
+ type CredentialRefreshFallbackReason = 'no-scope' | 'no-dpop-support' | 'endpoint-failed' | 'activation-timeout' | (string & {});
3464
+ /**
3465
+ * Emitted when the SDK falls back to the developer-provided
3466
+ * {@link CredentialProvider.refresh} because the Client Bound SAT path
3467
+ * could not take over.
3468
+ *
3469
+ * Common causes:
3470
+ * - The minted SAT lacks `sat:refresh` scope (`reason: 'no-scope'`).
3471
+ * - The `/devices/token` exchange failed transiently (`reason: 'endpoint-failed'`).
3472
+ *
3473
+ * Subscribe to this warning to detect:
3474
+ * - SDKs running with plain SATs that rely on developer-managed refresh
3475
+ * - Deployments expected to use bound tokens that silently downgraded to bearer
3476
+ * (a security-relevant signal for fleet observability)
3477
+ */
3478
+ interface CredentialRefreshFallbackWarning {
3479
+ code: 'credential_refresh_fallback';
3480
+ source: 'CredentialProvider';
3481
+ reason: CredentialRefreshFallbackReason;
3482
+ message: string;
3483
+ }
3484
+ /**
3485
+ * Emitted when a credential has an `expiry_at` but the provider supplies no
3486
+ * `refresh()` handler. The session will terminate at expiry with no fallback.
3487
+ *
3488
+ * Implementors who want long-lived sessions must provide a `refresh()` handler
3489
+ * or mint tokens with the `sat:refresh` scope (Client Bound SAT path).
3490
+ */
3491
+ interface CredentialNoRefreshHandlerWarning {
3492
+ code: 'credential_no_refresh_handler';
3493
+ source: 'CredentialProvider';
3494
+ message: string;
3495
+ /** Token expiry timestamp (epoch milliseconds). */
3496
+ expiresAt: number;
3497
+ }
3498
+ //#endregion
3210
3499
  //#region src/utils/logger.d.ts
3211
3500
  /** Log level names supported by the SDK. */
3212
3501
  type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent';
@@ -3221,11 +3510,30 @@ interface SDKLogger {
3221
3510
  debug(...args: unknown[]): void;
3222
3511
  trace(...args: unknown[]): void;
3223
3512
  }
3513
+ /** Options for WebSocket traffic logging. */
3514
+ interface WsTrafficOptions {
3515
+ type: 'send' | 'recv' | 'http';
3516
+ /** Parsed object or raw string — will be JSON.stringify'd for display if an object. */
3517
+ payload: unknown;
3518
+ }
3519
+ /**
3520
+ * Options for WebSocket traffic logging using raw strings.
3521
+ * The string is only parsed when logging is enabled, avoiding
3522
+ * unnecessary JSON.parse on every message.
3523
+ */
3524
+ interface WsTrafficRawOptions {
3525
+ type: 'send' | 'recv';
3526
+ raw: string;
3527
+ }
3224
3528
  /** Debug options that control verbose SDK logging. */
3225
3529
  interface DebugOptions {
3226
3530
  /** Log all WebSocket send/recv traffic to the console. */
3227
3531
  logWsTraffic?: boolean;
3228
3532
  }
3533
+ /** Extended logger with SDK-internal helpers (wsTraffic). */
3534
+ interface InternalSDKLogger extends SDKLogger {
3535
+ wsTraffic: (options: WsTrafficOptions | WsTrafficRawOptions) => void;
3536
+ }
3229
3537
  /** Replace the built-in logger with a custom implementation. Pass `null` to restore defaults. */
3230
3538
  declare const setLogger: (logger: SDKLogger | null) => void;
3231
3539
  /** Configure debug options (e.g., `{ logWsTraffic: true }`). */
@@ -3235,13 +3543,14 @@ declare const setDebugOptions: (options: DebugOptions | null) => void;
3235
3543
  * Has no effect when a custom logger is set via `setLogger()`.
3236
3544
  */
3237
3545
  declare const setLogLevel: (level: LogLevel) => void;
3546
+ declare const getLogger: () => InternalSDKLogger;
3238
3547
  //#endregion
3239
3548
  //#region src/clients/SignalWire.d.ts
3240
3549
  /** Options for constructing a {@link SignalWire}. */
3241
3550
  interface SignalWireOptions {
3242
3551
  /** Skip automatic WebSocket connection on construction. */
3243
3552
  skipConnection?: boolean;
3244
- /** Skip automatic subscriber registration on construction. */
3553
+ /** Skip automatic user registration on construction. */
3245
3554
  skipRegister?: boolean;
3246
3555
  /** Skip monitoring media device changes. */
3247
3556
  skipDeviceMonitoring?: boolean;
@@ -3260,8 +3569,12 @@ interface SignalWireOptions {
3260
3569
  * When `false` (default), session data lives in `sessionStorage` and is
3261
3570
  * lost on reload.
3262
3571
  *
3263
- * Call {@link SignalWire.destroy | destroy()} to clear all persisted state
3264
- * (explicit logout).
3572
+ * Both {@link SignalWire.disconnect | disconnect()} and
3573
+ * {@link SignalWire.destroy | destroy()} end the session and clear the
3574
+ * persisted resume state and attach records; credentials and device
3575
+ * preferences survive. Use `resetToDefaults()` for a full wipe, or
3576
+ * `unregister()` to temporarily stop receiving inbound calls while keeping
3577
+ * the session alive.
3265
3578
  */
3266
3579
  persistSession?: boolean;
3267
3580
  /** Custom storage implementation for persistence. */
@@ -3298,6 +3611,12 @@ interface DialOptions extends MediaOptions {
3298
3611
  stereo?: boolean;
3299
3612
  /** Optional node ID for routing the call */
3300
3613
  nodeId?: string;
3614
+ /**
3615
+ * Custom variables sent with the Verto invite. Merged with
3616
+ * `client.preferences.userVariables` and any query-string variables on the
3617
+ * destination URI; values here take precedence.
3618
+ */
3619
+ userVariables?: Record<string, unknown>;
3301
3620
  }
3302
3621
  /**
3303
3622
  * Main entry point for the SignalWire Browser SDK.
@@ -3314,7 +3633,7 @@ interface DialOptions extends MediaOptions {
3314
3633
  declare class SignalWire extends Destroyable implements DeviceController {
3315
3634
  /** Global SDK preferences (timeouts, ICE config, media defaults). */
3316
3635
  preferences: ClientPreferences;
3317
- private _subscriber$;
3636
+ private _user$;
3318
3637
  private _directory$;
3319
3638
  private _transport;
3320
3639
  private _clientSession;
@@ -3324,10 +3643,10 @@ declare class SignalWire extends Destroyable implements DeviceController {
3324
3643
  private _isConnected$;
3325
3644
  private _isRegistered$;
3326
3645
  private _errors$;
3646
+ private _warnings$;
3327
3647
  private _options;
3328
- private _refreshTimerId?;
3329
3648
  private _dpopManager?;
3330
- private _deviceTokenManager?;
3649
+ private _refreshCoordinator?;
3331
3650
  private _credentialProvider?;
3332
3651
  private _deps;
3333
3652
  private _networkMonitor?;
@@ -3356,11 +3675,58 @@ declare class SignalWire extends Destroyable implements DeviceController {
3356
3675
  private resolveCredentials;
3357
3676
  private validateCredentials;
3358
3677
  /**
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.
3678
+ * Reauthenticate the currently-open session with a freshly obtained
3679
+ * credential so the new token takes effect on the live socket immediately —
3680
+ * not just on the next reconnect. No-op when the session is not
3681
+ * connected/authenticated or the credential carries no token (e.g. an
3682
+ * authorization-state-only refresh). Non-fatal: reauth failures surface on
3683
+ * `errors$` without aborting the refresh that triggered this.
3684
+ */
3685
+ private reauthenticateLiveSession;
3686
+ /**
3687
+ * One-shot recovery for a live session that failed with a recoverable auth
3688
+ * error (`-32002`/`-32003`) because its token went stale — e.g. a refresh
3689
+ * timer that was throttled while the tab was backgrounded.
3690
+ *
3691
+ * Two steps, first that succeeds wins:
3692
+ * 1. Reauthenticate with the in-memory token (a fresh DPoP proof is
3693
+ * generated automatically). Heals a session whose token was already
3694
+ * refreshed by the coordinator but never applied to the open socket,
3695
+ * and a client-bound session whose server-side auth merely drifted.
3696
+ * 2. Re-mint via the developer provider's `refresh()` and reauthenticate.
3697
+ * Skipped for client-bound sessions (the DeviceTokenManager owns their
3698
+ * refresh; re-minting a base SAT here would drop the DPoP binding).
3699
+ *
3700
+ * @param allowRemint - Whether step 2 (provider re-mint) may run. Callers
3701
+ * pass `false` for non-auth failures so a transient network error never
3702
+ * escalates to a token re-mint; step 1 (in-memory reauth) always runs.
3703
+ * @returns `true` if the session was reauthenticated, `false` otherwise.
3704
+ */
3705
+ private recoverStaleCredential;
3706
+ /**
3707
+ * Re-mint a credential via `provider.refresh()`, routed through the
3708
+ * coordinator's shared in-flight guard so concurrent re-mint paths (a
3709
+ * scheduled/resume refresh, -32003 recovery, and reconnect) never fire a
3710
+ * second `provider.refresh()` in parallel — which rotating one-time-use
3711
+ * refresh tokens reject. Falls back to a direct call only if the coordinator
3712
+ * has not been constructed yet.
3713
+ */
3714
+ private remintCredential;
3715
+ /**
3716
+ * Re-mint credentials before a fresh (re)connect (`onBeforeReconnect` hook).
3717
+ * The session invokes this only when it is client-bound OR the in-memory
3718
+ * token is expired. The re-mint mechanism depends on the binding:
3719
+ * - Client-bound: `authenticate()` with the DPoP fingerprint to obtain a
3720
+ * fresh base SAT the upcoming reconnect can re-bind (the
3721
+ * DeviceTokenManager re-activates afterwards).
3722
+ * - Unbound: the developer's non-interactive `refresh()` handler.
3723
+ * `authenticate()` is deliberately NOT used here — it may be interactive
3724
+ * (a login prompt) and must not fire on a background reconnect.
3725
+ *
3726
+ * Rejects on failure so the session aborts the reconnect rather than
3727
+ * replaying a stale token.
3362
3728
  */
3363
- private scheduleCredentialRefresh;
3729
+ private refreshCredentialForReconnect;
3364
3730
  /** Persist credential to localStorage when persistSession is enabled. */
3365
3731
  private persistCredential;
3366
3732
  private init;
@@ -3404,19 +3770,19 @@ declare class SignalWire extends Destroyable implements DeviceController {
3404
3770
  */
3405
3771
  connect(): Promise<void>;
3406
3772
  /**
3407
- * Observable that emits the {@link Subscriber} profile once fetched,
3773
+ * Observable that emits the {@link User} profile once fetched,
3408
3774
  * or `undefined` before authentication completes.
3409
3775
  *
3410
3776
  * @example
3411
3777
  * ```ts
3412
- * client.subscriber$.subscribe(sub => {
3413
- * if (sub) console.log('Logged in as', sub.email);
3778
+ * client.user$.subscribe(u => {
3779
+ * if (u) console.log('Logged in as', u.email);
3414
3780
  * });
3415
3781
  * ```
3416
3782
  */
3417
- get subscriber$(): Observable<Subscriber | undefined>;
3418
- /** Current subscriber snapshot, or `undefined` if not yet authenticated. */
3419
- get subscriber(): Subscriber | undefined;
3783
+ get user$(): Observable<User | undefined>;
3784
+ /** Current user snapshot, or `undefined` if not yet authenticated. */
3785
+ get user(): User | undefined;
3420
3786
  /**
3421
3787
  * Observable that emits the {@link Directory} instance once the client is connected,
3422
3788
  * or `undefined` while disconnected. Subscribe to this to safely wait for the directory
@@ -3435,9 +3801,9 @@ declare class SignalWire extends Destroyable implements DeviceController {
3435
3801
  * Prefer {@link directory$} when you need to react to the directory becoming available.
3436
3802
  */
3437
3803
  get directory(): Directory | undefined;
3438
- /** Observable that emits when the subscriber registration state changes. */
3804
+ /** Observable that emits when the user registration state changes. */
3439
3805
  get isRegistered$(): Observable<boolean>;
3440
- /** Whether the subscriber is currently registered. */
3806
+ /** Whether the user is currently registered. */
3441
3807
  get isRegistered(): boolean;
3442
3808
  /** Whether the client is currently connected. */
3443
3809
  get isConnected(): boolean;
@@ -3447,6 +3813,17 @@ declare class SignalWire extends Destroyable implements DeviceController {
3447
3813
  get ready$(): Observable<boolean>;
3448
3814
  /** Observable stream of errors from transport, authentication, and devices. */
3449
3815
  get errors$(): Observable<Error>;
3816
+ /**
3817
+ * Observable stream of non-fatal SDK warnings.
3818
+ *
3819
+ * Subscribe to detect SDK behaviors that affect session liveness or developer-facing
3820
+ * contracts but do not warrant disconnection — e.g., a fallback from Client Bound SAT
3821
+ * refresh to the developer-provided `refresh()` because the SAT lacks `sat:refresh`
3822
+ * scope. Discriminated by `code`.
3823
+ *
3824
+ * Independent from {@link errors$}: existing error consumers are not notified.
3825
+ */
3826
+ get warnings$(): Observable<SDKWarning>;
3450
3827
  /** Platform WebRTC capabilities detected at construction time. */
3451
3828
  get platformCapabilities(): PlatformCapabilities;
3452
3829
  /** Observable that emits when the SDK auto-switches a device. */
@@ -3464,13 +3841,26 @@ declare class SignalWire extends Destroyable implements DeviceController {
3464
3841
  /**
3465
3842
  * Disconnects the WebSocket and tears down the current session.
3466
3843
  *
3844
+ * Ends the session identified by the protocol and clears its persisted
3845
+ * resume state (`authorization_state` + protocol) and attach records
3846
+ * together — a later {@link connect} with the same credentials starts a
3847
+ * fresh session and cannot reattach to the ended session's calls.
3848
+ * Credentials and device preferences are preserved. To temporarily stop
3849
+ * receiving inbound calls while keeping the session alive, use
3850
+ * `unregister()` instead.
3851
+ *
3467
3852
  * The client can be reconnected by calling {@link connect} again,
3468
3853
  * which creates a fresh transport and session.
3469
3854
  */
3470
3855
  disconnect(): Promise<void>;
3856
+ /**
3857
+ * Tear down the current transport / session / attach manager. Safe to call
3858
+ * when nothing has been initialized yet (e.g. first connect()).
3859
+ */
3860
+ private teardownTransportAndSession;
3471
3861
  private waitAuthentication;
3472
3862
  /**
3473
- * Registers the subscriber as online to receive inbound calls and events.
3863
+ * Registers the user as online to receive inbound calls and events.
3474
3864
  *
3475
3865
  * Waits for authentication to complete before sending the registration.
3476
3866
  * If the initial attempt fails, reauthentication is attempted automatically.
@@ -3479,7 +3869,7 @@ declare class SignalWire extends Destroyable implements DeviceController {
3479
3869
  */
3480
3870
  register(): Promise<void>;
3481
3871
  /**
3482
- * Unregisters the subscriber, going offline for inbound calls.
3872
+ * Unregisters the user, going offline for inbound calls.
3483
3873
  *
3484
3874
  * The WebSocket connection remains open; use {@link disconnect} to fully close it.
3485
3875
  */
@@ -3568,6 +3958,21 @@ declare class SignalWire extends Destroyable implements DeviceController {
3568
3958
  selectVideoInputDevice(device: MediaDeviceInfo | null): void;
3569
3959
  /** Sets the preferred audio output device. */
3570
3960
  selectAudioOutputDevice(device: MediaDeviceInfo | null): void;
3961
+ /**
3962
+ * Apply the currently selected audio output device to an HTMLMediaElement
3963
+ * (e.g. the `<audio>` or `<video>` element the consumer attached the
3964
+ * remote stream to). Uses `HTMLMediaElement.setSinkId` under the hood.
3965
+ * Returns a `Promise<boolean>`: `true` if the sink was applied,
3966
+ * `false` if the browser doesn't support `setSinkId` or no device is
3967
+ * selected.
3968
+ *
3969
+ * @example
3970
+ * ```ts
3971
+ * audioEl.srcObject = call.remoteStream;
3972
+ * await client.applySelectedAudioOutputDevice(audioEl);
3973
+ * ```
3974
+ */
3975
+ applySelectedAudioOutputDevice(element: HTMLMediaElement): Promise<boolean>;
3571
3976
  /** Starts monitoring for media device changes (connect/disconnect). */
3572
3977
  enableDeviceMonitoring(): void;
3573
3978
  /** Stops monitoring for media device changes. */
@@ -3625,7 +4030,15 @@ declare class SignalWire extends Destroyable implements DeviceController {
3625
4030
  * attached call IDs, and all SDK storage keys, then re-enumerates devices.
3626
4031
  */
3627
4032
  resetToDefaults(): Promise<void>;
3628
- /** Destroys the client, clearing timers and releasing all resources. */
4033
+ /**
4034
+ * Destroys the client, clearing timers and releasing all resources.
4035
+ *
4036
+ * Intentionally destroying the client ends its session: the resume state
4037
+ * (`authorization_state` + protocol) and the attach records are both
4038
+ * cleared. Credentials and device preferences are preserved — use
4039
+ * {@link resetToDefaults} for a full wipe. To temporarily stop receiving
4040
+ * inbound calls while keeping the session alive, use `unregister()`.
4041
+ */
3629
4042
  destroy(): void;
3630
4043
  }
3631
4044
  //#endregion
@@ -3668,6 +4081,126 @@ declare class StaticCredentialProvider implements CredentialProvider {
3668
4081
  authenticate(): Promise<SDKCredential>;
3669
4082
  }
3670
4083
  //#endregion
4084
+ //#region src/dependencies/EmbedTokenCredentialProvider.d.ts
4085
+ /** Credential provider that exchanges an embed token for a SAT via the host's token endpoint. */
4086
+ declare class EmbedTokenCredentialProvider implements CredentialProvider {
4087
+ private host;
4088
+ private embedToken;
4089
+ constructor(host: string, embedToken: string);
4090
+ private fetchSAT;
4091
+ authenticate(): Promise<{
4092
+ token: string;
4093
+ expiry_at: number;
4094
+ }>;
4095
+ refresh(): Promise<{
4096
+ token: string;
4097
+ expiry_at: number;
4098
+ }>;
4099
+ }
4100
+ //#endregion
4101
+ //#region src/controllers/LocalAudioPipeline.d.ts
4102
+ /**
4103
+ * Options for {@link LocalAudioPipeline}.
4104
+ */
4105
+ interface LocalAudioPipelineOptions {
4106
+ /** Factory for AudioContext — override for tests. Defaults to `new AudioContext()`. */
4107
+ audioContextFactory?: () => AudioContext;
4108
+ /** Initial gain (0..2, where 1 is unity). Defaults to 1. */
4109
+ initialGain?: number;
4110
+ /** RMS level [0..1] above which speaking$ emits true. Defaults to {@link VAD_THRESHOLD}. */
4111
+ speakingThreshold?: number;
4112
+ /**
4113
+ * Milliseconds of silence below the threshold before speaking$ flips back to
4114
+ * false. Prevents flicker on normal speech gaps. Defaults to {@link VAD_HOLD_MS}.
4115
+ */
4116
+ speakingHoldMs?: number;
4117
+ /** Polling interval for level$. Defaults to {@link AUDIO_LEVEL_POLL_INTERVAL_MS}. */
4118
+ pollIntervalMs?: number;
4119
+ }
4120
+ /**
4121
+ * Web Audio pipeline for the local microphone stream.
4122
+ *
4123
+ * Wraps the raw mic `MediaStreamTrack` in a graph of:
4124
+ *
4125
+ * ```
4126
+ * MediaStreamAudioSourceNode → GainNode → AnalyserNode → MediaStreamAudioDestinationNode
4127
+ * ```
4128
+ *
4129
+ * The {@link outputTrack} from the destination node is what callers should
4130
+ * attach to the `RTCRtpSender` in place of the raw mic track. The same
4131
+ * destination track is reused across input changes (device switch, mute /
4132
+ * unmute track replacement) so the sender reference stays stable — only the
4133
+ * source end of the graph is rebuilt.
4134
+ *
4135
+ * The pipeline owns a single {@link AudioContext}. Callers must invoke
4136
+ * {@link destroy} to release it when the call ends.
4137
+ */
4138
+ declare class LocalAudioPipeline extends Destroyable {
4139
+ private readonly _audioContext;
4140
+ private readonly _gainNode;
4141
+ private readonly _analyser;
4142
+ private readonly _destination;
4143
+ private readonly _analyserBuffer;
4144
+ private readonly _speakingThreshold;
4145
+ private readonly _speakingHoldMs;
4146
+ private readonly _pollIntervalMs;
4147
+ private _inputSource;
4148
+ private _inputStream;
4149
+ private _lastSpokeAt;
4150
+ private _gain$;
4151
+ /** 1 when audio should pass through, 0 when silenced by PTT. */
4152
+ private _pttMultiplier;
4153
+ constructor(options?: LocalAudioPipelineOptions);
4154
+ /** Observable of the current gain value (0..2). */
4155
+ get gain$(): Observable<number>;
4156
+ /** Current gain value (0..2). */
4157
+ get gain(): number;
4158
+ /**
4159
+ * Processed output track to attach to the RTCRtpSender. Stable reference
4160
+ * across input changes, so `sender.replaceTrack(pipeline.outputTrack)` only
4161
+ * needs to be called once.
4162
+ */
4163
+ get outputTrack(): MediaStreamTrack;
4164
+ /**
4165
+ * Root-mean-square audio level of the input signal, 0..1. Emits on a fixed
4166
+ * interval (~30fps by default).
4167
+ */
4168
+ get level$(): Observable<number>;
4169
+ /**
4170
+ * Boolean VAD derived from {@link level$}. True while level ≥ threshold or
4171
+ * during the hold window after the last frame that crossed the threshold.
4172
+ */
4173
+ get speaking$(): Observable<boolean>;
4174
+ /**
4175
+ * Set gain multiplier applied to the input signal. 0 = silence,
4176
+ * 1 = unity, 2 = 2x. Values are clamped to [0, 2]. The effective gain on
4177
+ * the graph also respects the current PTT state.
4178
+ */
4179
+ setGain(value: number): void;
4180
+ /**
4181
+ * Silence the graph when `active = false`, otherwise restore the configured
4182
+ * gain. Use this from a PTT handler: released → `false`, held → `true`.
4183
+ * Orthogonal to {@link setGain} — once PTT returns to active, the last
4184
+ * configured gain reappears.
4185
+ */
4186
+ setPTTActive(active: boolean): void;
4187
+ private applyEffectiveGain;
4188
+ /**
4189
+ * Wire a new raw mic track as the pipeline's input. Replaces any previous
4190
+ * input source and reconnects the graph so {@link outputTrack} continues
4191
+ * to emit the processed audio. Pass `null` to disconnect the input (the
4192
+ * output track stays alive but emits silence).
4193
+ *
4194
+ * Also resumes the underlying AudioContext on attach — Chrome creates it
4195
+ * in a suspended state and the graph won't process (the destination
4196
+ * track emits silence) until resume() succeeds.
4197
+ */
4198
+ setInputTrack(track: MediaStreamTrack | null): void;
4199
+ destroy(): void;
4200
+ private computeLevel;
4201
+ private evaluateSpeaking;
4202
+ }
4203
+ //#endregion
3671
4204
  //#region src/controllers/RTCPeerConnectionController.d.ts
3672
4205
  interface RTCPeerConnectionControllerOptions extends MediaOptions {
3673
4206
  callId?: string;
@@ -3728,6 +4261,7 @@ declare class RTCPeerConnectionController extends Destroyable {
3728
4261
  private _remoteDescription$;
3729
4262
  private _remoteStream$;
3730
4263
  private _remoteOfferMediaDirections;
4264
+ private _localAudioPipeline;
3731
4265
  constructor(options?: RTCPeerConnectionControllerOptionsPartial, remoteSessionDescription?: string, deviceController?: DeviceController);
3732
4266
  private get iceGatheringController();
3733
4267
  private get shouldEmitLocalDescription();
@@ -3737,6 +4271,7 @@ declare class RTCPeerConnectionController extends Destroyable {
3737
4271
  stopTrackSender(kind: 'audio' | 'video' | 'both', options?: {
3738
4272
  updateTransceiverDirection: boolean;
3739
4273
  }): void;
4274
+ private stopRawAudioInputForPipeline;
3740
4275
  get isNegotiating$(): Observable<boolean>;
3741
4276
  get isNegotiating(): boolean;
3742
4277
  updateMediaDevicesOptions(options: MediaOptions): void;
@@ -3815,7 +4350,6 @@ declare class RTCPeerConnectionController extends Destroyable {
3815
4350
  */
3816
4351
  private setupEventListeners;
3817
4352
  private negotiationEnded;
3818
- restarIce(): void;
3819
4353
  /**
3820
4354
  * Trigger an ICE restart through the existing negotiation pipeline.
3821
4355
  *
@@ -3837,10 +4371,41 @@ declare class RTCPeerConnectionController extends Destroyable {
3837
4371
  */
3838
4372
  private setupTrackHandling;
3839
4373
  private setupLocalTracks;
4374
+ /** True for a main connection with no local media to send. */
4375
+ private hasNoLocalMediaToSend;
4376
+ /** The media kinds this connection wants to send: 'audiovideo' | 'video' | 'audio'. */
4377
+ private get requestedMediaKinds();
4378
+ /**
4379
+ * Handle a local media acquisition failure with a typed, semantically
4380
+ * accurate MediaAccessError created at the acquisition site:
4381
+ * - Auxiliary connections (screenshare / additional-device) throw a
4382
+ * non-fatal error — VertoManager surfaces it and the call is unaffected.
4383
+ * - The main connection degrades to receive-only when allowed (default),
4384
+ * otherwise fails with a fatal error.
4385
+ */
4386
+ private handleLocalMediaFailure;
4387
+ /**
4388
+ * Negotiate receive-only m-lines when there are no local tracks to send.
4389
+ * Only offer-type connections add transceivers — answer-type connections
4390
+ * reuse the transceivers created from the remote offer.
4391
+ */
4392
+ private setupReceiveOnlyTransceivers;
3840
4393
  private getUserMedia;
3841
4394
  private getDisplayMedia;
3842
4395
  private setupRemoteTracks;
3843
4396
  restoreTrackSender(kind: 'audio' | 'video' | 'both'): Promise<void>;
4397
+ private restoreRawAudioInputForPipeline;
4398
+ /**
4399
+ * Return the lazily-created {@link LocalAudioPipeline}, constructing it on
4400
+ * first access. On creation the current audio sender's track is routed
4401
+ * through the pipeline (input → gain → analyser → destination) and the
4402
+ * sender is switched to emit the processed track. Returns `null` when no
4403
+ * audio sender exists yet (pre-negotiation).
4404
+ */
4405
+ ensureLocalAudioPipeline(): LocalAudioPipeline | null;
4406
+ /** The active LocalAudioPipeline, or null if it hasn't been created yet. */
4407
+ get localAudioPipeline(): LocalAudioPipeline | null;
4408
+ private applyLocalAudioPipelineToSender;
3844
4409
  /**
3845
4410
  * Add a local media track to the peer connection.
3846
4411
  * @param track - The MediaStreamTrack to add
@@ -3911,6 +4476,10 @@ interface WebRTCVerto extends VertoManager {
3911
4476
  requestIceRestartAll?: (relayOnly?: boolean) => Promise<void>;
3912
4477
  /** Request keyframes on all video-receiving legs (skips send-only screen share). */
3913
4478
  requestKeyframeAll?: () => void;
4479
+ /** Lazily create (or return) the local audio pipeline for the main peer connection. */
4480
+ ensureLocalAudioPipeline(): LocalAudioPipeline | null;
4481
+ /** Current local audio pipeline, or null if it has not been created yet. */
4482
+ readonly localAudioPipeline: LocalAudioPipeline | null;
3914
4483
  }
3915
4484
  //#endregion
3916
4485
  //#region src/managers/CallEventsManager.d.ts
@@ -4058,6 +4627,8 @@ declare class WebRTCCall extends Destroyable implements CallManager {
4058
4627
  private _bandwidthConstrained$;
4059
4628
  private _mediaParamsUpdated$;
4060
4629
  private _customSubscriptions;
4630
+ private _pushToTalkEnabled;
4631
+ private _remoteAudioMeter;
4061
4632
  constructor(clientSession: ClientSession, options: CallOptions, initialization: CallInitialization, address?: Address | undefined);
4062
4633
  /** Observable stream of errors from media, signaling, and peer connection layers. */
4063
4634
  get errors$(): Observable<CallError>;
@@ -4123,14 +4694,27 @@ declare class WebRTCCall extends Destroyable implements CallManager {
4123
4694
  *
4124
4695
  * Constructs call context (node_id, call_id, member_id) and sends the RPC request.
4125
4696
  *
4126
- * @param target - Target member ID string, or a {@link MemberTarget} object.
4697
+ * @param target - Target {@link MemberTarget} triple, or the local member's
4698
+ * ID string for self-operations (any other string is rejected — a bare
4699
+ * member id cannot carry the remote member's own call context).
4127
4700
  * @param method - Verto method name (e.g. `'call.mute'`, `'call.member.remove'`).
4128
4701
  * @param args - Parameters for the RPC method.
4129
4702
  * @returns The RPC response.
4703
+ * @throws {CallNotReadyError} If the call has no self member context yet.
4704
+ * @throws {InvalidParams} If a string target is not the local member's ID.
4130
4705
  * @throws {JSONRPCError} If the RPC call returns an error.
4131
4706
  */
4132
4707
  executeMethod<T extends JSONRPCResponse = JSONRPCResponse>(target: string | MemberTarget, method: string, args: Record<string, unknown>): Promise<T>;
4133
- private buildMethodParams;
4708
+ /**
4709
+ * The local leg's member triple — sent as `self` in every member RPC
4710
+ * envelope, and as the `target` of call-scoped self-operations (e.g. lock,
4711
+ * layout).
4712
+ *
4713
+ * @throws {CallNotReadyError} Before `call.joined` delivers the self member
4714
+ * context (`selfId`/`nodeId`) — an RPC without it cannot be routed, so fail
4715
+ * fast instead of sending a doomed request.
4716
+ */
4717
+ private get callSelf();
4134
4718
  /** Observable of the current call status (e.g. `'ringing'`, `'connected'`). */
4135
4719
  get status$(): Observable<CallStatus>;
4136
4720
  /** Observable of the participants list, emits on join/leave/update. */
@@ -4221,6 +4805,16 @@ declare class WebRTCCall extends Destroyable implements CallManager {
4221
4805
  * Called from within the status subscription to wire stats and recovery.
4222
4806
  */
4223
4807
  private initResilienceSubsystems;
4808
+ /**
4809
+ * Wait for the underlying RTCPeerConnection to reach 'connected' after
4810
+ * triggering an ICE restart. Resolves true on success, false on failure
4811
+ * or if the state doesn't transition within the configured timeout.
4812
+ *
4813
+ * Polls connectionState directly because the recovery manager already
4814
+ * wraps this call in its own withTimeout(); a separate listener-based
4815
+ * implementation would race the outer timeout in subtle ways.
4816
+ */
4817
+ private waitForPeerConnectionConnected;
4224
4818
  /**
4225
4819
  * @internal Stop and destroy resilience subsystems (on disconnect/destroy).
4226
4820
  * Clears references so they can be re-created on reconnect.
@@ -4354,11 +4948,27 @@ declare class WebRTCCall extends Destroyable implements CallManager {
4354
4948
  /** Observable that emits `true` when answered, `false` when rejected. */
4355
4949
  get answered$(): Observable<boolean>;
4356
4950
  /**
4357
- * Sets the call layout and participant positions.
4951
+ * Sets the call layout and, optionally, individual participant positions.
4952
+ *
4953
+ * The gateway `call.layout.set` DTO has **no** `positions` member, so when
4954
+ * `positions` is provided this method issues a `call.member.position.set`
4955
+ * request per member (via {@link Participant.setPosition}, which keys each
4956
+ * position by that member's own call context) alongside `call.layout.set`
4957
+ * (issue #19400, Flag #6).
4958
+ *
4959
+ * **These operations are NOT atomic.** The layout is applied first, then each
4960
+ * member position sequentially, so members may briefly flash into their
4961
+ * default slots before being moved to the requested positions. Targeted
4962
+ * members are validated upfront, though: when any of them has no
4963
+ * {@link Participant.target | member call context} yet, the whole call
4964
+ * rejects before any request is sent and the layout is left unchanged.
4358
4965
  *
4359
4966
  * @param layout - Layout name (must be one of {@link layouts}).
4360
- * @param positions - Map of member IDs to {@link VideoPosition} values.
4967
+ * @param positions - Optional map of member IDs to {@link VideoPosition} values.
4968
+ * When omitted or empty, only the layout is changed.
4361
4969
  * @throws {InvalidParams} If the layout is not in the available {@link layouts}.
4970
+ * @throws {ParticipantNotReadyError} If a targeted member's call context has
4971
+ * not been received yet — thrown before any request is sent.
4362
4972
  *
4363
4973
  * @example
4364
4974
  * ```ts
@@ -4367,7 +4977,7 @@ declare class WebRTCCall extends Destroyable implements CallManager {
4367
4977
  * });
4368
4978
  * ```
4369
4979
  */
4370
- setLayout(layout: string, positions: Record<string, VideoPosition>): Promise<void>;
4980
+ setLayout(layout: string, positions?: Record<string, VideoPosition>): Promise<void>;
4371
4981
  /**
4372
4982
  * Transfers the call to another destination.
4373
4983
  *
@@ -4375,12 +4985,86 @@ declare class WebRTCCall extends Destroyable implements CallManager {
4375
4985
  * @see {@link status$} to observe the transfer progress.
4376
4986
  */
4377
4987
  transfer(options: TransferOptions): Promise<void>;
4988
+ /**
4989
+ * Set the local microphone gain as a percentage applied before transmission.
4990
+ *
4991
+ * - `0` = silent
4992
+ * - `100` = unity (no change, default)
4993
+ * - `200` = 2× digital boost (max; expect clipping / noise amplification)
4994
+ *
4995
+ * Values are clamped to [0, 200]. Engages the local audio pipeline on
4996
+ * first use (one-time cost).
4997
+ *
4998
+ * Note: this is a **digital** multiplier applied in a Web Audio GainNode
4999
+ * between your mic track and the RTCRtpSender — it does not change the
5000
+ * physical mic's hardware sensitivity. Browsers' autoGainControl can
5001
+ * fight the setting; call {@link setAutoGainControl}(false) for
5002
+ * predictable behaviour.
5003
+ *
5004
+ * @param value - Gain percentage (0..200; 100 = unity).
5005
+ */
5006
+ setLocalMicrophoneGain(value: number): void;
5007
+ /** Observable of the current local microphone gain (0..200, where 100 = unity). */
5008
+ get localMicrophoneGain$(): Observable<number>;
5009
+ /**
5010
+ * Observable of the RMS audio level of the local microphone, 0..1.
5011
+ * Emits at ~30fps while a mic track is active. Engages the local audio
5012
+ * pipeline on first subscription.
5013
+ */
5014
+ get localAudioLevel$(): Observable<number>;
5015
+ /**
5016
+ * Observable that is `true` while the local participant is speaking
5017
+ * (RMS level above the VAD threshold, with hold time to avoid flicker).
5018
+ */
5019
+ get localSpeaking$(): Observable<boolean>;
5020
+ /**
5021
+ * Enable push-to-talk: while {@link setPushToTalkActive} has been called
5022
+ * with `false`, the microphone gain is forced to 0; calling
5023
+ * {@link setPushToTalkActive} with `true` restores the configured gain.
5024
+ * Use this instead of mute/unmute for instant talk/silence transitions
5025
+ * because it doesn't rebuild the track.
5026
+ *
5027
+ * This method installs the pipeline but does not attach any keyboard
5028
+ * listener — consumers bind the key themselves and call
5029
+ * {@link setPushToTalkActive} on keydown/keyup.
5030
+ */
5031
+ enablePushToTalk(): void;
5032
+ /** Disable push-to-talk; mic gain returns to the configured value. */
5033
+ disablePushToTalk(): void;
5034
+ /**
5035
+ * While push-to-talk is enabled, sets the talk state. `true` = transmitting,
5036
+ * `false` = silent. No-op if push-to-talk has not been enabled.
5037
+ */
5038
+ setPushToTalkActive(active: boolean): void;
5039
+ /**
5040
+ * Toggle echo cancellation on the local mic at runtime. Applied via
5041
+ * `track.applyConstraints`; browsers that don't honour runtime constraints
5042
+ * (notably iOS Safari) fall back to re-acquiring the track with the new
5043
+ * constraint set and plumbing the replacement through the local audio
5044
+ * pipeline if one is active.
5045
+ */
5046
+ setEchoCancellation(enabled: boolean): Promise<void>;
5047
+ /** Toggle browser noise suppression on the local mic at runtime. */
5048
+ setNoiseSuppression(enabled: boolean): Promise<void>;
5049
+ /** Toggle browser automatic gain control on the local mic at runtime. */
5050
+ setAutoGainControl(enabled: boolean): Promise<void>;
5051
+ /**
5052
+ * Observable of the aggregate remote audio level, 0..1 RMS. The server
5053
+ * delivers a single mixed audio stream for all remote participants — this
5054
+ * meter reports that mix. Per-participant audio is not available client-side.
5055
+ *
5056
+ * Engages a shared AudioContext on first subscription (cheap — one
5057
+ * AnalyserNode, no GainNode, no destination) so it does not affect the
5058
+ * caller's audio element playback.
5059
+ */
5060
+ get remoteAudioLevel$(): Observable<number>;
4378
5061
  /** Destroys the call, releasing all resources and subscriptions. */
4379
5062
  destroy(): void;
4380
5063
  /**
4381
5064
  * @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.
5065
+ * server's subscription list for this call. Returns the underlying RPC
5066
+ * promise so callers can decide whether to cache the observable on success
5067
+ * or retry on failure.
4384
5068
  */
4385
5069
  private _sendVertoSubscribe;
4386
5070
  }
@@ -4397,5 +5081,5 @@ declare const version: string;
4397
5081
  */
4398
5082
  declare const ready: boolean;
4399
5083
  //#endregion
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 };
5084
+ 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, CallNotReadyError, type CallOptions, type CallParticipant, type CallSelfParticipant, type CallState, type CallStatus, type Capability, ClientPreferences, CollectionFetchError, type ConstraintFallbackEvent, type CredentialNoRefreshHandlerWarning, type CredentialProvider, type CredentialRefreshFallbackReason, type CredentialRefreshFallbackWarning, DPoPInitError, type DebugOptions, type DeviceController, type DeviceRecoveryEvent, DeviceTokenError, type DiagnosticEvent, type DialOptions, type Directory, EmbedTokenCredentialProvider, type ExecuteMethod, InvalidCredentialsError, type JSONRPCErrorResponse, type JSONRPCRequest, type JSONRPCResponse, type JSONRPCSuccessResponse, type LayoutLayer, type LogLevel, MediaAccessError, type MediaDirection, type MediaDirections, type MediaOptions, type MediaParamsEvent, MediaTrackError, type MemberCapabilities, MessageParseError, type NodeSocketAdapter, type OnOffCapability, OverconstrainedFallbackError, Participant, ParticipantNotReadyError, 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 SDKWarning, type ScreenShareStatus, type SelectDeviceOptions, SelfCapabilities, SelfParticipant, type SessionDiagnostics, type SessionState, SignalWire, type SignalWireOptions, StaticCredentialProvider, type Storage, type StoredDevicePreference, type TextMessage, TokenRefreshError, type TransferOptions, UnexpectedError, User, type UserPresence, VertoPongError, type VideoPosition, type WebRTCApiProvider, WebRTCCall, type WebRTCMediaDevices, type WebSocketAdapter, embeddableCall, getLogger, isSelfParticipant, ready, setDebugOptions, setLogLevel, setLogger, version };
4401
5085
  //# sourceMappingURL=index.d.mts.map