@signalwire/js 4.0.0-beta.2 → 4.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.mjs +56 -36
- package/dist/browser.mjs.map +1 -1
- package/dist/browser.umd.js +56 -36
- package/dist/browser.umd.js.map +1 -1
- package/dist/index.cjs +56 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +49 -5
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +49 -5
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +56 -36
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["Subject","ReplaySubject","BehaviorSubject","ValidationError","result: Awaited<T>","logger","getLogger","baseURL: string","credential: SDKCredential","Subject","BehaviorSubject","UnexpectedError","timeout","RequestTimeoutError","headers: HTTPHeaders","logger","getLogger","STORED_NUMBER_KEYS: (keyof StoredPreferences & keyof Preferences)[]","STORED_BOOLEAN_KEYS: (keyof StoredPreferences & keyof Preferences)[]","logger","getLogger","initialDevicesState: DevicesState","initialSelectedDevicesState: SelectedDevicesState","device","devicesByKind: DevicesState","StorageNotAvailableError","storageImpl: Storage","SerializationError","StorageWriteError","item: string | null","StorageReadError","DeserializationError","DependencyError","fromPath: string","http: HTTPRequestController","tmpMap: VertoParams","VertoByeCauseCodes: Record<VertoByeCause, string>","logger","getLogger","storage: StorageManager","deviceController: DeviceController","reconnectCallsTimeout: number","attachKey: string","timeout","DEFAULT_ON_OFF: OnOffCapability","DEFAULT_MEMBER_CAPABILITIES: MemberCapabilities","DEFAULT_CALL_CAPABILITIES: CallCapabilitiesState","logger","getLogger","initialState: Partial<ParticipantState>","executeMethod: ExecuteMethod","deviceController: DeviceController","filterNull","UnimplementedError","vertoManager: VertoManager","logger","getLogger","initialSessionState: Partial<SessionState>","webRtcCallSession: CallManager","options: WebRTCCallEventManagerOptions","filterNull","DependencyError","filterAs","mediaSectionsValidCandidates: number[]","logger","getLogger","peerConnection: RTCPeerConnection","peerConnectionControllerNegotiating$: Observable<boolean>","logger","getLogger","options: LocalStreamControllerOptions","stream: MediaStream","constraints: MediaStreamConstraints","logger","getLogger","transceiverParams: RTCRtpTransceiverInit","MediaTrackError","constraints: MediaStreamConstraints","constraintsToApply: MediaTrackConstraints","logger","getLogger","options: RTCPeerConnectionControllerOptionsPartial","filterNull","track","options","DependencyError","options: RTCOfferOptions","sender","answer: RTCSessionDescriptionInit","logger","getLogger","webRtcCallSession: WebRTCCall","attachManager: AttachManager","deviceController: DeviceController","DependencyError","filterNull","VertoPongError","filterAs","JSONRPCError","getValueFrom","vertoMethod: VertoMethod","vertoByeOrAccepted: boolean | VertoByeParams","deviceKind: 'audio' | 'video' | 'both' | undefined","InvalidParams","rtcPeerConnController: RTCPeerConnectionController | null","removeTrack: 'audio' | 'video' | 'both' | undefined","executeMethod: ExecuteMethod","vertoManager: VertoManager","deviceController: DeviceController","logger","getLogger","clientSession: ClientSession","options: CallOptions","address?: Address","UnimplementedError","getValueFrom","filterAs","InvalidParams","sessionManager: ClientSession","deviceController: DeviceController","attachManager: AttachManager","logger","getLogger","endpoint: string","http: HTTPRequestController","fetchController: FetchController<T>","update$: Observable<Partial<T>>","onError?: (error: Error) => void","Subject","CollectionFetchError","ReplaySubject","originalCollection: EntityCollection<O>","filter: (i: unknown) => i is O","mapper: (item: O) => T","addressId: string","conversationManager: ConversationsProvider","addressProvider: AddressProvider<Address>","DependencyError","filterNull","UnimplementedError","logger","getLogger","Observable","RPCTimeoutError","NEVER","logger","getLogger","from","UnexpectedError","credential: SDKCredential","transport: TransportManager","storage: StorageManager","authorizationStateKey: string","attachManager: AttachManager","AuthStateHandlerError","VertoInviteHandlerError","filterAs","DependencyError","error","params: RPCConnectParams","throwOnRPCError","CallCreateError","address: Address | undefined","clientSessionManager: ClientSessionManager","logger","getLogger","groupId: string","clientSession: ClientSessionManager","http: HTTPRequestController","getSubscriberAddressId: () => string","onError?: (error: Error) => void","ConversationError","filterAs","logger","getLogger","http: HTTPRequestController","conversationManager: ConversationsProvider","onError?: (error: Error) => void","filterNull","filterAs","logger","getLogger","WebSocketConstructor: WebSocketAdapter | NodeSocketAdapter","endpoint: string","outgoingMessages$: Observable<string | ArrayBuffer | Blob>","UnexpectedError","WebSocketConnectionError","WebSocketTimeoutError","logger","getLogger","storage: StorageManager","protocolKey: string","onError?: (error: Error) => void","MessageParseError","EMPTY","TransportConnectionError","logger","getLogger","decodeHeader: JWTHeader","InvalidCredentialsError","error: unknown","UnexpectedError","ready","getLogger","host: string","embedToken: string","timeout","RequestError","RequestTimeoutError","DependencyError","credentials: SDKCredential","version: string","ready: boolean"],"sources":["../src/behaviors/Destroyable.ts","../src/utils/asyncRetry.ts","../src/controllers/HTTPRequestController.ts","../src/core/constants.ts","../src/utils/time.ts","../src/containers/PreferencesContainer.ts","../src/controllers/NavigatorDeviceController.ts","../src/dependencies/DefaultLocalStorage.ts","../src/managers/StorageManager.ts","../src/containers/DependencyContainer.ts","../src/behaviors/Fetchable.ts","../src/core/entities/Subscriber.ts","../src/core/RPCMessages/helpers.ts","../src/core/RPCMessages/RPCConnect.ts","../src/core/RPCMessages/RPCPing.ts","../src/core/RPCMessages/RPCExecute.ts","../src/core/RPCMessages/VertoMessages.ts","../src/core/RPCMessages/RPCEventAck.ts","../src/managers/AttachManager.ts","../src/core/capabilities/types.ts","../src/core/capabilities/computeCapabilities.ts","../src/core/capabilities/SelfCapabilities.ts","../src/core/RPCMessages/utils.ts","../src/core/entities/Participant.ts","../src/core/RPCMessages/guards/base.guards.ts","../src/core/RPCMessages/guards/events.guards.ts","../src/managers/CallEventsManager.ts","../src/helpers/SDPHelper.ts","../src/controllers/ICEGatheringController.ts","../src/controllers/LocalStreamController.ts","../src/controllers/TransceiverController.ts","../src/controllers/RTCPeerConnectionController.ts","../src/core/RPCMessages/guards/verto.guards.ts","../src/managers/VertoManager.ts","../src/managers/ParticipantFactory.ts","../src/core/entities/Call.ts","../src/managers/CallFactory.ts","../src/behaviors/Collection.ts","../src/core/entities/Address.ts","../src/core/utils.ts","../src/managers/ClientSessionManager.ts","../src/utils/isString.ts","../src/managers/ConversationsManager.ts","../src/utils/arrays.ts","../src/utils/warnup.ts","../src/managers/DirectoryManager.ts","../src/controllers/WebSocketController.ts","../src/core/RPCMessages/guards/methods.guards.ts","../src/managers/TransportManager.ts","../src/clients/SignalWire.ts","../src/dependencies/EmbedTokenCredentialProvider.ts","../src/utils/embeddableCall.ts","../src/dependencies/StaticCredentialProvider.ts","../src/index.ts"],"sourcesContent":["import { Subject, ReplaySubject, BehaviorSubject, merge, map, skip } from 'rxjs';\n\nimport type { Observable, Subscription, Observer } from 'rxjs';\n\nexport abstract class Destroyable {\n protected subscriptions: Subscription[] = [];\n protected subjects: Subject<unknown>[] = [];\n protected _destroyed$ = new Subject<void>();\n private _observableCache?: Map<string, Observable<unknown>>;\n\n public destroy(): void {\n this._observableCache?.clear();\n this.subscriptions.forEach((sub) => sub.unsubscribe());\n this.subjects.forEach((subject) => subject.complete());\n this._destroyed$.next();\n this._destroyed$.complete();\n }\n\n protected cachedObservable<T>(key: string, factory: () => Observable<T>): Observable<T> {\n this._observableCache ??= new Map();\n let cached = this._observableCache.get(key) as Observable<T> | undefined;\n if (!cached) {\n cached = factory();\n this._observableCache.set(key, cached as Observable<unknown>);\n }\n return cached;\n }\n\n protected subscribeTo<T>(\n observable: Observable<T>,\n observerOrNext: Partial<Observer<T>> | ((value: T) => void) | undefined\n ): void {\n const subscription = observable.subscribe(observerOrNext);\n this.subscriptions.push(subscription);\n }\n\n protected createSubject<T>(): Subject<T> {\n const subject = new Subject<T>();\n this.subjects.push(subject as Subject<unknown>);\n return subject;\n }\n\n protected createReplaySubject<T>(bufferSize?: number, windowTime?: number): ReplaySubject<T> {\n const subject = new ReplaySubject<T>(bufferSize, windowTime);\n this.subjects.push(subject as Subject<unknown>);\n return subject;\n }\n\n protected createBehaviorSubject<T>(initialValue: T): BehaviorSubject<T> {\n const subject = new BehaviorSubject<T>(initialValue);\n this.subjects.push(subject as Subject<unknown>);\n return subject;\n }\n\n public get $(): Observable<this> {\n return this.cachedObservable('$', () =>\n merge(\n // skip a burst of initial values from BehaviorSubjects\n ...this.subjects.map((s) => (s instanceof BehaviorSubject ? s.pipe(skip(1)) : s))\n ).pipe(map((_) => this))\n );\n }\n\n /**\n * Observable that emits when the instance is destroyed\n */\n public get destroyed$(): Observable<void> {\n return this._destroyed$.asObservable();\n }\n}\n","import { getLogger } from './logger';\nimport { ValidationError } from '../core/errors';\n\nconst DEFAULT_MAX_RETRIES = 10;\nconst DEFAULT_INITIAL_DELAY = 100;\nconst DEFAULT_DELAY_VARIATION = 1;\n\ninterface AsyncRetryOptions<T> {\n asyncCallable: () => Promise<T>;\n maxRetries?: number;\n delayFn?: () => number;\n validator?: (promiseResult: T) => void | never;\n expectedErrorHandler?: (error: unknown) => boolean;\n}\n\ninterface DelayOptions {\n initialDelay?: number;\n variation?: number;\n delayLimit?: number;\n}\n\nexport const increasingDelay = ({\n delayLimit: upperDelayLimit = Number.MAX_SAFE_INTEGER,\n initialDelay = DEFAULT_INITIAL_DELAY,\n variation = DEFAULT_DELAY_VARIATION\n}: DelayOptions): (() => number) => {\n if (initialDelay < 0) {\n throw new ValidationError('initialDelay must be gte 0');\n }\n if (upperDelayLimit < 0) {\n throw new ValidationError('upperDelayLimit must be gte 0');\n }\n if (variation < 0) {\n throw new ValidationError('variation must be gte 0');\n }\n if (initialDelay > upperDelayLimit) {\n throw new ValidationError('initialDelay must be lte delayLimit');\n }\n\n let delay = Math.min(initialDelay, upperDelayLimit);\n return () => {\n if (delay === upperDelayLimit) {\n // stop incrementing the delay and just return upperDelayLimit\n return upperDelayLimit;\n }\n const currentDelay = delay;\n delay = Math.min(delay + variation, upperDelayLimit);\n\n return currentDelay;\n };\n};\n\nexport const decreasingDelay = ({\n delayLimit: bottomDelayLimit = 0,\n initialDelay = DEFAULT_INITIAL_DELAY,\n variation = DEFAULT_DELAY_VARIATION\n}: DelayOptions): (() => number) => {\n if (initialDelay < 0) {\n throw new ValidationError('initialDelay must be gte 0');\n }\n if (bottomDelayLimit < 0) {\n throw new ValidationError('bottomDelayLimit must be gte 0');\n }\n if (variation < 0) {\n throw new ValidationError('variation must be gte 0');\n }\n if (initialDelay < bottomDelayLimit) {\n throw new ValidationError('initialDelay must be gte delayLimit');\n }\n\n let delay = Math.max(initialDelay, bottomDelayLimit);\n\n return () => {\n if (delay === bottomDelayLimit) {\n // stop incrementing the delay and just return upperDelayLimit\n return bottomDelayLimit;\n }\n const currentDelay = delay;\n delay = Math.max(delay - variation, bottomDelayLimit);\n\n return currentDelay;\n };\n};\n\nexport const constDelay = ({\n initialDelay = DEFAULT_INITIAL_DELAY\n}: Pick<DelayOptions, 'initialDelay'>): (() => number) => {\n if (initialDelay < 0) {\n throw new ValidationError('initialDelay must be gte 0');\n }\n return () => initialDelay;\n};\n\nexport const asyncRetry = async <T>({\n asyncCallable,\n maxRetries: retries = DEFAULT_MAX_RETRIES,\n delayFn,\n validator,\n expectedErrorHandler\n}: AsyncRetryOptions<T>): Promise<T> => {\n let remainingAttempts = retries - 1; // the 1st call counts as an attempt\n let wait = 0;\n\n const promiseAttempt = async (): Promise<T> => {\n try {\n let result: Awaited<T>;\n\n // Should not defer the call when: wait <= 0\n if (wait <= 0) {\n result = await asyncCallable();\n } else {\n result = await new Promise<T>((resolve, reject) =>\n setTimeout(() => {\n asyncCallable().then(resolve).catch(reject);\n }, wait)\n );\n }\n\n if (remainingAttempts) {\n // avoid messing with the normal returns in the last attempt\n validator?.(result);\n }\n\n return result;\n } catch (error) {\n if (remainingAttempts-- > 0 && !expectedErrorHandler?.(error)) {\n wait = delayFn?.() ?? 0;\n getLogger().debug(`Retrying request: ${retries - remainingAttempts} of ${retries}`);\n return promiseAttempt();\n } else {\n throw error;\n }\n }\n };\n\n return promiseAttempt();\n};\n","import { BehaviorSubject, Subject } from 'rxjs';\n\nimport { RequestTimeoutError, UnexpectedError } from '../core/errors';\nimport { asyncRetry, increasingDelay } from '../utils/asyncRetry';\nimport { getLogger } from '../utils/logger';\n\nimport type {\n HTTPRequest,\n HTTPResponse,\n HTTPHeaders,\n SDKCredential\n} from '../core/types/common.types';\nimport type { Observable } from 'rxjs';\n\nconst logger = getLogger();\n\nexport type HTTPRequestStatus = 'idle' | 'requesting' | 'success' | 'error';\n\nexport interface HTTPRequestControllerOptions {\n maxRetries?: number;\n retryDelayMin?: number;\n retryDelayMax?: number;\n requestTimeout?: number;\n}\n\nexport const GET_PARAMS = {\n method: 'GET',\n headers: {\n Accept: 'application/json'\n }\n} as const;\n\nexport const POST_PARAMS = {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n\n 'Content-Type': 'application/json'\n }\n} as const;\n\nexport class HTTPRequestController {\n // Default configuration values\n private static readonly defaultMaxRetries = 3;\n private static readonly defaultRetryDelayMinMs = 1000;\n private static readonly defaultRetryDelayMaxMs = 30000;\n private static readonly defaultRequestTimeoutMs = 30000;\n\n // Configuration\n private readonly maxRetries: number;\n private readonly retryDelayMin: number;\n private readonly retryDelayMax: number;\n private readonly requestTimeout: number;\n private _responses$ = new Subject<HTTPResponse>();\n private _errors$ = new Subject<Error>();\n\n // Observable streams\n private _status$ = new BehaviorSubject<HTTPRequestStatus>('idle');\n\n constructor(\n private baseURL: string,\n private credential: SDKCredential,\n options: HTTPRequestControllerOptions = {}\n ) {\n this.maxRetries = options.maxRetries ?? HTTPRequestController.defaultMaxRetries;\n this.retryDelayMin = options.retryDelayMin ?? HTTPRequestController.defaultRetryDelayMinMs;\n this.retryDelayMax = options.retryDelayMax ?? HTTPRequestController.defaultRetryDelayMaxMs;\n this.requestTimeout = options.requestTimeout ?? HTTPRequestController.defaultRequestTimeoutMs;\n }\n\n public get status$(): Observable<HTTPRequestStatus> {\n return this._status$.asObservable();\n }\n\n public get status(): HTTPRequestStatus {\n return this._status$.value;\n }\n\n public get responses$(): Observable<HTTPResponse> {\n return this._responses$.asObservable();\n }\n\n public get errors$(): Observable<Error> {\n return this._errors$.asObservable();\n }\n\n public async request(request: HTTPRequest): Promise<HTTPResponse> {\n this._status$.next('requesting');\n\n try {\n const response = await this.executeWithRetry(request);\n this._status$.next('success');\n this._responses$.next(response);\n return response;\n } catch (error) {\n logger.error('[HTTPRequestController] Request error:', error);\n this._status$.next('error');\n const err =\n error instanceof Error ? error : new Error('HTTP request failed', { cause: error });\n this._errors$.next(err);\n throw err;\n }\n }\n\n private async executeWithRetry(request: HTTPRequest): Promise<HTTPResponse> {\n // Calculate variation to spread delays evenly across retry attempts\n const variation = Math.ceil(\n (this.retryDelayMax - this.retryDelayMin) / Math.max(this.maxRetries - 1, 1)\n );\n\n const delayFn = increasingDelay({\n initialDelay: this.retryDelayMin,\n variation,\n delayLimit: this.retryDelayMax\n });\n\n return asyncRetry({\n asyncCallable: async () => this.executeRequest(request),\n maxRetries: this.maxRetries,\n delayFn,\n validator: (response) => {\n // Retry on 5xx server errors\n if (response.status >= 500 && response.status < 600) {\n throw new UnexpectedError(`Server error: ${response.status} ${response.statusText}`);\n }\n }\n });\n }\n\n private async executeRequest(request: HTTPRequest): Promise<HTTPResponse> {\n const url = this.buildURL(request.url);\n const headers = this.buildHeaders(request.headers);\n const timeout = request.timeout ?? this.requestTimeout;\n\n logger.debug('[HTTPRequestController] Executing request:', {\n method: request.method,\n url,\n headers: Object.keys(headers).reduce((acc, key) => {\n // Mask Authorization header for security\n // eslint-disable-next-line no-param-reassign\n acc[key] = key === 'Authorization' ? `${headers[key].substring(0, 20)}...` : headers[key];\n return acc;\n }, {} as HTTPHeaders),\n body: request.body\n });\n // {\"from_fabric_address_id\":\"03a98611-d38f-405a-af49-fcb51e7f22ad\",\"fabric_address_ids\":[\"31c0afc2-93f3-4530-9a7d-55613d40850d\",\"03a98611-d38f-405a-af49-fcb51e7f22ad\"]}\n // {\"from_fabric_address_id\":\"060b5d3e-5df0-45d9-911e-660779e593da\",\"fabric_address_ids\":[\"31c0afc2-93f3-4530-9a7d-55613d40850d\",\"060b5d3e-5df0-45d9-911e-660779e593da\"]}\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n method: request.method,\n headers,\n body: request.body,\n signal: controller.signal\n });\n\n clearTimeout(timeoutId);\n\n const httpResponse = await this.convertResponse(response);\n\n logger.debug('[HTTPRequestController] Response received:', {\n status: response.status,\n statusText: response.statusText,\n headers: [...response.headers.entries()],\n body: httpResponse.body ? httpResponse.body.substring(0, 200) : '(empty)' // Show first 200 chars\n });\n\n return httpResponse;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error && error.name === 'AbortError') {\n throw new RequestTimeoutError(`Request timeout after ${timeout}ms`, { cause: error });\n }\n\n logger.error('[HTTPRequestController] Request failed:', error);\n throw error;\n }\n }\n\n private buildURL(url: string | URL): string {\n const urlString = typeof url === 'string' ? url : url.toString();\n\n // If URL is absolute, return as-is\n if (urlString.startsWith('http://') || urlString.startsWith('https://')) {\n return urlString;\n }\n\n // Ensure base URL doesn't end with '/' and path starts with '/'\n const base = this.baseURL.endsWith('/') ? this.baseURL.slice(0, -1) : this.baseURL;\n const path = urlString.startsWith('/') ? urlString : `/${urlString}`;\n\n return `${base}${path}`;\n }\n\n private buildHeaders(requestHeaders?: HTTPHeaders): HTTPHeaders {\n const headers: HTTPHeaders = { ...(requestHeaders ?? {}) };\n\n // Add authentication header\n if (this.credential.token) {\n headers.Authorization = `Bearer ${this.credential.token}`;\n logger.debug(\n '[HTTPRequestController] Using Bearer token auth, token length:',\n this.credential.token.length\n );\n } else {\n logger.warn('[HTTPRequestController] No credentials available for authentication');\n }\n\n return headers;\n }\n\n private async convertResponse(response: Response): Promise<HTTPResponse> {\n // Convert Headers to plain object\n const headers: HTTPHeaders = {};\n response.headers.forEach((value, key) => {\n headers[key] = value;\n });\n\n // Read response body as text\n const bodyText = await response.text();\n\n return {\n status: response.status,\n statusText: response.statusText,\n headers,\n body: bodyText,\n ok: response.ok,\n url: response.url\n };\n }\n}\n","export const INVITE_VERSION = 1000;\nexport const DEFAULT_ICE_CANDIDATE_TIMEOUT_MS = 600;\nexport const DEFAULT_ICE_GATHERING_TIMEOUT_MS = 6_000;\nexport const DEFAULT_RECONNECT_CALLS_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\nexport const DEFAULT_CONNECTION_TIMEOUT_MS = 10_000;\nexport const DEFAULT_RECONNECT_DELAY_MIN_MS = 100;\nexport const DEFAULT_RECONNECT_DELAY_MAX_MS = 3000;\nexport const DEFAULT_DEVICE_DEBOUNCE_TIME_MS = 1500;\nexport const DEFAULT_DEVICE_POLLING_INTERVAL_MS = 0; // Disabled by default\nexport const PREFERENCES_STORAGE_KEY = 'sw:preferences';\n","export function fromSecToMs(seconds: number): number {\n return seconds * 1000;\n}\n\nexport function fromMsToSec(milliseconds: number): number {\n return Math.round(milliseconds / 100) / 10;\n}\n","import {\n DEFAULT_CONNECTION_TIMEOUT_MS,\n DEFAULT_DEVICE_DEBOUNCE_TIME_MS,\n DEFAULT_DEVICE_POLLING_INTERVAL_MS,\n DEFAULT_ICE_CANDIDATE_TIMEOUT_MS,\n DEFAULT_ICE_GATHERING_TIMEOUT_MS,\n DEFAULT_RECONNECT_CALLS_TIMEOUT_MS,\n DEFAULT_RECONNECT_DELAY_MAX_MS,\n DEFAULT_RECONNECT_DELAY_MIN_MS,\n PREFERENCES_STORAGE_KEY\n} from '../core/constants';\nimport { getLogger } from '../utils/logger';\nimport { fromMsToSec, fromSecToMs } from '../utils/time';\n\nimport type { MediaOptions } from '../core/types/media.types';\nimport type { StorageManager } from '../managers/StorageManager';\n\nconst logger = getLogger();\n\nexport interface Preferences {\n connectionTimeout: number;\n reconnectDelayMin: number;\n reconnectDelayMax: number;\n reconnectCallsTimeout: number;\n relayHost?: string;\n receiveVideo: boolean;\n receiveAudio: boolean;\n preferredAudioInput: MediaDeviceInfo | null;\n preferredAudioOutput: MediaDeviceInfo | null;\n preferredVideoInput: MediaDeviceInfo | null;\n inputAudioDeviceConstraints: MediaTrackConstraints | undefined;\n inputVideoDeviceConstraints: MediaTrackConstraints | undefined;\n disableUdpIceServers: boolean;\n relayOnly: boolean;\n iceCandidateTimeout: number;\n iceGatheringTimeout: number;\n deviceDebounceTime: number;\n devicePollingInterval: number;\n iceServers?: RTCIceServer[];\n defaultSignalWireOptions: {\n skipConnection: boolean;\n skipRegister: boolean;\n reconnectAttachedCalls: boolean;\n skipDeviceMonitoring: boolean;\n savePreferences: boolean;\n };\n inviteSubscribeScreenshare: string[];\n inviteSubscribeAdditionalDevice: string[];\n inviteSubscribeMainDevice: string[];\n userVariables: Record<string, unknown>;\n readonly preferredMediaOptions: MediaOptions;\n}\nexport class PreferencesContainer implements Preferences {\n static get instance(): Preferences {\n this._instance ??= new PreferencesContainer();\n return this._instance;\n }\n\n deviceDebounceTime = DEFAULT_DEVICE_DEBOUNCE_TIME_MS;\n devicePollingInterval = DEFAULT_DEVICE_POLLING_INTERVAL_MS;\n\n reconnectCallsTimeout = DEFAULT_RECONNECT_CALLS_TIMEOUT_MS;\n // 5 minutes\n iceServers?: RTCIceServer[];\n connectionTimeout = DEFAULT_CONNECTION_TIMEOUT_MS;\n reconnectDelayMin = DEFAULT_RECONNECT_DELAY_MIN_MS;\n reconnectDelayMax = DEFAULT_RECONNECT_DELAY_MAX_MS;\n disableUdpIceServers = false;\n relayOnly = false;\n iceCandidateTimeout = DEFAULT_ICE_CANDIDATE_TIMEOUT_MS;\n iceGatheringTimeout = DEFAULT_ICE_GATHERING_TIMEOUT_MS;\n defaultSignalWireOptions = {\n skipConnection: false,\n skipRegister: false,\n reconnectAttachedCalls: false,\n skipDeviceMonitoring: false,\n savePreferences: false\n };\n relayHost?: string;\n receiveVideo = true;\n receiveAudio = true;\n preferredAudioInput: MediaDeviceInfo | null = null;\n preferredAudioOutput: MediaDeviceInfo | null = null;\n preferredVideoInput: MediaDeviceInfo | null = null;\n inviteSubscribeScreenshare: string[] = ['video.room.screenshare'];\n inviteSubscribeAdditionalDevice: string[] = [\n // FIXME verify what to subscribe to for additional devices\n ];\n inviteSubscribeMainDevice: string[] = [\n 'track',\n 'destroy',\n 'member.updated.videoMuted',\n 'layout.changed',\n 'room.subscribed',\n 'member.updated.audioMuted',\n 'media.connected',\n 'room.updated',\n 'call.joined'\n ];\n userVariables = {};\n\n private _inputAudioDeviceConstraints?: MediaTrackConstraints;\n private _inputVideoDeviceConstraints?: MediaTrackConstraints;\n private static _instance?: PreferencesContainer;\n\n private constructor() {\n // Private constructor to enforce singleton pattern\n }\n\n public get preferredMediaOptions(): MediaOptions {\n return {\n receiveVideo: this.receiveVideo,\n receiveAudio: this.receiveAudio,\n inputAudioDeviceConstraints: this.inputAudioDeviceConstraints,\n inputVideoDeviceConstraints: this.inputVideoDeviceConstraints\n };\n }\n\n get inputAudioDeviceConstraints(): MediaTrackConstraints | undefined {\n return this._inputAudioDeviceConstraints;\n }\n\n set inputAudioDeviceConstraints(value: MediaTrackConstraints | undefined) {\n this._inputAudioDeviceConstraints = value;\n }\n\n get inputVideoDeviceConstraints(): MediaTrackConstraints | undefined {\n return this._inputVideoDeviceConstraints;\n }\n\n set inputVideoDeviceConstraints(value: MediaTrackConstraints | undefined) {\n this._inputVideoDeviceConstraints = value;\n }\n}\n\n/** Serializable subset of preferences that can be persisted to storage. */\ninterface StoredPreferences {\n connectionTimeout?: number;\n reconnectCallsTimeout?: number;\n reconnectDelayMin?: number;\n reconnectDelayMax?: number;\n relayHost?: string;\n receiveVideo?: boolean;\n receiveAudio?: boolean;\n disableUdpIceServers?: boolean;\n relayOnly?: boolean;\n iceCandidateTimeout?: number;\n iceGatheringTimeout?: number;\n deviceDebounceTime?: number;\n devicePollingInterval?: number;\n iceServers?: RTCIceServer[];\n userVariables?: Record<string, unknown>;\n}\n\n/** Keys of StoredPreferences that map to number fields on PreferencesContainer. */\nconst STORED_NUMBER_KEYS: (keyof StoredPreferences & keyof Preferences)[] = [\n 'connectionTimeout',\n 'reconnectCallsTimeout',\n 'reconnectDelayMin',\n 'reconnectDelayMax',\n 'iceCandidateTimeout',\n 'iceGatheringTimeout',\n 'deviceDebounceTime',\n 'devicePollingInterval'\n];\n\n/** Keys of StoredPreferences that map to boolean fields on PreferencesContainer. */\nconst STORED_BOOLEAN_KEYS: (keyof StoredPreferences & keyof Preferences)[] = [\n 'receiveVideo',\n 'receiveAudio',\n 'disableUdpIceServers',\n 'relayOnly'\n];\n\n/** Collects the serializable preferences from the container. */\nfunction collectStoredPreferences(): StoredPreferences {\n const container = PreferencesContainer.instance;\n return {\n connectionTimeout: container.connectionTimeout,\n reconnectCallsTimeout: container.reconnectCallsTimeout,\n reconnectDelayMin: container.reconnectDelayMin,\n reconnectDelayMax: container.reconnectDelayMax,\n relayHost: container.relayHost,\n receiveVideo: container.receiveVideo,\n receiveAudio: container.receiveAudio,\n disableUdpIceServers: container.disableUdpIceServers,\n relayOnly: container.relayOnly,\n iceCandidateTimeout: container.iceCandidateTimeout,\n iceGatheringTimeout: container.iceGatheringTimeout,\n deviceDebounceTime: container.deviceDebounceTime,\n devicePollingInterval: container.devicePollingInterval,\n iceServers: container.iceServers,\n userVariables: container.userVariables\n };\n}\n\n/** Applies stored preferences to the container. */\nfunction applyStoredPreferences(stored: StoredPreferences): void {\n const container = PreferencesContainer.instance as unknown as Record<string, unknown>;\n for (const key of STORED_NUMBER_KEYS) {\n if (stored[key] !== undefined) container[key] = stored[key];\n }\n for (const key of STORED_BOOLEAN_KEYS) {\n if (stored[key] !== undefined) container[key] = stored[key];\n }\n if (stored.relayHost !== undefined) container.relayHost = stored.relayHost;\n if (stored.iceServers !== undefined) container.iceServers = stored.iceServers;\n if (stored.userVariables !== undefined) container.userVariables = stored.userVariables;\n}\n\n/**\n * Public preferences API for configuring SDK behavior.\n *\n * Exposed as {@link SignalWire.preferences}. All timeout values\n * are in seconds when accessed through this class.\n *\n * When {@link enableSavePreferences} is called, preferences are\n * automatically loaded from storage and synced back on every change.\n */\nexport class ClientPreferences {\n private _storage: StorageManager | null = null;\n\n /**\n * Enables persistence of preferences to storage.\n * Loads any previously saved preferences and syncs future changes.\n */\n public enableSavePreferences(storage: StorageManager): void {\n this._storage = storage;\n this._loadFromStorage();\n }\n\n /** WebSocket connection timeout in seconds. */\n public get connectionTimeout(): number {\n return fromMsToSec(PreferencesContainer.instance.connectionTimeout);\n }\n public set connectionTimeout(seconds: number) {\n PreferencesContainer.instance.connectionTimeout = fromSecToMs(seconds);\n this._saveToStorage();\n }\n\n /** Timeout for reconnecting to previously attached calls, in seconds. */\n public get reconnectCallsTimeout(): number {\n return fromMsToSec(PreferencesContainer.instance.reconnectCallsTimeout);\n }\n public set reconnectCallsTimeout(seconds: number) {\n PreferencesContainer.instance.reconnectCallsTimeout = fromSecToMs(seconds);\n this._saveToStorage();\n }\n\n /** Minimum reconnection backoff delay in seconds. */\n public get reconnectDelayMin(): number {\n return fromMsToSec(PreferencesContainer.instance.reconnectDelayMin);\n }\n public set reconnectDelayMin(seconds: number) {\n PreferencesContainer.instance.reconnectDelayMin = fromSecToMs(seconds);\n this._saveToStorage();\n }\n\n /** Maximum reconnection backoff delay in seconds. */\n public get reconnectDelayMax(): number {\n return fromMsToSec(PreferencesContainer.instance.reconnectDelayMax);\n }\n public set reconnectDelayMax(seconds: number) {\n PreferencesContainer.instance.reconnectDelayMax = fromSecToMs(seconds);\n this._saveToStorage();\n }\n\n /** Custom relay host URL. Empty string uses the default. */\n public get relayHost(): string {\n return PreferencesContainer.instance.relayHost ?? '';\n }\n public set relayHost(value: string) {\n PreferencesContainer.instance.relayHost = value;\n this._saveToStorage();\n }\n\n /** Whether to receive remote video by default. */\n public get receiveVideo(): boolean {\n return PreferencesContainer.instance.receiveVideo;\n }\n public set receiveVideo(value: boolean) {\n PreferencesContainer.instance.receiveVideo = value;\n this._saveToStorage();\n }\n\n /** Whether to receive remote audio by default. */\n public get receiveAudio(): boolean {\n return PreferencesContainer.instance.receiveAudio;\n }\n public set receiveAudio(value: boolean) {\n PreferencesContainer.instance.receiveAudio = value;\n this._saveToStorage();\n }\n\n /** Preferred audio input device for new calls. */\n public get preferredAudioInput(): MediaDeviceInfo | null {\n return PreferencesContainer.instance.preferredAudioInput;\n }\n public set preferredAudioInput(value: MediaDeviceInfo | null) {\n PreferencesContainer.instance.preferredAudioInput = value;\n }\n\n /** Preferred audio output device for new calls. */\n public get preferredAudioOutput(): MediaDeviceInfo | null {\n return PreferencesContainer.instance.preferredAudioOutput;\n }\n public set preferredAudioOutput(value: MediaDeviceInfo | null) {\n PreferencesContainer.instance.preferredAudioOutput = value;\n }\n\n /** Preferred video input device for new calls. */\n public get preferredVideoInput(): MediaDeviceInfo | null {\n return PreferencesContainer.instance.preferredVideoInput;\n }\n public set preferredVideoInput(value: MediaDeviceInfo | null) {\n PreferencesContainer.instance.preferredVideoInput = value;\n }\n\n /** Default audio input track constraints. */\n public get inputAudioConstraints(): MediaTrackConstraints | undefined {\n return PreferencesContainer.instance.inputAudioDeviceConstraints;\n }\n public set inputAudioConstraints(value: MediaTrackConstraints | undefined) {\n PreferencesContainer.instance.inputAudioDeviceConstraints = value;\n }\n\n /** Default video input track constraints. */\n public get inputVideoConstraints(): MediaTrackConstraints | undefined {\n return PreferencesContainer.instance.inputVideoDeviceConstraints;\n }\n public set inputVideoConstraints(value: MediaTrackConstraints | undefined) {\n PreferencesContainer.instance.inputVideoDeviceConstraints = value;\n }\n\n /** Debounce time for device change events, in seconds. */\n public get deviceDebounceTime(): number {\n return fromMsToSec(PreferencesContainer.instance.deviceDebounceTime);\n }\n public set deviceDebounceTime(seconds: number) {\n PreferencesContainer.instance.deviceDebounceTime = fromSecToMs(seconds);\n this._saveToStorage();\n }\n\n /** Polling interval for device enumeration, in seconds. */\n public get devicePollingInterval(): number {\n return fromMsToSec(PreferencesContainer.instance.devicePollingInterval);\n }\n public set devicePollingInterval(seconds: number) {\n PreferencesContainer.instance.devicePollingInterval = fromSecToMs(seconds);\n this._saveToStorage();\n }\n\n /** Whether to filter out UDP-based ICE servers. */\n public get disableUdpIceServers(): boolean {\n return PreferencesContainer.instance.disableUdpIceServers;\n }\n public set disableUdpIceServers(value: boolean) {\n PreferencesContainer.instance.disableUdpIceServers = value;\n this._saveToStorage();\n }\n\n /** Whether to force TURN relay-only ICE candidates. */\n public get relayOnly(): boolean {\n return PreferencesContainer.instance.relayOnly;\n }\n public set relayOnly(value: boolean) {\n PreferencesContainer.instance.relayOnly = value;\n this._saveToStorage();\n }\n\n /** Timeout for individual ICE candidate gathering, in seconds. */\n public get iceCandidateTimeout(): number {\n return fromMsToSec(PreferencesContainer.instance.iceCandidateTimeout);\n }\n public set iceCandidateTimeout(seconds: number) {\n PreferencesContainer.instance.iceCandidateTimeout = fromSecToMs(seconds);\n this._saveToStorage();\n }\n\n /** Timeout for the entire ICE gathering phase, in seconds. */\n public get iceGatheringTimeout(): number {\n return fromMsToSec(PreferencesContainer.instance.iceGatheringTimeout);\n }\n public set iceGatheringTimeout(seconds: number) {\n PreferencesContainer.instance.iceGatheringTimeout = fromSecToMs(seconds);\n this._saveToStorage();\n }\n\n /** Custom ICE servers for TURN/STUN configuration. */\n public get iceServers(): RTCIceServer[] | undefined {\n return PreferencesContainer.instance.iceServers;\n }\n public set iceServers(value: RTCIceServer[] | undefined) {\n PreferencesContainer.instance.iceServers = value;\n this._saveToStorage();\n }\n\n /** Custom user variables attached to calls. */\n public get userVariables(): Record<string, unknown> {\n return PreferencesContainer.instance.userVariables;\n }\n public set userVariables(value: Record<string, unknown>) {\n PreferencesContainer.instance.userVariables = value;\n this._saveToStorage();\n }\n\n /** Saves current preferences to storage (fire-and-forget). */\n private _saveToStorage(): void {\n if (!this._storage) return;\n const data = collectStoredPreferences();\n this._storage.setItem(PREFERENCES_STORAGE_KEY, data, 'local').catch((error: unknown) => {\n logger.error(`[ClientPreferences] Failed to save preferences: ${String(error)}`);\n });\n }\n\n /** Loads preferences from storage and applies them to the container. */\n private _loadFromStorage(): void {\n if (!this._storage) return;\n this._storage\n .getItem<StoredPreferences>(PREFERENCES_STORAGE_KEY, 'local')\n .then((stored) => {\n if (stored) {\n applyStoredPreferences(stored);\n }\n })\n .catch((error: unknown) => {\n logger.error(`[ClientPreferences] Failed to load preferences: ${String(error)}`);\n });\n }\n}\n","import { debounceTime, distinctUntilChanged, interval, map, takeUntil, tap } from 'rxjs';\n\nimport { Destroyable } from '../behaviors/Destroyable';\nimport { PreferencesContainer } from '../containers/PreferencesContainer';\nimport { getLogger } from '../utils/logger';\n\nimport type { DeviceController } from '../interfaces/DeviceController';\nimport type { Observable, Subscription } from 'rxjs';\n\nconst logger = getLogger();\n\ninterface DevicesState {\n audioinput: MediaDeviceInfo[];\n audiooutput: MediaDeviceInfo[];\n videoinput: MediaDeviceInfo[];\n}\n\ninterface SelectedDevicesState {\n audioinput: MediaDeviceInfo | null;\n audiooutput: MediaDeviceInfo | null;\n videoinput: MediaDeviceInfo | null;\n}\n\nconst initialDevicesState: DevicesState = {\n audioinput: [],\n audiooutput: [],\n videoinput: []\n};\n\nconst initialSelectedDevicesState: SelectedDevicesState = {\n audioinput: null,\n audiooutput: null,\n videoinput: null\n};\n\nconst selectDevice = (\n devices: MediaDeviceInfo[] = [],\n selected: MediaDeviceInfo | null,\n preferred: MediaDeviceInfo | null\n): MediaDeviceInfo | null => {\n const available = selected\n ? Boolean(\n devices.find(\n // if the selected device was a default device(changed), a new default device will be selected automatically\n (device) => device.deviceId === selected.deviceId || device.label === selected.label\n )\n )\n : true;\n\n if ((!selected || !available) && devices.length > 0) {\n const preferredDevice = preferred\n ? devices.find(\n (device) => device.deviceId === preferred.deviceId || device.label === preferred.label\n )\n : undefined;\n return preferredDevice ?? devices[0];\n }\n\n return selected;\n};\n\nexport class NavigatorDeviceController extends Destroyable implements DeviceController {\n private deviceChangeHandler = () => {\n logger.debug('[DeviceController] Device change detected');\n void this.enumerateDevices();\n };\n\n private _devicesPoolingSubscription?: Subscription;\n private _devicesState$ = this.createBehaviorSubject<DevicesState>(initialDevicesState);\n private _selectedDevicesState$ = this.createBehaviorSubject<SelectedDevicesState>(\n initialSelectedDevicesState\n );\n\n // Error stream\n private _errors$ = this.createSubject<Error>();\n constructor() {\n super();\n this.init();\n }\n public get selectedAudioInputDeviceConstraints(): MediaTrackConstraints {\n return this.deviceInfoToConstraints(this.selectedAudioInputDevice);\n }\n\n public get selectedVideoInputDeviceConstraints(): MediaTrackConstraints {\n return this.deviceInfoToConstraints(this.selectedVideoInputDevice);\n }\n\n public deviceInfoToConstraints(deviceInfo: MediaDeviceInfo | null): MediaTrackConstraints {\n if (!deviceInfo?.deviceId || deviceInfo.deviceId.trim() === '') {\n return {};\n }\n const devices =\n deviceInfo.kind === 'audioinput' ? this.audioInputDevices : this.videoInputDevices;\n const device =\n devices.find((device) => device.deviceId === deviceInfo.deviceId) ??\n devices.find((device) => device.label === deviceInfo.label);\n if (device) {\n return { deviceId: { exact: device.deviceId } };\n }\n return {};\n }\n\n public get errors$(): Observable<Error> {\n return this.cachedObservable('errors$', () =>\n this._errors$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n // Observable getters for device lists by kind\n public get audioInputDevices$(): Observable<MediaDeviceInfo[]> {\n return this.cachedObservable('audioInputDevices$', () =>\n this._devicesState$.pipe(\n map((state) => state.audioinput),\n distinctUntilChanged(),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n public get audioOutputDevices$(): Observable<MediaDeviceInfo[]> {\n return this.cachedObservable('audioOutputDevices$', () =>\n this._devicesState$.pipe(\n map((state) => state.audiooutput),\n distinctUntilChanged(),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n public get videoInputDevices$(): Observable<MediaDeviceInfo[]> {\n return this.cachedObservable('videoInputDevices$', () =>\n this._devicesState$.pipe(\n map((state) => state.videoinput),\n distinctUntilChanged(),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n public get selectedAudioInputDevice$(): Observable<MediaDeviceInfo | null> {\n return this.cachedObservable('selectedAudioInputDevice$', () =>\n this._selectedDevicesState$.asObservable().pipe(\n map((state) => state.audioinput),\n distinctUntilChanged(),\n takeUntil(this.destroyed$),\n tap((info) => logger.debug('[DeviceController] Selected audio input device changed:', info))\n )\n );\n }\n\n public get selectedAudioOutputDevice$(): Observable<MediaDeviceInfo | null> {\n return this.cachedObservable('selectedAudioOutputDevice$', () =>\n this._selectedDevicesState$.asObservable().pipe(\n map((state) => state.audiooutput),\n distinctUntilChanged(),\n takeUntil(this.destroyed$),\n tap((info) =>\n logger.debug('[DeviceController] Selected audio output device changed:', info)\n )\n )\n );\n }\n\n public get selectedVideoInputDevice$(): Observable<MediaDeviceInfo | null> {\n return this.cachedObservable('selectedVideoInputDevice$', () =>\n this._selectedDevicesState$.asObservable().pipe(\n map((state) => state.videoinput),\n distinctUntilChanged(),\n takeUntil(this.destroyed$),\n tap((info) => logger.debug('[DeviceController] Selected video input device changed:', info))\n )\n );\n }\n\n // Current value getters for selected devices\n public get selectedAudioInputDevice(): MediaDeviceInfo | null {\n return this._selectedDevicesState$.value.audioinput;\n }\n\n public get selectedAudioOutputDevice(): MediaDeviceInfo | null {\n return this._selectedDevicesState$.value.audiooutput;\n }\n\n public get selectedVideoInputDevice(): MediaDeviceInfo | null {\n return this._selectedDevicesState$.value.videoinput;\n }\n\n public get audioInputDevices(): MediaDeviceInfo[] {\n return this._devicesState$.value.audioinput;\n }\n\n public get audioOutputDevices(): MediaDeviceInfo[] {\n return this._devicesState$.value.audiooutput;\n }\n\n public get videoInputDevices(): MediaDeviceInfo[] {\n return this._devicesState$.value.videoinput;\n }\n\n // Setters for selected devices\n public selectAudioInputDevice(device: MediaDeviceInfo | null): void {\n this._selectedDevicesState$.next({\n ...this._selectedDevicesState$.value,\n audioinput: device\n });\n }\n\n public selectVideoInputDevice(device: MediaDeviceInfo | null): void {\n logger.debug('[DeviceController] Setting selected video input device:', device);\n this._selectedDevicesState$.next({\n ...this._selectedDevicesState$.value,\n videoinput: device\n });\n }\n\n public selectAudioOutputDevice(device: MediaDeviceInfo | null): void {\n this._selectedDevicesState$.next({\n ...this._selectedDevicesState$.value,\n audiooutput: device\n });\n }\n\n private init(): void {\n // Listen for device changes\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (navigator.mediaDevices) {\n // Subscribe to device state changes and auto-select devices\n this.subscribeTo(\n this._devicesState$.pipe(debounceTime(PreferencesContainer.instance.deviceDebounceTime)),\n (devicesState) => {\n const currentSelected = this._selectedDevicesState$.value;\n\n const newAudioInput = selectDevice(\n devicesState.audioinput,\n currentSelected.audioinput,\n PreferencesContainer.instance.preferredAudioInput\n );\n\n const newAudioOutput = selectDevice(\n devicesState.audiooutput,\n currentSelected.audiooutput,\n PreferencesContainer.instance.preferredAudioOutput\n );\n\n const newVideoInput = selectDevice(\n devicesState.videoinput,\n currentSelected.videoinput,\n PreferencesContainer.instance.preferredVideoInput\n );\n\n // Only update if something changed\n if (\n newAudioInput !== currentSelected.audioinput ||\n newAudioOutput !== currentSelected.audiooutput ||\n newVideoInput !== currentSelected.videoinput\n ) {\n this._selectedDevicesState$.next({\n audioinput: newAudioInput,\n audiooutput: newAudioOutput,\n videoinput: newVideoInput\n });\n }\n }\n );\n void this.enumerateDevices();\n }\n }\n\n public enableDeviceMonitoring(): void {\n this.disableDeviceMonitoring();\n navigator.mediaDevices.addEventListener('devicechange', this.deviceChangeHandler);\n\n if (PreferencesContainer.instance.devicePollingInterval > 0) {\n this._devicesPoolingSubscription = interval(\n PreferencesContainer.instance.devicePollingInterval\n ).subscribe(() => {\n logger.debug('[DeviceController] Polling devices due to interval');\n void this.enumerateDevices();\n });\n }\n\n void this.enumerateDevices();\n }\n\n public disableDeviceMonitoring(): void {\n navigator.mediaDevices.removeEventListener('devicechange', this.deviceChangeHandler);\n if (this._devicesPoolingSubscription) {\n this._devicesPoolingSubscription.unsubscribe();\n this._devicesPoolingSubscription = undefined;\n }\n }\n\n private async enumerateDevices(): Promise<void> {\n try {\n const devices = await navigator.mediaDevices.enumerateDevices();\n\n const devicesByKind: DevicesState = devices.reduce(\n (acc, device) => {\n const kind = device.kind as keyof DevicesState;\n acc[kind].push(device);\n return acc;\n },\n {\n audioinput: [],\n audiooutput: [],\n videoinput: []\n } as DevicesState\n );\n\n // Update state in a single emission\n this._devicesState$.next(devicesByKind);\n\n logger.debug('[DeviceController] Devices enumerated:', {\n audioInputs: devicesByKind.audioinput.length,\n audioOutputs: devicesByKind.audiooutput.length,\n videoInputs: devicesByKind.videoinput.length\n });\n } catch (error) {\n logger.error('[DeviceController] Failed to enumerate devices:', error);\n this._errors$.next(error as Error);\n }\n }\n\n public async getDeviceCapabilities(\n deviceInfo: MediaDeviceInfo\n ): Promise<MediaTrackCapabilities | null> {\n if (deviceInfo.kind === 'audiooutput') {\n return null;\n }\n\n try {\n const constraints = this.deviceInfoToConstraints(deviceInfo);\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: deviceInfo.kind === 'audioinput' ? constraints : false,\n video: deviceInfo.kind === 'videoinput' ? constraints : false\n });\n\n const track =\n deviceInfo.kind === 'audioinput' ? stream.getAudioTracks()[0] : stream.getVideoTracks()[0];\n\n const capabilities = track.getCapabilities();\n\n // Stop all tracks to release devices\n stream.getTracks().forEach((t) => t.stop());\n\n return capabilities;\n } catch (error) {\n logger.error('[DeviceController] Failed to get device capabilities:', error);\n this._errors$.next(error as Error);\n throw error;\n }\n }\n\n public async isValidDevice(deviceInfo: MediaDeviceInfo | null): Promise<boolean> {\n if (!deviceInfo || deviceInfo.kind === 'audiooutput') {\n return false;\n }\n try {\n const capabilities = await this.getDeviceCapabilities(deviceInfo);\n return capabilities !== null;\n } catch {\n return false;\n }\n }\n\n public destroy(): void {\n this.disableDeviceMonitoring();\n super.destroy();\n }\n}\n","import { StorageNotAvailableError } from '../core/errors';\nimport { getLogger } from '../utils/logger';\n\nimport type { Storage, StorageScope } from './interfaces';\n\nexport class DefaultLocalStorage implements Storage {\n constructor() {\n // Check if localStorage is available\n if (typeof localStorage === 'undefined') {\n throw new StorageNotAvailableError('localStorage');\n }\n if (typeof sessionStorage === 'undefined') {\n throw new StorageNotAvailableError('sessionStorage');\n }\n\n // Test if localStorage is actually accessible (some browsers block it)\n try {\n const testKey = '__storage_test__';\n localStorage.setItem(testKey, 'test');\n localStorage.removeItem(testKey);\n } catch (error) {\n getLogger().error('LocalStorage is not accessible:', error);\n throw new StorageNotAvailableError('localStorage');\n }\n }\n\n private storage(scope: StorageScope) {\n return scope === 'local' ? localStorage : sessionStorage;\n }\n\n async setItem(key: string, value: string, scope: StorageScope = 'session'): Promise<void> {\n this.storage(scope).setItem(key, value);\n return Promise.resolve();\n }\n\n async getItem(key: string, scope: StorageScope = 'session'): Promise<string | null> {\n return Promise.resolve(this.storage(scope).getItem(key));\n }\n\n async removeItem(key: string, scope: StorageScope = 'session'): Promise<void> {\n this.storage(scope).removeItem(key);\n return Promise.resolve();\n }\n}\n","import {\n SerializationError,\n StorageWriteError,\n DeserializationError,\n StorageReadError\n} from '../core/errors';\nimport { DefaultLocalStorage } from '../dependencies/DefaultLocalStorage';\n\nimport type { Storage, StorageScope } from '../dependencies/interfaces';\n\nexport class StorageManager {\n constructor(private storageImpl: Storage = new DefaultLocalStorage()) {}\n\n /**\n * Validates that a value can be safely serialized to JSON\n * @throws SerializationError if value contains non-serializable types\n */\n private serialize(value: unknown, key?: string): string | null {\n if (value === undefined || value === null) {\n // undefined is acceptable, will be stored as null\n return null;\n }\n\n try {\n return JSON.stringify(value);\n } catch (e) {\n throw new SerializationError(key ?? 'unknown', e as Error);\n }\n }\n\n /**\n * Stores a value in storage\n * @throws InvalidStorageValueError if value contains non-serializable types\n * @throws SerializationError if JSON serialization fails\n * @throws StorageWriteError if writing to storage fails\n */\n public async setItem(\n key: string,\n value: unknown,\n scope: StorageScope = 'session'\n ): Promise<void> {\n const serialized = this.serialize(value, key);\n\n try {\n await this.storageImpl.setItem(key, serialized, scope);\n } catch (error) {\n throw new StorageWriteError(key, error as Error);\n }\n }\n\n /**\n * Retrieves a value from storage\n *\n * This method distinguishes between:\n * - Storage errors (network, permission, etc.) - these are thrown\n * - JSON parse errors - these trigger onParseError and return raw string\n * - Missing keys - returns null\n *\n * @returns The parsed value, raw string (on parse error), or null\n * @throws StorageReadError\n */\n public async getItem<T = unknown>(\n key: string,\n scope: StorageScope = 'session'\n ): Promise<T | null> {\n let item: string | null;\n\n try {\n item = await this.storageImpl.getItem(key, scope);\n } catch (error) {\n throw new StorageReadError(key, error as Error);\n }\n\n if (!item) {\n return null;\n }\n\n try {\n return JSON.parse(item) as T;\n } catch (error) {\n throw new DeserializationError(key, error as Error);\n }\n }\n\n /**\n * Removes a value from storage\n * @throws Error from underlying storage implementation\n */\n public async removeItem(key: string, scope: StorageScope = 'session'): Promise<void> {\n try {\n await this.storageImpl.removeItem(key, scope);\n } catch (error) {\n throw new StorageWriteError(key, error as Error);\n }\n }\n}\n","import { HTTPRequestController } from '../controllers/HTTPRequestController';\nimport { NavigatorDeviceController } from '../controllers/NavigatorDeviceController';\nimport { DependencyError } from '../core/errors';\nimport { DefaultLocalStorage } from '../dependencies/DefaultLocalStorage';\nimport { StorageManager } from '../managers/StorageManager';\n\nimport type { Subscriber } from '../core/entities/Subscriber';\nimport type {\n NodeSocketAdapter,\n SDKCredential,\n WebSocketAdapter\n} from '../core/types/common.types';\nimport type { Storage } from '../dependencies/interfaces';\nimport type { ConversationsProvider } from '../interfaces/Conversations';\nimport type { Dependency } from '../interfaces/Dependency';\nimport type { DeviceController } from '../interfaces/DeviceController';\n\nexport class DependencyContainer implements Dependency {\n private _conversationManager?: ConversationsProvider;\n\n private _subscriber?: Subscriber;\n\n private _host?: string;\n\n private _domain?: string;\n\n private _storageManager?: StorageManager;\n private _storageImpl?: Storage;\n private _webSocketConstructor?: WebSocketAdapter | NodeSocketAdapter =\n typeof WebSocket !== 'undefined' ? WebSocket : undefined;\n private _baseURL: string = this.apiHost;\n private _credential: SDKCredential = {};\n private _httpRequestController?: HTTPRequestController;\n private _deviceController?: NavigatorDeviceController;\n public get subscriberId(): string {\n return this.subscriber.id;\n }\n\n public get subscriber(): Subscriber {\n if (!this._subscriber) {\n throw new DependencyError('Subscriber');\n }\n return this._subscriber;\n }\n public set subscriber(subscriber: Subscriber) {\n this._subscriber = subscriber;\n }\n\n public get storage(): StorageManager {\n if (!this._storageManager) {\n // Lazily initialize storage implementation if not already set\n this._storageImpl ??= new DefaultLocalStorage();\n this._storageManager = new StorageManager(this._storageImpl);\n }\n return this._storageManager;\n }\n\n public get http(): HTTPRequestController {\n this._httpRequestController ??= new HTTPRequestController(this._baseURL, this._credential);\n return this._httpRequestController;\n }\n\n public get conversationManager(): ConversationsProvider {\n if (!this._conversationManager) {\n throw new DependencyError('ConversationsManager');\n }\n return this._conversationManager;\n }\n\n public set conversationManager(conversationManager: ConversationsProvider) {\n this._conversationManager = conversationManager;\n }\n\n public get WebSocket(): WebSocketAdapter | NodeSocketAdapter {\n if (!this._webSocketConstructor) {\n throw new DependencyError('WebSocket constructor');\n }\n return this._webSocketConstructor;\n }\n\n public set WebSocket(WebSocketConstructor: WebSocketAdapter | NodeSocketAdapter) {\n this._webSocketConstructor = WebSocketConstructor;\n }\n\n public get deviceController(): DeviceController {\n this._deviceController ??= new NavigatorDeviceController();\n return this._deviceController;\n }\n\n public get authorizationStateKey(): string {\n return `sw:${this.subscriberId}:as`;\n }\n\n public get protocolKey(): string {\n return `sw:${this.subscriberId}:pt`;\n }\n\n public get attachedCallsKey(): string {\n return `sw:${this.subscriberId}:att`;\n }\n\n public getSubscriberFromAddressId(): string {\n return this.subscriber.addresses[0]?.id ?? '';\n }\n\n public set baseURL(baseURL: string) {\n this._baseURL = baseURL;\n this._httpRequestController = undefined;\n }\n\n public get credential(): SDKCredential {\n return this._credential;\n }\n\n public set credential(credential: SDKCredential) {\n this._credential = credential;\n this._httpRequestController = undefined;\n }\n\n public set storageImpl(storageImpl: Storage) {\n this._storageImpl = storageImpl;\n this._storageManager = undefined;\n }\n\n public set ch(ch: string | undefined) {\n if (!ch) {\n return;\n }\n\n const firstDot = ch.indexOf('.');\n if (firstDot !== -1) {\n this._host = ch.substring(0, firstDot);\n this._domain = ch.substring(firstDot + 1);\n }\n }\n\n public get relayHost(): string {\n return `wss://${this._host ?? 'puc'}.${this._domain ?? 'signalwire.com'}`;\n }\n\n public get apiHost(): string {\n return `https://${this._host ?? 'fabric'}.${this._domain ?? 'signalwire.com'}`;\n }\n}\n","import { defer, from, shareReplay, takeUntil } from 'rxjs';\n\nimport { Destroyable } from './Destroyable';\n\nimport type { HTTPRequestController } from '../controllers/HTTPRequestController';\nimport type { Observable } from 'rxjs';\n\nexport abstract class Fetchable<T = unknown> extends Destroyable {\n public fetched$: Observable<boolean>;\n\n constructor(\n public fromPath: string,\n protected http: HTTPRequestController\n ) {\n super();\n this.fetched$ = defer(() => from(this.fetch())).pipe(\n shareReplay(1),\n takeUntil(this.destroyed$)\n );\n }\n\n protected abstract populateInstance(data: T): void;\n\n private async fetch(): Promise<boolean> {\n const response = await this.http.request({\n url: this.fromPath,\n method: 'GET',\n headers: {\n Accept: 'application/json'\n }\n });\n if (response.ok && response.body) {\n const data = JSON.parse(response.body) as T;\n this.populateInstance(data);\n return true;\n }\n return false;\n }\n}\n","import { Fetchable } from '../../behaviors/Fetchable';\n\nimport type { HTTPRequestController } from '../../controllers/HTTPRequestController';\nimport type { GetAddressResponse } from '../types/address.types';\nimport type { GetSubscriberInfoResponse } from '../types/subscriber.types';\n\n/** Subscriber online presence state. */\nexport type SubscriberPresence = 'online' | 'offline' | 'busy';\n\n/**\n * Authenticated subscriber profile.\n *\n * Fetched automatically when a {@link SignalWire} connects.\n * Contains identity, contact, and organization details.\n */\nexport class Subscriber extends Fetchable<GetSubscriberInfoResponse> {\n /** Unique subscriber identifier. */\n public id!: string;\n /** Subscriber email address. */\n public email!: string;\n /** First name. */\n public firstName?: string;\n /** Last name. */\n public lastName?: string;\n /** Display name shown to other participants. */\n public displayName?: string;\n /** Job title. */\n public jobTitle?: string;\n /** Time zone offset. */\n public timeZone?: number;\n /** Country code. */\n public country?: string;\n /** Region/state. */\n public region?: string;\n /** Company name. */\n public companyName?: string;\n /** Push notification key for mobile/web push. */\n public pushNotificationKey!: string;\n /** Application-level settings (display name, permission scopes). */\n public appSettings?: {\n displayName: string;\n scopes: string[];\n };\n /** Fabric addresses associated with this subscriber. */\n public addresses!: GetAddressResponse[];\n\n constructor(http: HTTPRequestController) {\n super('/api/fabric/subscriber/info', http);\n }\n\n protected populateInstance(data: GetSubscriberInfoResponse): void {\n this.id = data.id;\n this.email = data.email;\n this.firstName = data.first_name;\n this.lastName = data.last_name;\n this.displayName = data.display_name;\n this.jobTitle = data.job_title;\n this.timeZone = data.time_zone;\n this.country = data.country;\n this.region = data.region;\n this.companyName = data.company_name;\n this.pushNotificationKey = data.push_notification_key;\n this.appSettings = data.app_settings\n ? {\n displayName: data.app_settings.display_name,\n scopes: data.app_settings.scopes\n }\n : undefined;\n this.addresses = data.fabric_addresses;\n }\n}\n","import { v4 as uuid } from 'uuid';\n\nimport type { JSONRPCRequest, JSONRPCResponse } from './types/base';\n\ninterface MakeRPCRequestParams<\n T extends string = 'execute',\n P extends Record<string, unknown> = Record<string, unknown>\n> {\n id?: string;\n method: T;\n params: P;\n}\nexport const buildRPCRequest = <\n T extends string = 'execute',\n P extends Record<string, unknown> = Record<string, unknown>\n>(\n params: MakeRPCRequestParams<T, P>\n): JSONRPCRequest<P> & { method: T; params: P } => {\n return {\n jsonrpc: '2.0' as const,\n id: params.id ?? uuid(),\n ...params\n };\n};\n\ninterface MakeRPCResponseParams {\n id: string;\n result: Record<string, unknown>;\n}\nexport const makeRPCResponse = <T extends JSONRPCResponse = JSONRPCResponse>(\n params: MakeRPCResponseParams\n): T => {\n return {\n jsonrpc: '2.0' as const,\n ...params\n } as T;\n};\n","import { buildRPCRequest } from './helpers';\n\nimport type { JSONRPCRequest } from './types/base';\n\ninterface WithToken {\n token: string;\n\n jwt_token?: never;\n}\ninterface WithJWT {\n token?: never;\n\n jwt_token: string;\n}\nexport type RPCConnectAuthentication = { project?: string } & (WithToken | WithJWT);\nexport interface RPCConnectParams {\n authentication: RPCConnectAuthentication;\n version?: typeof DEFAULT_CONNECT_VERSION;\n agent?: string;\n protocol?: string;\n\n authorization_state?: string;\n contexts?: string[];\n topics?: string[];\n eventing?: string[];\n\n event_acks?: boolean;\n}\n\nexport interface Authorization {\n jti: string;\n\n project_id: string;\n\n fabric_subscriber: {\n version: number;\n\n expires_at: number;\n\n subscriber_id: string;\n\n application_id: string;\n\n project_id: string;\n\n space_id: string;\n };\n}\n\nexport interface RPCConnectResult {\n identity: string;\n authorization: Authorization;\n protocol: string;\n\n ice_servers?: RTCIceServer[];\n}\n\nexport const DEFAULT_CONNECT_VERSION = {\n major: 4,\n minor: 0,\n revision: 0\n};\n\nexport const RPCConnect = (params: RPCConnectParams): JSONRPCRequest => {\n return buildRPCRequest({\n method: 'signalwire.connect',\n params: {\n version: DEFAULT_CONNECT_VERSION,\n\n event_acks: true,\n ...params\n }\n });\n};\n","import { buildRPCRequest, makeRPCResponse } from './helpers';\n\nimport type { SignalwirePingRequest } from './types/events';\nimport type { SignalwirePingResponse } from './types/methods';\n\nexport const RPCPing = (): SignalwirePingRequest => {\n return buildRPCRequest({\n method: 'signalwire.ping',\n params: {\n timestamp: Date.now() / 1000\n }\n });\n};\n\nexport const RPCPingResponse = (id: string, timestamp?: number): SignalwirePingResponse => {\n return makeRPCResponse<SignalwirePingResponse>({\n id,\n result: {\n timestamp: timestamp ?? Date.now() / 1000\n }\n });\n};\n","import { buildRPCRequest } from './helpers';\n\nimport type { JSONRPCRequest, JSONRPCMethod } from './types/base';\n\ninterface RPCExecuteParams {\n id?: string;\n method: JSONRPCMethod;\n params: Record<string, unknown>;\n}\n\nexport const RPCExecute = ({ method, params }: RPCExecuteParams): JSONRPCRequest => {\n return buildRPCRequest({\n method,\n params\n });\n};\n","import { buildRPCRequest, makeRPCResponse } from './helpers';\n\nimport type { VertoMethod } from '../types/rpc.types';\nimport type { JSONRPCResponse } from './types/base';\nimport type { WebrtcVertoParams, WebrtcVertoRequest } from './types/methods';\nimport type { VertoByeCause } from './types/verto';\n\ntype VertoParams = Record<string, unknown>;\n\nconst tmpMap: VertoParams = {\n id: 'callID',\n destinationNumber: 'destination_number',\n remoteCallerName: 'remote_caller_id_name',\n remoteCallerNumber: 'remote_caller_id_number',\n callerName: 'caller_id_name',\n callerNumber: 'caller_id_number',\n fromCallAddressId: 'from_fabric_address_id'\n};\n\n/**\n * Translate SDK fields into verto variables\n */\n/* eslint-disable */\nconst filterVertoParams = (params: VertoParams) => {\n if (Object.prototype.hasOwnProperty.call(params, 'dialogParams')) {\n // prettier-ignore\n const { \n remoteSdp,\n localStream,\n remoteStream,\n ...dialogParams\n } = params.dialogParams as Record<string, unknown>;\n for (const key in tmpMap) {\n if (key && Object.prototype.hasOwnProperty.call(dialogParams, key)) {\n // @ts-ignore\n dialogParams[tmpMap[key]] = dialogParams[key];\n delete dialogParams[key];\n }\n }\n params.dialogParams = dialogParams;\n }\n\n return params;\n};\n\n/* eslint-enable */\n\nconst buildVertoRPCMessage = (method: VertoMethod) => {\n return (params: VertoParams = {}) => {\n return buildRPCRequest({\n method,\n params: filterVertoParams(params)\n });\n };\n};\n\nexport type VertoRPCMessage = ReturnType<ReturnType<typeof buildVertoRPCMessage>>;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type JSONRPCParams = Record<string, any>;\n\n// export interface WebrtcVertoParams extends JSONRPCParams {\n// message: JSONRPCRequest<VertoMethod>;\n// callID?: string;\n// node_id?: string;\n// subscribe?: string[];\n// }\n\nexport const WebrtcVerto = (params: WebrtcVertoParams): WebrtcVertoRequest => {\n return buildRPCRequest({\n method: 'webrtc.verto',\n params\n });\n};\n\nexport type WebrtcVertoRPCMessage = ReturnType<ReturnType<typeof buildVertoRPCMessage>>;\n\nexport const VertoInvite = buildVertoRPCMessage('verto.invite');\nexport const VertoBye = buildVertoRPCMessage('verto.bye');\nexport const VertoAttach = buildVertoRPCMessage('verto.attach');\nexport const VertoModify = buildVertoRPCMessage('verto.modify');\nexport const VertoInfo = buildVertoRPCMessage('verto.info');\nexport const VertoAnswer = buildVertoRPCMessage('verto.answer');\nexport const VertoSubscribe = buildVertoRPCMessage('verto.subscribe');\nexport const VertoPong = buildVertoRPCMessage('verto.pong');\nexport const VertoResult = (id: string, method: VertoMethod): JSONRPCResponse => {\n return makeRPCResponse({\n id,\n result: {\n method\n }\n });\n};\n\nexport interface VertoModifyResponse {\n action: string;\n callID: string;\n holdState: 'held' | 'active';\n\n node_id?: string;\n sdp?: string;\n}\n\nexport const VertoByeCauseCodes: Record<VertoByeCause, string> = {\n NORMAL_CLEARING: '16',\n\n USER_BUSY: '17',\n\n MEDIA_TIMEOUT: '804'\n} as const;\n","import { makeRPCResponse } from './helpers';\n\nimport type { JSONRPCResponse } from './types/base';\n\nexport const RPCEventAckResponse = (id: string): JSONRPCResponse =>\n makeRPCResponse({ id, result: {} });\n","import { getLogger } from '../utils/logger';\n\nimport type { StorageManager } from './StorageManager';\nimport type { Address } from '../core/entities/Address';\nimport type { Call, CallOptions } from '../core/entities/types/call.types';\nimport type { MediaDirections } from '../core/types/media.types';\nimport type { DeviceController } from '../interfaces/DeviceController';\n\nconst logger = getLogger();\ninterface AttachableCall {\n id: string;\n to?: string;\n mediaDirections: MediaDirections;\n}\n\nexport interface OutboundCallProvider {\n createOutboundCall(destination: string | Address, options?: CallOptions): Promise<Call>;\n}\n\ninterface Attachment {\n destination: string;\n mediaDirections: MediaDirections;\n audioInputDevice: MediaDeviceInfo | null;\n videoInputDevice: MediaDeviceInfo | null;\n attachedAt: number;\n}\n\nexport class AttachManager {\n private session!: OutboundCallProvider;\n constructor(\n private readonly storage: StorageManager,\n\n private readonly deviceController: DeviceController,\n private readonly reconnectCallsTimeout: number,\n private attachKey: string\n ) {}\n\n async detachAll(): Promise<void> {\n const attached = await this.readAttached();\n for (const callId of Object.keys(attached)) {\n await this.detach({ id: callId, mediaDirections: attached[callId].mediaDirections });\n }\n }\n\n public setSession(session: OutboundCallProvider): void {\n this.session = session;\n }\n\n private async readAttached(): Promise<Record<string, Attachment>> {\n try {\n return (await this.storage.getItem(this.attachKey)) ?? {};\n } catch (error) {\n logger.warn('[AttachManager] Failed to retrieve attached calls from storage', error);\n return {};\n }\n }\n\n private async writeAttached(attached: Record<string, Attachment>): Promise<void> {\n try {\n await this.storage.setItem(this.attachKey, attached);\n } catch (error) {\n logger.warn('[AttachManager] Failed to write attached calls to storage', error);\n }\n }\n\n public async attach(call: AttachableCall): Promise<void> {\n if (!call.to) {\n logger.warn('[AttachManager] Skip attach for calls with no destination');\n return;\n }\n const attachment = {\n destination: call.to,\n mediaDirections: call.mediaDirections,\n audioInputDevice:\n call.mediaDirections.audio !== 'inactive'\n ? this.deviceController.selectedAudioInputDevice\n : null,\n videoInputDevice:\n call.mediaDirections.video !== 'inactive'\n ? this.deviceController.selectedVideoInputDevice\n : null,\n attachedAt: Date.now()\n };\n const attached = await this.readAttached();\n attached[call.id] = attachment;\n await this.writeAttached(attached);\n }\n\n public async detach(call: AttachableCall): Promise<void> {\n const attached = await this.readAttached();\n delete attached[call.id];\n await this.writeAttached(attached);\n }\n\n public async flush(): Promise<void> {\n await this.writeAttached({});\n }\n\n public async reattachCalls(): Promise<void> {\n const attached = await this.readAttached();\n\n await this.detachExpired();\n\n for (const [callId, attachment] of Object.entries(attached)) {\n const { destination } = attachment;\n\n const options = this.buildCallOptions(attachment);\n\n await this.session.createOutboundCall(destination, { callId, ...options });\n }\n }\n\n private buildCallOptions(attachment: Attachment): CallOptions {\n const { audio: audioDirection, video: videoDirection } = attachment.mediaDirections;\n const { audioInputDevice, videoInputDevice } = attachment;\n const receiveAudio = audioDirection.includes('recv');\n const receiveVideo = videoDirection.includes('recv');\n const inputAudioDeviceConstraints = {\n ...{ audio: audioDirection.includes('send') },\n ...this.deviceController.deviceInfoToConstraints(audioInputDevice)\n };\n const inputVideoDeviceConstraints = {\n ...{ video: videoDirection.includes('send') },\n ...this.deviceController.deviceInfoToConstraints(videoInputDevice)\n };\n return {\n receiveAudio,\n receiveVideo,\n inputAudioDeviceConstraints,\n inputVideoDeviceConstraints,\n reattach: true\n };\n }\n\n private async detachExpired() {\n const attached = await this.readAttached();\n\n const expired = Object.entries(attached).filter(([, attachment]) => {\n const now = Date.now();\n const timeout = this.reconnectCallsTimeout;\n return now - attachment.attachedAt > timeout;\n });\n expired.forEach(([callId]) => {\n delete attached[callId];\n });\n\n if (expired.length > 0) {\n await this.writeAttached(attached);\n }\n }\n}\n","/**\n * Represents an on/off capability state\n * Both `on` and `off` can be true if the parent permission grants both\n */\nexport interface OnOffCapability {\n readonly on: boolean;\n readonly off: boolean;\n}\n\n/**\n * Member-level capabilities for self or other members\n */\nexport interface MemberCapabilities {\n readonly muteAudio: OnOffCapability;\n readonly muteVideo: OnOffCapability;\n readonly deaf: OnOffCapability;\n readonly raisehand: OnOffCapability;\n readonly microphoneVolume: boolean;\n readonly microphoneSensitivity: boolean;\n readonly speakerVolume: boolean;\n readonly position: boolean;\n readonly meta: boolean;\n readonly remove: boolean;\n readonly audioFlags: boolean;\n}\n\n/**\n * Call-level capabilities state\n */\nexport interface CallCapabilitiesState {\n readonly self: MemberCapabilities;\n readonly member: MemberCapabilities;\n readonly end: boolean;\n readonly setLayout: boolean;\n readonly sendDigit: boolean;\n readonly vmutedHide: OnOffCapability;\n readonly lock: OnOffCapability;\n readonly device: boolean;\n readonly screenshare: boolean;\n}\n\n/**\n * Default on/off state with no permissions\n */\nexport const DEFAULT_ON_OFF: OnOffCapability = {\n on: false,\n off: false\n};\n\n/**\n * Default member capabilities with no permissions\n */\nexport const DEFAULT_MEMBER_CAPABILITIES: MemberCapabilities = {\n muteAudio: DEFAULT_ON_OFF,\n muteVideo: DEFAULT_ON_OFF,\n deaf: DEFAULT_ON_OFF,\n raisehand: DEFAULT_ON_OFF,\n microphoneVolume: false,\n microphoneSensitivity: false,\n speakerVolume: false,\n position: false,\n meta: false,\n remove: false,\n audioFlags: false\n};\n\n/**\n * Default call capabilities with no permissions\n */\nexport const DEFAULT_CALL_CAPABILITIES: CallCapabilitiesState = {\n self: DEFAULT_MEMBER_CAPABILITIES,\n member: DEFAULT_MEMBER_CAPABILITIES,\n end: false,\n setLayout: false,\n sendDigit: false,\n vmutedHide: DEFAULT_ON_OFF,\n lock: DEFAULT_ON_OFF,\n device: false,\n screenshare: false\n};\n","import { DEFAULT_CALL_CAPABILITIES, DEFAULT_MEMBER_CAPABILITIES, DEFAULT_ON_OFF } from './types';\n\nimport type { CallCapabilitiesState, MemberCapabilities, OnOffCapability } from './types';\n\ntype MemberType = 'self' | 'member';\n\n/**\n * Computes an on/off capability state from filtered flags\n *\n * Logic:\n * - `on` is true if any flag does NOT end with `.off`\n * - `off` is true if any flag does NOT end with `.on`\n *\n * This means parent permissions (without .on/.off suffix) grant both on and off\n */\nfunction computeOnOffCapability(filteredFlags: string[]): OnOffCapability {\n if (filteredFlags.length === 0) {\n return DEFAULT_ON_OFF;\n }\n\n return {\n on: filteredFlags.some((flag) => !flag.endsWith('.off')),\n off: filteredFlags.some((flag) => !flag.endsWith('.on'))\n };\n}\n\n/**\n * Filters flags for a specific member capability with on/off support\n *\n * Matches:\n * - The member type itself (e.g., \"self\" grants all self capabilities)\n * - The parent capability (e.g., \"self.mute\" grants all mute capabilities)\n * - The specific capability and its on/off variants (e.g., \"self.mute.audio*\")\n */\nfunction filterMemberOnOffFlags(\n flags: string[],\n memberType: MemberType,\n parent: string,\n capability: string\n): string[] {\n return flags.filter(\n (flag) =>\n flag === memberType ||\n flag === `${memberType}.${parent}` ||\n flag.startsWith(`${memberType}.${parent}.${capability}`)\n );\n}\n\n/**\n * Checks if a boolean capability is granted\n *\n * Matches:\n * - The member type itself (e.g., \"self\" grants all self capabilities)\n * - The parent capability if provided (e.g., \"self.microphone\" grants volume and sensitivity)\n * - The specific capability (e.g., \"self.microphone.volume.set\")\n */\nfunction hasBooleanCapability(\n flags: string[],\n memberType: MemberType,\n parent: string | null,\n capability: string\n): boolean {\n return flags.some(\n (flag) =>\n flag === memberType ||\n (parent !== null && flag === `${memberType}.${parent}`) ||\n flag.startsWith(`${memberType}.${parent ? `${parent}.` : ''}${capability}`)\n );\n}\n\n/**\n * Computes member-level capabilities (self or member) from raw flags\n */\nfunction computeMemberCapabilities(flags: string[], memberType: MemberType): MemberCapabilities {\n // Filter only flags relevant to this member type\n const memberFlags = flags.filter((flag) => flag.startsWith(memberType) || flag === memberType);\n\n if (memberFlags.length === 0) {\n return DEFAULT_MEMBER_CAPABILITIES;\n }\n\n return {\n muteAudio: computeOnOffCapability(filterMemberOnOffFlags(flags, memberType, 'mute', 'audio')),\n muteVideo: computeOnOffCapability(filterMemberOnOffFlags(flags, memberType, 'mute', 'video')),\n deaf: computeOnOffCapability(\n flags.filter((flag) => flag === memberType || flag.startsWith(`${memberType}.deaf`))\n ),\n raisehand: computeOnOffCapability(\n flags.filter((flag) => flag === memberType || flag.startsWith(`${memberType}.raisehand`))\n ),\n microphoneVolume: hasBooleanCapability(flags, memberType, 'microphone', 'volume'),\n microphoneSensitivity: hasBooleanCapability(flags, memberType, 'microphone', 'sensitivity'),\n speakerVolume: hasBooleanCapability(flags, memberType, 'speaker', 'volume'),\n position: hasBooleanCapability(flags, memberType, null, 'position'),\n meta: hasBooleanCapability(flags, memberType, null, 'meta'),\n remove: hasBooleanCapability(flags, memberType, null, 'remove'),\n audioFlags: hasBooleanCapability(flags, memberType, null, 'audioflags')\n };\n}\n\n/**\n * Computes all call capabilities from raw capability strings\n *\n * This is a pure function that transforms the raw capability strings\n * from the `call.joined` event into a structured capabilities state.\n *\n * @param capabilities - Raw capability strings from the server\n * @returns Computed capabilities state\n */\nexport function computeCapabilities(capabilities: string[]): CallCapabilitiesState {\n if (capabilities.length === 0) {\n return DEFAULT_CALL_CAPABILITIES;\n }\n\n return {\n self: computeMemberCapabilities(capabilities, 'self'),\n member: computeMemberCapabilities(capabilities, 'member'),\n end: capabilities.some((cap) => cap === 'end'),\n setLayout: capabilities.some((cap) => cap.startsWith('layout')),\n sendDigit: capabilities.some((cap) => cap.startsWith('digit')),\n vmutedHide: computeOnOffCapability(capabilities.filter((flag) => flag.startsWith('vmuted'))),\n lock: computeOnOffCapability(capabilities.filter((flag) => flag.startsWith('lock'))),\n device: capabilities.some((cap) => cap === 'device'),\n screenshare: capabilities.some((cap) => cap === 'screenshare')\n };\n}\n","import { distinctUntilChanged, map } from 'rxjs';\n\nimport { computeCapabilities } from './computeCapabilities';\nimport { DEFAULT_CALL_CAPABILITIES } from './types';\nimport { Destroyable } from '../../behaviors/Destroyable';\n\nimport type { CallCapabilitiesState, MemberCapabilities, OnOffCapability } from './types';\nimport type { Observable } from 'rxjs';\n\n/**\n * SelfCapabilities manages the capability state for the self participant.\n *\n * Capabilities are received from the server via `call.joined` events and determine\n * what actions the current participant is allowed to perform.\n *\n * Each capability is exposed as both:\n * - An observable (e.g., `end$`) for reactive state management\n * - A synchronous getter (e.g., `end`) for immediate access\n *\n * Member-level capabilities are accessed via the grouped `self` / `member` accessors:\n * - `capabilities.self.muteAudio` (sync)\n * - `capabilities.self$` (observable)\n *\n * When a new `call.joined` event is received, the capabilities state is\n * completely replaced (not merged).\n */\nexport class SelfCapabilities extends Destroyable {\n private _state$ = this.createBehaviorSubject<CallCapabilitiesState>(DEFAULT_CALL_CAPABILITIES);\n\n /**\n * Updates the capabilities state from raw capability strings.\n * This completely replaces the current state.\n *\n * @param capabilities - Raw capability strings from the server\n * @internal\n */\n public updateFromRaw(capabilities: string[]): void {\n const newState = computeCapabilities(capabilities);\n this._state$.next(newState);\n }\n\n // ============================================\n // Self member capabilities\n // ============================================\n\n /** Observable for self member capabilities */\n public get self$(): Observable<MemberCapabilities> {\n return this.cachedObservable('self$', () =>\n this._state$.pipe(\n map((state) => state.self),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current self member capabilities */\n public get self(): MemberCapabilities {\n return this._state$.value.self;\n }\n\n // ============================================\n // Member capabilities (other participants)\n // ============================================\n\n /** Observable for other member capabilities */\n public get member$(): Observable<MemberCapabilities> {\n return this.cachedObservable('member$', () =>\n this._state$.pipe(\n map((state) => state.member),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current other member capabilities */\n public get member(): MemberCapabilities {\n return this._state$.value.member;\n }\n\n // ============================================\n // Call-level capabilities\n // ============================================\n\n /** Observable for end call capability */\n public get end$(): Observable<boolean> {\n return this.cachedObservable('end$', () =>\n this._state$.pipe(\n map((state) => state.end),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current end call capability */\n public get end(): boolean {\n return this._state$.value.end;\n }\n\n /** Observable for set layout capability */\n public get setLayout$(): Observable<boolean> {\n return this.cachedObservable('setLayout$', () =>\n this._state$.pipe(\n map((state) => state.setLayout),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current set layout capability */\n public get setLayout(): boolean {\n return this._state$.value.setLayout;\n }\n\n /** Observable for send digit capability */\n public get sendDigit$(): Observable<boolean> {\n return this.cachedObservable('sendDigit$', () =>\n this._state$.pipe(\n map((state) => state.sendDigit),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current send digit capability */\n public get sendDigit(): boolean {\n return this._state$.value.sendDigit;\n }\n\n /** Observable for vmuted hide capability */\n public get vmutedHide$(): Observable<OnOffCapability> {\n return this.cachedObservable('vmutedHide$', () =>\n this._state$.pipe(\n map((state) => state.vmutedHide),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current vmuted hide capability */\n public get vmutedHide(): OnOffCapability {\n return this._state$.value.vmutedHide;\n }\n\n /** Observable for lock capability */\n public get lock$(): Observable<OnOffCapability> {\n return this.cachedObservable('lock$', () =>\n this._state$.pipe(\n map((state) => state.lock),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current lock capability */\n public get lock(): OnOffCapability {\n return this._state$.value.lock;\n }\n\n /** Observable for device capability */\n public get device$(): Observable<boolean> {\n return this.cachedObservable('device$', () =>\n this._state$.pipe(\n map((state) => state.device),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current device capability */\n public get device(): boolean {\n return this._state$.value.device;\n }\n\n /** Observable for screenshare capability */\n public get screenshare$(): Observable<boolean> {\n return this.cachedObservable('screenshare$', () =>\n this._state$.pipe(\n map((state) => state.screenshare),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current screenshare capability */\n public get screenshare(): boolean {\n return this._state$.value.screenshare;\n }\n\n // ============================================\n // Full state access\n // ============================================\n\n /** Observable for the full capabilities state */\n public get state$(): Observable<CallCapabilitiesState> {\n return this._state$.asObservable();\n }\n\n /** Current full capabilities state */\n public get state(): CallCapabilitiesState {\n return this._state$.value;\n }\n}\n","export function toggleDeafMethod(is: boolean): 'call.undeaf' | 'call.deaf' {\n return is ? 'call.undeaf' : 'call.deaf';\n}\n\nexport function toggleHandraiseMethod(is: boolean): 'call.lowerhand' | 'call.raisehand' {\n return is ? 'call.lowerhand' : 'call.raisehand';\n}\n","import { distinctUntilChanged, map } from 'rxjs/operators';\n\nimport { Destroyable } from '../../behaviors/Destroyable';\nimport { PreferencesContainer } from '../../containers/PreferencesContainer';\nimport { filterNull } from '../../operators/filterNull';\nimport { getLogger } from '../../utils/logger';\nimport { SelfCapabilities } from '../capabilities';\nimport { UnimplementedError } from '../errors';\nimport { toggleDeafMethod, toggleHandraiseMethod } from '../RPCMessages/utils';\n\nimport type { CallParticipant, CallSelfParticipant } from './types/call.types';\nimport type { SelectDeviceOptions } from './types/participant.types';\nimport type { DeviceController } from '../../interfaces/DeviceController';\nimport type { VertoManager } from '../../interfaces/VertoManager';\nimport type { ScreenShareStatus } from '../../managers/types/verto-manager.types';\nimport type { JSONRPCResponse } from '../RPCMessages/types/base';\nimport type { Member, LayoutLayer } from '../RPCMessages/types/common';\nimport type { VideoPosition } from '../types/call.types';\nimport type { MediaOptions } from '../types/media.types';\nimport type { Observable } from 'rxjs';\n\nconst logger = getLogger();\n\n/**\n * Callback type for executing call methods\n * Injected to avoid circular dependency with Call class\n */\nexport type ExecuteMethod = <T extends JSONRPCResponse = JSONRPCResponse>(\n target: string,\n method: string,\n args: Record<string, unknown>\n) => Promise<T>;\n\ntype ParticipantState = Member & { position: LayoutLayer };\n\nconst initialState: Partial<ParticipantState> = {};\n\n/**\n * Represents a participant in a call.\n *\n * Provides observable state (audio/video mute, hand raise, volume, etc.)\n * and control methods for the participant. See {@link SelfParticipant} for\n * the local participant with additional device control.\n */\nexport class Participant extends Destroyable implements CallParticipant {\n /** Unique member ID of this participant. */\n public readonly id!: string;\n private _state$ = this.createBehaviorSubject<Partial<ParticipantState>>(initialState);\n constructor(\n id: string,\n protected executeMethod: ExecuteMethod,\n protected deviceController: DeviceController\n ) {\n super();\n this.id = id;\n }\n /** @internal */\n public upnext(data: Partial<ParticipantState>): void {\n this._state$.next({ ...this._state$.value, ...data });\n }\n\n /** Observable of the participant's display name. */\n public get name$(): Observable<string> {\n return this.cachedObservable('name$', () =>\n this._state$.pipe(\n map((state) => state.name),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable of the participant type (e.g. `'member'`, `'screen'`). */\n public get type$(): Observable<string> {\n return this.cachedObservable('type$', () =>\n this._state$.pipe(\n map((state) => state.type),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether the participant has raised their hand. */\n public get handraised$(): Observable<boolean> {\n return this.cachedObservable('handraised$', () =>\n this._state$.pipe(\n map((state) => state.handraised),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether the participant is visible in the layout. */\n public get visible$(): Observable<boolean> {\n return this.cachedObservable('visible$', () =>\n this._state$.pipe(\n map((state) => state.visible),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether the participant's audio is muted. */\n public get audioMuted$(): Observable<boolean> {\n return this.cachedObservable('audioMuted$', () =>\n this._state$.pipe(\n map((state) => state.audio_muted),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether the participant's video is muted. */\n public get videoMuted$(): Observable<boolean> {\n return this.cachedObservable('videoMuted$', () =>\n this._state$.pipe(\n map((state) => state.video_muted),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether the participant is deafened. */\n public get deaf$(): Observable<boolean> {\n return this.cachedObservable('deaf$', () =>\n this._state$.pipe(\n map((state) => state.deaf),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable of the participant's microphone input volume. */\n public get inputVolume$(): Observable<number> {\n return this.cachedObservable('inputVolume$', () =>\n this._state$.pipe(\n map((state) => state.input_volume),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable of the participant's speaker output volume. */\n public get outputVolume$(): Observable<number> {\n return this.cachedObservable('outputVolume$', () =>\n this._state$.pipe(\n map((state) => state.output_volume),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable of the microphone input sensitivity level. */\n public get inputSensitivity$(): Observable<number> {\n return this.cachedObservable('inputSensitivity$', () =>\n this._state$.pipe(\n map((state) => state.input_sensitivity),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether echo cancellation is enabled. */\n public get echoCancellation$(): Observable<boolean> {\n return this.cachedObservable('echoCancellation$', () =>\n this._state$.pipe(\n map((state) => state.echo_cancellation),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether auto-gain control is enabled. */\n public get autoGain$(): Observable<boolean> {\n return this.cachedObservable('autoGain$', () =>\n this._state$.pipe(\n map((state) => state.auto_gain),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether noise suppression is enabled. */\n public get noiseSuppression$(): Observable<boolean> {\n return this.cachedObservable('noiseSuppression$', () =>\n this._state$.pipe(\n map((state) => state.noise_suppression),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether low-bitrate mode is active. */\n public get lowbitrate$(): Observable<boolean> {\n return this.cachedObservable('lowbitrate$', () =>\n this._state$.pipe(\n map((state) => state.lowbitrate),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether noise reduction is active. */\n public get denoise$(): Observable<boolean> {\n return this.cachedObservable('denoise$', () =>\n this._state$.pipe(\n map((state) => state.denoise),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable of custom metadata for this participant. */\n public get meta$(): Observable<Record<string, unknown>> {\n return this.cachedObservable('meta$', () =>\n this._state$.pipe(\n map((state) => state.meta),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable of the participant's subscriber ID. */\n public get subscriberId$(): Observable<string> {\n return this.cachedObservable('subscriberId$', () =>\n this._state$.pipe(\n map((state) => state.subscriber_id),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable of the participant's address ID. */\n public get addressId$(): Observable<string> {\n return this.cachedObservable('addressId$', () =>\n this._state$.pipe(\n map((state) => state.address_id),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable of the server node ID for this participant. */\n public get nodeId$(): Observable<string> {\n return this.cachedObservable('nodeId$', () =>\n this._state$.pipe(\n map((state) => state.node_id),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether the participant is currently speaking. */\n public get isTalking$(): Observable<boolean> {\n return this.cachedObservable('isTalking$', () =>\n this._state$.pipe(\n map((state) => state.talking),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Whether the participant is currently speaking. */\n public get isTalking(): boolean {\n return this._state$.value.talking ?? false;\n }\n\n /** Observable of the participant's layout position. */\n public get position$(): Observable<LayoutLayer | undefined> {\n return this.cachedObservable('position$', () =>\n this._state$.pipe(\n map((state) => state.position),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Current layout position. */\n public get position(): LayoutLayer | undefined {\n return this._state$.value.position;\n }\n\n /** Whether the participant is an audience member (view-only). */\n public get isAudience(): boolean {\n return this._state$.value.isAudience ?? false;\n }\n\n /** Display name of this participant. */\n public get name(): string | undefined {\n return this._state$.value.name;\n }\n\n /** Participant type (e.g. `'member'`, `'screen'`). */\n public get type(): string | undefined {\n return this._state$.value.type;\n }\n\n public get handraised(): boolean {\n return this._state$.value.handraised ?? false;\n }\n\n public get visible(): boolean {\n return this._state$.value.visible ?? false;\n }\n\n public get audioMuted(): boolean {\n return this._state$.value.audio_muted ?? false;\n }\n\n public get videoMuted(): boolean {\n return this._state$.value.video_muted ?? false;\n }\n\n public get deaf(): boolean {\n return this._state$.value.deaf ?? false;\n }\n\n public get inputVolume(): number | undefined {\n return this._state$.value.input_volume;\n }\n\n public get outputVolume(): number | undefined {\n return this._state$.value.output_volume;\n }\n\n public get inputSensitivity(): number | undefined {\n return this._state$.value.input_sensitivity;\n }\n\n public get echoCancellation(): boolean {\n return this._state$.value.echo_cancellation ?? false;\n }\n\n public get autoGain(): boolean {\n return this._state$.value.auto_gain ?? false;\n }\n\n public get noiseSuppression(): boolean {\n return this._state$.value.noise_suppression ?? false;\n }\n\n public get lowbitrate(): boolean {\n return this._state$.value.lowbitrate ?? false;\n }\n\n public get denoise(): boolean {\n return this._state$.value.denoise ?? false;\n }\n\n public get meta(): Record<string, unknown> | undefined {\n return this._state$.value.meta;\n }\n\n public get subscriberId(): string | undefined {\n return this._state$.value.subscriber_id;\n }\n\n public get addressId(): string | undefined {\n return this._state$.value.address_id;\n }\n\n public get nodeId(): string | undefined {\n return this._state$.value.node_id;\n }\n\n /** @internal */\n public get value(): Partial<Member> {\n return this._state$.value;\n }\n\n /** Toggles the deafened state (mutes/unmutes incoming audio). */\n public async toggleDeaf(): Promise<void> {\n const method = toggleDeafMethod(this.deaf);\n const params = {};\n await this.executeMethod(this.id, method, params);\n }\n\n /** Toggles the hand-raised state. */\n public async toggleHandraise(): Promise<void> {\n await this.executeMethod(this.id, toggleHandraiseMethod(this.handraised), {});\n }\n\n /** Mutes the participant's audio. */\n public async mute(): Promise<void> {\n await this.executeMethod(this.id, 'call.mute', { channels: ['audio'] });\n }\n\n /** Unmutes the participant's audio. */\n public async unmute(): Promise<void> {\n await this.executeMethod(this.id, 'call.unmute', { channels: ['audio'] });\n }\n\n /** Toggles the participant's audio mute state. */\n public async toggleMute(): Promise<void> {\n return this.audioMuted ? this.unmute() : this.mute();\n }\n\n /** Mutes the participant's video. */\n public async muteVideo(): Promise<void> {\n await this.executeMethod(this.id, 'call.mute', { channels: ['video'] });\n }\n\n /** Unmutes the participant's video. */\n public async unmuteVideo(): Promise<void> {\n await this.executeMethod(this.id, 'call.unmute', { channels: ['video'] });\n }\n\n /** Toggles the participant's video mute state. */\n public async toggleMuteVideo(): Promise<void> {\n return this.videoMuted ? this.unmuteVideo() : this.muteVideo();\n }\n\n /** Toggles echo cancellation on the audio input. */\n public async toggleEchoCancellation(): Promise<void> {\n await this.executeMethod(this.id, 'call.audioflags.set', {\n echo_cancellation: !this.echoCancellation,\n auto_gain: this.autoGain,\n noise_suppression: this.noiseSuppression\n });\n }\n\n /** Toggles automatic gain control on the audio input. */\n public async toggleAudioInputAutoGain(): Promise<void> {\n await this.executeMethod(this.id, 'call.audioflags.set', {\n echo_cancellation: this.echoCancellation,\n auto_gain: !this.autoGain,\n noise_suppression: this.noiseSuppression\n });\n }\n\n /** Toggles noise suppression on the audio input. */\n public async toggleNoiseSuppression(): Promise<void> {\n await this.executeMethod(this.id, 'call.audioflags.set', {\n echo_cancellation: this.echoCancellation,\n auto_gain: this.autoGain,\n noise_suppression: !this.noiseSuppression\n });\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n public async toggleLowbitrate(): Promise<void> {\n // NEEDS check backend implementation\n throw new UnimplementedError();\n }\n\n /** Sets the microphone input sensitivity level. */\n public async setAudioInputSensitivity(value: number): Promise<void> {\n await this.executeMethod(this.id, 'call.microphone.sensitivity.set', {\n sensitivity: value\n });\n }\n\n /** Sets the microphone input volume level. */\n public async setAudioInputVolume(value: number): Promise<void> {\n await this.executeMethod(this.id, 'call.microphone.volume.set', {\n volume: value\n });\n }\n\n /** Sets the speaker output volume level. */\n public async setAudioOutputVolume(value: number): Promise<void> {\n await this.executeMethod(this.id, 'call.speaker.volume.set', {\n volume: value\n });\n }\n\n /** Sets the participant's position in the video layout. */\n public async setPosition(value: VideoPosition): Promise<void> {\n await this.executeMethod(this.id, 'call.member.position.set', {\n position: value\n });\n }\n\n /** Removes this participant from the call. */\n public async remove(): Promise<void> {\n await this.executeMethod(this.id, 'call.member.remove', {});\n }\n\n /** Ends the call for this participant. */\n public async end(): Promise<void> {\n await this.executeMethod(this.id, 'call.end', {});\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n public async setMeta(_meta: Record<string, unknown>): Promise<void> {\n // NEEDS backend implementation\n throw new UnimplementedError();\n }\n // eslint-disable-next-line @typescript-eslint/require-await\n public async updateMeta(_meta: Record<string, unknown>): Promise<void> {\n // NEEDS backend implementation\n throw new UnimplementedError();\n }\n\n public destroy(): void {\n // Cleanup callback reference - intentionally breaking type safety for cleanup\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any\n this.executeMethod = undefined as any;\n super.destroy();\n }\n}\n\n/**\n * The local participant in a call, with additional device and media control.\n *\n * Extends {@link Participant} with screen sharing, device selection,\n * and local media stream management.\n */\nexport class SelfParticipant extends Participant implements CallSelfParticipant {\n /**\n * Capabilities for this participant.\n * Contains all capability flags as both observables and values.\n */\n public readonly capabilities: SelfCapabilities;\n\n constructor(\n id: string,\n executeMethod: ExecuteMethod,\n private vertoManager: VertoManager,\n deviceController: DeviceController\n ) {\n super(id, executeMethod, deviceController);\n this.capabilities = new SelfCapabilities();\n }\n\n public override destroy(): void {\n this.capabilities.destroy();\n super.destroy();\n }\n\n /** Starts sharing the local screen. */\n public async startScreenShare(): Promise<void> {\n try {\n await this.vertoManager.addScreenMedia();\n } catch (error) {\n logger.error('[Participant.startScreenShare] Screen share error:', error);\n }\n }\n\n /** Observable of the current screen share status. */\n public get screenShareStatus$(): Observable<ScreenShareStatus> {\n return this.vertoManager.screenShareStatus$;\n }\n\n /** Current screen share status. */\n public get screenShareStatus(): ScreenShareStatus {\n return this.vertoManager.screenShareStatus;\n }\n\n /** Stops the current screen share. */\n public async stopScreenShare(): Promise<void> {\n return this.vertoManager.removeScreenMedia();\n }\n\n /** Adds an additional media input device to the call. */\n public async addAdditionalDevice(options: MediaOptions): Promise<void> {\n try {\n await this.vertoManager.addInputDevice(options);\n } catch (error) {\n logger.error('[Participant.startScreenShare] Screen share error:', error);\n }\n }\n\n /** Removes an additional media input device by ID. */\n public async removeAdditionalDevice(id: string): Promise<void> {\n return this.vertoManager.removeInputDevices(id);\n }\n\n /** Adds or replaces the primary audio input device with optional constraints or stream. */\n public async addAudioInputDevice({\n constraints,\n stream\n }: {\n constraints?: MediaTrackConstraints;\n stream?: MediaStream;\n } = {}): Promise<void> {\n const audio = (constraints ?? stream) ? undefined : true;\n return this.vertoManager.addMainInputDevices({\n audio,\n inputAudioDeviceConstraints: constraints,\n inputAudioStream: stream\n });\n }\n\n /** Adds or replaces the primary video input device with optional constraints or stream. */\n public async addVideoInputDevice({\n constraints,\n stream\n }: {\n constraints?: MediaTrackConstraints;\n stream?: MediaStream;\n } = {}): Promise<void> {\n const video = (constraints ?? stream) ? undefined : true;\n return this.vertoManager.addMainInputDevices({\n video,\n inputVideoDeviceConstraints: constraints,\n inputVideoStream: stream\n });\n }\n\n /** Adds or replaces primary input devices (audio and/or video). */\n public async addInputDevices(options: MediaOptions = {}): Promise<void> {\n await this.vertoManager.addMainInputDevices(options);\n }\n\n /** Selects the audio input device for future calls. Optionally saves as a preference. */\n public selectAudioInputDevice(device: MediaDeviceInfo, options: SelectDeviceOptions = {}): void {\n this.deviceController.selectAudioInputDevice(device);\n if (options.savePreference) {\n PreferencesContainer.instance.preferredAudioInput = device;\n }\n }\n\n /** Updates the audio input track constraints for the active call. */\n public async setAudioInputDeviceConstraints(constraints: MediaTrackConstraints): Promise<void> {\n await this.vertoManager.updateMediaConstraints({ audio: constraints });\n }\n\n /** Updates both audio and video input track constraints for the active call. */\n public async setInputDevicesConstraints(constraints: {\n audio: MediaTrackConstraints;\n video: MediaTrackConstraints;\n }): Promise<void> {\n await this.vertoManager.updateMediaConstraints(constraints);\n }\n\n /** Selects the video input device for future calls. Optionally saves as a preference. */\n public selectVideoInputDevice(device: MediaDeviceInfo, options: SelectDeviceOptions = {}): void {\n this.deviceController.selectVideoInputDevice(device);\n if (options.savePreference) {\n PreferencesContainer.instance.preferredVideoInput = device;\n }\n }\n\n /** Updates the video input track constraints for the active call. */\n public async setVideoInputDeviceConstraints(constraints: MediaTrackConstraints): Promise<void> {\n await this.vertoManager.updateMediaConstraints({ video: constraints });\n }\n\n /** Selects the audio output device. Optionally saves as a preference. */\n public selectAudioOutputDevice(device: MediaDeviceInfo, options: SelectDeviceOptions = {}): void {\n this.deviceController.selectAudioOutputDevice(device);\n if (options.savePreference) {\n PreferencesContainer.instance.preferredAudioOutput = device;\n }\n }\n\n public async mute(): Promise<void> {\n try {\n await super.mute();\n } catch (error) {\n logger.warn(\n '[Participant.toggleAudioInput] Server Error while muting audio input, proceeding with local toggle anyway',\n error\n );\n } finally {\n this.vertoManager.muteMainAudioInputDevice();\n }\n }\n\n public async unmute(): Promise<void> {\n try {\n await super.unmute();\n } catch (error) {\n logger.warn(\n '[Participant.toggleAudioInput] Server Error while unmuting audio input, proceeding with local toggle anyway',\n error\n );\n } finally {\n await this.vertoManager.unmuteMainAudioInputDevice();\n }\n }\n\n public async muteVideo(): Promise<void> {\n try {\n await super.muteVideo();\n } catch (error) {\n logger.warn(\n '[Participant.toggleVideoInput] Server Error while muting video input, proceeding with local toggle anyway',\n error\n );\n } finally {\n this.vertoManager.muteMainVideoInputDevice();\n }\n }\n\n public async unmuteVideo(): Promise<void> {\n try {\n await super.unmuteVideo();\n } catch (error) {\n logger.warn(\n '[Participant.toggleVideoInput] Server Error while unmuting video input, proceeding with local toggle anyway',\n error\n );\n } finally {\n await this.vertoManager.unmuteMainVideoInputDevice();\n }\n }\n}\n\n/** Type guard that checks if a participant is the local {@link SelfParticipant}. */\nexport const isSelfParticipant = (participant: Participant): participant is SelfParticipant => {\n return participant instanceof SelfParticipant;\n};\n","// =============================================================================\n// BASE TYPE GUARDS\n// =============================================================================\n// This file contains type guards for base JSON-RPC types.\n\nimport type { JSONRPCRequest, JSONRPCResponse } from '../types/base';\n\n// =============================================================================\n// TYPE GUARD HELPERS\n// =============================================================================\n\nexport function isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nexport function hasProperty<T extends object, K extends string>(\n obj: T,\n key: K\n): obj is T & Record<K, unknown> {\n return key in obj;\n}\n\nexport function hasStringProperty<T extends object, K extends string>(\n obj: T,\n key: K\n): obj is T & Record<K, string> {\n return key in obj && typeof (obj as Record<string, unknown>)[key] === 'string';\n}\n\n// =============================================================================\n// BASE TYPE GUARDS\n// =============================================================================\n\nexport function isJSONRPCRequest(value: unknown): value is JSONRPCRequest {\n return (\n isObject(value) &&\n hasProperty(value, 'jsonrpc') &&\n value.jsonrpc === '2.0' &&\n hasProperty(value, 'id') &&\n typeof value.id === 'string' &&\n hasProperty(value, 'method') &&\n typeof value.method === 'string'\n );\n}\n\nexport function isJSONRPCResponse(value: unknown): value is JSONRPCResponse {\n return (\n isObject(value) &&\n hasProperty(value, 'jsonrpc') &&\n value.jsonrpc === '2.0' &&\n hasProperty(value, 'id') &&\n typeof value.id === 'string' &&\n hasProperty(value, 'result')\n );\n}\n","// =============================================================================\n// SIGNALWIRE EVENT TYPE GUARDS\n// =============================================================================\n// This file contains type guards for SignalWire event types.\n\nimport { hasProperty, isJSONRPCRequest, isObject } from './base.guards';\n\nimport type { TypeGuard, ExtractParams } from '../types/base';\nimport type {\n CallConnectPayload,\n CallJoinedPayload,\n CallJoinedRequest,\n CallLeftPayload,\n CallLeftRequest,\n CallPlayPayload,\n CallPlayRequest,\n CallStatePayload,\n CallStateRequest,\n CallUpdatedPayload,\n CallUpdatedRequest,\n CallConnectRequest,\n ConversationMessagePayload,\n ConversationMessageRequest,\n ConversationMessageUpdatedPayload,\n ConversationMessageUpdatedRequest,\n LayoutChangedPayload,\n LayoutChangedRequest,\n MemberJoinedPayload,\n MemberJoinedRequest,\n MemberLeftPayload,\n MemberLeftRequest,\n MemberTalkingPayload,\n MemberTalkingRequest,\n MemberUpdatedPayload,\n MemberUpdatedRequest,\n SignalwireAuthorizationStatePayload,\n SignalwireAuthorizationStateRequest,\n SignalwireCallMetadata,\n SignalwireCallRequest,\n SignalwireEventRequestBase,\n SignalwireMetadata,\n SignalwireRequest,\n WebrtcMessagePayload,\n WebrtcMessageRequest\n} from '../types/events';\n\n// =============================================================================\n// TYPE GUARD FACTORY SYSTEM\n// =============================================================================\n\n/**\n * Registry of all SignalWire event types.\n * This is the single source of truth for event type strings.\n */\n// eslint-disable-next-line unused-imports/no-unused-vars\nconst EVENT_TYPE_REGISTRY = {\n 'signalwire.authorization.state': true,\n 'webrtc.message': true,\n 'call.joined': true,\n 'call.left': true,\n 'call.updated': true,\n 'call.state': true,\n 'call.play': true,\n 'call.connect': true,\n 'member.updated': true,\n 'member.joined': true,\n 'member.left': true,\n 'member.talking': true,\n 'layout.changed': true,\n 'conversation.message': true,\n 'conversation.message.updated': true\n} as const;\n\nexport type RegisteredEventType = keyof typeof EVENT_TYPE_REGISTRY;\n\n/**\n * Factory function to create Request-level type guards.\n */\nexport function createEventRequestGuard<T extends SignalwireEventRequestBase>(\n eventType: RegisteredEventType\n): TypeGuard<T> {\n return (value: unknown): value is T =>\n isSignalwireRequest(value) && value.params.event_type === eventType;\n}\n\n/**\n * Factory function to create Metadata-level type guards.\n */\nexport function createEventMetadataGuard<T extends SignalwireMetadata>(\n eventType: RegisteredEventType\n): TypeGuard<T> {\n return (value: unknown): value is T =>\n isSignalwireMetadata(value) && value.event_type === eventType;\n}\n\n// =============================================================================\n// SIGNALWIRE EVENT TYPE GUARDS\n// =============================================================================\n\nexport function isSignalwireRequest(value: unknown): value is SignalwireRequest {\n return (\n isJSONRPCRequest(value) &&\n value.method === 'signalwire.event' &&\n isObject(value.params) &&\n hasProperty(value.params, 'event_type')\n );\n}\n\nexport function isSignalwireCallRequest(value: unknown): value is SignalwireCallRequest {\n return (\n isSignalwireRequest(value) &&\n (isCallJoinedRequest(value) ||\n isCallLeftRequest(value) ||\n isCallUpdatedRequest(value) ||\n isCallStateRequest(value) ||\n isCallPlayRequest(value) ||\n isCallConnectRequest(value) ||\n isMemberUpdatedRequest(value) ||\n isMemberJoinedRequest(value) ||\n isMemberLeftRequest(value) ||\n isMemberTalkingRequest(value) ||\n isLayoutChangedRequest(value) ||\n isWebrtcMessageRequest(value) ||\n isConversationMessageRequest(value) ||\n isConversationMessageUpdatedRequest(value))\n );\n}\n\n// Generated Request guards using factory pattern\nexport const isSignalwireAuthorizationStateRequest =\n createEventRequestGuard<SignalwireAuthorizationStateRequest>('signalwire.authorization.state');\n\nexport const isWebrtcMessageRequest =\n createEventRequestGuard<WebrtcMessageRequest>('webrtc.message');\n\nexport const isCallJoinedRequest = createEventRequestGuard<CallJoinedRequest>('call.joined');\n\nexport const isCallLeftRequest = createEventRequestGuard<CallLeftRequest>('call.left');\n\nexport const isCallUpdatedRequest = createEventRequestGuard<CallUpdatedRequest>('call.updated');\n\nexport const isCallStateRequest = createEventRequestGuard<CallStateRequest>('call.state');\n\nexport const isCallPlayRequest = createEventRequestGuard<CallPlayRequest>('call.play');\n\nexport const isCallConnectRequest = createEventRequestGuard<CallConnectRequest>('call.connect');\n\nexport const isMemberUpdatedRequest =\n createEventRequestGuard<MemberUpdatedRequest>('member.updated');\n\nexport const isMemberJoinedRequest = createEventRequestGuard<MemberJoinedRequest>('member.joined');\n\nexport const isMemberLeftRequest = createEventRequestGuard<MemberLeftRequest>('member.left');\n\nexport const isMemberTalkingRequest =\n createEventRequestGuard<MemberTalkingRequest>('member.talking');\n\nexport const isLayoutChangedRequest =\n createEventRequestGuard<LayoutChangedRequest>('layout.changed');\n\nexport const isConversationMessageRequest =\n createEventRequestGuard<ConversationMessageRequest>('conversation.message');\n\nexport const isConversationMessageUpdatedRequest =\n createEventRequestGuard<ConversationMessageUpdatedRequest>('conversation.message.updated');\n\n// =============================================================================\n// SIGNALWIRE EVENT METADATA TYPE GUARDS (outer wrapper with event_type)\n// =============================================================================\n\nexport function isSignalwireMetadata(value: unknown): value is SignalwireMetadata {\n return (\n isObject(value) &&\n hasProperty(value, 'event_type') &&\n typeof value.event_type === 'string' &&\n hasProperty(value, 'params')\n );\n}\n\nexport function isSignalwireCallMetadata(value: unknown): value is SignalwireCallMetadata {\n return (\n isSignalwireMetadata(value) &&\n (isCallJoinedMetadata(value) ||\n isCallLeftMetadata(value) ||\n isCallUpdatedMetadata(value) ||\n isCallStateMetadata(value) ||\n isCallPlayMetadata(value) ||\n isCallConnectMetadata(value) ||\n isMemberUpdatedMetadata(value) ||\n isMemberJoinedMetadata(value) ||\n isMemberLeftMetadata(value) ||\n isMemberTalkingMetadata(value) ||\n isLayoutChangedMetadata(value) ||\n isWebrtcMessageMetadata(value) ||\n isConversationMessageMetadata(value) ||\n isConversationMessageUpdatedMetadata(value))\n );\n}\n\n// Generated Metadata guards using factory pattern\nexport const isSignalwireAuthorizationStateMetadata = createEventMetadataGuard<\n ExtractParams<SignalwireAuthorizationStateRequest>\n>('signalwire.authorization.state');\n\nexport const isWebrtcMessageMetadata =\n createEventMetadataGuard<ExtractParams<WebrtcMessageRequest>>('webrtc.message');\n\nexport const isCallJoinedMetadata =\n createEventMetadataGuard<ExtractParams<CallJoinedRequest>>('call.joined');\n\nexport const isCallLeftMetadata =\n createEventMetadataGuard<ExtractParams<CallLeftRequest>>('call.left');\n\nexport const isCallUpdatedMetadata =\n createEventMetadataGuard<ExtractParams<CallUpdatedRequest>>('call.updated');\n\nexport const isCallStateMetadata =\n createEventMetadataGuard<ExtractParams<CallStateRequest>>('call.state');\n\nexport const isCallPlayMetadata =\n createEventMetadataGuard<ExtractParams<CallPlayRequest>>('call.play');\n\nexport const isCallConnectMetadata =\n createEventMetadataGuard<ExtractParams<CallConnectRequest>>('call.connect');\n\nexport const isMemberUpdatedMetadata =\n createEventMetadataGuard<ExtractParams<MemberUpdatedRequest>>('member.updated');\n\nexport const isMemberJoinedMetadata =\n createEventMetadataGuard<ExtractParams<MemberJoinedRequest>>('member.joined');\n\nexport const isMemberLeftMetadata =\n createEventMetadataGuard<ExtractParams<MemberLeftRequest>>('member.left');\n\nexport const isMemberTalkingMetadata =\n createEventMetadataGuard<ExtractParams<MemberTalkingRequest>>('member.talking');\n\nexport const isLayoutChangedMetadata =\n createEventMetadataGuard<ExtractParams<LayoutChangedRequest>>('layout.changed');\n\nexport const isConversationMessageMetadata =\n createEventMetadataGuard<ExtractParams<ConversationMessageRequest>>('conversation.message');\n\nexport const isConversationMessageUpdatedMetadata = createEventMetadataGuard<\n ExtractParams<ConversationMessageUpdatedRequest>\n>('conversation.message.updated');\n\n// =============================================================================\n// EVENT PAYLOAD TYPE GUARDS\n// =============================================================================\n\nexport function isSignalwireAuthorizationStatePayload(\n value: unknown\n): value is SignalwireAuthorizationStatePayload {\n return isObject(value) && hasProperty(value, 'authorization_state');\n}\n\nexport function isCallJoinedPayload(value: unknown): value is CallJoinedPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'room_session') &&\n hasProperty(value, 'call_id') &&\n hasProperty(value, 'member_id') &&\n hasProperty(value, 'capabilities')\n );\n}\n\nexport function isCallLeftPayload(value: unknown): value is CallLeftPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'room_session') &&\n hasProperty(value, 'call_id') &&\n hasProperty(value, 'reason')\n );\n}\n\nexport function isMemberUpdatedPayload(value: unknown): value is MemberUpdatedPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'member') &&\n hasProperty(value, 'room_id') &&\n hasProperty(value, 'room_session_id') &&\n !hasProperty(value, 'reason') &&\n !hasProperty((value as MemberUpdatedPayload).member, 'talking')\n );\n}\n\nexport function isMemberJoinedPayload(value: unknown): value is MemberJoinedPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'member') &&\n hasProperty(value, 'room_id') &&\n !hasProperty(value, 'reason')\n );\n}\n\nexport function isMemberLeftPayload(value: unknown): value is MemberLeftPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'member') &&\n hasProperty(value, 'room_id') &&\n hasProperty(value, 'reason')\n );\n}\n\nexport function isMemberTalkingPayload(value: unknown): value is MemberTalkingPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'member') &&\n hasProperty(value, 'room_id') &&\n hasProperty(value, 'room_session_id') &&\n !hasProperty(value, 'reason') &&\n hasProperty((value as MemberTalkingPayload).member, 'talking')\n );\n}\n\nexport function isLayoutChangedPayload(value: unknown): value is LayoutChangedPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'room_id') &&\n hasProperty(value, 'room_session_id') &&\n hasProperty(value, 'layout')\n );\n}\n\nexport function isCallUpdatedPayload(value: unknown): value is CallUpdatedPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'room_session') &&\n hasProperty(value, 'room_id') &&\n hasProperty(value, 'room_session_id')\n );\n}\n\nexport function isCallStatePayload(value: unknown): value is CallStatePayload {\n return (\n isObject(value) &&\n hasProperty(value, 'call_id') &&\n hasProperty(value, 'call_state') &&\n hasProperty(value, 'direction')\n );\n}\n\nexport function isCallPlayPayload(value: unknown): value is CallPlayPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'control_id') &&\n hasProperty(value, 'call_id') &&\n hasProperty(value, 'state')\n );\n}\n\nexport function isCallConnectPayload(value: unknown): value is CallConnectPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'connect_state') &&\n hasProperty(value, 'call_id') &&\n hasProperty(value, 'segment_id')\n );\n}\n\nexport function isConversationMessagePayload(value: unknown): value is ConversationMessagePayload {\n return (\n isObject(value) &&\n hasProperty(value, 'id') &&\n hasProperty(value, 'type') &&\n hasProperty(value, 'kind') &&\n hasProperty(value, 'conversation_name')\n );\n}\n\nexport function isConversationMessageUpdatedPayload(\n value: unknown\n): value is ConversationMessageUpdatedPayload {\n return isConversationMessagePayload(value);\n}\n\nexport function isWebrtcMessageEventInnerParams(value: unknown): value is WebrtcMessagePayload {\n return (\n isObject(value) &&\n hasProperty(value, 'jsonrpc') &&\n value.jsonrpc === '2.0' &&\n hasProperty(value, 'id') &&\n hasProperty(value, 'method') &&\n typeof value.method === 'string'\n );\n}\n\n// =============================================================================\n// EVENT TYPE MAPPING\n// =============================================================================\n\nexport const EventTypeMap = {\n 'signalwire.authorization.state': isSignalwireAuthorizationStateRequest,\n 'webrtc.message': isWebrtcMessageRequest,\n 'call.joined': isCallJoinedRequest,\n 'call.left': isCallLeftRequest,\n 'call.updated': isCallUpdatedRequest,\n 'call.state': isCallStateRequest,\n 'call.play': isCallPlayRequest,\n 'call.connect': isCallConnectRequest,\n 'member.updated': isMemberUpdatedRequest,\n 'member.joined': isMemberJoinedRequest,\n 'member.left': isMemberLeftRequest,\n 'member.talking': isMemberTalkingRequest,\n 'layout.changed': isLayoutChangedRequest,\n 'conversation.message': isConversationMessageRequest,\n 'conversation.message.updated': isConversationMessageUpdatedRequest\n} as const;\n\nexport type EventType = keyof typeof EventTypeMap;\n\n/**\n * Gets the appropriate type guard for an event type.\n */\nexport function getEventGuard(eventType: string): TypeGuard<SignalwireRequest> | undefined {\n return EventTypeMap[eventType as EventType];\n}\n\n// =============================================================================\n// EVENT METADATA TYPE MAPPING\n// =============================================================================\n\nexport const EventMetadataTypeMap = {\n 'signalwire.authorization.state': isSignalwireAuthorizationStateMetadata,\n 'webrtc.message': isWebrtcMessageMetadata,\n 'call.joined': isCallJoinedMetadata,\n 'call.left': isCallLeftMetadata,\n 'call.updated': isCallUpdatedMetadata,\n 'call.state': isCallStateMetadata,\n 'call.play': isCallPlayMetadata,\n 'call.connect': isCallConnectMetadata,\n 'member.updated': isMemberUpdatedMetadata,\n 'member.joined': isMemberJoinedMetadata,\n 'member.left': isMemberLeftMetadata,\n 'member.talking': isMemberTalkingMetadata,\n 'layout.changed': isLayoutChangedMetadata,\n 'conversation.message': isConversationMessageMetadata,\n 'conversation.message.updated': isConversationMessageUpdatedMetadata\n} as const;\n\n/**\n * Gets the appropriate metadata type guard for an event type.\n */\nexport function getEventMetadataGuard(\n eventType: string\n): TypeGuard<SignalwireMetadata> | undefined {\n return EventMetadataTypeMap[eventType as EventType];\n}\n","import { distinctUntilChanged, filter, map, merge, tap } from 'rxjs';\n\nimport { Destroyable } from '../behaviors/Destroyable';\nimport { isSelfParticipant } from '../core/entities/Participant';\nimport { DependencyError } from '../core/errors';\nimport {\n isCallJoinedPayload,\n isLayoutChangedPayload\n} from '../core/RPCMessages/guards/events.guards';\nimport { filterAs } from '../operators';\nimport { filterNull } from '../operators/filterNull';\nimport { getLogger } from '../utils/logger';\n\nimport type { Participant, SelfParticipant } from '../core/entities/Participant';\nimport type {\n CallManager,\n CallParticipant,\n CallSelfParticipant,\n CallStatus\n} from '../core/entities/types/call.types';\nimport type {\n LayoutLayer,\n Member,\n RoomSession,\n Layout,\n MemberTalkingInfo\n} from '../core/RPCMessages/types/common';\nimport type { CallLayoutListResponse } from '../core/RPCMessages/types/methods';\nimport type { Observable } from 'rxjs';\n\nconst logger = getLogger();\n\ntype SessionState = RoomSession & { capabilities: string[] } & {\n layouts: string[];\n} & { layout_layers: LayoutLayer[] };\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface WebRTCCallEventManagerOptions {}\n\nconst initialSessionState: Partial<SessionState> = {};\n\nexport class CallEventsManager extends Destroyable {\n private selfId?: string;\n private originCallId?: string;\n private callIds = new Set<string>();\n private roomSessionIds = new Set<string>();\n private _status$ = this.createBehaviorSubject<CallStatus>('trying');\n\n private _participants$ = this.createBehaviorSubject<Record<string, Participant>>({});\n\n private _self$ = this.createBehaviorSubject<SelfParticipant | null>(null);\n private _sessionState$ = this.createBehaviorSubject<Partial<SessionState>>(initialSessionState);\n constructor(\n protected webRtcCallSession: CallManager,\n protected options: WebRTCCallEventManagerOptions = {}\n ) {\n super();\n this.initSubscriptions();\n }\n public get participants$(): Observable<CallParticipant[]> {\n return this.cachedObservable('participants$', () =>\n this._participants$\n .asObservable()\n .pipe(map((participantsRecord) => Object.values(participantsRecord)))\n );\n }\n\n public get self$(): Observable<CallSelfParticipant> {\n return this.cachedObservable('self$', () => this._self$.asObservable().pipe(filterNull()));\n }\n\n public get status$(): Observable<CallStatus> {\n return this._status$.asObservable();\n }\n\n public get status(): CallStatus {\n return this._status$.value;\n }\n\n // check if this call session has joined that same room session\n public isRoomSessionIdValid(roomSessionId: string): boolean {\n return this.roomSessionIds.has(roomSessionId);\n }\n\n public addCallId(callId: string): void {\n this.callIds.add(callId);\n }\n\n public isCallIdValid(callId: string): boolean {\n return this.callIds.has(callId);\n }\n\n public get recording$(): Observable<boolean> {\n return this.cachedObservable('recording$', () =>\n this._sessionState$.pipe(\n map((state) => state.recording),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get recordings$(): Observable<Record<string, unknown>[]> {\n return this.cachedObservable('recordings$', () =>\n this._sessionState$.pipe(\n map((state) => state.recordings),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get streaming$(): Observable<boolean> {\n return this.cachedObservable('streaming$', () =>\n this._sessionState$.pipe(\n map((state) => state.streaming),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get streams$(): Observable<Record<string, unknown>[]> {\n return this.cachedObservable('streams$', () =>\n this._sessionState$.pipe(\n map((state) => state.streams),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get playbacks$(): Observable<Record<string, unknown>[]> {\n return this.cachedObservable('playbacks$', () =>\n this._sessionState$.pipe(\n map((state) => state.playbacks),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get raiseHandPriority$(): Observable<boolean> {\n return this.cachedObservable('raiseHandPriority$', () =>\n this._sessionState$.pipe(\n map((state) => state.prioritize_handraise),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get locked$(): Observable<boolean> {\n return this.cachedObservable('locked$', () =>\n this._sessionState$.pipe(\n map((state) => state.locked),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get meta$(): Observable<Record<string, unknown>> {\n return this.cachedObservable('meta$', () =>\n this._sessionState$.pipe(\n map((state) => state.meta),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get capabilities$(): Observable<string[]> {\n return this.cachedObservable('capabilities$', () =>\n this._sessionState$.pipe(\n map((state) => state.capabilities),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get layout$(): Observable<string> {\n return this.cachedObservable('layout$', () =>\n this._sessionState$.pipe(\n map((state) => state.layout_name),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get layouts$(): Observable<string[]> {\n return this.cachedObservable('layouts$', () =>\n this._sessionState$.pipe(\n map((state) => state.layouts),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get layoutLayers$(): Observable<LayoutLayer[]> {\n return this.cachedObservable('layoutLayers$', () =>\n this._sessionState$.pipe(\n map((state) => state.layout_layers),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get self(): CallSelfParticipant | null {\n return this._self$.value;\n }\n\n public get layoutLayers(): LayoutLayer[] {\n return this._sessionState$.value.layout_layers ?? [];\n }\n\n public get recording(): boolean {\n return this._sessionState$.value.recording ?? false;\n }\n\n public get streaming(): boolean {\n return this._sessionState$.value.streaming ?? false;\n }\n\n public get raiseHandPriority(): boolean {\n return this._sessionState$.value.prioritize_handraise ?? false;\n }\n\n public get locked(): boolean {\n return this._sessionState$.value.locked ?? false;\n }\n\n public get meta(): Record<string, unknown> {\n return this._sessionState$.value.meta ?? {};\n }\n\n public get layout(): string | undefined {\n return this._sessionState$.value.layout_name;\n }\n\n public get layouts(): string[] {\n return this._sessionState$.value.layouts ?? [];\n }\n\n public get capabilities(): string[] {\n return this._sessionState$.value.capabilities ?? [];\n }\n\n public isSessionEvent(id: string): boolean {\n return this.callIds.has(id) || this.roomSessionIds.has(id);\n }\n\n protected initSubscriptions(): void {\n this.subscribeTo(this.callJoinedEvent$, (callJoinedEvent) => {\n logger.debug('[CallEventsManager] Handling call.joined event for call/session IDs:', {\n callId: callJoinedEvent.call_id,\n roomSessionId: callJoinedEvent.room_session_id\n });\n this._status$.next('connected');\n\n const sessionState = callJoinedEvent.room_session;\n const { capabilities } = callJoinedEvent;\n // Don't update selfId and originCallId from nested call.joined events\n this.selfId = this.selfId ?? callJoinedEvent.member_id;\n this.originCallId = this.originCallId ?? callJoinedEvent.origin_call_id;\n this.callIds.add(callJoinedEvent.call_id);\n this.roomSessionIds.add(callJoinedEvent.room_session_id);\n\n this._sessionState$.next({\n ...this._sessionState$.value,\n recording: sessionState.recording,\n recordings: sessionState.recordings,\n streaming: sessionState.streaming,\n streams: sessionState.streams,\n playbacks: sessionState.playbacks,\n\n prioritize_handraise: sessionState.prioritize_handraise,\n locked: sessionState.locked,\n meta: sessionState.meta,\n\n capabilities\n });\n\n this.updateParticipants(sessionState.members);\n\n // Update capabilities on the self participant\n // This must happen after updateParticipants to ensure self exists\n this._self$.value?.capabilities.updateFromRaw(capabilities);\n\n this.updateLayouts();\n });\n this.subscribeTo(this.memberUpdates$, (member) => {\n logger.debug('[CallEventsManager] Handling member update event for member ID:', member);\n this.upsertParticipant(member);\n });\n this.subscribeTo(this.webRtcCallSession.memberLeft$, (memberLeftEvent) => {\n logger.debug(\n '[CallEventsManager] Handling member.left event for member ID:',\n memberLeftEvent.member.member_id\n );\n const participants = { ...this._participants$.value };\n if (memberLeftEvent.member.member_id in participants) {\n delete participants[memberLeftEvent.member.member_id];\n // in case in subscription is observing the participants collection\n this._participants$.next(participants);\n } else {\n logger.warn(\n `[CallEventsManager] Received member.left event for unknown member ID: ${memberLeftEvent.member.member_id}`\n );\n }\n });\n this.subscribeTo(this.layoutChangedEvent$, (layoutChangedEvent) => {\n logger.debug('[CallEventsManager] Handling layout.changed event:', layoutChangedEvent);\n this._sessionState$.next({\n ...this._sessionState$.value,\n\n layout_name: layoutChangedEvent.id,\n\n layout_layers: layoutChangedEvent.layers\n });\n\n this.updateParticipantPositions(layoutChangedEvent);\n });\n }\n private updateParticipantPositions(layoutChangedEvent: Layout) {\n if (\n Object.keys(this._participants$.value).length > 0 &&\n !layoutChangedEvent.layers.some((layer) => !!layer.member_id)\n ) {\n logger.warn(\n '[CallEventsManager] No layers with member_id found in layout.changed event. Nothing to update.'\n );\n }\n layoutChangedEvent.layers\n .filter((layer) => Boolean(layer.member_id))\n .map((layer) => {\n // update participant state with new position\n if (!layer.member_id) {\n throw new DependencyError('Layer member_id is required');\n }\n this._participants$.value[layer.member_id].upnext({\n position: layer\n });\n return this._participants$.value[layer.member_id];\n })\n .forEach((participant) => {\n if (isSelfParticipant(participant)) {\n this._self$.next(participant);\n }\n // update the collection observable to notify changes\n this._participants$.next({\n ...this._participants$.value,\n [participant.id]: participant\n });\n });\n }\n\n updateLayouts(): void {\n if (!this.selfId) return;\n\n this.webRtcCallSession\n .executeMethod<CallLayoutListResponse>(this.selfId, 'call.layout.list', {})\n .then((response) => {\n this._sessionState$.next({\n ...this._sessionState$.value,\n layouts: response.result.layouts\n });\n })\n .catch((error) => {\n logger.error('[CallEventsManager] Error fetching layouts:', error);\n });\n }\n\n private updateParticipants(members: Member[]) {\n members.forEach((member) => this.upsertParticipant(member));\n }\n\n private upsertParticipant(member: Member | MemberTalkingInfo) {\n if (!(member.member_id in this._participants$.value)) {\n // Pass selfId from call.joined event to ensure correct self participant identification\n const newParticipant = this.webRtcCallSession.createParticipant(\n member.member_id,\n this.selfId\n );\n\n this._participants$.next({\n ...this._participants$.value,\n [member.member_id]: newParticipant\n });\n }\n\n const participant = this._participants$.value[member.member_id];\n\n const oldValue = participant.value;\n logger.debug('[CallEventsManager] Updating participant:', member.member_id, {\n oldValue,\n newValue: member\n });\n participant.upnext({\n ...oldValue,\n ...member\n });\n\n if (isSelfParticipant(participant)) {\n this._self$.next(participant);\n }\n // in case in subscription is observing the participants collection\n this._participants$.next(this._participants$.value);\n }\n\n private get callJoinedEvent$() {\n return this.cachedObservable('callJoinedEvent$', () =>\n this.webRtcCallSession.callEvent$.pipe(\n filter(isCallJoinedPayload),\n tap((event) => {\n logger.debug('[CallEventsManager] Call joined event:', event);\n })\n )\n );\n }\n\n private get layoutChangedEvent$() {\n return this.cachedObservable('layoutChangedEvent$', () =>\n this.webRtcCallSession.callEvent$.pipe(\n filterAs(isLayoutChangedPayload, 'layout'),\n tap((event) => {\n logger.debug('[CallEventsManager] Layout changed event:', event);\n })\n )\n );\n }\n\n private get memberUpdates$() {\n return this.cachedObservable('memberUpdates$', () =>\n merge(\n this.webRtcCallSession.memberJoined$,\n this.webRtcCallSession.memberUpdated$,\n this.webRtcCallSession.memberTalking$\n ).pipe(\n map((event) => event.member),\n tap((event) => {\n logger.debug('[CallEventsManager] Member update event:', event);\n })\n )\n );\n }\n\n public override destroy(): void {\n const participants = Object.values(this._participants$.value);\n participants.forEach((participant) => {\n participant.destroy();\n });\n this._participants$.next({});\n this._self$.next(null);\n\n this.callIds.clear();\n this.roomSessionIds.clear();\n this.selfId = undefined;\n this.originCallId = undefined;\n //@ts-expect-error -- avoiding circular references\n this.webRtcCallSession = undefined;\n //@ts-expect-error -- avoiding circular references\n this.callSession = undefined;\n\n super.destroy();\n }\n}\n","/**\n * SDPHelper - Utility functions for SDP (Session Description Protocol) parsing and validation.\n *\n * This module provides helper functions to analyze and validate SDP content,\n * particularly for ICE candidate validation in WebRTC connections.\n */\n\n/**\n * Validates that an SDP string has at least one non-host ICE candidate\n * for each media section (m= line).\n *\n * Non-host candidates (srflx, prflx, relay) indicate that the SDP has\n * gathered candidates that can be used for connectivity through NAT\n * traversal mechanisms.\n *\n * @param sdp - The SDP string to validate\n * @returns true if the SDP is valid (has non-host candidates for all media sections,\n * or has no media sections), false otherwise\n *\n * @example\n * ```typescript\n * const sdp = `v=0\n * m=audio 9 UDP/TLS/RTP/SAVPF 111\n * a=candidate:1 1 UDP 1694498815 203.0.113.1 50001 typ srflx\n * m=video 9 UDP/TLS/RTP/SAVPF 96\n * a=candidate:2 1 UDP 1694498815 203.0.113.1 50002 typ relay`;\n *\n * isValidLocalDescription(sdp); // returns true\n * ```\n */\nexport function isValidLocalDescription(sdp: string): boolean {\n if (!sdp) {\n return false;\n }\n\n // Parse SDP to find media sections (m= lines)\n const lines = sdp.split('\\r\\n');\n const mediaSectionsValidCandidates: number[] = [];\n let currentSection = -1;\n\n for (const line of lines) {\n if (line.startsWith('m=')) {\n // New media section\n currentSection += 1;\n mediaSectionsValidCandidates[currentSection] = 0;\n } else if (line.startsWith('a=candidate:')) {\n const typeMatch = /\\styp\\s+(host|srflx|prflx|relay)/.exec(line);\n if (typeMatch && typeMatch[1] !== 'host') {\n // count only non-host candidates\n mediaSectionsValidCandidates[currentSection] += 1;\n }\n }\n }\n\n return (\n !mediaSectionsValidCandidates.length ||\n // Check if localDescription has at least one non-host candidate for each media section.\n mediaSectionsValidCandidates.every((count) => count > 0)\n );\n}\n","import { filter, map, withLatestFrom } from 'rxjs';\n\nimport { Destroyable } from '../behaviors/Destroyable';\nimport {\n DEFAULT_ICE_CANDIDATE_TIMEOUT_MS,\n DEFAULT_ICE_GATHERING_TIMEOUT_MS\n} from '../core/constants';\nimport { isValidLocalDescription } from '../helpers/SDPHelper';\nimport { getLogger } from '../utils/logger';\n\nimport type { Observable } from 'rxjs';\n\nconst logger = getLogger();\n\nexport interface ICEGatheringControllerOptions {\n iceCandidateTimeout?: number;\n iceGatheringTimeout?: number;\n relayOnly?: boolean;\n}\n\nexport type ICEGatheringStates = 'new' | 'gathering' | 'complete' | 'timeout';\nexport interface ICECandidateState {\n state: ICEGatheringStates;\n validSDP: boolean;\n}\n\nexport class ICEGatheringController extends Destroyable {\n private iceCandidateTimeout: number;\n private iceGatheringTimeout: number;\n private iceCandidateTimer?: ReturnType<typeof setTimeout>;\n private iceGatheringTimer?: ReturnType<typeof setTimeout>;\n private relayOnly: boolean;\n\n // Event handlers (bound to this instance)\n private onicegatheringstatechangeHandler = () => {\n const { iceGatheringState } = this.peerConnection;\n logger.debug(`[ICEGatheringController] ICE gathering state changed to: ${iceGatheringState}`);\n if (iceGatheringState === 'gathering') {\n this._iceCandidatesState.next({\n state: 'gathering',\n validSDP: false\n });\n }\n };\n\n private onicecandidateHandler = (event: RTCPeerConnectionIceEvent) => {\n logger.debug('[ICEGatheringController] ICE candidate event received:', event.candidate);\n this.removeTimer('iceCandidateTimer');\n\n if (event.candidate) {\n this.iceCandidateTimer = setTimeout(() => {\n if (this.peerConnection.iceGatheringState !== 'complete') {\n logger.warn('[ICEGatheringController] ICE candidate timeout, using current SDP');\n this.handleICECandidateTimeout();\n }\n }, this.iceCandidateTimeout);\n } else {\n logger.debug('[ICEGatheringController] ICE gathering completed: null candidate received');\n this.removeTimer('iceGatheringTimer');\n\n this.handleICEGatheringComplete();\n }\n };\n\n private _iceCandidatesState = this.createBehaviorSubject<ICECandidateState>({\n state: 'new',\n validSDP: false\n });\n constructor(\n private peerConnection: RTCPeerConnection,\n private peerConnectionControllerNegotiating$: Observable<boolean>,\n options: ICEGatheringControllerOptions = {}\n ) {\n super();\n this.iceCandidateTimeout = options.iceCandidateTimeout ?? DEFAULT_ICE_CANDIDATE_TIMEOUT_MS;\n this.iceGatheringTimeout = options.iceGatheringTimeout ?? DEFAULT_ICE_GATHERING_TIMEOUT_MS;\n this.relayOnly = options.relayOnly ?? false;\n // Setup ICE candidate handling\n this.setupEventListeners();\n this.subscribeTo(\n this.peerConnectionControllerNegotiating$.pipe(filter((isNegotiating) => isNegotiating)),\n (isNegotiating) => {\n if (isNegotiating) {\n this.setupEventListeners();\n this.iceGatheringTimer = setTimeout(() => {\n if (this.peerConnection.iceGatheringState !== 'complete') {\n logger.warn('[ICEGatheringController] ICE gathering timeout, using current SDP');\n this.handleICEGatheringTimeout();\n }\n }, this.iceGatheringTimeout);\n }\n }\n );\n }\n\n private setupEventListeners() {\n this.peerConnection.removeEventListener('icecandidate', this.onicecandidateHandler);\n this.peerConnection.addEventListener('icecandidate', this.onicecandidateHandler);\n\n // Setup ICE gathering state change handling\n this.peerConnection.removeEventListener(\n 'icegatheringstatechange',\n this.onicegatheringstatechangeHandler\n );\n this.peerConnection.addEventListener(\n 'icegatheringstatechange',\n this.onicegatheringstatechangeHandler\n );\n }\n\n public get iceCandidatesState$(): Observable<ICEGatheringStates> {\n return this._iceCandidatesState.pipe(\n withLatestFrom(this.peerConnectionControllerNegotiating$),\n filter(([_, isNegotiating]) => isNegotiating),\n map(([state, _]) => state.state)\n );\n }\n\n public get hasValidLocalDescriptionSDP(): boolean {\n const sdp = this.peerConnection.localDescription?.sdp;\n return isValidLocalDescription(sdp ?? '');\n }\n\n public get isRelayOnly(): boolean {\n return this.relayOnly;\n }\n\n public setRelayOnly(value: boolean): void {\n this.relayOnly = value;\n }\n\n private handleICEGatheringComplete(): void {\n logger.debug('[ICEGatheringController] Handling ICE gathering complete');\n\n logger.debug(\n `[ICEGatheringController] Checking ICE gathering state: ${this.peerConnection.iceGatheringState}`\n );\n\n logger.debug('[ICEGatheringController] ICE gathering complete');\n\n this._iceCandidatesState.next({\n state: 'complete',\n validSDP: this.hasValidLocalDescriptionSDP\n });\n this.stopGathering();\n }\n\n private stopGathering(): void {\n this.peerConnection.removeEventListener(\n 'icegatheringstatechange',\n this.onicegatheringstatechangeHandler\n );\n this.peerConnection.removeEventListener('icecandidate', this.onicecandidateHandler);\n this.clearAllTimers();\n }\n\n private handleICEGatheringTimeout(): void {\n this.removeTimer('iceGatheringTimer');\n\n const validSDP = this.hasValidLocalDescriptionSDP;\n if (validSDP) {\n logger.debug('[ICEGatheringController] Local SDP is valid');\n this._iceCandidatesState.next({\n state: 'timeout',\n validSDP: validSDP\n });\n this.stopGathering();\n } else {\n logger.debug('### ICE gathering timeout\\n', this.peerConnection.localDescription?.sdp);\n }\n }\n\n public handleICECandidateTimeout(): void {\n if (this.iceCandidateTimer) {\n this.removeTimer('iceCandidateTimer');\n }\n\n logger.warn('[ICEGatheringController] ICE candidate timeout');\n\n const validSDP = this.hasValidLocalDescriptionSDP;\n if (!validSDP && !this.relayOnly) {\n this.restartICEGatheringWithRelayOnly();\n } else {\n logger.debug('[ICEGatheringController] Using current SDP due to ICE candidate timeout');\n this._iceCandidatesState.next({\n state: 'timeout',\n validSDP: validSDP\n });\n this.stopGathering();\n }\n }\n\n public restartICEGatheringWithRelayOnly(): void {\n logger.debug('[ICEGatheringController] Restarting ICE gathering with relay-only candidates');\n this.relayOnly = true;\n this.peerConnection.setConfiguration({\n ...this.peerConnection.getConfiguration(),\n iceTransportPolicy: 'relay'\n });\n if (!(this.peerConnection.connectionState === 'connected')) {\n this.peerConnection.restartIce();\n }\n }\n\n public removeTimer(timer: 'iceGatheringTimer' | 'iceCandidateTimer'): void {\n if (this[timer]) {\n clearTimeout(this[timer]);\n this[timer] = undefined;\n }\n }\n\n private clearAllTimers(): void {\n logger.debug('[ICEGatheringController] Clearing all timers');\n\n this.removeTimer('iceGatheringTimer');\n this.removeTimer('iceCandidateTimer');\n }\n\n public removeEventListeners(): void {\n this.peerConnection.removeEventListener(\n 'icegatheringstatechange',\n this.onicegatheringstatechangeHandler\n );\n this.peerConnection.removeEventListener('icecandidate', this.onicecandidateHandler);\n }\n\n public destroy(): void {\n logger.debug('[ICEGatheringController] Destroying ICEGatheringController');\n this.clearAllTimers();\n this.removeEventListeners();\n super.destroy();\n }\n}\n","import { takeUntil } from 'rxjs';\n\nimport { Destroyable } from '../behaviors/Destroyable';\nimport { getLogger } from '../utils/logger';\n\nimport type { MediaOptions } from '../core/types/media.types';\nimport type { Observable } from 'rxjs';\n\nconst logger = getLogger();\n\nexport interface LocalStreamControllerOptions extends Omit<\n MediaOptions,\n 'inputAudioDeviceConstraints' | 'inputVideoDeviceConstraints'\n> {\n getUserMedia: (constraints: MediaStreamConstraints) => Promise<MediaStream>;\n getDisplayMedia: (options: DisplayMediaStreamOptions) => Promise<MediaStream>;\n propose: 'main' | 'screenshare' | 'additional-device';\n inputAudioDeviceConstraints?: MediaTrackConstraints | boolean;\n inputVideoDeviceConstraints?: MediaTrackConstraints | boolean;\n}\n\nexport class LocalStreamController extends Destroyable {\n private mediaTrackEndedHandler = (event: unknown) => {\n this._mediaTrackEnded$.next(event as MediaStreamTrack);\n };\n private _localStream$ = this.createBehaviorSubject<MediaStream | null>(null);\n private _localAudioTracks$ = this.createBehaviorSubject<MediaStreamTrack[]>([]);\n private _localVideoTracks$ = this.createBehaviorSubject<MediaStreamTrack[]>([]);\n private _mediaTrackEnded$ = this.createSubject<MediaStreamTrack>();\n\n constructor(private options: LocalStreamControllerOptions) {\n super();\n }\n\n public get localStream$(): Observable<MediaStream | null> {\n return this._localStream$.asObservable().pipe(takeUntil(this.destroyed$));\n }\n\n public get localAudioTracks$(): Observable<MediaStreamTrack[]> {\n return this._localAudioTracks$.asObservable().pipe(takeUntil(this.destroyed$));\n }\n\n public get localVideoTracks$(): Observable<MediaStreamTrack[]> {\n return this._localVideoTracks$.asObservable().pipe(takeUntil(this.destroyed$));\n }\n\n public get mediaTrackEnded$(): Observable<MediaStreamTrack> {\n return this._mediaTrackEnded$.asObservable().pipe(takeUntil(this.destroyed$));\n }\n\n public get localStream(): MediaStream | null {\n return this._localStream$.value;\n }\n\n public get localAudioTracks(): MediaStreamTrack[] {\n return this._localAudioTracks$.value;\n }\n\n public get localVideoTracks(): MediaStreamTrack[] {\n return this._localVideoTracks$.value;\n }\n\n /**\n * Build the local media stream based on the provided options.\n */\n public async buildLocalStream(): Promise<MediaStream> {\n logger.debug('[LocalStreamController] Building local media stream.');\n let stream: MediaStream;\n if (this.options.inputAudioStream ?? this.options.inputVideoStream) {\n const tracks = [\n ...(this.options.inputAudioStream?.getTracks() ?? []),\n ...(this.options.inputVideoStream?.getTracks() ?? [])\n ];\n stream = new MediaStream(tracks);\n } else if (this.options.propose === 'screenshare') {\n logger.debug(\n '[LocalStreamController] Requesting display media for screen sharing with audio:',\n Boolean(this.options.inputAudioDeviceConstraints)\n );\n stream = await this.options.getDisplayMedia({\n video: true,\n audio: Boolean(this.options.inputAudioDeviceConstraints)\n });\n logger.debug('[LocalStreamController] Screen share media obtained:', stream);\n } else {\n const constraints: MediaStreamConstraints = {\n audio: this.options.inputAudioDeviceConstraints,\n video: this.options.inputVideoDeviceConstraints\n };\n logger.debug('[LocalStreamController] Requesting user media with constraints:', constraints);\n stream = await this.options.getUserMedia(constraints);\n logger.debug('[LocalStreamController] User media obtained:', stream);\n }\n this._localStream$.next(stream);\n return stream;\n }\n\n /**\n * Add a local media track to the local stream.\n * @param track - The MediaStreamTrack to add\n * @returns The MediaStream (either existing or newly created)\n */\n public addTrack(track: MediaStreamTrack): MediaStream {\n const localStream = this._localStream$.value ?? new MediaStream();\n\n track.addEventListener('ended', this.mediaTrackEndedHandler);\n localStream.addTrack(track);\n this._localStream$.next(localStream);\n\n if (track.kind === 'video') {\n this._localVideoTracks$.next(localStream.getVideoTracks());\n } else {\n this._localAudioTracks$.next(localStream.getAudioTracks());\n }\n\n logger.debug(`[LocalStreamController] ${track.kind} track added:`, track.id);\n return localStream;\n }\n\n /**\n * Remove a local media track from the local stream.\n * @param trackId - The ID of the track to remove\n * @returns The removed track, or undefined if not found\n */\n public removeTrack(trackId: string): MediaStreamTrack | undefined {\n const stream = this._localStream$.value;\n const track = stream?.getTracks().find((t: MediaStreamTrack) => t.id === trackId);\n\n if (!track) {\n logger.debug(`[LocalStreamController] track not found: ${trackId}`);\n return undefined;\n }\n\n track.removeEventListener('ended', this.mediaTrackEndedHandler);\n stream?.removeTrack(track);\n track.stop();\n this._localStream$.next(stream);\n\n if (track.kind === 'video') {\n this._localVideoTracks$.next(stream?.getVideoTracks() ?? []);\n } else {\n this._localAudioTracks$.next(stream?.getAudioTracks() ?? []);\n }\n\n logger.debug(`[LocalStreamController] ${track.kind} track removed:`, trackId);\n return track;\n }\n\n /**\n * Get or create a local stream.\n */\n public getOrCreateLocalStream(): MediaStream {\n return this._localStream$.value ?? new MediaStream();\n }\n\n /**\n * Set the local stream directly.\n */\n public setLocalStream(stream: MediaStream | null): void {\n this._localStream$.next(stream);\n }\n\n /**\n * Add a track ended event listener to a track.\n */\n public addTrackEndedListener(track: MediaStreamTrack): void {\n track.addEventListener('ended', this.mediaTrackEndedHandler);\n }\n\n /**\n * Stop all local tracks and clean up.\n */\n public stopAllTracks(): void {\n const localStream = this._localStream$.value;\n localStream?.getTracks().forEach((track: MediaStreamTrack) => {\n logger.debug(`[LocalStreamController] Stopping local track: ${track.kind}`);\n track.removeEventListener('ended', this.mediaTrackEndedHandler);\n track.stop();\n });\n }\n\n /**\n * Clean up resources.\n */\n public override destroy(): void {\n this.stopAllTracks();\n super.destroy();\n }\n}\n","import { Destroyable } from '../behaviors/Destroyable';\nimport { MediaTrackError } from '../core/errors';\nimport { getLogger } from '../utils/logger';\n\nimport type { LocalStreamController } from './LocalStreamController';\nimport type { RTCPeerConnectionPropose } from '../core/types/call.types';\n\nconst logger = getLogger();\n\nconst getDirection = (send: boolean, recv: boolean): RTCRtpTransceiverDirection => {\n if (send && recv) {\n return 'sendrecv';\n } else if (send && !recv) {\n return 'sendonly';\n } else if (!send && recv) {\n return 'recvonly';\n }\n\n return 'inactive';\n};\n\nexport interface TransceiverControllerOptions {\n peerConnection: RTCPeerConnection;\n propose: RTCPeerConnectionPropose;\n simulcast?: boolean;\n sfu?: boolean;\n msStreamsNumber?: number;\n receiveAudio?: boolean;\n receiveVideo?: boolean;\n localStreamController: LocalStreamController;\n getInputAudioDeviceConstraints: () => MediaTrackConstraints | boolean;\n getInputVideoDeviceConstraints: () => MediaTrackConstraints | boolean;\n getUserMedia: (constraints: MediaStreamConstraints) => Promise<MediaStream>;\n onError?: (error: Error) => void;\n}\n\nexport class TransceiverController extends Destroyable {\n private peerConnection: RTCPeerConnection;\n private options: TransceiverControllerOptions;\n\n constructor(options: TransceiverControllerOptions) {\n super();\n this.peerConnection = options.peerConnection;\n this.options = options;\n }\n\n public get useAddTransceivers(): boolean {\n return typeof this.peerConnection.addTransceiver === 'function';\n }\n\n public get useAddTrack(): boolean {\n return typeof this.peerConnection.addTrack === 'function';\n }\n\n public get useAddStream(): boolean {\n return (\n // @ts-expect-error -- Ignore ---\n typeof this.peerConnection.addStream === 'function' &&\n !this.useAddTransceivers &&\n !this.useAddTrack\n );\n }\n\n private get propose(): RTCPeerConnectionPropose {\n return this.options.propose;\n }\n\n private get isAdditionalDevice(): boolean {\n return this.propose === 'additional-device';\n }\n\n private get isScreenShare(): boolean {\n return this.propose === 'screenshare';\n }\n\n private get isSimulcast(): boolean {\n return Boolean(this.options.simulcast);\n }\n\n private get isSFU(): boolean {\n return Boolean(this.options.sfu);\n }\n\n private get receiveVideo(): boolean {\n return Boolean(this.options.receiveVideo);\n }\n\n private get receiveAudio(): boolean {\n return Boolean(this.options.receiveAudio);\n }\n\n private get localStream(): MediaStream | null {\n return this.options.localStreamController.localStream;\n }\n\n private get inputAudioDeviceConstraints(): MediaTrackConstraints | boolean {\n return this.options.getInputAudioDeviceConstraints();\n }\n\n private get inputVideoDeviceConstraints(): MediaTrackConstraints | boolean {\n return this.options.getInputVideoDeviceConstraints();\n }\n\n public get audioDirection(): RTCRtpTransceiverDirection {\n if (this.isAdditionalDevice) {\n return 'sendonly';\n }\n const { localStream } = this;\n const hasAudioTrack = localStream?.getAudioTracks().some((track) => track.enabled);\n const wantsToSendAudio = Boolean(this.inputAudioDeviceConstraints);\n const wantsToReceiveAudio = Boolean(this.receiveAudio);\n const send = hasAudioTrack ?? wantsToSendAudio;\n const recv = wantsToReceiveAudio;\n return getDirection(send, recv);\n }\n\n public get videoDirection(): RTCRtpTransceiverDirection {\n if (this.isAdditionalDevice || this.isScreenShare) {\n return 'sendonly';\n }\n\n if (this.isSFU) {\n return 'recvonly';\n }\n\n const { localStream } = this;\n const hasVideoTrack = localStream?.getVideoTracks().some((track) => track.enabled);\n const wantsToSendVideo = Boolean(this.inputVideoDeviceConstraints);\n const wantsToReceiveVideo = Boolean(this.receiveVideo);\n const send = hasVideoTrack ?? wantsToSendVideo;\n const recv = wantsToReceiveVideo;\n return getDirection(send, recv);\n }\n\n private get sendEncodings(): RTCRtpEncodingParameters[] | undefined {\n if (!this.isSimulcast) {\n return undefined;\n }\n\n return ['0', '1', '2'].map((rid) => ({\n active: true,\n rid,\n scaleResolutionDownBy: Number(rid) * 6 || 1.0\n }));\n }\n\n private getConstraintsFor(kind: 'audio' | 'video'): MediaTrackConstraints {\n const constraints =\n kind === 'audio' ? this.inputAudioDeviceConstraints : this.inputVideoDeviceConstraints;\n\n // If constraints is a boolean (true/false), return empty object for track constraints\n // false case means no media of this kind is requested, but that's handled elsewhere\n return typeof constraints === 'boolean' ? {} : constraints;\n }\n\n public transceiverByKind(kind: 'audio' | 'video' | 'both'): RTCRtpTransceiver[] {\n return this.peerConnection\n .getTransceivers()\n .filter((t) => kind === 'both' || t.receiver.track.kind === kind);\n }\n\n public get audioTransceivers(): RTCRtpTransceiver[] {\n return this.transceiverByKind('audio');\n }\n\n public get videoTransceivers(): RTCRtpTransceiver[] {\n return this.transceiverByKind('video');\n }\n\n public async setupTransceiverSender(\n track: MediaStreamTrack,\n localStream: MediaStream,\n transceiver?: RTCRtpTransceiver\n ): Promise<void> {\n const isAudio = track.kind === 'audio';\n const direction = isAudio ? this.audioDirection : this.videoDirection;\n const transceiverParams: RTCRtpTransceiverInit = {\n direction,\n sendEncodings: isAudio ? undefined : this.sendEncodings,\n streams: direction === 'recvonly' ? undefined : [localStream]\n };\n logger.debug(\n `[TransceiverController] Setting up transceiver sender for local ${track.kind} track:`,\n { transceiver, transceiverParams }\n );\n if (\n transceiverParams.direction &&\n ['sendonly', 'sendrecv'].includes(transceiverParams.direction)\n ) {\n if (transceiver) {\n await transceiver.sender.replaceTrack(track);\n // eslint-disable-next-line no-param-reassign\n transceiver.direction = transceiverParams.direction;\n if (transceiverParams.streams?.some((stream) => Boolean(stream))) {\n logger.debug(\n `[TransceiverController] Setting streams for transceiver sender for local ${track.kind} track:`,\n transceiverParams.streams\n );\n transceiver.sender.setStreams(...transceiverParams.streams);\n }\n } else {\n logger.debug(\n `[TransceiverController] Adding new transceiver for local ${track.kind} track:`,\n track.id\n );\n this.peerConnection.addTransceiver(track, transceiverParams);\n }\n }\n }\n\n public stopTrackSender(\n kind: 'audio' | 'video' | 'both',\n options = { updateTransceiverDirection: false }\n ): void {\n try {\n const transceivers = this.transceiverByKind(kind);\n for (const transceiver of transceivers) {\n if (transceiver.sender.track?.readyState === 'live') {\n const trackId = transceiver.sender.track.id;\n transceiver.sender.track.stop();\n this.options.localStreamController.removeTrack(trackId);\n if (options.updateTransceiverDirection) {\n transceiver.direction = 'inactive';\n }\n }\n }\n } catch (error) {\n logger.error('[TransceiverController] stopTrackSender error', kind, error);\n this.options.onError?.(new MediaTrackError('stopTrackSender', kind, error));\n }\n }\n\n public async restoreTrackSender(kind: 'audio' | 'video' | 'both'): Promise<void> {\n try {\n logger.debug('[TransceiverController] restoreTrackSender called', kind);\n const constraints: MediaStreamConstraints = {};\n const transceivers = this.transceiverByKind(kind);\n for (const transceiver of transceivers) {\n const { track } = transceiver.sender;\n // Check if track is null, ended - all need restoration\n const needsRestore = !track || track.readyState === 'ended';\n if (needsRestore) {\n const trackKind = track?.kind ?? transceiver.receiver.track.kind;\n if (trackKind === 'audio' || trackKind === 'video') {\n constraints[trackKind] = this.getConstraintsFor(trackKind);\n }\n }\n }\n\n logger.debug('[TransceiverController] restoreTrackSender constraints:', constraints);\n\n // Don't call getUserMedia if no tracks need restoration\n if (Object.keys(constraints).length === 0) {\n logger.warn('[TransceiverController] restoreTrackSender: no tracks need restoration', kind);\n return;\n }\n\n const stream = await this.options.getUserMedia(constraints);\n const newTracks = stream.getTracks();\n\n logger.debug('[TransceiverController] restoreTrackSender new tracks:', newTracks);\n for (const newTrack of newTracks) {\n this.options.localStreamController.addTrack(newTrack);\n const trackKind = newTrack.kind as 'audio' | 'video';\n const transceiverOfKind = this.transceiverByKind(trackKind)[0];\n transceiverOfKind.direction =\n trackKind === 'audio' ? this.audioDirection : this.videoDirection;\n logger.debug(\n '[TransceiverController] restoreTrackSender setting direction for',\n trackKind,\n transceiverOfKind.direction\n );\n await transceiverOfKind.sender.replaceTrack(newTrack);\n }\n } catch (error) {\n logger.error('[TransceiverController] restoreTrackSender error', kind, error);\n this.options.onError?.(new MediaTrackError('restoreTrackSender', kind, error));\n }\n }\n\n public async replaceSenderTrack(kind: 'audio' | 'video', track: MediaStreamTrack): Promise<void> {\n const transceivers = kind === 'audio' ? this.audioTransceivers : this.videoTransceivers;\n for (const transceiver of transceivers) {\n await transceiver.sender.replaceTrack(track);\n }\n }\n\n public async setupRemoteTransceivers(type: 'offer' | 'answer'): Promise<void> {\n if (type === 'answer') {\n // remote setup was made by the offerer\n return;\n }\n\n for (const kind of ['audio', 'video']) {\n const transceivers = kind === 'audio' ? this.audioTransceivers : this.videoTransceivers;\n for (const transceiver of transceivers) {\n const direction = kind === 'audio' ? this.audioDirection : this.videoDirection;\n\n if (['inactive', 'recvonly'].includes(direction)) {\n transceiver.direction = direction;\n await transceiver.sender.replaceTrack(null);\n transceiver.sender.setStreams();\n }\n }\n }\n\n if (this.videoDirection === 'recvonly' && this.isSFU && this.useAddTransceivers) {\n const { msStreamsNumber = 5 } = this.options;\n for (let i = 0; i < Number(msStreamsNumber); i++) {\n this.peerConnection.addTransceiver('video', { direction: 'recvonly' });\n }\n }\n }\n\n public async updateSendersConstraints(\n kind: 'audio' | 'video',\n constraints?: MediaTrackConstraints\n ): Promise<void> {\n if (!constraints) {\n this.stopTrackSender(kind);\n return Promise.resolve();\n }\n\n const senders = this.peerConnection\n .getSenders()\n .filter((sender) => sender.track?.kind === kind && sender.track.readyState === 'live');\n\n for (const sender of senders) {\n const { track } = sender;\n if (track) {\n const constraintsToApply: MediaTrackConstraints = {\n ...track.getConstraints(),\n ...constraints\n };\n try {\n await track.applyConstraints(constraintsToApply);\n logger.debug(\n `[TransceiverController] Updated ${kind} sender constraints:`,\n constraintsToApply\n );\n logger.debug(\n `[TransceiverController] Updated ${kind} sender constraints:`,\n track.getConstraints()\n );\n } catch (error) {\n logger.warn(\n `[TransceiverController] Failed to apply constraints to ${kind} track ${track.id}:`,\n error\n );\n this.options.onError?.(new MediaTrackError('updateSendersConstraints', kind, error));\n }\n }\n }\n }\n\n public getMediaDirections(): {\n audio: RTCRtpTransceiverDirection;\n video: RTCRtpTransceiverDirection;\n } {\n if (this.peerConnection.connectionState === 'connected') {\n // If we are connected let's get the actual directions from the transceivers\n return this.peerConnection.getTransceivers().reduce(\n (acc, transceiver) => {\n return {\n ...acc,\n [transceiver.receiver.track.kind]: transceiver.direction\n };\n },\n { audio: 'inactive', video: 'inactive' }\n );\n }\n\n return {\n audio: this.audioDirection,\n video: this.videoDirection\n };\n }\n\n public updatePeerConnection(peerConnection: RTCPeerConnection): void {\n this.peerConnection = peerConnection;\n }\n\n public updateOptions(options: Partial<TransceiverControllerOptions>): void {\n this.options = {\n ...this.options,\n ...options\n };\n }\n}\n","/* eslint-disable max-lines */\nimport {\n auditTime,\n defer,\n exhaustMap,\n filter,\n from,\n map,\n shareReplay,\n switchMap,\n takeUntil,\n tap,\n skipWhile,\n merge\n} from 'rxjs';\nimport { v4 as uuid } from 'uuid';\n\nimport { ICEGatheringController } from './ICEGatheringController';\nimport { LocalStreamController } from './LocalStreamController';\nimport { TransceiverController } from './TransceiverController';\nimport { Destroyable } from '../behaviors/Destroyable';\nimport { PreferencesContainer } from '../containers/PreferencesContainer';\nimport { DependencyError } from '../core/errors';\nimport { isValidLocalDescription } from '../helpers/SDPHelper';\nimport { filterNull } from '../operators';\nimport { getLogger } from '../utils/logger';\n\nimport type { RTCPeerConnectionPropose, RTCPeerConnectionType } from '../core/types/call.types';\nimport type { MediaOptions } from '../core/types/media.types';\nimport type { DeviceController } from '../interfaces/DeviceController';\nimport type { Observable } from 'rxjs';\n\nconst logger = getLogger();\n\nexport interface RTCPeerConnectionControllerOptions extends MediaOptions {\n callId?: string;\n\n WebRTCPeerConnectionConstructor?: typeof RTCPeerConnection;\n getUserMedia?: (constraints: MediaStreamConstraints) => Promise<MediaStream>;\n getDisplayMedia?: (options: DisplayMediaStreamOptions) => Promise<MediaStream>;\n rtcConfiguration?: RTCConfiguration;\n simulcast?: boolean;\n sfu?: boolean;\n msStreamsNumber?: number;\n propose: RTCPeerConnectionPropose;\n iceServers?: RTCIceServer[];\n disableUdpIceServers?: boolean;\n relayOnly?: boolean;\n iceCandidateTimeout?: number;\n iceGatheringTimeout?: number;\n}\n\nexport type RTCPeerConnectionControllerOptionsPartial = Partial<RTCPeerConnectionControllerOptions>;\n\nexport interface UpdateSDPStatusParams {\n status: 'received' | 'sent' | 'failed';\n sdp?: string;\n}\n\nexport class RTCPeerConnectionController extends Destroyable {\n public readonly id: string;\n public firstSDPExchangeCompleted = false;\n public sdpInit?: RTCSessionDescriptionInit;\n private negotiationNeeded$ = this.createSubject<void>();\n private deviceController: DeviceController;\n private localStreamController: LocalStreamController;\n // Transceiver controller - initialized lazily when peerConnection is created\n private transceiverController?: TransceiverController;\n public readonly localDescription$: Observable<RTCSessionDescription | null> = defer(() =>\n from(this.init())\n ).pipe(\n switchMap(() =>\n // Wait for ICE negotiation before emitting localDescription\n this.iceGatheringController.iceCandidatesState$.pipe(\n filter((iceCandidateState) => !['new', 'gathering'].includes(iceCandidateState)),\n tap(() => {\n this.negotiationEnded();\n }),\n // Only emit when signaling state is 'have-local-offer'\n filter(() => this.shouldEmitLocalDescription),\n map(() => this.peerConnection?.localDescription),\n filterNull(),\n tap((desc) => {\n if (desc.type === 'answer') {\n // Once the answer is emitted, switch type to offer for future negotiations\n this._type = 'offer';\n }\n })\n )\n ),\n shareReplay(1),\n takeUntil(this.destroyed$)\n );\n public peerConnection?: RTCPeerConnection;\n private initPromise?: Promise<void>;\n private connectionTimeout = 3_000;\n private connectionTimer?: ReturnType<typeof setTimeout>;\n private oniceconnectionstatechangeHandler = () => {\n if (this.peerConnection) {\n const { iceConnectionState } = this.peerConnection;\n logger.debug(\n `[RTCPeerConnectionController] ICE connection state changed to: ${iceConnectionState}`\n );\n this._iceConnectionState$.next(this.peerConnection.iceConnectionState);\n }\n };\n private onconnectionstatechangeHandler = () => {\n if (this.peerConnection) {\n const { connectionState } = this.peerConnection;\n logger.debug(`[RTCPeerConnectionController] Connection state changed to: ${connectionState}`);\n if (connectionState === 'connected') {\n this.removeConnectionTimer();\n }\n this._connectionState$.next(this.peerConnection.connectionState);\n }\n };\n private onsignalingstatechangeHandler = () => {\n logger.debug(\n `[RTCPeerConnectionController] Signaling state changed to: ${this.peerConnection?.signalingState}`\n );\n };\n private onicegatheringstatechangeHandler = () => {\n if (this.peerConnection) {\n this._iceGatheringState$.next(this.peerConnection.iceGatheringState);\n }\n };\n private onnegotiationneededHandler = (event: unknown) => {\n logger.debug('[RTCPeerConnectionController] Negotiation needed event received.', event);\n this.negotiationNeeded$.next();\n };\n private updateSelectedInputDevice = async (\n kind: 'audio' | 'video',\n deviceInfo: MediaDeviceInfo | null\n ): Promise<void> => {\n try {\n const { localStream } = this;\n if (!localStream) {\n logger.warn(\n '[RTCPeerConnectionController] No local stream available to update input device.'\n );\n return;\n }\n\n logger.debug(\n `[RTCPeerConnectionController] Updating selected ${kind} input device:`,\n localStream.getTracks()\n );\n // Stop existing audio tracks\n const track = localStream.getTracks().find((track: MediaStreamTrack) => track.kind === kind);\n\n if (track) {\n this.transceiverController?.stopTrackSender(kind);\n this.localStream?.removeTrack(track);\n logger.debug(\n `[RTCPeerConnectionController] Stopped existing ${kind} track: ${track.id}`,\n localStream.getTracks()\n );\n\n if (!deviceInfo) {\n logger.debug(`[RTCPeerConnectionController] ${kind} input device selected: none`);\n return;\n }\n\n const stream = await navigator.mediaDevices.getUserMedia({\n [kind]: {\n ...track.getConstraints(),\n ...this.deviceController.deviceInfoToConstraints(deviceInfo)\n }\n });\n\n const streamTrack = stream.getTracks().find((t) => t.kind === kind);\n\n if (streamTrack) {\n logger.debug(`[RTCPeerConnectionController] Adding new ${kind} track: ${streamTrack.id}`);\n this.localStream?.addTrack(streamTrack);\n await this.transceiverController?.replaceSenderTrack(kind, streamTrack);\n logger.debug(\n `[RTCPeerConnectionController] Added new ${kind} track: ${streamTrack.id}`,\n this.localStream?.getTracks()\n );\n }\n }\n\n logger.debug(\n `[RTCPeerConnectionController] ${kind} input device selected:`,\n deviceInfo?.label\n );\n } catch (error) {\n logger.error(`[RTCPeerConnectionController] Failed to select ${kind} input device:`, error);\n this._errors$.next(error as Error);\n throw error;\n }\n };\n private _isNegotiating$ = this.createBehaviorSubject<boolean>(false);\n private _iceGatheringController?: ICEGatheringController;\n private _memberId: string | null = null;\n private _type: RTCPeerConnectionType;\n // Observable state streams - exposed as public observables\n private _iceConnectionState$ = this.createReplaySubject<RTCIceConnectionState>(1);\n private _connectionState$ = this.createReplaySubject<RTCPeerConnectionState>(1);\n private _signalingState$ = this.createReplaySubject<RTCSignalingState>(1);\n private _iceGatheringState$ = this.createReplaySubject<RTCIceGatheringState>(1);\n // Error stream\n private _errors$ = this.createSubject<Error>();\n // ICE candidates stream\n private _iceCandidates$ = this.createReplaySubject<RTCIceCandidate[]>(1);\n // Initialization state\n private _initialized$ = this.createReplaySubject<boolean>(1);\n // Remote description\n private _remoteDescription$ = this.createReplaySubject<RTCSessionDescription | null>(1);\n private _remoteStream$ = this.createBehaviorSubject<MediaStream | null>(null);\n constructor(\n protected options: RTCPeerConnectionControllerOptionsPartial = {},\n remoteSessionDescription?: string,\n deviceController?: DeviceController\n ) {\n super();\n this.deviceController = deviceController ?? ({} as DeviceController);\n this.id = options.callId ?? uuid();\n this._type = remoteSessionDescription ? 'answer' : 'offer';\n\n this.sdpInit = remoteSessionDescription\n ? {\n type: 'offer',\n sdp: remoteSessionDescription\n }\n : undefined;\n this.options = {\n receiveAudio: options.receiveAudio ?? PreferencesContainer.instance.receiveAudio,\n receiveVideo: options.receiveVideo ?? PreferencesContainer.instance.receiveVideo,\n ...options\n };\n\n // Initialize the local stream controller\n this.localStreamController = new LocalStreamController({\n propose: this.propose,\n inputAudioStream: this.options.inputAudioStream,\n inputVideoStream: this.options.inputVideoStream,\n inputAudioDeviceConstraints: this.inputAudioDeviceConstraints,\n inputVideoDeviceConstraints: this.inputVideoDeviceConstraints,\n getUserMedia: async (constraints: MediaStreamConstraints) => this.getUserMedia(constraints),\n getDisplayMedia: async (options: DisplayMediaStreamOptions) => this.getDisplayMedia(options)\n });\n }\n\n private get iceGatheringController(): ICEGatheringController {\n if (!this._iceGatheringController) {\n throw new DependencyError('ICEGatheringController is not initialized');\n }\n return this._iceGatheringController;\n }\n\n private get shouldEmitLocalDescription(): boolean {\n if (!this.peerConnection) {\n return false;\n }\n\n const { localDescription, signalingState } = this.peerConnection;\n\n if (!localDescription || !isValidLocalDescription(localDescription.sdp)) {\n return false;\n }\n\n return (\n (localDescription.type === 'offer' && signalingState === 'have-local-offer') ||\n (localDescription.type === 'answer' && signalingState === 'stable')\n );\n }\n\n private removeConnectionTimer(): void {\n if (this.connectionTimer) {\n clearTimeout(this.connectionTimer);\n this.connectionTimer = undefined;\n }\n }\n\n public setMemberId(memberId: string | null): void {\n this._memberId = memberId;\n }\n\n public get memberId(): string | null {\n return this._memberId;\n }\n\n public stopTrackSender(\n kind: 'audio' | 'video' | 'both',\n options = { updateTransceiverDirection: false }\n ): void {\n this.transceiverController?.stopTrackSender(kind, options);\n }\n\n public get isNegotiating$(): Observable<boolean> {\n return this._isNegotiating$.asObservable();\n }\n\n public get isNegotiating(): boolean {\n return this._isNegotiating$.value;\n }\n\n public updateMediaDevicesOptions(options: MediaOptions): void {\n this.options = {\n ...this.options,\n ...options\n };\n }\n\n public get iceGatheringState$(): Observable<RTCIceGatheringState> {\n return this.cachedObservable('iceGatheringState$', () =>\n this._iceGatheringState$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get mediaTrackEnded$(): Observable<MediaStreamTrack> {\n return this.cachedObservable('mediaTrackEnded$', () =>\n this.localStreamController.mediaTrackEnded$.pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get errors$(): Observable<Error> {\n return this.cachedObservable('errors$', () =>\n this._errors$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get iceCandidates$(): Observable<RTCIceCandidate[]> {\n return this.cachedObservable('iceCandidates$', () =>\n this._iceCandidates$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get initialized$(): Observable<boolean> {\n return this.cachedObservable('initialized$', () =>\n this._initialized$.asObservable().pipe(\n filter((initialized) => initialized),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n public get remoteDescription$(): Observable<RTCSessionDescription | null> {\n return this.cachedObservable('remoteDescription$', () =>\n this._remoteDescription$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get localStream$(): Observable<MediaStream | null> {\n return this.cachedObservable('localStream$', () =>\n this.localStreamController.localStream$.pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get remoteStream$(): Observable<MediaStream | null> {\n return this.cachedObservable('remoteStream$', () =>\n this._remoteStream$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get localAudioTracks$(): Observable<MediaStreamTrack[]> {\n return this.cachedObservable('localAudioTracks$', () =>\n this.localStreamController.localAudioTracks$.pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get localVideoTracks$(): Observable<MediaStreamTrack[]> {\n return this.cachedObservable('localVideoTracks$', () =>\n this.localStreamController.localVideoTracks$.pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get iceConnectionState$(): Observable<RTCIceConnectionState> {\n return this.cachedObservable('iceConnectionState$', () =>\n this._iceConnectionState$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get connectionState$(): Observable<RTCPeerConnectionState> {\n return this.cachedObservable('connectionState$', () =>\n this._connectionState$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get signalingState$(): Observable<RTCSignalingState> {\n return this.cachedObservable('signalingState$', () =>\n this._signalingState$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get type(): RTCPeerConnectionType {\n return this._type;\n }\n\n public get propose(): RTCPeerConnectionPropose {\n return this.options.propose ?? 'main';\n }\n\n public get isAdditionalDevice(): boolean {\n return this.propose === 'additional-device';\n }\n\n public get isMainDevice(): boolean {\n return this.propose === 'main';\n }\n\n public get isScreenShare(): boolean {\n return this.propose === 'screenshare';\n }\n\n protected get iceServers(): RTCIceServer[] {\n if (!this.options.disableUdpIceServers) {\n return this.options.iceServers ?? [];\n }\n const tcpTransportParam = 'transport=tcp';\n\n // When disabling UDP, keep only URLs that explicitly specify transport=tcp\n // URLs without a transport parameter default to UDP and should be filtered out\n return (this.options.iceServers ?? []).map((server) => {\n const urls = Array.isArray(server.urls) ? server.urls : [server.urls];\n return {\n ...server,\n urls: urls.filter((url) => url.includes(tcpTransportParam))\n } as RTCIceServer;\n });\n }\n\n private get rtcConfiguration(): RTCConfiguration {\n // Destructure to exclude iceServers from options spread, since we use the filtered this.iceServers\n const { iceServers: _iceServers, ...restOptions } = this.options;\n return {\n bundlePolicy: 'max-compat',\n iceCandidatePoolSize: 10,\n iceServers: this.iceServers,\n iceTransportPolicy: this.options.relayOnly ? 'relay' : 'all',\n //@ts-expect-error -- Ignore ---\n sdpSemantics: 'unified-plan',\n ...restOptions\n };\n }\n\n public get receiveVideo(): boolean {\n return Boolean(this.options.receiveVideo);\n }\n\n public get receiveAudio(): boolean {\n return Boolean(this.options.receiveAudio);\n }\n\n public get localStream(): MediaStream | null {\n return this.localStreamController.localStream;\n }\n\n public get remoteStream(): MediaStream | null {\n return this._remoteStream$.value;\n }\n\n private get inputAudioDeviceConstraints(): MediaTrackConstraints | boolean {\n if (this.options.audio === false && !this.options.inputAudioDeviceConstraints) {\n return false;\n }\n return {\n ...this.options.inputAudioDeviceConstraints,\n ...this.deviceController.selectedAudioInputDeviceConstraints\n };\n }\n\n private get inputVideoDeviceConstraints(): MediaTrackConstraints | boolean {\n if (this.options.video === false && !this.options.inputVideoDeviceConstraints) {\n return false;\n }\n return {\n ...this.options.inputVideoDeviceConstraints,\n ...this.deviceController.selectedVideoInputDeviceConstraints\n };\n }\n\n private get WebRTCPeerConnectionConstructor(): typeof RTCPeerConnection {\n return this.options.WebRTCPeerConnectionConstructor ?? RTCPeerConnection;\n }\n\n private get offerOptions(): RTCOfferOptions {\n const options: RTCOfferOptions = {\n iceRestart: this.firstSDPExchangeCompleted ? true : undefined\n };\n switch (this.propose) {\n case 'screenshare':\n case 'additional-device':\n return {\n ...options,\n offerToReceiveAudio: false,\n offerToReceiveVideo: false\n };\n case 'main':\n default:\n return {\n ...options,\n offerToReceiveAudio: true,\n offerToReceiveVideo: Boolean(this.inputVideoDeviceConstraints)\n };\n }\n }\n\n private get answerOptions(): RTCAnswerOptions {\n // Currently no specific answer options\n return {};\n }\n\n /**\n * Initialize the RTCPeerConnection and setup event listeners.\n * Called automatically when localDescription$ is subscribed to (deferred pattern).\n * Uses Promise memoization to ensure initialization only happens once,\n * even if called concurrently.\n */\n private async init(): Promise<void> {\n this.initPromise ??= this.doInit();\n return this.initPromise;\n }\n\n /**\n * Internal initialization implementation.\n * Should only be called via init() to ensure single execution.\n */\n private async doInit(): Promise<void> {\n try {\n this.setupPeerConnection();\n\n this.subscribeTo(\n this.negotiationNeeded$.pipe(\n auditTime(0), //When updating multiple tracks, batches all the events together\n exhaustMap(async () => this.startNegotiation()) // Ignore new events while negotiation is ongoing\n ),\n {\n next: () => {\n logger.debug('[RTCPeerConnectionController] Start Negotiation completed successfully');\n },\n error: (error) => {\n logger.error('[RTCPeerConnectionController] Start Negotiation error:', error);\n this._errors$.next(error as Error);\n }\n }\n );\n\n this.subscribeTo(\n merge(\n this.deviceController.selectedAudioInputDevice$.pipe(\n map((deviceInfo) => ['audio', deviceInfo] as const)\n ),\n this.deviceController.selectedVideoInputDevice$.pipe(\n map((deviceInfo) => ['video', deviceInfo] as const)\n )\n ).pipe(\n // we only want to react to changes after the localstream is created\n // before that the device selection is handle int the localstream creation\n skipWhile(() => !this.localStreamController.localStream)\n ),\n async ([kind, deviceInfo]) => {\n logger.debug(`[RTCPeerConnectionController] Selected input device changed for:`, {\n kind,\n deviceInfo\n });\n await this.updateSelectedInputDevice(kind, deviceInfo);\n }\n );\n\n await this.setupTrackHandling();\n\n this._initialized$.next(true);\n\n // Start answer negotiation\n if (this.type === 'answer' && this.sdpInit) {\n this.setupEventListeners();\n await this.handleOfferReceived();\n }\n } catch (error) {\n logger.error('[RTCPeerConnectionController] Initialization error:', error);\n this._errors$.next(error as Error);\n this.destroy();\n }\n }\n\n private setupPeerConnection() {\n this.peerConnection = new this.WebRTCPeerConnectionConstructor(this.rtcConfiguration);\n this.peerConnection.addEventListener('negotiationneeded', this.onnegotiationneededHandler);\n this._iceGatheringController = new ICEGatheringController(\n this.peerConnection,\n this.isNegotiating$,\n {\n iceCandidateTimeout: this.options.iceCandidateTimeout,\n iceGatheringTimeout: this.options.iceGatheringTimeout,\n relayOnly: this.options.relayOnly\n }\n );\n\n // Initialize the transceiver controller\n this.transceiverController = new TransceiverController({\n peerConnection: this.peerConnection,\n propose: this.propose,\n simulcast: this.options.simulcast,\n sfu: this.options.sfu,\n msStreamsNumber: this.options.msStreamsNumber,\n receiveAudio: this.receiveAudio,\n receiveVideo: this.receiveVideo,\n localStreamController: this.localStreamController,\n getInputAudioDeviceConstraints: () => this.inputAudioDeviceConstraints,\n getInputVideoDeviceConstraints: () => this.inputVideoDeviceConstraints,\n getUserMedia: async (constraints: MediaStreamConstraints) => this.getUserMedia(constraints),\n onError: (error: Error) => {\n this._errors$.next(error);\n }\n });\n }\n\n private async startNegotiation() {\n if (this.isNegotiating) {\n logger.debug('[RTCPeerConnectionController] Negotiation already in progress, skipping.');\n return;\n }\n\n this.setupEventListeners();\n\n if (this.type === 'answer') {\n logger.debug(\n '[RTCPeerConnectionController] This is an answer type still, skipping offer creation.'\n );\n return;\n }\n\n this._isNegotiating$.next(true);\n logger.debug('[RTCPeerConnectionController] Starting negotiation.');\n\n try {\n const { offerOptions } = this;\n logger.debug('[RTCPeerConnectionController] Creating offer with options:', offerOptions);\n await this.createOffer(offerOptions);\n } catch (error) {\n logger.error('[RTCPeerConnectionController] Error during negotiation:', error);\n this._errors$.next(error as Error);\n }\n }\n\n /**\n * Create an SDP offer and set it as local description.\n */\n private async createOffer(options?: RTCOfferOptions): Promise<void> {\n if (!this.peerConnection) {\n throw new DependencyError('RTCPeerConnection is not initialized');\n }\n\n const offer = await this.peerConnection.createOffer(options);\n await this.setLocalDescription(offer);\n\n // Note: localDescription will be emitted by setupEventListeners initial emission\n // and updated when ICE gathering state changes\n }\n\n public async updateAnswerStatus({ status, sdp }: UpdateSDPStatusParams): Promise<void> {\n let readyToConnect = status !== 'failed';\n\n try {\n if (status === 'received' && sdp) {\n logger.debug('[RTCPeerConnectionController] Received answer SDP:', sdp);\n await this._setRemoteDescription({\n type: 'answer',\n sdp\n });\n }\n } catch (error) {\n logger.error('[RTCPeerConnectionController] Error updating answer status:', error);\n this._errors$.next(error as Error);\n readyToConnect = false;\n } finally {\n if (readyToConnect) {\n this.readyToConnect();\n } else {\n this.iceGatheringController.restartICEGatheringWithRelayOnly();\n }\n }\n }\n\n public async updateOfferStatus({ status, sdp }: UpdateSDPStatusParams): Promise<void> {\n switch (status) {\n case 'received':\n this._type = 'answer';\n this.sdpInit = {\n type: 'offer',\n sdp: sdp\n };\n await this.handleOfferReceived();\n break;\n case 'failed':\n logger.error('[RTCPeerConnectionController] Offer failed to be processed by remote.');\n break;\n case 'sent':\n default:\n // No action needed for sent offers\n }\n }\n\n private async handleOfferReceived() {\n if (!this.sdpInit) {\n throw new DependencyError('SDP initialization parameters are not set');\n }\n\n this._isNegotiating$.next(true);\n await this._setRemoteDescription(this.sdpInit);\n\n const { answerOptions } = this;\n logger.debug('[RTCPeerConnectionController] Creating answer with options:', answerOptions);\n await this.createAnswer(answerOptions);\n }\n\n private readyToConnect() {\n this.firstSDPExchangeCompleted = true;\n this.connectionTimer = setTimeout(() => {\n this.removeConnectionTimer();\n if (this.peerConnection?.connectionState !== 'connected') {\n logger.debug(\n '[RTCPeerConnectionController] Connection timeout, restarting ICE gathering with relay only.'\n );\n this.iceGatheringController.restartICEGatheringWithRelayOnly();\n }\n }, this.connectionTimeout);\n }\n\n private async setRemoteDescriptionBefore(sdp: string = ''): Promise<string> {\n // TODO use the options hooks\n return Promise.resolve(sdp);\n }\n protected async setLocalDescription(params: RTCSessionDescriptionInit): Promise<void> {\n const finalLocal = await this.setLocalDescriptionBefore(params.sdp);\n return this.peerConnection?.setLocalDescription({\n ...params,\n sdp: finalLocal\n });\n }\n async setLocalDescriptionBefore(sdp: string = ''): Promise<string> {\n // TODO use the options hooks\n return Promise.resolve(sdp);\n }\n /**\n * Create an SDP answer and set it as local description.\n */\n private async createAnswer(options?: RTCAnswerOptions): Promise<void> {\n if (!this.peerConnection) {\n throw new DependencyError('RTCPeerConnection is not initialized');\n }\n\n const answer = await this.peerConnection.createAnswer(options);\n await this.setLocalDescription(answer);\n // Note: localDescription will be emitted by setupEventListeners initial emission\n // and updated when ICE gathering state changes\n }\n /**\n * Setup event listeners on RTCPeerConnection for state changes.\n */\n private setupEventListeners(): void {\n if (!this.peerConnection) {\n throw new DependencyError('RTCPeerConnection is not initialized');\n }\n\n // Emit initial states from the actual RTCPeerConnection\n this._iceConnectionState$.next(this.peerConnection.iceConnectionState);\n this._connectionState$.next(this.peerConnection.connectionState);\n this._signalingState$.next(this.peerConnection.signalingState);\n this._iceGatheringState$.next(this.peerConnection.iceGatheringState);\n // Note: localDescription is NOT emitted here - it will be emitted when ICE gathering completes\n this._remoteDescription$.next(this.peerConnection.remoteDescription);\n\n this.peerConnection.removeEventListener(\n 'icegatheringstatechange',\n this.onicegatheringstatechangeHandler\n );\n this.peerConnection.addEventListener(\n 'icegatheringstatechange',\n this.onicegatheringstatechangeHandler\n );\n this.peerConnection.removeEventListener(\n 'iceconnectionstatechange',\n this.oniceconnectionstatechangeHandler\n );\n this.peerConnection.addEventListener(\n 'iceconnectionstatechange',\n this.oniceconnectionstatechangeHandler\n );\n\n // Signaling state changes\n this.peerConnection.removeEventListener(\n 'connectionstatechange',\n this.onconnectionstatechangeHandler\n );\n this.peerConnection.addEventListener(\n 'connectionstatechange',\n this.onconnectionstatechangeHandler\n );\n\n this.peerConnection.removeEventListener(\n 'signalingstatechange',\n this.onsignalingstatechangeHandler\n );\n\n this.peerConnection.addEventListener(\n 'signalingstatechange',\n this.onsignalingstatechangeHandler\n );\n }\n\n private negotiationEnded() {\n this._isNegotiating$.next(false);\n }\n\n public restarIce(): void {\n this.peerConnection?.restartIce();\n }\n /**\n * Setup track handling for remote tracks.\n */\n private async setupTrackHandling(): Promise<void> {\n if (!this.peerConnection) {\n throw new DependencyError('RTCPeerConnection is not initialized');\n }\n\n await this.setupLocalTracks();\n\n await this.setupRemoteTracks();\n }\n\n // eslint-disable-next-line complexity\n private async setupLocalTracks(): Promise<void> {\n logger.debug('[RTCPeerConnectionController] Setting up local tracks/transceivers.');\n let { localStream } = this;\n if (!localStream) {\n try {\n localStream = await this.localStreamController.buildLocalStream();\n } catch (error) {\n logger.error('[RTCPeerConnectionController] Error building local stream:', error);\n this._errors$.next(error as Error);\n }\n }\n\n if (localStream) {\n if (this.transceiverController?.useAddStream ?? false) {\n logger.warn(\n '[RTCPeerConnectionController] Using deprecated addStream API to add local stream.'\n );\n //@ts-expect-error -- Ignore -- useAddStream checked if the deprecated API should be used\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n this.peerConnection?.addStream(localStream);\n // In case the browser doesn't fire negotiationneeded automatically\n if (!this.isNegotiating) {\n logger.debug(\n '[RTCPeerConnectionController] Forcing negotiationneeded after local tracks setup.'\n );\n this.negotiationNeeded$.next();\n }\n return;\n }\n\n for (const kind of ['audio', 'video']) {\n const tracks = (\n kind === 'audio' ? localStream.getAudioTracks() : localStream.getVideoTracks()\n ).map((track, index) => ({ index, track }));\n for (const { index, track } of tracks) {\n this.localStreamController.addTrackEndedListener(track);\n if (this.transceiverController?.useAddTransceivers ?? false) {\n const transceivers =\n (kind === 'audio'\n ? this.transceiverController?.audioTransceivers\n : this.transceiverController?.videoTransceivers) ?? [];\n await this.transceiverController?.setupTransceiverSender(\n track,\n localStream,\n transceivers[index]\n );\n } else {\n logger.debug(\n `[RTCPeerConnectionController] Using addTrack for local ${kind} track:`,\n track.id\n );\n this.peerConnection?.addTrack(track, localStream);\n }\n }\n }\n }\n }\n private async getUserMedia(constraints: MediaStreamConstraints): Promise<MediaStream> {\n return (\n this.options.getUserMedia?.(constraints) ?? navigator.mediaDevices.getUserMedia(constraints)\n );\n }\n\n private async getDisplayMedia(options: DisplayMediaStreamOptions): Promise<MediaStream> {\n return (\n this.options.getDisplayMedia?.(options) ?? navigator.mediaDevices.getDisplayMedia(options)\n );\n }\n private async setupRemoteTracks(): Promise<void> {\n if (!this.peerConnection) {\n throw new DependencyError('RTCPeerConnection is not initialized');\n }\n this.peerConnection.ontrack = (event) => {\n logger.debug('[RTCPeerConnectionController] Remote track received:', event.track.kind);\n this._remoteStream$.next(event.streams[0]);\n };\n\n await this.transceiverController?.setupRemoteTransceivers(this.type);\n }\n\n public async restoreTrackSender(kind: 'audio' | 'video' | 'both'): Promise<void> {\n await this.transceiverController?.restoreTrackSender(kind);\n }\n /**\n * Add a local media track to the peer connection.\n * @param track - The MediaStreamTrack to add\n */\n public addLocalTrack(track: MediaStreamTrack): void {\n if (!this.peerConnection) {\n const error = new DependencyError('RTCPeerConnection is not initialized');\n this._errors$.next(error);\n throw error;\n }\n\n try {\n // Add track to local stream controller\n const localStream = this.localStreamController.addTrack(track);\n\n // Add track to peer connection\n this.peerConnection.addTrack(track, localStream);\n\n logger.debug(`[RTCPeerConnectionController] ${track.kind} track added:`, track.id);\n } catch (error) {\n logger.error(`[RTCPeerConnectionController] Failed to add ${track.kind} track:`, error);\n this._errors$.next(error as Error);\n throw error;\n }\n }\n /**\n * Remove a local media track from the peer connection.\n * @param trackId - The ID of the track to remove\n */\n public removeLocalTrack(trackId: string): void {\n if (!this.peerConnection) {\n const error = new DependencyError('RTCPeerConnection is not initialized');\n this._errors$.next(error);\n throw error;\n }\n\n const sender = this.peerConnection.getSenders().find((sender) => sender.track?.id === trackId);\n if (!sender) {\n logger.debug(`[RTCPeerConnectionController] track not found: ${trackId}`);\n return;\n }\n\n try {\n // Remove sender from peer connection\n this.peerConnection.removeTrack(sender);\n\n // Remove track from local stream controller\n this.localStreamController.removeTrack(trackId);\n\n logger.debug(`[RTCPeerConnectionController] ${sender.track?.kind} track removed:`, trackId);\n } catch (error) {\n logger.error(\n `[RTCPeerConnectionController] Failed to remove ${sender.track?.kind} track:`,\n error\n );\n this._errors$.next(error as Error);\n throw error;\n }\n }\n /**\n * Replace all existing media tracks with a new media track.\n * Convenience method for single-track scenarios.\n * @param track - The MediaStreamTrack to set\n */\n public setLocalTrack(track: MediaStreamTrack): void {\n // Remove all existing media tracks\n const existingTracks = [\n ...(track.kind === 'audio'\n ? this.localStreamController.localAudioTracks\n : this.localStreamController.localVideoTracks)\n ];\n for (const existingTrack of existingTracks) {\n this.removeLocalTrack(existingTrack.id);\n }\n\n // Add the new track\n this.addLocalTrack(track);\n }\n public async updateSendersConstraints(\n kind: 'audio' | 'video',\n constraints?: MediaTrackConstraints\n ): Promise<void> {\n await this.transceiverController?.updateSendersConstraints(kind, constraints);\n }\n\n /**\n * Clean up resources and close the peer connection.\n * Completes all observables to prevent memory leaks.\n */\n public destroy(): void {\n logger.debug(\n `[RTCPeerConnectionController] Destroying RTCPeerConnectionController. ${this.propose}`\n );\n this.removeConnectionTimer();\n this._iceGatheringController?.destroy();\n this.localStreamController.destroy();\n this.transceiverController?.destroy();\n\n // Close peer connection\n if (this.peerConnection) {\n this.stopRemoteTracks();\n this.removeAllListeners();\n this.peerConnection.close();\n this.peerConnection = undefined;\n }\n\n // Call parent destroy to clean up subscriptions and complete destroyed$\n super.destroy();\n }\n private removeAllListeners() {\n if (this.peerConnection) {\n this.peerConnection.removeEventListener(\n 'icegatheringstatechange',\n this.onicegatheringstatechangeHandler\n );\n this.peerConnection.removeEventListener(\n 'iceconnectionstatechange',\n this.oniceconnectionstatechangeHandler\n );\n this.peerConnection.removeEventListener(\n 'connectionstatechange',\n this.onconnectionstatechangeHandler\n );\n this.peerConnection.removeEventListener(\n 'signalingstatechange',\n this.onsignalingstatechangeHandler\n );\n this.peerConnection.removeEventListener('negotiationneeded', this.onnegotiationneededHandler);\n }\n }\n\n private stopRemoteTracks() {\n const remoteStream = this._remoteStream$.value;\n remoteStream?.getTracks().forEach((track: MediaStreamTrack) => {\n logger.debug(`[RTCPeerConnectionController] Stopping remote track: ${track.kind}`);\n track.stop();\n });\n }\n\n public get mediaDirections(): {\n audio: RTCRtpTransceiverDirection;\n video: RTCRtpTransceiverDirection;\n } {\n return (\n this.transceiverController?.getMediaDirections() ?? {\n audio: 'inactive',\n video: 'inactive'\n }\n );\n }\n protected async _setRemoteDescription(params: RTCSessionDescriptionInit): Promise<void> {\n if (!this.peerConnection) {\n throw new DependencyError('RTCPeerConnection is not initialized');\n }\n\n const finalRemote = await this.setRemoteDescriptionBefore(params.sdp);\n\n const answer: RTCSessionDescriptionInit = {\n ...params,\n sdp: finalRemote\n };\n logger.debug('[RTCPeerConnectionController] Setting remote description:', answer);\n return this.peerConnection.setRemoteDescription(answer);\n }\n}\n","// =============================================================================\n// VERTO TYPE GUARDS\n// =============================================================================\n// This file contains type guards for Verto protocol types.\n\nimport { hasProperty, isObject } from './base.guards';\n\nimport type { TypeGuard } from '../types/base';\nimport type { WebrtcMessagePayload } from '../types/events';\nimport type {\n VertoAnswerMessage,\n VertoAnswerParams,\n VertoAnswerResultMessage,\n VertoAttachMessage,\n VertoAttachParams,\n VertoByeMessage,\n VertoByeParams,\n VertoInviteMessage,\n VertoInviteParams,\n VertoMediaParamsMessage,\n VertoMediaParamsParams,\n VertoMethodMessage,\n VertoPingMessage,\n VertoPingParams,\n VertoPongMessage,\n VertoPongParams\n} from '../types/verto';\n\n// =============================================================================\n// VERTO MESSAGE TYPE GUARDS\n// =============================================================================\n\nexport function isVertoMethodMessage(value: unknown): value is VertoMethodMessage {\n return (\n isObject(value) &&\n hasProperty(value, 'jsonrpc') &&\n value.jsonrpc === '2.0' &&\n hasProperty(value, 'id')\n );\n}\n\nexport function isVertoAnswerMessage(value: unknown): value is VertoAnswerMessage {\n if (!isVertoMethodMessage(value)) return false;\n const msg = value as unknown as Record<string, unknown>;\n return (\n msg.method === 'verto.answer' &&\n isObject(msg.params) &&\n hasProperty(msg.params, 'callID') &&\n hasProperty(msg.params, 'sdp')\n );\n}\n\nexport function isVertoMediaParamsMessage(value: unknown): value is VertoMediaParamsMessage {\n if (!isVertoMethodMessage(value)) return false;\n const msg = value as unknown as Record<string, unknown>;\n return (\n msg.method === 'verto.mediaParams' &&\n isObject(msg.params) &&\n hasProperty(msg.params, 'mediaParams')\n );\n}\n\nexport function isVertoPingMessage(value: unknown): value is VertoPingMessage {\n if (!isVertoMethodMessage(value)) return false;\n const msg = value as unknown as Record<string, unknown>;\n return msg.method === 'verto.ping';\n}\n\nexport function isVertoPongMessage(value: unknown): value is VertoPongMessage {\n if (!isVertoMethodMessage(value)) return false;\n const msg = value as unknown as Record<string, unknown>;\n return msg.method === 'verto.pong';\n}\n\nexport function isVertoInviteMessage(value: unknown): value is VertoInviteMessage {\n if (!isVertoMethodMessage(value)) return false;\n const msg = value as unknown as Record<string, unknown>;\n return (\n msg.method === 'verto.invite' &&\n isObject(msg.params) &&\n hasProperty(msg.params, 'sdp') &&\n hasProperty(msg.params, 'callID')\n );\n}\n\nexport function isVertoByeMessage(value: unknown): value is VertoByeMessage {\n if (!isVertoMethodMessage(value)) return false;\n const msg = value as unknown as Record<string, unknown>;\n return msg.method === 'verto.bye';\n}\n\nexport function isVertoAnswerResultMessage(value: unknown): value is VertoAnswerResultMessage {\n if (!isVertoMethodMessage(value)) return false;\n const msg = value as unknown as Record<string, unknown>;\n return (\n isObject(msg.result) &&\n hasProperty(msg.result, 'method') &&\n msg.result.method === 'verto.answer'\n );\n}\n\nexport function isVertoAttachMessage(value: unknown): value is VertoAttachMessage {\n if (!isVertoMethodMessage(value)) return false;\n const msg = value as unknown as Record<string, unknown>;\n return msg.method === 'verto.attach';\n}\n\n// =============================================================================\n// WEBRTC MESSAGE EVENT DATA (inner params.params) TYPE GUARDS\n// =============================================================================\n\nexport function isVertoAnswerInnerParams(value: unknown): value is WebrtcMessagePayload & {\n method: 'verto.answer';\n params: VertoAnswerParams;\n} {\n return (\n isObject(value) &&\n hasProperty(value, 'jsonrpc') &&\n value.jsonrpc === '2.0' &&\n hasProperty(value, 'method') &&\n value.method === 'verto.answer' &&\n isObject(value.params) &&\n hasProperty(value.params, 'callID') &&\n hasProperty(value.params, 'sdp')\n );\n}\n\nexport function isVertoMediaParamsInnerParams(value: unknown): value is WebrtcMessagePayload & {\n method: 'verto.mediaParams';\n params: VertoMediaParamsParams;\n} {\n return (\n isObject(value) &&\n hasProperty(value, 'jsonrpc') &&\n value.jsonrpc === '2.0' &&\n hasProperty(value, 'method') &&\n value.method === 'verto.mediaParams' &&\n isObject(value.params) &&\n hasProperty(value.params, 'mediaParams')\n );\n}\n\nexport function isVertoPingInnerParams(value: unknown): value is WebrtcMessagePayload & {\n method: 'verto.ping';\n params: VertoPingParams;\n} {\n return (\n isObject(value) &&\n hasProperty(value, 'jsonrpc') &&\n value.jsonrpc === '2.0' &&\n hasProperty(value, 'method') &&\n value.method === 'verto.ping'\n );\n}\n\n// =============================================================================\n// VERTO PARAMS TYPE GUARDS (for use with filterAs on Verto method params)\n// =============================================================================\n\nexport function isVertoAnswerParamsGuard(value: unknown): value is VertoAnswerParams {\n return (\n isObject(value) &&\n hasProperty(value, 'callID') &&\n typeof value.callID === 'string' &&\n hasProperty(value, 'sdp') &&\n typeof value.sdp === 'string'\n );\n}\n\nexport function isVertoMediaParamsParamsGuard(value: unknown): value is VertoMediaParamsParams {\n return (\n isObject(value) &&\n hasProperty(value, 'callID') &&\n typeof value.callID === 'string' &&\n hasProperty(value, 'mediaParams') &&\n isObject(value.mediaParams)\n );\n}\n\nexport function isVertoPingParamsGuard(value: unknown): value is VertoPingParams {\n return (\n isObject(value) &&\n hasProperty(value, 'callID') &&\n typeof value.callID === 'string' &&\n hasProperty(value, 'dialogParams') &&\n isObject(value.dialogParams)\n );\n}\n\nexport function isVertoPongParamsGuard(value: unknown): value is VertoPongParams {\n return isVertoPingParamsGuard(value);\n}\n\nexport function isVertoInviteParamsGuard(value: unknown): value is VertoInviteParams {\n return (\n isObject(value) &&\n hasProperty(value, 'dialogParams') &&\n isObject(value.dialogParams) &&\n hasProperty(value, 'sdp') &&\n typeof value.sdp === 'string'\n );\n}\n\nexport function isVertoByeParamsGuard(value: unknown): value is VertoByeParams {\n return isObject(value) && hasProperty(value, 'callID') && typeof value.callID === 'string';\n}\n\nexport function isVertoAttachParamsGuard(value: unknown): value is VertoAttachParams {\n return (\n isObject(value) &&\n hasProperty(value, 'callID') &&\n typeof value.callID === 'string' &&\n hasProperty(value, 'callee_id_number') &&\n typeof value.callee_id_number === 'string' &&\n hasProperty(value, 'callee_id_name') &&\n typeof value.callee_id_name === 'string' &&\n hasProperty(value, 'caller_id_number') &&\n typeof value.caller_id_number === 'string' &&\n hasProperty(value, 'caller_id_name') &&\n typeof value.caller_id_name === 'string'\n );\n}\n\n// Duplicate guards for backwards compatibility (without \"Guard\" suffix)\nexport function isVertoAnswerParams(value: unknown): value is VertoAnswerParams {\n return isVertoAnswerParamsGuard(value);\n}\n\nexport function isVertoMediaParamsParams(value: unknown): value is VertoMediaParamsParams {\n return isVertoMediaParamsParamsGuard(value);\n}\n\nexport function isVertoPingParams(value: unknown): value is VertoPingParams {\n return isVertoPingParamsGuard(value);\n}\n\nexport function isVertoPongParams(value: unknown): value is VertoPongParams {\n return isVertoPongParamsGuard(value);\n}\n\nexport function isVertoInviteParams(value: unknown): value is VertoInviteParams {\n return isVertoInviteParamsGuard(value);\n}\n\nexport function isVertoByeParams(value: unknown): value is VertoByeParams {\n return isVertoByeParamsGuard(value);\n}\n\nexport function isVertoAttachParams(value: unknown): value is VertoAttachParams {\n return isVertoAttachParamsGuard(value);\n}\n\n// =============================================================================\n// VERTO METHOD TYPE MAPPING\n// =============================================================================\n\nexport const VertoMethodTypeMap = {\n 'verto.answer': isVertoAnswerMessage,\n 'verto.mediaParams': isVertoMediaParamsMessage,\n 'verto.ping': isVertoPingMessage,\n 'verto.pong': isVertoPongMessage,\n 'verto.invite': isVertoInviteMessage,\n 'verto.bye': isVertoByeMessage\n} as const;\n\nexport type VertoMethodType = keyof typeof VertoMethodTypeMap;\n\n/**\n * Gets the appropriate type guard for a Verto method.\n */\nexport function getVertoMethodGuard(method: string): TypeGuard<VertoMethodMessage> | undefined {\n return VertoMethodTypeMap[method as VertoMethodType];\n}\n\n// =============================================================================\n// VERTO PARAMS TYPE MAPPING\n// =============================================================================\n\nexport const VertoParamsTypeMap = {\n 'verto.answer': isVertoAnswerParamsGuard,\n 'verto.mediaParams': isVertoMediaParamsParamsGuard,\n 'verto.ping': isVertoPingParamsGuard,\n 'verto.pong': isVertoPongParamsGuard,\n 'verto.invite': isVertoInviteParamsGuard,\n 'verto.attach': isVertoAttachParamsGuard,\n 'verto.bye': isVertoByeParamsGuard\n} as const;\n\n/**\n * Gets the appropriate params type guard for a Verto method.\n */\nexport function getVertoParamsGuard(\n method: string\n):\n | TypeGuard<\n | VertoAnswerParams\n | VertoMediaParamsParams\n | VertoPingParams\n | VertoPongParams\n | VertoInviteParams\n | VertoByeParams\n | VertoAttachParams\n >\n | undefined {\n return VertoParamsTypeMap[method as VertoMethodType];\n}\n","/* eslint-disable max-lines */\nimport { filter, firstValueFrom, map, merge, race, take, takeUntil, timeout } from 'rxjs';\n\nimport { Destroyable } from '../behaviors/Destroyable';\nimport { PreferencesContainer } from '../containers/PreferencesContainer';\nimport { RTCPeerConnectionController } from '../controllers/RTCPeerConnectionController';\nimport { INVITE_VERSION } from '../core/constants';\nimport { DependencyError, InvalidParams, JSONRPCError, VertoPongError } from '../core/errors';\nimport {\n VertoAnswer,\n VertoBye,\n VertoByeCauseCodes,\n VertoInfo,\n VertoInvite,\n VertoModify,\n VertoPong,\n WebrtcVerto\n} from '../core/RPCMessages';\nimport {\n isVertoAnswerInnerParams,\n isVertoAttachMessage,\n isVertoByeMessage,\n isVertoMediaParamsInnerParams,\n isVertoPingInnerParams\n} from '../core/RPCMessages/guards/verto.guards';\nimport { filterAs } from '../operators';\nimport { filterNull } from '../operators/filterNull';\nimport { getValueFrom } from '../utils/getValueFrom';\nimport { getLogger } from '../utils/logger';\n\nimport type { AttachManager } from './AttachManager';\nimport type { WebRTCCall } from '../core/entities/Call';\nimport type { VertoRPCMessage } from '../core/RPCMessages';\nimport type {\n ExecuteVertoOptions,\n ScreenShareStatus,\n SignalingStatus,\n TransferOptions,\n WebRTCVertoManagerOptions\n} from './types/verto-manager.types';\nimport type { JSONRPCResponse } from '../core/RPCMessages/types/base';\nimport type {\n VertoAnswerParams,\n VertoAttachParams,\n VertoByeCause,\n VertoByeParams,\n VertoMediaParamsParams,\n VertoPingParams\n} from '../core/RPCMessages/types/verto';\nimport type { RTCPeerConnectionPropose } from '../core/types/call.types';\nimport type { MediaOptions, MediaDirections } from '../core/types/media.types';\nimport type { VertoMethod } from '../core/types/rpc.types';\nimport type { DeviceController } from '../interfaces/DeviceController';\nimport type { WebRTCVerto } from '../interfaces/WebRTCVerto';\nimport type { BehaviorSubject, Observable } from 'rxjs';\n\nconst logger = getLogger();\nexport abstract class VertoManager extends Destroyable {\n protected callSession?: WebRTCCall;\n\n constructor(callSession?: WebRTCCall) {\n super();\n this.callSession = callSession;\n }\n\n public destroy(): void {\n this.callSession = undefined;\n super.destroy();\n }\n}\nexport class WebRTCVertoManager extends VertoManager implements WebRTCVerto {\n public mediaDirections$!: Observable<MediaDirections>;\n public localStream$!: Observable<MediaStream>;\n public remoteStream$!: Observable<MediaStream>;\n private readonly onError?: (error: Error) => void;\n private _rtcPeerConnections$ = this.createBehaviorSubject<RTCPeerConnectionController[]>([]);\n\n private _nodeId$: BehaviorSubject<string | null>;\n private _selfId$ = this.createBehaviorSubject<string | null>(null);\n private _signalingStatus$ = this.createBehaviorSubject<SignalingStatus | null>(null);\n private _screenShareStatus$ = this.createBehaviorSubject<ScreenShareStatus>('none');\n private _rtcPeerConnectionsMap = new Map<string, RTCPeerConnectionController>();\n private _screenShareId?: string;\n private _screenShareTimeoutMs = 50000;\n\n constructor(\n protected webRtcCallSession: WebRTCCall,\n private readonly attachManager: AttachManager,\n private readonly deviceController: DeviceController,\n options: WebRTCVertoManagerOptions = {}\n ) {\n super(webRtcCallSession);\n this._nodeId$ = this.createBehaviorSubject<string | null>(options.nodeId ?? null);\n this.onError = options.onError;\n this.initSubscriptions();\n this.initMainPeerConnection();\n }\n async hold(): Promise<void> {\n const vertoModifyMessage = VertoModify({\n sessid: this.webRtcCallSession.id,\n dialogParams: {\n callID: this.webRtcCallSession.id\n },\n action: 'hold'\n });\n\n try {\n await this.executeVerto(vertoModifyMessage);\n } catch (error) {\n logger.warn(\n '[WebRTCManager] Call might already be disconnected, error sending Verto hold:',\n error\n );\n throw error;\n }\n }\n async unhold(): Promise<void> {\n const vertoModifyMessage = VertoModify({\n sessid: this.webRtcCallSession.id,\n dialogParams: {\n callID: this.webRtcCallSession.id\n },\n action: 'unhold'\n });\n try {\n await this.executeVerto(vertoModifyMessage);\n } catch (error) {\n logger.warn(\n '[WebRTCManager] Call might already be disconnected, error sending Verto unhold:',\n error\n );\n throw error;\n }\n }\n\n public get mediaDirections(): MediaDirections {\n return this.mainPeerConnection.mediaDirections;\n }\n\n public get rtcPeerConnections$(): Observable<RTCPeerConnectionController[]> {\n return this._rtcPeerConnections$.asObservable();\n }\n\n public get rtcPeerConnections(): RTCPeerConnectionController[] {\n return this._rtcPeerConnections$.value;\n }\n\n public get nodeId$(): Observable<string | null> {\n return this._nodeId$.asObservable();\n }\n\n public get selfId$(): Observable<string | null> {\n return this._selfId$.asObservable();\n }\n\n public get localStream(): MediaStream | null {\n return this._rtcPeerConnectionsMap.get(this.webRtcCallSession.id)?.localStream ?? null;\n }\n\n public get remoteStream(): MediaStream | null {\n return this._rtcPeerConnectionsMap.get(this.webRtcCallSession.id)?.remoteStream ?? null;\n }\n\n public get nodeId(): string | null {\n return this._nodeId$.value;\n }\n\n public get screenShareStatus(): ScreenShareStatus {\n return this._screenShareStatus$.value;\n }\n\n public get screenShareStatus$(): Observable<ScreenShareStatus> {\n return this._screenShareStatus$.asObservable();\n }\n\n public get mainPeerConnection(): RTCPeerConnectionController {\n const rtcPeerConnection = this._rtcPeerConnectionsMap.get(this.webRtcCallSession.id);\n if (!rtcPeerConnection) {\n throw new DependencyError('Main peer connection not found');\n }\n return rtcPeerConnection;\n }\n\n public get signalingStatus$(): Observable<SignalingStatus> {\n return this.cachedObservable('signalingStatus$', () =>\n merge(\n this._signalingStatus$.pipe(filterNull()),\n this.mainPeerConnection.connectionState$.pipe(\n filter((connectionState) =>\n ['connected', 'disconnected', 'failed'].includes(connectionState)\n )\n ) as Observable<SignalingStatus>\n )\n );\n }\n\n private initSubscriptions() {\n this.subscribeTo(this.vertoAnswer$, (event: VertoAnswerParams) => {\n logger.debug('[WebRTCManager] Received Verto answer event:', event);\n const { sdp } = event;\n const rtcPeerConnController = this._rtcPeerConnectionsMap.get(event.callID);\n void rtcPeerConnController?.updateAnswerStatus({\n status: 'received',\n sdp: sdp\n });\n });\n\n this.subscribeTo(this.vertoMediaParams$, (event: VertoMediaParamsParams) => {\n logger.debug('[WebRTCManager] Received Verto mediaParams event:', event);\n\n const { mediaParams, callID } = event;\n const rtcPeerConnController = this._rtcPeerConnectionsMap.get(callID);\n const { audio, video } = mediaParams;\n if (audio) {\n void rtcPeerConnController?.updateSendersConstraints('audio', audio);\n }\n if (video) {\n void rtcPeerConnController?.updateSendersConstraints('video', video);\n }\n });\n\n this.subscribeTo(this.vertoPing$, (vertoPing: VertoPingParams) => {\n void this.attachManager.attach(this.webRtcCallSession);\n void this.sendVertoPong(vertoPing);\n });\n }\n\n private async sendVertoPong(vertoPing: VertoPingParams) {\n try {\n const vertoPongMessage = VertoPong({\n ...vertoPing\n });\n await this.executeVerto(vertoPongMessage);\n } catch (error) {\n logger.warn('[WebRTCManager] Call might disconnect, error sending Verto pong:', error);\n this.onError?.(new VertoPongError(error));\n }\n }\n\n public async updateMediaConstraints(\n options: {\n audio?: MediaTrackConstraints;\n video?: MediaTrackConstraints;\n } = {}\n ): Promise<void> {\n const { audio, video } = options;\n try {\n if (audio) {\n await this.mainPeerConnection.updateSendersConstraints('audio', audio);\n }\n if (video) {\n await this.mainPeerConnection.updateSendersConstraints('video', video);\n }\n } catch (error) {\n logger.warn('[WebRTCManager] Error updating media constraints:', error);\n this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));\n throw error;\n }\n }\n\n public get selfId(): string | null {\n return this._selfId$.value;\n }\n\n private get vertoAnswer$() {\n return this.cachedObservable('vertoAnswer$', () =>\n this.webRtcCallSession.webrtcMessages$.pipe(\n filterAs(isVertoAnswerInnerParams, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n private get vertoMediaParams$() {\n return this.cachedObservable('vertoMediaParams$', () =>\n this.webRtcCallSession.webrtcMessages$.pipe(\n filterAs(isVertoMediaParamsInnerParams, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n private get vertoBye$() {\n return this.cachedObservable('vertoBye$', () =>\n this.webRtcCallSession.webrtcMessages$.pipe(\n filterAs(isVertoByeMessage, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n private get vertoAttach$() {\n return this.cachedObservable('vertoAttach$', () =>\n this.webRtcCallSession.webrtcMessages$.pipe(\n filterAs(isVertoAttachMessage, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n private get vertoPing$() {\n return this.cachedObservable('vertoPing$', () =>\n this.webRtcCallSession.webrtcMessages$.pipe(\n filterAs(isVertoPingInnerParams, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n private async executeVerto(\n message: VertoRPCMessage,\n optionals: ExecuteVertoOptions = {}\n ): Promise<JSONRPCResponse<unknown>> {\n const params = {\n callID: optionals.callID ?? this.webRtcCallSession.id,\n\n node_id: optionals.node_id ?? this._nodeId$.value ?? '',\n message,\n subscribe: optionals.subscribe\n };\n const webrtcVertoMessage = WebrtcVerto(params);\n\n const response = await this.webRtcCallSession.execute(webrtcVertoMessage);\n\n // Check for error at top level\n if (response.error) {\n const error = new JSONRPCError(\n response.error.code,\n response.error.message,\n response.error.data\n );\n this.onError?.(error);\n throw error;\n }\n\n // Check for nested error in result.result (webrtc.verto wraps the inner response)\n const innerResult = getValueFrom<{ error?: { code: number; message: string; data?: unknown } }>(\n response,\n 'result.result'\n );\n if (innerResult?.error) {\n const error = new JSONRPCError(\n innerResult.error.code,\n innerResult.error.message,\n innerResult.error.data\n );\n this.onError?.(error);\n throw error;\n }\n\n return response;\n }\n\n private async sendLocalDescription(\n message: VertoRPCMessage,\n rtcPeerConnController: RTCPeerConnectionController\n ): Promise<void> {\n const vertoMethod: VertoMethod = message.method;\n\n const optionalsParams = this.getSendLocalSDPOptionalParams(rtcPeerConnController);\n\n try {\n const response = await this.executeVerto(message, optionalsParams);\n\n switch (vertoMethod) {\n case 'verto.invite':\n this.processInviteResponse(response, rtcPeerConnController);\n break;\n case 'verto.modify':\n await this.processModifyResponse(response, rtcPeerConnController);\n break;\n default:\n }\n } catch (error) {\n logger.error(`[WebRTCManager] Error sending Verto ${vertoMethod}:`, error);\n throw error;\n }\n }\n private async processModifyResponse(\n response: JSONRPCResponse<unknown>,\n rtcPeerConnController: RTCPeerConnectionController\n ) {\n if (!response.error) {\n const action = getValueFrom<string>(response, 'result.result.result.action');\n const sdp = getValueFrom<string>(response, 'result.result.result.sdp');\n if (action === 'updateMedia' && !!sdp) {\n try {\n await rtcPeerConnController.updateAnswerStatus({\n status: 'received',\n sdp\n });\n } catch (error) {\n logger.warn('[WebRTCManager] Error processing modify response:', error);\n this.onError?.(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n }\n }\n }\n }\n\n private processInviteResponse(\n response: JSONRPCResponse<unknown>,\n rtcPeerConnController: RTCPeerConnectionController\n ) {\n if (\n !response.error &&\n getValueFrom(response, 'result.result.result.message') === 'CALL CREATED'\n ) {\n this._nodeId$.next(getValueFrom<string>(response, 'result.node_id') ?? null);\n const memberId = getValueFrom<string>(response, 'result.result.result.memberID') ?? null;\n const callId = getValueFrom<string>(response, 'result.result.result.callID') ?? null;\n logger.debug('[WebRTCManager] Verto invite response:', { callId, memberId, response });\n\n this._selfId$.next(memberId);\n rtcPeerConnController.setMemberId(memberId);\n if (callId) {\n this.webRtcCallSession.addCallId(callId);\n }\n this._signalingStatus$.next('ringing');\n void this.attachManager.attach(this.webRtcCallSession);\n logger.info('[WebRTCManager] Verto invite successful');\n logger.debug(\n `[WebRTCManager] nodeid: ${this._nodeId$.value}, selfId: ${this._selfId$.value}`\n );\n } else {\n logger.error('[WebRTCManager] Verto invite failed:', response);\n const inviteError = response.error\n ? new JSONRPCError(response.error.code, response.error.message, response.error.data)\n : new Error('Verto invite failed: unexpected response');\n this.onError?.(inviteError);\n }\n }\n\n private get RTCPeerConnectionConfig() {\n return {\n iceServers:\n this.webRtcCallSession.clientSession.iceServers ?? PreferencesContainer.instance.iceServers,\n relayOnly:\n PreferencesContainer.instance.relayOnly ||\n PreferencesContainer.instance.disableUdpIceServers,\n disableUdpIceServers: PreferencesContainer.instance.disableUdpIceServers,\n iceCandidateTimeout: PreferencesContainer.instance.iceCandidateTimeout,\n iceGatheringTimeout: PreferencesContainer.instance.iceGatheringTimeout\n };\n }\n\n private initMainPeerConnection() {\n //if (this.webRtcCallSession.direction === 'outbound') {\n const { options } = this.webRtcCallSession;\n const rtcPeerConnController = new RTCPeerConnectionController(\n {\n propose: 'main',\n callId: this.webRtcCallSession.id,\n audio: options.audio,\n video: options.video,\n inputAudioDeviceConstraints: options.inputAudioDeviceConstraints,\n inputVideoDeviceConstraints: options.inputVideoDeviceConstraints,\n inputAudioStream: options.inputAudioStream,\n inputVideoStream: options.inputVideoStream,\n receiveAudio: options.receiveAudio,\n receiveVideo: options.receiveVideo,\n ...this.RTCPeerConnectionConfig\n },\n options.initOffer,\n this.deviceController\n );\n this.setupLocalDescriptionHandler(rtcPeerConnController);\n this.setupVertoByeHandler();\n this.setupVertoAttachHandler();\n this.initObservables(rtcPeerConnController);\n this._rtcPeerConnectionsMap.set(rtcPeerConnController.id, rtcPeerConnController);\n this._rtcPeerConnections$.next(Array.from(this._rtcPeerConnectionsMap.values()));\n this.subscribeTo(rtcPeerConnController.errors$, (error) => {\n this.onError?.(error);\n });\n //}\n }\n\n private setupVertoAttachHandler(): void {\n this.subscribeTo(this.vertoAttach$, async (vertoAttach: VertoAttachParams) => {\n logger.debug('[WebRTCManager] Received Verto attach event:', vertoAttach);\n const { callID } = vertoAttach;\n await this.attachManager.attach({\n id: callID,\n to: vertoAttach.callee_id_number,\n mediaDirections: {\n audio: 'sendrecv',\n // this might be changed in future to support video attach, but this feature was originally supposed in the non-video SDK.\n video: 'inactive'\n }\n });\n await this.attachManager.reattachCalls();\n });\n }\n\n private initObservables(rtcPeerConnController: RTCPeerConnectionController): void {\n this.mediaDirections$ = rtcPeerConnController.connectionState$.pipe(\n filter((state) => state === 'connected'),\n takeUntil(this.destroyed$),\n map(() => rtcPeerConnController.mediaDirections)\n );\n this.localStream$ = rtcPeerConnController.localStream$.pipe(\n filterNull(),\n takeUntil(this.destroyed$)\n );\n this.remoteStream$ = rtcPeerConnController.remoteStream$.pipe(\n filterNull(),\n takeUntil(this.destroyed$)\n );\n }\n private setupLocalDescriptionHandler(rtcPeerConnController: RTCPeerConnectionController): void {\n this.subscribeTo(\n // watch for local description from the RTCPeerConnection and send it to remote peer\n rtcPeerConnController.localDescription$.pipe(\n // Filter out null descriptions\n filter((description): description is RTCSessionDescription => description !== null),\n takeUntil(this.destroyed$)\n ),\n (description) => {\n const { type, sdp } = description;\n const dialogParams = this.dialogParams(rtcPeerConnController);\n const initial = !rtcPeerConnController.firstSDPExchangeCompleted;\n if (type === 'answer') {\n {\n const vertoMessageRequest = VertoAnswer({\n dialogParams,\n sdp: sdp\n });\n void this.sendLocalDescriptionOnceAccepted(vertoMessageRequest, rtcPeerConnController);\n }\n } else if (initial) {\n this._signalingStatus$.next('trying');\n const vertoMessageRequest = VertoInvite({\n dialogParams,\n sdp\n });\n void this.sendLocalDescription(vertoMessageRequest, rtcPeerConnController);\n } else {\n const vertoMessageRequest = VertoModify({\n dialogParams,\n sdp,\n action: 'updateMedia'\n });\n void this.sendLocalDescription(vertoMessageRequest, rtcPeerConnController);\n }\n }\n );\n }\n\n private setupVertoByeHandler() {\n this.subscribeTo(this.vertoBye$, () => {\n void this.attachManager.detach(this.webRtcCallSession);\n this.callSession?.destroy();\n });\n }\n\n private getSendLocalSDPOptionalParams(\n rtcPeerConnController: RTCPeerConnectionController\n ): ExecuteVertoOptions {\n let subscribe = undefined;\n const initial = !rtcPeerConnController.firstSDPExchangeCompleted;\n if (initial) {\n subscribe = [];\n if (rtcPeerConnController.isMainDevice) {\n subscribe.push(...PreferencesContainer.instance.inviteSubscribeMainDevice);\n } else if (rtcPeerConnController.isAdditionalDevice) {\n subscribe.push(...PreferencesContainer.instance.inviteSubscribeAdditionalDevice);\n } else if (rtcPeerConnController.isScreenShare) {\n subscribe.push(...PreferencesContainer.instance.inviteSubscribeScreenshare);\n }\n }\n const optionalsParams = {\n callID: rtcPeerConnController.id,\n // don't send a node_id `verto.invite`\n node_id: initial ? '' : (this._nodeId$.value ?? ''),\n subscribe\n };\n return optionalsParams;\n }\n\n async sendLocalDescriptionOnceAccepted(\n vertoMessageRequest: VertoRPCMessage,\n rtcPeerConnectionController: RTCPeerConnectionController\n ): Promise<void> {\n logger.debug('[WebRTCManager] Waiting for call to be accepted or ended before sending answer');\n const vertoByeOrAccepted: boolean | VertoByeParams = await firstValueFrom(\n race(this.vertoBye$, this.webRtcCallSession.answered$)\n );\n\n if (isVertoByeMessage(vertoByeOrAccepted)) {\n logger.info('[WebRTCManager] Call ended before answer was sent.');\n this.callSession?.destroy();\n } else if (!vertoByeOrAccepted) {\n logger.info('[WebRTCManager] Call was not accepted, sending verto.bye.');\n await this.bye('USER_BUSY');\n } else {\n logger.debug('[WebRTCManager] Call accepted, sending answer');\n try {\n this._signalingStatus$.next('connecting');\n await this.sendLocalDescription(vertoMessageRequest, rtcPeerConnectionController);\n await rtcPeerConnectionController.updateAnswerStatus({\n status: 'sent'\n });\n await this.attachManager.attach(this.webRtcCallSession);\n } catch (error) {\n logger.error('[WebRTCManager] Error sending Verto answer:', error);\n this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));\n await rtcPeerConnectionController.updateAnswerStatus({\n status: 'failed'\n });\n }\n }\n }\n\n dialogParams(rtcPeerConnectionController: RTCPeerConnectionController): Record<string, unknown> {\n const memberId = rtcPeerConnectionController.memberId ?? this._selfId$.value ?? undefined;\n const attach =\n rtcPeerConnectionController.propose === 'main' &&\n !rtcPeerConnectionController.firstSDPExchangeCompleted &&\n this.webRtcCallSession.options.reattach;\n\n return {\n id: rtcPeerConnectionController.isMainDevice\n ? this.webRtcCallSession.id\n : rtcPeerConnectionController.id,\n destinationNumber: this.webRtcCallSession.to ?? this.webRtcCallSession.from,\n attach,\n reattaching: attach,\n callerName: this.webRtcCallSession.fromName,\n callerNumber: this.webRtcCallSession.from,\n remoteCallerName: this.webRtcCallSession.toName,\n remoteCallerNumber: this.webRtcCallSession.to,\n userVariables: {\n memberCallId: this.webRtcCallSession.id,\n memberId,\n ...this.webRtcCallSession.options.userVariables,\n ...PreferencesContainer.instance.userVariables\n },\n screenShare: rtcPeerConnectionController.isScreenShare,\n additionalDevice: rtcPeerConnectionController.isAdditionalDevice,\n pingSupported: true,\n version: INVITE_VERSION\n };\n }\n\n public muteMainAudioInputDevice(): void {\n return this.mainPeerConnection.stopTrackSender('audio');\n }\n\n public muteMainVideoInputDevice(): void {\n return this.mainPeerConnection.stopTrackSender('video');\n }\n\n public async unmuteMainAudioInputDevice(): Promise<void> {\n return this.mainPeerConnection.restoreTrackSender('audio');\n }\n\n public async unmuteMainVideoInputDevice(): Promise<void> {\n return this.mainPeerConnection.restoreTrackSender('video');\n }\n\n public async addInputDevice(\n options: MediaOptions = { audio: false, video: true }\n ): Promise<string | undefined> {\n return this.initAdditionalPeerConnection('additional-device', options);\n }\n\n /**\n * Add a new input device to the main peer connection,\n * only if a device of the same kind is not present already.\n *\n * @see selectAudioInputDevice\n * @see selectVideoInputDevice\n * @param options\n */\n public async addMainInputDevices(options: MediaOptions = { audio: true }): Promise<void> {\n let deviceKind: 'audio' | 'video' | 'both' | undefined = undefined;\n\n const { mediaDirections } = this.mainPeerConnection;\n\n if (\n options.audio ??\n options.inputAudioDeviceConstraints ??\n (options.inputAudioStream && mediaDirections.audio.startsWith('send'))\n ) {\n deviceKind = 'audio';\n }\n if (\n options.video ??\n options.inputVideoDeviceConstraints ??\n (options.inputVideoStream && !mediaDirections.video.startsWith('send'))\n ) {\n deviceKind = deviceKind === 'audio' ? 'both' : 'video';\n }\n if (deviceKind) {\n this.mainPeerConnection.updateMediaDevicesOptions(options);\n await this.mainPeerConnection.restoreTrackSender(deviceKind);\n } else {\n const error = new InvalidParams('No valid device to be added');\n this.onError?.(error);\n throw error;\n }\n }\n\n public async addScreenMedia(options: MediaOptions = { audio: false }): Promise<void> {\n await this.initAdditionalPeerConnection('screenshare', options);\n }\n\n private async initAdditionalPeerConnection(\n propose: RTCPeerConnectionPropose,\n options: MediaOptions\n ): Promise<string | undefined> {\n let rtcPeerConnController: RTCPeerConnectionController | null = null;\n try {\n this._screenShareStatus$.next('starting');\n rtcPeerConnController = new RTCPeerConnectionController(\n {\n ...options,\n ...this.RTCPeerConnectionConfig,\n propose\n },\n undefined,\n this.deviceController\n );\n this.setupLocalDescriptionHandler(rtcPeerConnController);\n if (propose === 'screenshare') {\n this._screenShareId = rtcPeerConnController.id;\n }\n this._rtcPeerConnectionsMap.set(rtcPeerConnController.id, rtcPeerConnController);\n this._rtcPeerConnections$.next(Array.from(this._rtcPeerConnectionsMap.values()));\n this.subscribeTo(rtcPeerConnController.errors$, (error) => {\n this.onError?.(error);\n });\n await firstValueFrom(\n rtcPeerConnController.connectionState$.pipe(\n filter((state) => state === 'connected'),\n take(1),\n timeout(this._screenShareTimeoutMs)\n )\n );\n this._screenShareStatus$.next('started');\n logger.info('[WebRTCManager] Screen share started successfully.');\n return rtcPeerConnController.id;\n } catch (error) {\n logger.warn('[WebRTCManager] Error initializing additional peer connection:', error);\n this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));\n if (rtcPeerConnController) {\n rtcPeerConnController.destroy();\n }\n this._screenShareStatus$.next('none');\n }\n }\n\n public async removeInputDevices(id: string): Promise<void> {\n return this.removeAdditionalPeerConnection(id);\n }\n\n public removeMainInputDevice(options = { removeAudio: false, removeVideo: true }): void {\n let removeTrack: 'audio' | 'video' | 'both' | undefined = undefined;\n if (options.removeAudio) {\n removeTrack = 'audio';\n }\n if (options.removeVideo) {\n removeTrack = removeTrack === 'audio' ? 'both' : 'video';\n }\n\n if (removeTrack) {\n return this.mainPeerConnection.stopTrackSender(removeTrack, {\n updateTransceiverDirection: true\n });\n }\n }\n\n public async removeScreenMedia(): Promise<void> {\n if (!['starting', 'started'].includes(this._screenShareStatus$.value)) {\n logger.warn('[WebRTCManager] No active screen share to stop.');\n }\n if (!this._screenShareId) {\n logger.debug('[WebRTCManager] No screen share peer connection found.');\n return;\n }\n this._screenShareStatus$.next('stopping');\n await this.removeAdditionalPeerConnection(this._screenShareId);\n this._screenShareId = undefined;\n this._screenShareStatus$.next('none');\n }\n\n public async removeAdditionalPeerConnection(id: string): Promise<void> {\n const rtcPeerConnController = this._rtcPeerConnectionsMap.get(id);\n try {\n if (rtcPeerConnController) {\n await this.executeVertoBye(rtcPeerConnController);\n }\n } finally {\n rtcPeerConnController?.destroy();\n this._rtcPeerConnectionsMap.delete(id);\n this._rtcPeerConnections$.next(Array.from(this._rtcPeerConnectionsMap.values()));\n }\n }\n\n private async executeVertoBye(\n rtcPeerConnController: RTCPeerConnectionController,\n cause?: VertoByeCause\n ): Promise<void> {\n try {\n const causeParams = cause\n ? {\n cause: cause,\n cause_code: VertoByeCauseCodes[cause]\n }\n : {};\n\n await this.executeVerto(\n VertoBye({\n ...causeParams,\n dialogParams: this.dialogParams(rtcPeerConnController)\n })\n );\n } catch (error) {\n logger.warn(\n '[WebRTCManager] Call might already be disconnected, error sending Verto bye:',\n error\n );\n throw error;\n }\n }\n public async bye(cause?: VertoByeCause): Promise<void> {\n void this.attachManager.detach(this.webRtcCallSession);\n const rtcPeerConnController = this._rtcPeerConnectionsMap.get(this.webRtcCallSession.id);\n if (rtcPeerConnController) {\n await this.executeVertoBye(rtcPeerConnController, cause);\n }\n }\n\n public async sendDigits(dtmf: string): Promise<void> {\n const vertoInfoMessage = VertoInfo({\n sessid: this.webRtcCallSession.id,\n dialogParams: {\n callID: this.webRtcCallSession.id\n },\n dtmf\n });\n\n try {\n await this.executeVerto(vertoInfoMessage);\n } catch (error) {\n logger.warn('[WebRTCManager] Error sending DTMF digits:', error);\n throw error;\n }\n }\n\n public async transfer(options: TransferOptions): Promise<void> {\n const message = VertoModify({\n ...options,\n dialogParams: this.dialogParams(this.mainPeerConnection),\n action: 'transfer'\n });\n try {\n logger.debug('[WebRTCManager] Transferring call with options:', options);\n await this.executeVerto(message);\n } catch (error) {\n logger.error('[WebRTCManager] Error transferring call:', error);\n throw error;\n }\n }\n\n public destroy(): void {\n this._rtcPeerConnectionsMap.forEach((rtcPeerConnController) => {\n rtcPeerConnController.destroy();\n });\n this._rtcPeerConnectionsMap.clear();\n this._rtcPeerConnections$.complete();\n super.destroy();\n }\n}\n","import { Participant, SelfParticipant, type ExecuteMethod } from '../core/entities/Participant';\n\nimport type { DeviceController } from '../interfaces/DeviceController';\nimport type { VertoManager } from '../interfaces/VertoManager';\n\n/**\n * Factory for creating Participant instances with proper dependency injection\n * Eliminates circular dependency between Call and Participant\n */\nexport class ParticipantFactory {\n constructor(\n private executeMethod: ExecuteMethod,\n private vertoManager: VertoManager,\n private deviceController: DeviceController\n ) {}\n\n /**\n * Create a self participant (the local user in the call)\n */\n public createSelfParticipant(id: string): SelfParticipant {\n return new SelfParticipant(id, this.executeMethod, this.vertoManager, this.deviceController);\n }\n\n /**\n * Create a remote participant\n */\n public createParticipant(id: string): Participant {\n return new Participant(id, this.executeMethod, this.deviceController);\n }\n}\n","import { filter, firstValueFrom, from, map, merge, share, takeUntil, tap } from 'rxjs';\nimport { v4 as uuid } from 'uuid';\n\nimport { Destroyable } from '../../behaviors/Destroyable';\nimport { ParticipantFactory } from '../../managers/ParticipantFactory';\nimport { filterAs } from '../../operators';\nimport { getValueFrom } from '../../utils/getValueFrom';\nimport { getLogger } from '../../utils/logger';\nimport { InvalidParams, UnimplementedError } from '../errors';\nimport { buildRPCRequest } from '../RPCMessages';\nimport {\n isCallStateMetadata,\n isCallUpdatedMetadata,\n isLayoutChangedMetadata,\n isMemberJoinedMetadata,\n isMemberLeftMetadata,\n isMemberTalkingMetadata,\n isMemberUpdatedMetadata,\n isSignalwireCallMetadata,\n isWebrtcMessageMetadata\n} from '../RPCMessages/guards/events.guards';\n\nimport type { Address } from './Address';\nimport type { Participant, SelfParticipant } from './Participant';\nimport type { ClientSession } from '../../interfaces/ClientSession';\nimport type { DeviceController } from '../../interfaces/DeviceController';\nimport type { JSONRPCParams } from '../RPCMessages';\nimport type {\n CallStatus,\n CallOptions,\n CallManager,\n CallParticipant,\n CallSelfParticipant\n} from './types/call.types';\nimport type { WebRTCVerto } from '../../interfaces/WebRTCVerto';\nimport type { CallEventsManager } from '../../managers/CallEventsManager';\nimport type { TransferOptions } from '../../managers/types/verto-manager.types';\nimport type { JSONRPCRequest, JSONRPCResponse } from '../RPCMessages/types/base';\nimport type { LayoutLayer } from '../RPCMessages/types/common';\nimport type {\n CallStatePayload,\n CallUpdatedPayload,\n LayoutChangedPayload,\n MemberJoinedPayload,\n MemberLeftPayload,\n MemberTalkingPayload,\n MemberUpdatedPayload\n} from '../RPCMessages/types/events';\nimport type { CallDirection, VideoPosition } from '../types/call.types';\nimport type { MediaDirections } from '../types/media.types';\nimport type { PendingRPCOptions } from '../utils';\nimport type { Observable, BehaviorSubject } from 'rxjs';\n\nconst logger = getLogger();\n\n/**\n * Manager instances returned by initialization callback\n */\nexport interface CallManagers {\n vertoManager: WebRTCVerto;\n callEventsManager: CallEventsManager;\n}\n\n/**\n * Initialization callback that creates managers for a Call instance\n * @param call - The WebRTCCall instance being initialized\n * @returns Manager instances for the call\n */\nexport type ManagerInitializer = (call: WebRTCCall) => CallManagers;\n\n/**\n * Required initialization configuration for Call constructor.\n * Calls must be created via {@link CallFactory} which provides these dependencies.\n */\nexport interface CallInitialization {\n /**\n * Callback function that creates and wires manager instances\n */\n initializeManagers: ManagerInitializer;\n /**\n * Device controller for media device access\n */\n deviceController: DeviceController;\n}\n\n/**\n * Concrete WebRTC call implementation.\n *\n * Manages the full lifecycle of a call including signaling, media streams,\n * participants, layout, and event routing. Created via {@link SignalWire.dial}\n * or received as an inbound call.\n */\nexport class WebRTCCall extends Destroyable implements CallManager {\n /** Unique identifier for this call. */\n public readonly id: string;\n /** Destination URI this call was placed to. */\n public to?: string;\n protected readonly participantsMap = new Map<string, Participant>();\n private vertoManager!: WebRTCVerto;\n private callEventsManager!: CallEventsManager;\n private participantFactory: ParticipantFactory;\n private _errors$ = this.createSubject<Error>();\n private _status$: BehaviorSubject<CallStatus>;\n private _answered$ = this.createReplaySubject<boolean>();\n private _holdState = false;\n\n constructor(\n public clientSession: ClientSession,\n public options: CallOptions,\n initialization: CallInitialization,\n public address?: Address\n ) {\n super();\n this.id = options.callId ?? uuid();\n this.to = options.to;\n\n const managers = initialization.initializeManagers(this);\n this.vertoManager = managers.vertoManager;\n this.callEventsManager = managers.callEventsManager;\n\n if (options.initOffer) {\n this._status$ = this.createBehaviorSubject<CallStatus>('ringing');\n } else {\n this._status$ = this.createBehaviorSubject<CallStatus>('new');\n }\n\n const { deviceController } = initialization;\n\n // Create participant factory with bound executeMethod\n this.participantFactory = new ParticipantFactory(\n this.executeMethod.bind(this),\n this.vertoManager,\n deviceController\n );\n }\n\n /** Observable stream of errors from media, signaling, and peer connection layers. */\n public get errors$(): Observable<Error> {\n return this._errors$.asObservable();\n }\n\n /** @internal Push an error to the call's error stream. */\n public emitError(error: Error): void {\n this._errors$.next(error);\n }\n\n /** Whether this call is `'inbound'` or `'outbound'`. */\n public get direction(): CallDirection {\n return this.options.initOffer ? 'inbound' : 'outbound';\n }\n\n /** Observable of the address associated with this call. */\n public get address$(): Observable<Address | undefined> {\n return from([this.address]);\n }\n\n /** Display name of the caller. */\n public get fromName(): string | undefined {\n return this.options.fromName;\n }\n\n /** Address URI of the caller. */\n public get from(): string | undefined {\n return this.options.from;\n }\n\n /** Display name of the callee. */\n public get toName(): string | undefined {\n return this.options.toName;\n }\n\n /** Toggles whether incoming video is received. @throws {UnimplementedError} Not yet implemented. */\n // eslint-disable-next-line @typescript-eslint/require-await\n public async toggleIncomingVideo(): Promise<void> {\n throw new UnimplementedError();\n }\n\n /** Toggles whether incoming audio is received. @throws {UnimplementedError} Not yet implemented. */\n // eslint-disable-next-line @typescript-eslint/require-await\n public async toggleIncomingAudio(): Promise<void> {\n throw new UnimplementedError();\n }\n\n /** @internal Registers an additional call ID for event routing. */\n public addCallId(callId: string): void {\n this.callEventsManager.addCallId(callId);\n }\n\n /** List of capabilities available in the current call. */\n public get capabilities(): string[] {\n return this.callEventsManager.capabilities;\n }\n\n /** Current snapshot of all participants in the call. */\n public get participants(): CallParticipant[] {\n return Array.from(this.participantsMap.values());\n }\n\n /** The local participant, or `null` if not yet joined. */\n public get self(): CallSelfParticipant | null {\n return this.callEventsManager.self;\n }\n\n async toggleLock(): Promise<void> {\n const method = this.locked ? 'call.unlock' : 'call.lock';\n await this.executeMethod(this.selfId ?? '', method, {});\n throw new UnimplementedError();\n }\n\n async toggleHold(): Promise<void> {\n if (this._holdState) {\n await this.vertoManager.unhold();\n } else {\n await this.vertoManager.hold();\n }\n this._holdState = !this._holdState;\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async startRecording(): Promise<void> {\n // NEEDS check backend API status\n throw new UnimplementedError();\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async startStreaming(): Promise<void> {\n // V3 VIDEO\n // NEEDS check backend API status\n throw new UnimplementedError();\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async setMeta(_meta: Record<string, unknown>): Promise<void> {\n // NEEDS backend implementation\n throw new UnimplementedError();\n }\n // eslint-disable-next-line @typescript-eslint/require-await\n async updateMeta(_meta: Record<string, unknown>): Promise<void> {\n // NEEDS backend implementation\n throw new UnimplementedError();\n }\n\n /** Observable of layout layer positions for all participants. */\n public get layoutLayers$(): Observable<LayoutLayer[]> {\n return this.callEventsManager.layoutLayers$;\n }\n\n /** Current snapshot of layout layers. */\n public get layoutLayers(): LayoutLayer[] {\n return this.callEventsManager.layoutLayers;\n }\n\n /** Executes a Verto RPC method targeting a specific participant. */\n public async executeMethod<T extends JSONRPCResponse = JSONRPCResponse>(\n target: string,\n method: string,\n args: Record<string, unknown>\n ): Promise<T> {\n const params = this.buildMethodParams(target, args);\n\n const request = buildRPCRequest({\n method,\n params\n });\n\n try {\n return await this.clientSession.execute(request);\n } catch (error) {\n logger.error(`[Call] Error executing method ${method} with params`, params, error);\n throw error;\n }\n }\n\n private buildMethodParams(target: string, args: Record<string, unknown>): JSONRPCParams {\n const reference = {\n node_id: this.nodeId,\n call_id: this.id\n };\n return {\n ...args,\n self: {\n ...reference,\n member_id: this.vertoManager.selfId\n },\n target: {\n ...reference,\n member_id: target\n }\n };\n }\n\n /** Observable of the current call status (e.g. `'ringing'`, `'connected'`). */\n public get status$(): Observable<CallStatus> {\n return this.cachedObservable('status$', () =>\n merge(this._status$.asObservable(), this.vertoManager.signalingStatus$)\n );\n }\n /** Observable of the participants list, emits on join/leave/update. */\n public get participants$(): Observable<CallParticipant[]> {\n return this.callEventsManager.participants$;\n }\n /** Observable of the local (self) participant. */\n public get self$(): Observable<CallSelfParticipant> {\n return this.callEventsManager.self$;\n }\n /** Observable indicating whether the call is being recorded. */\n public get recording$(): Observable<boolean> {\n return this.callEventsManager.recording$;\n }\n\n /** Observable indicating whether the call is being streamed. */\n public get streaming$(): Observable<boolean> {\n return this.callEventsManager.streaming$;\n }\n\n /** Observable indicating whether raise-hand priority is active. */\n public get raiseHandPriority$(): Observable<boolean> {\n return this.callEventsManager.raiseHandPriority$;\n }\n\n /** Observable indicating whether the call room is locked. */\n public get locked$(): Observable<boolean> {\n return this.callEventsManager.locked$;\n }\n\n /** Observable of custom metadata associated with the call. */\n public get meta$(): Observable<Record<string, unknown>> {\n return this.callEventsManager.meta$;\n }\n\n /** Observable of the call's capability flags. */\n public get capabilities$(): Observable<string[]> {\n return this.callEventsManager.capabilities$;\n }\n\n /** Observable of the current layout name. */\n public get layout$(): Observable<string> {\n return this.callEventsManager.layout$;\n }\n\n /** Current call status. */\n public get status(): CallStatus {\n return this._status$.value;\n }\n\n /** Whether the call is currently being recorded. */\n public get recording(): boolean {\n return this.callEventsManager.recording;\n }\n\n /** Whether the call is currently being streamed. */\n public get streaming(): boolean {\n return this.callEventsManager.streaming;\n }\n\n /** Whether raise-hand priority is active. */\n public get raiseHandPriority(): boolean {\n return this.callEventsManager.raiseHandPriority;\n }\n\n /** Whether the call room is locked. */\n public get locked(): boolean {\n return this.callEventsManager.locked;\n }\n\n /** Current custom metadata of the call. */\n public get meta(): Record<string, unknown> {\n return this.callEventsManager.meta;\n }\n\n /** Current layout name, or `undefined` if not set. */\n public get layout(): string | undefined {\n return this.callEventsManager.layout;\n }\n\n /** Observable of available layout names. */\n public get layouts$(): Observable<string[]> {\n return this.callEventsManager.layouts$;\n }\n\n /** Current snapshot of available layout names. */\n public get layouts(): string[] {\n return this.callEventsManager.layouts;\n }\n\n /** Observable of the local media stream (camera/microphone). */\n public get localStream$(): Observable<MediaStream> {\n return this.vertoManager.localStream$;\n }\n /** Current local media stream, or `null` if not available. */\n public get localStream(): MediaStream | null {\n return this.vertoManager.localStream;\n }\n /** Observable of the remote media stream from the far end. */\n public get remoteStream$(): Observable<MediaStream> {\n return this.vertoManager.remoteStream$;\n }\n /** Current remote media stream, or `null` if not available. */\n public get remoteStream(): MediaStream | null {\n return this.vertoManager.remoteStream;\n }\n\n /** @internal */\n public createParticipant(\n memberId: string,\n selfId?: string | null\n ): Participant | SelfParticipant {\n // Use provided selfId (from call.joined event) or fall back to vertoManager.selfId\n const effectiveSelfId = selfId ?? this.vertoManager.selfId;\n if (memberId === effectiveSelfId) {\n return this.participantFactory.createSelfParticipant(memberId);\n }\n return this.participantFactory.createParticipant(memberId);\n }\n\n /** Observable of the current audio/video send/receive directions. */\n public get mediaDirections$(): Observable<MediaDirections> {\n return this.vertoManager.mediaDirections$;\n }\n\n /** Current audio/video send/receive directions. */\n public get mediaDirections(): MediaDirections {\n return this.vertoManager.mediaDirections;\n }\n\n protected get participantsId$(): Observable<string[]> {\n return this.cachedObservable('participantsId$', () =>\n this.participants$.pipe(\n map((participants) => participants.map((participant) => participant.id))\n )\n );\n }\n\n /** Executes a raw JSON-RPC request on the client session. */\n public async execute<T extends JSONRPCResponse = JSONRPCResponse>(\n request: JSONRPCRequest,\n options?: PendingRPCOptions\n ): Promise<T> {\n return this.clientSession.execute(request, options);\n }\n\n /** Observable of the local participant's member ID. */\n public get selfId$(): Observable<string | null> {\n return this.vertoManager.selfId$;\n }\n\n /** Local participant's member ID, or `null` if not joined. */\n public get selfId(): string | null {\n return this.vertoManager.selfId;\n }\n\n /** Observable of the server node ID handling this call. */\n public get nodeId$(): Observable<string | null> {\n return this.vertoManager.nodeId$;\n }\n\n /** Server node ID handling this call, or `null`. */\n public get nodeId(): string | null {\n return this.vertoManager.nodeId;\n }\n\n private isCallSessionEvent(event: unknown): event is Event {\n try {\n logger.debug('[Call] Checking if event is for this call session:', event);\n const callId =\n getValueFrom<string>(event, 'params.params.callID') ??\n getValueFrom<string>(event, 'params.call_id');\n const roomSessionId = getValueFrom<string>(event, 'params.room_session_id');\n logger.debug(\n `[Call] Extracted session identifiers callID: ${callId} and roomSessionID: ${roomSessionId} from event:`\n );\n return (\n callId === this.id ||\n (!!callId && this.callEventsManager.isCallIdValid(callId)) ||\n (!!roomSessionId && this.callEventsManager.isRoomSessionIdValid(roomSessionId))\n );\n } catch (error) {\n logger.error('[Call] Error checking if event is for this call session:', error);\n return false;\n }\n }\n\n private get callSessionEvents$() {\n return this.cachedObservable('callSessionEvents$', () =>\n this.clientSession.signalingEvent$.pipe(\n filter((event) => this.isCallSessionEvent(event)),\n tap((event) => logger.debug('[Call] Received call session event:', event)),\n takeUntil(this.destroyed$),\n share()\n )\n );\n }\n\n /** Observable of call-updated events. */\n public get callUpdated$(): Observable<CallUpdatedPayload> {\n return this.cachedObservable('callUpdated$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isCallUpdatedMetadata, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n /** Observable of member-joined events. */\n public get memberJoined$(): Observable<MemberJoinedPayload> {\n return this.cachedObservable('memberJoined$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isMemberJoinedMetadata, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Observable of member-left events. */\n public get memberLeft$(): Observable<MemberLeftPayload> {\n return this.cachedObservable('memberLeft$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isMemberLeftMetadata, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n /** Observable of member-updated events (mute, volume, etc.). */\n public get memberUpdated$(): Observable<MemberUpdatedPayload> {\n return this.cachedObservable('memberUpdated$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isMemberUpdatedMetadata, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Observable of member-talking events (speech start/stop). */\n public get memberTalking$(): Observable<MemberTalkingPayload> {\n return this.cachedObservable('memberTalking$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isMemberTalkingMetadata, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Observable of call state-change events. */\n public get callStates$(): Observable<CallStatePayload> {\n return this.cachedObservable('callStates$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isCallStateMetadata, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Observable of layout-changed events. */\n public get layoutUpdates$(): Observable<LayoutChangedPayload> {\n return this.cachedObservable('layoutUpdates$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isLayoutChangedMetadata, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Underlying `RTCPeerConnection`, for advanced use cases. */\n public get rtcPeerConnection(): RTCPeerConnection | undefined {\n return this.vertoManager.mainPeerConnection.peerConnection;\n }\n /** Observable of raw signaling events as plain objects. */\n public get signalingEvent$(): Observable<Record<string, unknown>> {\n return this.cachedObservable('signalingEvent$', () =>\n this.callEvent$.pipe(\n map((event) => JSON.parse(JSON.stringify(event)) as Record<string, unknown>)\n )\n );\n }\n\n /** Observable of WebRTC-specific signaling messages. */\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n public get webrtcMessages$() {\n return this.cachedObservable('webrtcMessages$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isWebrtcMessageMetadata, 'params'),\n tap((event) => logger.debug('[Call] Event is a WebRTC message event:', event)),\n takeUntil(this.destroyed$),\n share()\n )\n );\n }\n\n /** Observable of call-level signaling events. */\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n public get callEvent$() {\n return this.cachedObservable('callEvent$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isSignalwireCallMetadata, 'params'),\n tap((event) => logger.debug('[Call] Event is a call event:', event)),\n takeUntil(this.destroyed$),\n share()\n )\n );\n }\n\n /** Observable of layout-changed signaling events. */\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n public get layoutEvent$() {\n return this.cachedObservable('layoutEvent$', () =>\n this.callEvent$.pipe(filterAs(isLayoutChangedMetadata, 'params'))\n );\n }\n\n /** Hangs up the call and releases all resources. */\n async hangup(): Promise<void> {\n this._status$.next('disconnecting');\n try {\n await this.vertoManager.bye();\n } finally {\n this._status$.next('destroyed');\n this.destroy();\n }\n }\n\n /** Sends DTMF digits (e.g. `'1234#'`) on the call. */\n async sendDigits(dtmf: string): Promise<void> {\n return this.vertoManager.sendDigits(dtmf);\n }\n\n /** Accepts an inbound call. */\n public answer(): void {\n this._answered$.next(true);\n }\n\n /** Rejects an inbound call. */\n public reject(): void {\n this._answered$.next(false);\n }\n\n /** Observable that emits `true` when answered, `false` when rejected. */\n public get answered$(): Observable<boolean> {\n return this._answered$.asObservable();\n }\n\n /**\n * Sets the call layout and participant positions.\n * @param layout - Layout name (must be one of {@link layouts}).\n * @param positions - Map of member IDs to video positions.\n */\n async setLayout(layout: string, positions: Record<string, VideoPosition>): Promise<void> {\n if (!this.layouts.includes(layout)) {\n throw new InvalidParams(\n `Layout ${layout} is not available in the current call layouts: ${this.layouts.join(', ')}`\n );\n }\n\n const selfId = await firstValueFrom(\n this.selfId$.pipe(filter((id): id is string => id !== null))\n );\n\n await this.executeMethod(selfId, 'call.layout.set', {\n layout,\n positions\n });\n }\n\n /** Transfers the call to other participants. */\n public async transfer(options: TransferOptions): Promise<void> {\n return this.vertoManager.transfer(options);\n }\n\n /** Destroys the call, releasing all resources and subscriptions. */\n public destroy(): void {\n this.vertoManager.destroy();\n this.callEventsManager.destroy();\n this.participantsMap.clear();\n super.destroy();\n }\n}\n","import { CallEventsManager } from './CallEventsManager';\nimport { WebRTCVertoManager } from './VertoManager';\nimport { WebRTCCall } from '../core/entities/Call';\n\nimport type { AttachManager } from './AttachManager';\nimport type { Address } from '../core/entities/Address';\nimport type { CallOptions } from '../core/entities/types/call.types';\nimport type { ClientSession } from '../interfaces/ClientSession';\nimport type { DeviceController } from '../interfaces/DeviceController';\n\n/**\n * Factory for creating WebRTCCall instances with proper manager wiring.\n * Eliminates circular dependencies by centralizing Call and Manager creation.\n */\nexport class CallFactory {\n constructor(\n private sessionManager: ClientSession,\n private deviceController: DeviceController,\n private attachManager: AttachManager\n ) {}\n\n /**\n * Create a new WebRTCCall with properly initialized managers\n */\n createCall(address: Address | undefined, options: CallOptions): WebRTCCall {\n const call = new WebRTCCall(\n this.sessionManager,\n options,\n {\n initializeManagers: (callInstance: WebRTCCall) => {\n const vertoManager = new WebRTCVertoManager(\n callInstance,\n this.attachManager,\n this.deviceController,\n {\n nodeId: options.nodeId,\n onError: (error: Error) => {\n callInstance.emitError(error);\n }\n }\n );\n\n const callEventsManager = new CallEventsManager(callInstance);\n\n return {\n vertoManager,\n callEventsManager\n };\n },\n deviceController: this.deviceController\n },\n address\n );\n\n return call;\n }\n}\n","import {\n defer,\n distinctUntilChanged,\n filter,\n from,\n map,\n ReplaySubject,\n shareReplay,\n Subject,\n takeUntil,\n skip,\n pipe\n} from 'rxjs';\n\nimport { Destroyable } from './Destroyable';\nimport { GET_PARAMS } from '../controllers/HTTPRequestController';\nimport { CollectionFetchError } from '../core/errors';\nimport { getLogger } from '../utils/logger';\n\nimport type {\n PaginatedResponse,\n Entity,\n FetchController,\n Collection\n} from './types/collection.types';\nimport type { HTTPRequestController } from '../controllers/HTTPRequestController';\nimport type { Observable, Subscription } from 'rxjs';\n\nconst logger = getLogger();\n\nexport class Fetcher<T extends Entity = Entity> implements FetchController<Entity> {\n private nextUrl?: string;\n public hasMore: boolean | undefined;\n public filter = (_item: Entity): _item is T => true;\n public mapper = (item: unknown): T => item as T;\n\n constructor(\n protected endpoint: string,\n params: string,\n protected http: HTTPRequestController\n ) {\n this.nextUrl = `${this.endpoint}?${params}`;\n }\n\n public async next(): Promise<T[]> {\n if (!this.nextUrl) return [];\n\n const response = await this.http.request({\n ...GET_PARAMS,\n url: this.nextUrl\n });\n if (response.ok && !!response.body) {\n const result = JSON.parse(response.body) as PaginatedResponse<T>;\n this.nextUrl = result.links.next;\n const filtered = result.data.filter(this.filter);\n return filtered.map(this.mapper);\n }\n logger.error('Failed to fetch entity');\n return [];\n }\n\n public async id(v: unknown): Promise<T | undefined> {\n const response = await this.http.request({\n ...GET_PARAMS,\n url: `${this.endpoint}/${String(v)}`\n });\n if (response.ok && !!response.body) {\n return JSON.parse(response.body) as T;\n }\n }\n}\n\nexport class EntityCollection<T extends Entity = Entity>\n extends Destroyable\n implements Collection<T>\n{\n public loading$ = this.createBehaviorSubject<boolean>(false);\n public values$ = this.createReplaySubject<T[]>(1);\n public hasMore$: Observable<boolean>;\n private collectionData = new Map<string, T>();\n private observablesRegistry = new Map<string, ReplaySubject<T>>();\n private updateSubscription: Subscription;\n private upsertData = (data: Partial<T>) => {\n if (!data.id) return;\n const existing = this.collectionData.get(data.id) ?? {};\n const updated = { ...existing, ...data } as T;\n this.collectionData.set(data.id, updated);\n this.observablesRegistry.get(data.id)?.next(updated);\n this.values$.next(Array.from(this.collectionData.values()));\n };\n\n private _destroy$ = new Subject<void>();\n constructor(\n private fetchController: FetchController<T>,\n private update$: Observable<Partial<T>>,\n private readonly onError?: (error: Error) => void\n ) {\n super();\n this.updateSubscription = this.update$.subscribe(this.upsertData);\n this.loading$.next(false);\n this.hasMore$ = defer(() => from(this.init())).pipe(shareReplay(1), takeUntil(this._destroy$));\n }\n public get loading(): boolean {\n return this.loading$.value;\n }\n\n public get hasMore(): boolean {\n return this.fetchController.hasMore ?? true;\n }\n\n public get updated$(): Observable<void> {\n return this.cachedObservable('updated$', () =>\n this.loading$.pipe(\n distinctUntilChanged(),\n skip(1), // skiping the loading === true event\n filter((loading) => !loading),\n map(() => void 0),\n takeUntil(this._destroy$)\n )\n );\n }\n\n public get values(): T[] {\n return Array.from(this.collectionData.values());\n }\n\n private async init(): Promise<boolean> {\n if (this.fetchController.hasMore === false) {\n return Promise.resolve(false);\n }\n await this.fetchMore();\n return this.fetchController.hasMore ?? true;\n }\n\n private async fetchMore(): Promise<void> {\n try {\n this.loading$.next(true);\n const datas = await this.fetchController.next();\n datas.forEach(this.upsertData);\n this.loading$.next(false);\n } catch (error) {\n logger.error(`Failed to fetch initial collection data`, error);\n this.loading$.next(false);\n this.onError?.(new CollectionFetchError('fetchMore', error));\n }\n }\n\n private async tryFetch(key: keyof FetchController<T>, value: unknown): Promise<T | undefined> {\n try {\n this.loading$.next(true);\n const data = await this.fetchController[key]?.(value);\n this.loading$.next(false);\n if (data) {\n this.upsertData(data);\n }\n return data;\n } catch (error) {\n logger.error(`Failed to fetch data for (${String(key)}:${String(value)}) :`, error);\n this.loading$.next(false);\n this.onError?.(new CollectionFetchError(`tryFetch(${String(key)})`, error));\n }\n }\n\n public get$(id: string): Observable<T> | undefined {\n if (!this.observablesRegistry.has(id)) {\n this.observablesRegistry.set(id, new ReplaySubject<T>(1));\n const data = this.collectionData.get(id);\n if (data) {\n this.observablesRegistry.get(id)?.next(data);\n } else {\n void this.tryFetch('id', id);\n }\n }\n return this.observablesRegistry.get(id)?.asObservable();\n }\n\n public async find$(key: keyof T, value: unknown): Promise<Observable<T> | undefined> {\n const data =\n Array.from(this.collectionData.values()).find((item) => item[key] === value) ??\n (await this.tryFetch(key, value));\n\n return data ? this.get$(data.id) : undefined;\n }\n\n public loadMore(): void {\n if (this.fetchController.hasMore !== false) {\n void this.fetchMore();\n }\n }\n\n public destroy(): void {\n this._destroy$.next();\n this._destroy$.complete();\n this.updateSubscription.unsubscribe();\n this.loading$.complete();\n this.observablesRegistry.forEach((subject) => subject.complete());\n }\n}\n\nexport class EntityCollectionTransformed<\n O extends Entity = Entity,\n T extends Entity = Entity\n> implements Collection<T> {\n private _values$?: Observable<T[]>;\n\n constructor(\n private originalCollection: EntityCollection<O>,\n private filter: (i: unknown) => i is O = (i): i is O => !!i,\n private mapper: (item: O) => T = (item) => item as unknown as T\n ) {}\n\n public get loading$(): Observable<boolean> {\n return this.originalCollection.loading$;\n }\n\n public get loading(): boolean {\n return this.originalCollection.loading;\n }\n public get hasMore$(): Observable<boolean> {\n return this.originalCollection.hasMore$;\n }\n public get hasMore(): boolean {\n return this.originalCollection.hasMore;\n }\n public get values(): T[] {\n return this.originalCollection.values.filter(this.filter).map(this.mapper);\n }\n public get values$(): Observable<T[]> {\n return (this._values$ ??= this.originalCollection.values$.pipe(\n map((values) => values.filter(this.filter).map(this.mapper))\n ));\n }\n\n public get$(id: string): Observable<T> | undefined {\n const original$ = this.originalCollection.get$(id);\n return !original$ ? original$ : original$.pipe(pipe(filter(this.filter), map(this.mapper)));\n }\n\n public async find$(key: keyof T, value: unknown): Promise<Observable<T> | undefined> {\n const original$ = await this.originalCollection.find$(key as keyof O, value);\n return !original$ ? original$ : original$.pipe(pipe(filter(this.filter), map(this.mapper)));\n }\n public loadMore(): void {\n this.originalCollection.loadMore();\n }\n public destroy(): void {\n this.originalCollection.destroy();\n }\n}\n","import { defer, map, shareReplay, takeUntil, type Observable } from 'rxjs';\n\nimport { EntityCollectionTransformed } from '../../behaviors/Collection';\nimport { Destroyable } from '../../behaviors/Destroyable';\nimport { filterNull } from '../../operators';\nimport { DependencyError, UnimplementedError } from '../errors';\n\nimport type { CallState } from './types/call.types';\nimport type { AddressProvider } from '../../interfaces/AddressProvider';\nimport type {\n ConversationMessageCollection,\n ConversationsProvider\n} from '../../interfaces/Conversations';\nimport type { GetAddressResponse } from '../types/address.types';\nimport type { ResourceType } from '../types/common.types';\nimport type {\n AddressHistory,\n AddressHistoryCollection,\n GetConversationMessageResponse,\n TextMessage,\n TextMessageCollection\n} from '../types/conversation.types';\n\ntype AddressState = GetAddressResponse;\n/**\n * Represents a contact or room in the directory.\n *\n * Provides identity metadata, conversation history, text messaging,\n * and activity state for an address entry.\n */\nexport class Address extends Destroyable {\n private initConversationMessages = async (): Promise<ConversationMessageCollection> => {\n this._conversationMessages =\n this._conversationMessages ??\n (await this.conversationManager.getConversationMessageCollection(this.id));\n if (this._conversationMessages.hasMore) {\n this._conversationMessages.loadMore();\n }\n return this._conversationMessages;\n };\n\n /** Observable of text messages for this address. Lazily loads conversation data. */\n public textMessages$ = defer(this.initConversationMessages).pipe(\n map(() => this.textMessage),\n shareReplay(1),\n takeUntil(this.destroyed$)\n );\n /** Observable of call history for this address. Lazily loads conversation data. */\n public history$ = defer(this.initConversationMessages).pipe(\n map(() => this.history),\n shareReplay(1),\n takeUntil(this.destroyed$)\n );\n private _conversationMessages?: ConversationMessageCollection;\n\n private _state$ = this.createBehaviorSubject<AddressState | null>(null);\n\n private _history$?: AddressHistoryCollection<Address>;\n\n private _textMessages$?: TextMessageCollection<Address>;\n\n // FIXME after presence API is available\n // this should be a dynamic view of the address existing calls,\n // independent if the user is on the call or not.\n // private _callsStates$ = this.createBehaviorSubject<CallState[]>([]);\n\n constructor(\n private readonly addressId: string,\n private conversationManager: ConversationsProvider,\n private addressProvider: AddressProvider<Address>\n ) {\n super();\n }\n\n /** @internal */\n public upnext(state: Partial<AddressState>): void {\n const update = {\n ...this._state$.value,\n ...state\n } as AddressState;\n this._state$.next(update);\n }\n\n /** @internal */\n public get state(): AddressState | null {\n return this._state$.value;\n }\n\n /** Unique address identifier. */\n public get id(): string {\n return this.addressId;\n }\n /** Address name (resource identifier). */\n public get name(): string {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.name;\n }\n\n /** ISO timestamp of when the address was created. */\n public get createdAt(): string {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.created_at;\n }\n\n /** Default communication channel URI (video for rooms, audio otherwise). */\n public get defaultChannel(): string | undefined {\n return this.type === 'room' ? this.channels.video : this.channels.audio;\n }\n\n /** Observable of the human-readable display name. */\n public get displayName$(): Observable<string> {\n return this.cachedObservable('displayName$', () =>\n this._state$.pipe(\n filterNull(),\n map((state) => state.display_name),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Human-readable display name. */\n public get displayName(): string {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.display_name;\n }\n\n /** Observable of the preview image URL. */\n public get previewUrl$(): Observable<string | undefined> {\n return this.cachedObservable('previewUrl$', () =>\n this._state$.pipe(\n filterNull(),\n map((state) => state.preview_url),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Preview image URL. */\n public get previewUrl(): string | undefined {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.preview_url;\n }\n\n /** Observable of the cover image URL. */\n public get coverUrl$(): Observable<string | undefined> {\n return this.cachedObservable('coverUrl$', () =>\n this._state$.pipe(\n filterNull(),\n shareReplay(1),\n map((state) => state.cover_url),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Cover image URL. */\n public get coverUrl(): string | undefined {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.cover_url;\n }\n\n /** Observable of the underlying resource ID. */\n public get resourceId$(): Observable<string> {\n return this.cachedObservable('resourceId$', () =>\n this._state$.pipe(\n filterNull(),\n shareReplay(1),\n map((state) => state.resource_id),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Underlying resource ID. */\n public get resourceId(): string {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.resource_id;\n }\n\n /** Observable of the resource type (e.g. `'room'`, `'subscriber'`). */\n public get type$(): Observable<ResourceType> {\n return this.cachedObservable('type$', () =>\n this._state$.pipe(\n filterNull(),\n shareReplay(1),\n map((state) => state.type),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Resource type (e.g. `'room'`, `'subscriber'`). */\n public get type(): ResourceType {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.type;\n }\n\n /** Observable of available communication channels (audio, video, messaging). */\n public get channels$(): Observable<{\n audio?: string;\n messaging?: string;\n video?: string;\n }> {\n return this.cachedObservable('channels$', () =>\n this._state$.pipe(\n filterNull(),\n shareReplay(1),\n map((state) => state.channels),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Available communication channels. */\n public get channels(): {\n audio?: string;\n messaging?: string;\n video?: string;\n } {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.channels;\n }\n\n /** Whether the address (room) is locked. */\n public get locked(): boolean {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.locked;\n }\n\n /** Observable indicating whether the address (room) is locked. */\n public get locked$(): Observable<boolean> {\n return this.cachedObservable('locked$', () =>\n this._state$.pipe(\n filterNull(),\n shareReplay(1),\n map((state) => state.locked),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Sends a text message to this address. */\n public async sendText(text: string): Promise<void> {\n return this.conversationManager.sendText(text, this.id);\n }\n\n /** Collection of text messages for this address, with pagination support. */\n public get textMessage():\n | EntityCollectionTransformed<GetConversationMessageResponse, TextMessage<Address>>\n | undefined {\n if (!this._conversationMessages) {\n return;\n }\n this._textMessages$ =\n this._textMessages$ ??\n new EntityCollectionTransformed<GetConversationMessageResponse, TextMessage<Address>>(\n this._conversationMessages,\n (item): item is GetConversationMessageResponse =>\n (item as GetConversationMessageResponse).subtype === 'chat',\n (item) =>\n ({\n id: item.id,\n text: item.text,\n created: item.ts,\n fromAddress$: this.addressProvider.get$(item.from_fabric_address_id)\n }) as TextMessage<Address>\n );\n return this._textMessages$;\n }\n\n /** Collection of call history entries for this address, with pagination support. */\n public get history():\n | EntityCollectionTransformed<GetConversationMessageResponse, AddressHistory<Address>>\n | undefined {\n if (!this._conversationMessages) {\n return;\n }\n this._history$ =\n this._history$ ??\n new EntityCollectionTransformed<GetConversationMessageResponse, AddressHistory<Address>>(\n this._conversationMessages,\n (item): item is GetConversationMessageResponse =>\n (item as GetConversationMessageResponse).subtype === 'log',\n (item) =>\n ({\n id: item.id,\n kind: item.kind,\n status: item.details.status,\n started: item.details.start_time,\n ended: item.details.end_time,\n fromAddress$: this.addressProvider.get$(item.from_fabric_address_id)\n }) as AddressHistory<Address>\n );\n return this._history$;\n }\n\n /** Observable of active call states for this address. @throws {UnimplementedError} Requires presence support. */\n public get activity$(): Observable<CallState[]> {\n // NEEDS Presence\n throw new UnimplementedError();\n }\n\n /** Active call states for this address. @throws {UnimplementedError} Requires presence support. */\n public get activity(): CallState[] {\n // NEEDS Presence\n throw new UnimplementedError();\n }\n}\n","import { filter, NEVER, Observable, race, take } from 'rxjs';\nimport { v4 as uuid } from 'uuid';\n\nimport { InvalidListenerError, RPCTimeoutError } from './errors';\nimport { Destroyable } from '../behaviors/Destroyable';\nimport { getLogger } from '../utils/logger';\n\nimport type { RPCConnectResult } from './RPCMessages';\nimport type { JSONRPCRequest, JSONRPCResponse } from './RPCMessages/types/base';\n\nconst logger = getLogger();\n\nexport async function callListener<T>(\n listener: ((value: T) => void) | ((value: T) => Promise<void>),\n value: T,\n onError?: (error: unknown) => void\n): Promise<void> {\n try {\n if (typeof listener !== 'function') {\n throw new InvalidListenerError();\n }\n await listener(value);\n } catch (error) {\n if (error instanceof InvalidListenerError) {\n logger.error(error.message);\n } else {\n logger.warn('Error calling listener:', error);\n }\n onError?.(error);\n }\n}\n\nexport const isRPCConnectResult = (e: unknown): e is RPCConnectResult => {\n logger.debug('isRPCConnectResult check:', e);\n if (!e || typeof e !== 'object') return false;\n\n // Check if this is a JSON-RPC response with a result property\n\n const result = e as RPCConnectResult;\n\n const is =\n typeof result.identity === 'string' &&\n typeof result.protocol === 'string' &&\n typeof result.authorization === 'object' &&\n typeof result.authorization.jti === 'string' &&\n typeof result.authorization.project_id === 'string' &&\n typeof result.authorization.fabric_subscriber === 'object';\n\n logger.debug('isRPCConnectResult check result:', is);\n return is;\n};\n\nexport interface PendingRPCOptions {\n /**\n * Timeout in milliseconds. Defaults to 5000ms (5 seconds).\n * If the response is not received within this time, the promise will reject with RPCTimeoutError.\n */\n timeoutMs?: number;\n\n /**\n * Optional AbortSignal for cancellation support.\n * If the signal is aborted, the promise will reject with an AbortError.\n */\n signal?: AbortSignal;\n}\n\nexport class PendingRPC<T extends JSONRPCResponse = JSONRPCResponse> {\n private static readonly defaultTimeoutMs = 5000;\n private id = uuid();\n\n public readonly request: JSONRPCRequest;\n public promise: Promise<T>;\n\n constructor(request: JSONRPCRequest, responses$: Observable<T>, options?: PendingRPCOptions) {\n logger.debug(\n `[PendingRPC(${this.id}) request:${request.id}: method:${request.method}] Creating PendingRPC`\n );\n this.request = request;\n\n const timeoutMs = options?.timeoutMs ?? PendingRPC.defaultTimeoutMs;\n const signal = options?.signal;\n\n this.promise = new Promise<T>((resolve, reject) => {\n // Check if already aborted\n if (signal?.aborted) {\n reject(new DOMException('The operation was aborted', 'AbortError'));\n return;\n }\n\n // Track if promise has been settled to prevent unhandled rejections\n let isSettled = false;\n\n // Create the main response observable\n const response$ = responses$.pipe(\n filter((result) => result.id === request.id),\n take(1)\n );\n\n // Create timeout observable\n const timeout$ = new Observable<never>((subscriber) => {\n const timer = setTimeout(() => {\n subscriber.error(new RPCTimeoutError(request.id, timeoutMs));\n }, timeoutMs);\n\n return () => clearTimeout(timer);\n });\n\n // Create abort observable if signal provided\n const abort$ = signal\n ? new Observable<never>((subscriber) => {\n const abortHandler = () => {\n subscriber.error(new DOMException('The operation was aborted', 'AbortError'));\n };\n signal.addEventListener('abort', abortHandler);\n\n return () => signal.removeEventListener('abort', abortHandler);\n })\n : NEVER; // Observable that never emits\n\n // Race between response, timeout, and abort\n const subscription = race(response$, timeout$, abort$).subscribe({\n next: (response) => {\n logger.debug(\n `[PendingRPC(${this.id}) request:${request.id}] Resolving promise with response:`,\n response\n );\n isSettled = true;\n resolve(response);\n subscription.unsubscribe();\n },\n error: (error) => {\n logger.debug(\n `[PendingRPC(${this.id}) request:${request.id}] Rejecting promise with error:`,\n error\n );\n isSettled = true;\n reject(error as Error);\n subscription.unsubscribe();\n },\n complete: () => {\n logger.debug(`[PendingRPC(${this.id}) request:${request.id}] Observable completed`);\n if (!isSettled) {\n reject(new RPCTimeoutError(request.id, timeoutMs));\n }\n subscription.unsubscribe();\n }\n });\n });\n }\n\n // Make it thenable (Promise-like)\n async then<TResult1 = JSONRPCResponse, TResult2 = never>(\n onfulfilled?: ((value: JSONRPCResponse) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): Promise<TResult1 | TResult2> {\n return this.promise.then(onfulfilled, onrejected);\n }\n\n async catch<TResult = never>(\n onrejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null\n ): Promise<JSONRPCResponse | TResult> {\n return this.promise.catch(onrejected);\n }\n\n async finally(onfinally?: (() => void) | null): Promise<JSONRPCResponse> {\n return this.promise.finally(onfinally);\n }\n}\n\n// Re-export Destroyable for backward compatibility\nexport { Destroyable };\n","import {\n catchError,\n combineLatest,\n defer,\n filter,\n firstValueFrom,\n from,\n lastValueFrom,\n map,\n share,\n shareReplay,\n take,\n takeUntil,\n tap,\n timeout\n} from 'rxjs';\n\nimport { CallFactory } from './CallFactory';\nimport { Address } from '../core/entities/Address';\nimport {\n AuthStateHandlerError,\n CallCreateError,\n DependencyError,\n UnexpectedError,\n VertoInviteHandlerError\n} from '../core/errors';\nimport { RPCConnect } from '../core/RPCMessages';\nimport {\n isSignalwireAuthorizationStateMetadata,\n isSignalwireRequest,\n isWebrtcMessageMetadata\n} from '../core/RPCMessages/guards/events.guards';\nimport { isVertoInviteMessage } from '../core/RPCMessages/guards/verto.guards';\nimport { Destroyable, isRPCConnectResult } from '../core/utils';\nimport { filterAs } from '../operators/filterEventAs';\nimport { throwOnRPCError } from '../operators/throwOnRPCError';\nimport { getLogger } from '../utils/logger';\n\nimport type { AttachManager } from './AttachManager';\nimport type { StorageManager } from './StorageManager';\nimport type { TransportManager } from './TransportManager';\nimport type { WebRTCCall } from '../core/entities/Call';\nimport type { Directory } from '../core/entities/Directory';\nimport type { Call, CallOptions } from '../core/entities/types/call.types';\nimport type {\n RPCConnectParams,\n RPCConnectAuthentication,\n Authorization\n} from '../core/RPCMessages';\nimport type { JSONRPCRequest, JSONRPCResponse } from '../core/RPCMessages/types/base';\nimport type { VertoInviteParams } from '../core/RPCMessages/types/verto';\nimport type { SDKCredential, JSONSerializable } from '../core/types/common.types';\nimport type { PendingRPCOptions } from '../core/utils';\nimport type { DeviceController } from '../interfaces/DeviceController';\nimport type { SessionState } from '../interfaces/SessionState';\nimport type { Observable } from 'rxjs';\n\nconst logger = getLogger();\n\nconst getAddressSearchURI = (options: CallOptions): string => {\n const to = options.to?.split('?')[0];\n const from = options.from?.startsWith('subscriber://')\n ? options.from.replace('subscriber://', '')\n : options.from;\n const name = to ?? from;\n if (!name) {\n throw new UnexpectedError('Error building Address name');\n }\n return name;\n};\n\nexport class ClientSessionManager extends Destroyable implements SessionState {\n private callFactory: CallFactory;\n private callCreateTimeout = 6000;\n private readonly agent = `signalwire-typescript-sdk/1.0.0`;\n private readonly eventAcks = true;\n public initialized$: Observable<boolean>;\n public authorization$ = this.createSubject<Authorization>();\n private authorizationState$ = this.createReplaySubject<string | undefined>(1);\n private connectVersion = {\n major: 4,\n minor: 0,\n revision: 0\n };\n private _errors$ = this.createSubject<Error>();\n private _directory?: Directory;\n\n private _authenticated$ = this.createBehaviorSubject<boolean>(false);\n\n private _subscriberInfo$ = this.createBehaviorSubject<Address | null>(null);\n private _calls$ = this.createBehaviorSubject<Record<string, Call>>({});\n private _iceServers$ = this.createBehaviorSubject<RTCIceServer[]>([]);\n\n constructor(\n private credential: SDKCredential,\n private readonly transport: TransportManager,\n private readonly storage: StorageManager,\n private readonly authorizationStateKey: string,\n deviceController: DeviceController,\n private readonly attachManager: AttachManager\n ) {\n super();\n attachManager.setSession(this);\n this.callFactory = new CallFactory(this, deviceController, attachManager);\n this.initialized$ = defer(() => from(this.init())).pipe(\n shareReplay(1),\n takeUntil(this.destroyed$)\n );\n }\n public get incomingCalls$(): Observable<Call[]> {\n return this.cachedObservable('incomingCalls$', () =>\n this.calls$.pipe(map((calls) => calls.filter((call) => call.direction === 'inbound')))\n );\n }\n\n public get incomingCalls(): Call[] {\n const calls = Object.values(this._calls$.value);\n return calls.filter((call) => call.direction === 'inbound');\n }\n\n public get subscriberInfo$(): Observable<Address | null> {\n return this._subscriberInfo$.asObservable();\n }\n\n public get subscriberInfo(): Address | null {\n return this._subscriberInfo$.value;\n }\n\n public get calls$(): Observable<Call[]> {\n return this.cachedObservable('calls$', () =>\n this._calls$.pipe(map((calls) => Object.values(calls)))\n );\n }\n\n public get calls(): Call[] {\n return Object.values(this._calls$.value);\n }\n\n public get iceServers(): RTCIceServer[] | undefined {\n return this._iceServers$.value;\n }\n\n public get errors$(): Observable<Error> {\n return this._errors$.asObservable();\n }\n\n public get authenticated$(): Observable<boolean> {\n return this._authenticated$.asObservable();\n }\n\n public get authenticated(): boolean {\n return this._authenticated$.value;\n }\n\n /**\n * Set the directory instance\n * Called by SignalWire after directory is created\n * @internal\n */\n public setDirectory(directory: Directory): void {\n this._directory = directory;\n }\n\n public async execute<T extends JSONRPCResponse = JSONRPCResponse>(\n request: JSONRPCRequest,\n options?: PendingRPCOptions\n ): Promise<T> {\n try {\n return await this.transport.execute(request, options);\n } catch (error) {\n logger.debug('[Session] Execute Error', error);\n this._errors$.next(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n throw error;\n }\n }\n\n public send(message: JSONSerializable): void {\n this.transport.send(message);\n }\n\n private async init(): Promise<boolean> {\n await this.loadAuthorizationStateFromStorage();\n this.setupMessageHandlers();\n return true;\n }\n\n private setupMessageHandlers(): void {\n logger.debug('[Session] Setting up message handlers');\n\n this.subscribeTo(this.authStateEvent$, async (authStateEvent) => {\n logger.debug('[Session] Authorization state event received:', authStateEvent);\n try {\n await this.updateAuthorizationStateInStorage(authStateEvent.authorization_state);\n } catch (error) {\n logger.error('[Session] Failed to handle authorization state update:', error);\n this._errors$.next(new AuthStateHandlerError(error));\n }\n });\n\n this.subscribeTo(\n this.transport.connectionStatus$.pipe(filter((status) => status === 'connected')),\n async () => {\n try {\n logger.debug('[Session] Connection established, initiating authentication');\n await this.authenticate();\n } catch (error) {\n this.handleAuthenticationError(error as Error).catch((err) => {\n logger.error('[Session] Error handling authentication failure:', err);\n });\n }\n }\n );\n\n this.subscribeTo(this.vertoInvite$, async (invite) => {\n logger.debug('[Session] Verto invite received:', invite);\n try {\n await this.createInboundCall(invite);\n } catch (error) {\n logger.error('[Session] Error handling Verto invite:', error);\n this._errors$.next(new VertoInviteHandlerError(error));\n }\n });\n }\n\n private async loadAuthorizationStateFromStorage(): Promise<void> {\n try {\n const storedState = await this.storage.getItem<string>(this.authorizationStateKey);\n // Always emit a value, even if undefined, so combineLatest can proceed\n this.authorizationState$.next(storedState ?? undefined);\n } catch (error) {\n logger.error('Failed to retrieve authorization state from storage:', error);\n // Emit undefined on error so authentication can proceed without stored state\n this.authorizationState$.next(undefined);\n }\n }\n\n private async updateAuthorizationStateInStorage(authorizationState?: string): Promise<void> {\n if (!authorizationState) {\n logger.debug('[Session] Removing authorization state from storage');\n try {\n await this.storage.removeItem(this.authorizationStateKey);\n } catch (error) {\n logger.error('Failed to remove authorization state from storage:', error);\n throw error;\n }\n return;\n }\n\n try {\n logger.debug('[Session] Updating authorization state in storage');\n await this.storage.setItem(this.authorizationStateKey, authorizationState);\n this.authorizationState$.next(authorizationState);\n } catch (error) {\n logger.error('Failed to retrieve authorization state from storage:', error);\n throw error;\n }\n }\n\n private get authStateEvent$() {\n return this.cachedObservable('authStateEvent$', () =>\n this.signalingEvent$.pipe(\n tap((msg) => {\n logger.debug('[Session] Received incoming message:', msg);\n }),\n filterAs(isSignalwireAuthorizationStateMetadata, 'params'),\n tap((event) => {\n logger.debug('[Session] Authorization state event received:', event.authorization_state);\n })\n )\n );\n }\n\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n public get signalingEvent$() {\n return this.cachedObservable('signalingEvent$', () =>\n this.transport.incomingEvent$.pipe(filterAs(isSignalwireRequest, 'params'), share())\n );\n }\n\n private get vertoInvite$() {\n return this.cachedObservable('vertoInvite$', () =>\n this.signalingEvent$.pipe(\n filter(isWebrtcMessageMetadata),\n filter((event) => isVertoInviteMessage(event.params)),\n map((event) => ({\n node_id: event.node_id,\n ...(event.params.params as VertoInviteParams)\n }))\n )\n );\n }\n\n private get contexts(): string[] {\n return [];\n }\n\n private get eventing(): string[] {\n return [];\n }\n\n private get topics(): string[] {\n return [];\n }\n\n private get authentication(): RPCConnectAuthentication {\n if (!this.credential.token) {\n throw new DependencyError('Credential token is undefined');\n }\n return {\n jwt_token: this.credential.token\n };\n }\n\n async connect(): Promise<void> {\n // Ensure session is initialized before proceeding\n await firstValueFrom(this.initialized$);\n\n // Now initiate the connection - the subscription above will handle authentication\n await this.transport.connect();\n }\n\n private async handleAuthenticationError(error: Error): Promise<void> {\n logger.error('Authentication error:', error);\n this._errors$.next(error);\n if (error.message === 'Requester validation failed') {\n // the server is not accepting our credentials, potentially corrupted authorizationState or protocol\n try {\n await this.cleanupStoredConnectionParams();\n } catch (error) {\n logger.error('Failed to cleanup stored connection params:', error);\n } finally {\n this.transport.reconnect();\n }\n }\n }\n\n async cleanupStoredConnectionParams(): Promise<void> {\n await this.transport.setProtocol(undefined);\n await this.updateAuthorizationStateInStorage(undefined);\n await this.attachManager.detachAll();\n }\n\n protected async updateAuthState(authorization_state: string): Promise<void> {\n try {\n await this.storage.setItem(this.authorizationStateKey, authorization_state);\n } catch (error) {\n logger.error('Failed to update authorization state in storage:', error);\n this._errors$.next(new AuthStateHandlerError(error));\n }\n }\n\n private async authenticate(): Promise<void> {\n logger.debug('[Session] Starting authentication process');\n\n const params: RPCConnectParams = {\n authentication: this.authentication,\n version: this.connectVersion,\n agent: this.agent,\n contexts: this.contexts,\n eventing: this.eventing,\n topics: this.topics,\n\n event_acks: this.eventAcks\n };\n\n const persistedParams = await firstValueFrom(\n combineLatest({\n protocol: this.transport.protocol$,\n\n authorization_state: this.authorizationState$\n }).pipe(take(1))\n );\n\n logger.debug('[Session] Persisted params:\\n', {\n protocol: persistedParams.protocol,\n authStateLength: persistedParams.authorization_state?.length\n });\n\n const rpcConnectRequest = RPCConnect({ ...params, ...persistedParams });\n\n const response = await lastValueFrom(\n from(this.transport.execute(rpcConnectRequest)).pipe(\n throwOnRPCError(),\n map((res) => res.result),\n filter(isRPCConnectResult),\n tap(() => {\n logger.debug('[Session] Response passed filter, processing authentication result');\n }),\n take(1),\n catchError((err) => {\n logger.error('[Session] Authentication RPC failed:', err);\n throw err;\n })\n )\n );\n\n logger.debug('[Session] Processing authentication result:', {\n hasProtocol: !!response.protocol,\n hasAuthorization: !!response.authorization,\n hasIceServers: !!response.ice_servers\n });\n\n if (response.protocol) {\n await this.transport.setProtocol(response.protocol);\n }\n this.authorization$.next(response.authorization);\n this._iceServers$.next(response.ice_servers ?? []);\n this._authenticated$.next(true);\n\n logger.debug('[Session] Authentication completed successfully');\n }\n\n async disconnect(): Promise<void> {\n this.transport.disconnect();\n this._authenticated$.next(false);\n await this.cleanupStoredConnectionParams();\n }\n\n private async createInboundCall(invite: VertoInviteParams & { node_id: string }): Promise<void> {\n const callSession = await this.createCall({\n nodeId: invite.node_id,\n callId: invite.callID,\n initOffer: invite.sdp,\n toName: invite.callee_id_name,\n to: invite.callee_id_number,\n fromName: invite.caller_id_name,\n from: invite.caller_id_number,\n displayDirection: invite.display_direction\n });\n\n await firstValueFrom(callSession.status$);\n\n this._calls$.next({\n [`${callSession.id}`]: callSession,\n ...this._calls$.value\n });\n }\n\n public async createOutboundCall(\n destination: string | Address,\n options: CallOptions = {}\n ): Promise<Call> {\n const destinationURI =\n destination instanceof Address ? destination.defaultChannel : destination;\n try {\n const callSession = await this.createCall({\n to: destinationURI,\n ...options\n });\n\n await firstValueFrom(\n callSession.selfId$.pipe(\n filter((id) => Boolean(id)),\n take(1),\n timeout(this.callCreateTimeout)\n )\n );\n\n this._calls$.next({\n [`${callSession.id}`]: callSession,\n ...this._calls$.value\n });\n\n return callSession;\n } catch (error) {\n logger.error('[Session] Error creating outbound call:', error);\n const callError = new CallCreateError('Call create timeout', error);\n this._errors$.next(callError);\n throw callError;\n }\n }\n\n private async createCall(options: CallOptions = {}): Promise<WebRTCCall> {\n try {\n const addressURI = getAddressSearchURI(options);\n\n // For PSTN numbers (starting with +), skip the directory lookup\n // and create the call directly with the phone number as destination.\n let address: Address | undefined;\n if (!addressURI.startsWith('+')) {\n if (!this._directory) {\n throw new DependencyError('Directory not initialized');\n }\n\n const addressId = await this._directory.findAddressIdByURI(addressURI);\n if (!addressId) {\n throw new DependencyError(`Address name: ${addressURI} not found`);\n }\n\n address = this._directory.get(addressId);\n if (!address) {\n throw new DependencyError(`Address ID: ${addressId} not found`);\n }\n }\n\n const callSession = this.callFactory.createCall(address, {\n ...options\n });\n\n callSession.status$\n .pipe(\n filter((status) => status === 'destroyed'),\n take(1)\n )\n .subscribe(() => {\n const { [`${callSession.id}`]: _, ...remainingCalls } = this._calls$.value;\n this._calls$.next(remainingCalls);\n });\n\n return callSession;\n } catch (error) {\n logger.error('[Session] Error creating call session:', error);\n throw new CallCreateError('Call create error', error);\n }\n }\n\n public destroy(): void {\n for (const call of Object.values(this._calls$.value)) {\n void call.hangup();\n }\n super.destroy();\n }\n}\n\nexport class ClientSessionWrapper implements SessionState {\n constructor(private clientSessionManager: ClientSessionManager) {}\n\n public get authenticated$(): Observable<boolean> {\n return this.clientSessionManager.authenticated$;\n }\n\n public get authenticated(): boolean {\n return this.clientSessionManager.authenticated;\n }\n\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n public get signalingEvent$() {\n return this.clientSessionManager.signalingEvent$;\n }\n\n public get iceServers(): RTCIceServer[] | undefined {\n return this.clientSessionManager.iceServers;\n }\n\n public async execute<T extends JSONRPCResponse = JSONRPCResponse>(\n request: JSONRPCRequest,\n options?: PendingRPCOptions\n ): Promise<T> {\n return this.clientSessionManager.execute(request, options);\n }\n\n public get incomingCalls$(): Observable<Call[]> {\n return this.clientSessionManager.incomingCalls$;\n }\n\n public get incomingCalls(): Call[] {\n return this.clientSessionManager.incomingCalls;\n }\n\n public get calls$(): Observable<Call[]> {\n return this.clientSessionManager.calls$;\n }\n\n public get calls(): Call[] {\n return this.clientSessionManager.calls;\n }\n}\n","export const isString = (obj: unknown): obj is string => typeof obj === 'string';\n","import { map, tap, type Observable } from 'rxjs';\n\nimport { EntityCollection, Fetcher } from '../behaviors/Collection';\nimport { POST_PARAMS } from '../controllers/HTTPRequestController';\nimport { ConversationError } from '../core/errors';\nimport { isConversationMessageMetadata } from '../core/RPCMessages/guards/events.guards';\nimport { filterAs } from '../operators/filterEventAs';\nimport { isString } from '../utils/isString';\nimport { getLogger } from '../utils/logger';\n\nimport type { ClientSessionManager } from './ClientSessionManager';\nimport type { HTTPRequestController } from '../controllers/HTTPRequestController';\nimport type {\n GetConversationMessageResponse,\n GetConversationResponse\n} from '../core/types/conversation.types';\nimport type { ConversationsProvider } from '../interfaces/Conversations';\n\nconst logger = getLogger();\n\nconst toAddressId = (groupId: string): string => {\n const [, toAddressId] = groupId.split('_');\n return toAddressId;\n};\n\nclass ConversationMessagesFetcher extends Fetcher<GetConversationMessageResponse> {\n constructor(\n public readonly groupId: string,\n http: HTTPRequestController\n ) {\n super(`/api/fabric/conversations/${groupId}/messages`, 'page_size=100', http);\n }\n}\n\nclass ConversationsFetcher extends Fetcher<GetConversationResponse> {\n filter = (item: unknown): item is GetConversationResponse =>\n !!(item as GetConversationResponse).from_fabric_address_id;\n mapper = (item: unknown) => ({\n ...(item as GetConversationResponse),\n id: (item as GetConversationResponse).group_id,\n\n address_id: toAddressId((item as GetConversationResponse).group_id)\n });\n constructor(http: HTTPRequestController) {\n super(`/api/fabric/conversations`, 'page_size=100', http);\n }\n}\n\nexport class ConversationMessageCollection extends EntityCollection<GetConversationMessageResponse> {\n constructor(\n groupId: string,\n update$: Observable<Partial<GetConversationMessageResponse>>,\n http: HTTPRequestController,\n onError?: (error: Error) => void\n ) {\n super(new ConversationMessagesFetcher(groupId, http), update$, onError);\n }\n}\n\nexport class ConversationCollection extends EntityCollection<GetConversationResponse> {\n constructor(\n update$: Observable<Partial<GetConversationResponse>>,\n http: HTTPRequestController,\n onError?: (error: Error) => void\n ) {\n super(new ConversationsFetcher(http), update$, onError);\n }\n}\n\nexport class ConversationsManager implements ConversationsProvider {\n private groupIds = new Map<string, string>();\n\n constructor(\n private clientSession: ClientSessionManager,\n private http: HTTPRequestController,\n private getSubscriberAddressId: () => string,\n private readonly onError?: (error: Error) => void\n ) {}\n private async join(addressId: string): Promise<string> {\n const subscriberFromAddressId = this.getSubscriberAddressId();\n\n try {\n const response = await this.http.request({\n ...POST_PARAMS,\n url: `/api/fabric/conversations/join`,\n body: JSON.stringify({\n from_fabric_address_id: subscriberFromAddressId,\n fabric_address_ids: [addressId, subscriberFromAddressId]\n })\n });\n\n if (response.ok && !!response.body) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const data = JSON.parse(response.body);\n /* eslint-disable @typescript-eslint/no-unsafe-member-access */\n\n if (isString(data.group_id)) {\n this.groupIds.set(addressId, data.group_id as string);\n return data.group_id as string;\n }\n /* eslint-enable @typescript-eslint/no-unsafe-member-access */\n }\n throw new ConversationError('Join Failed - Unexpected response');\n } catch (error) {\n logger.error('[ConversationsManager] Failed to join conversation:', error);\n throw error;\n }\n }\n\n public async getConversationMessageCollection(\n addressId: string\n ): Promise<ConversationMessageCollection> {\n const groupId = this.groupIds.get(addressId) ?? (await this.join(addressId));\n\n return Promise.resolve(\n new ConversationMessageCollection(\n groupId,\n this.clientSession.signalingEvent$.pipe(\n filterAs(isConversationMessageMetadata, 'params'),\n tap((event) => logger.debug('[ConversationsManager ] Conversation Event:', event)),\n // FIXME after Conversation API Fixes\n map(\n (params) =>\n ({\n ...params\n }) as Partial<GetConversationMessageResponse>\n )\n ),\n this.http,\n this.onError\n )\n );\n }\n\n public async sendText(text: string, destinationAddressId: string): Promise<void> {\n const groupId =\n this.groupIds.get(destinationAddressId) ?? (await this.join(destinationAddressId));\n const subscriberFromAddressId = this.getSubscriberAddressId();\n\n try {\n const response = await this.http.request({\n ...POST_PARAMS,\n url: '/api/fabric/messages',\n body: JSON.stringify({\n group_id: groupId,\n from_fabric_address_id: subscriberFromAddressId,\n text\n })\n });\n if (response.ok) {\n return;\n }\n throw new ConversationError('Send Text Failed - Unexpected response');\n } catch (error) {\n logger.error('[ConversationsManager] Failed to send text message:', error);\n }\n }\n}\n","export const isEmptyArray = (a?: unknown[]): boolean => {\n return (a?.length ?? 0) === 0;\n};\n","import { take } from 'rxjs';\n\nimport type { Observable } from 'rxjs';\n\nexport const warnup = (observable: Observable<unknown>): void => {\n observable.pipe(take(1)).subscribe();\n};\n","import { firstValueFrom, map, type Observable } from 'rxjs';\n\nimport { EntityCollection, Fetcher } from '../behaviors/Collection';\nimport { Destroyable } from '../behaviors/Destroyable';\nimport { GET_PARAMS } from '../controllers/HTTPRequestController';\nimport { Address } from '../core/entities/Address';\nimport { isConversationMessageUpdatedMetadata } from '../core/RPCMessages/guards/events.guards';\nimport { filterAs, filterNull } from '../operators';\nimport { isEmptyArray } from '../utils/arrays';\nimport { getLogger } from '../utils/logger';\nimport { warnup } from '../utils/warnup';\n\nimport type { ClientSessionManager } from './ClientSessionManager';\nimport type { PaginatedResponse } from '../behaviors/types/collection.types';\nimport type { HTTPRequestController } from '../controllers/HTTPRequestController';\nimport type { Directory } from '../core/entities/Directory';\nimport type { GetAddressResponse } from '../core/types/address.types';\nimport type { ConversationsProvider } from '../interfaces/Conversations';\n\nconst logger = getLogger();\n\nclass AddressFetcher extends Fetcher<GetAddressResponse> {\n constructor(http: HTTPRequestController) {\n super('/api/fabric/addresses', 'sort_by=name&sort_order=asc', http);\n }\n\n async name(name: unknown): Promise<GetAddressResponse | undefined> {\n const response = await this.http.request({\n ...GET_PARAMS,\n url: `${this.endpoint}?name=${encodeURIComponent(name as string)}`\n });\n if (response.ok && !!response.body) {\n const result = JSON.parse(response.body) as PaginatedResponse<GetAddressResponse>;\n if (!isEmptyArray(result.data)) {\n return result.data[0];\n }\n }\n logger.error('Failed to fetch addresses');\n }\n}\n\nexport class AddressStateCollection extends EntityCollection<GetAddressResponse> {\n constructor(\n update$: Observable<Partial<GetAddressResponse>>,\n http: HTTPRequestController,\n onError?: (error: Error) => void\n ) {\n super(new AddressFetcher(http), update$, onError);\n }\n}\n\nexport class DirectoryManager extends Destroyable implements Directory {\n private addNewAddress = (id: string): void => {\n const address = new Address(id, this.conversationManager, this);\n const observable = this._statesCollection.get$(id)?.pipe(\n filterNull(),\n map((data) => {\n address.upnext(data);\n return address;\n })\n );\n if (observable) {\n warnup(observable);\n this._observableRegistry.set(id, observable);\n }\n this._addressesInstances.set(id, address);\n };\n private _addresses$ = this.createBehaviorSubject<Address[]>([]);\n private _statesCollection: AddressStateCollection;\n private _addressesInstances = new Map<string, Address>();\n private _observableRegistry = new Map<string, Observable<Address>>();\n\n constructor(\n private http: HTTPRequestController,\n clientSession: ClientSessionManager,\n private conversationManager: ConversationsProvider,\n private readonly onError?: (error: Error) => void\n ) {\n super();\n this._statesCollection = new AddressStateCollection(\n clientSession.signalingEvent$.pipe(\n filterAs(isConversationMessageUpdatedMetadata, 'params'),\n // FIXME after Conversation API Fixes\n map((_) => ({}) as Partial<GetAddressResponse>)\n ),\n this.http,\n this.onError\n );\n this.initSubscriptions();\n }\n\n public get loading(): boolean {\n return this._statesCollection.loading;\n }\n\n private initSubscriptions(): void {\n this.subscribeTo(this._statesCollection.updated$, () => {\n const existing = Array.from(this._addressesInstances.values().map((address) => address.id));\n const newStates = this._statesCollection.values.filter(\n (state) => !existing.includes(state.id)\n );\n if (!isEmptyArray(newStates)) {\n newStates.forEach((state) => this.addNewAddress(state.id));\n this._addresses$.next(Array.from(this._addressesInstances.values()));\n }\n });\n }\n\n public get addresses$(): Observable<Address[]> {\n return this._addresses$.asObservable();\n }\n\n public get addresses(): Address[] {\n return this._addresses$.value;\n }\n\n public get hasMore$(): Observable<boolean> {\n return this._statesCollection.hasMore$;\n }\n\n public get loading$(): Observable<boolean> {\n return this._statesCollection.loading$;\n }\n\n public loadMore(): void {\n if (this._statesCollection.hasMore) {\n this._statesCollection.loadMore();\n }\n }\n\n public get$(id: string): Observable<Address> | undefined {\n if (!this._observableRegistry.has(id)) {\n this.addNewAddress(id);\n }\n return this._observableRegistry.get(id);\n }\n\n public get(addressId: string): Address | undefined {\n return this._addressesInstances.get(addressId);\n }\n\n public async findAddressIdByURI(name: string): Promise<string | undefined> {\n let addressId = this._addressesInstances.values().find((addr) => addr.name === name)?.id;\n if (!addressId) {\n const found$ = await this._statesCollection.find$('name', name);\n if (found$) {\n const state = await firstValueFrom(found$);\n this.addNewAddress(state.id);\n addressId = state.id;\n }\n }\n return addressId;\n }\n}\n","import { Destroyable } from '../behaviors/Destroyable';\nimport { UnexpectedError, WebSocketConnectionError, WebSocketTimeoutError } from '../core/errors';\nimport { getLogger } from '../utils/logger';\n\nimport type {\n NodeSocketAdapter,\n NodeSocketClient,\n WebSocketAdapter,\n WebSocketClient\n} from '../core/types/common.types';\nimport type { Observable } from 'rxjs';\n\nconst logger = getLogger();\n\nexport type WebSocketConnectionStatus =\n | 'disconnected'\n | 'disconnecting'\n | 'reconnecting'\n | 'connected'\n | 'connecting';\n\nexport interface WebSocketControllerOptions {\n reconnectDelayMin?: number;\n reconnectDelayMax?: number;\n connectionTimeout?: number;\n}\n\nexport class WebSocketController extends Destroyable {\n // Default configuration values\n\n private static readonly DEFAULT_RECONNECT_DELAY_MIN_MS = 1_000;\n\n private static readonly DEFAULT_RECONNECT_DELAY_MAX_MS = 30_000;\n\n private static readonly DEFAULT_CONNECTION_TIMEOUT_MS = 10_000;\n\n // Private state\n private socket?: WebSocketClient | NodeSocketClient;\n private messageQueue: (string | ArrayBuffer | Blob)[] = [];\n private reconnectTimer?: ReturnType<typeof setTimeout>;\n private connectionTimeoutTimer?: ReturnType<typeof setTimeout>;\n private currentReconnectDelay: number;\n private shouldReconnect = false;\n // Configuration\n private readonly reconnectDelayMin: number;\n private readonly reconnectDelayMax: number;\n private readonly connectionTimeout: number;\n // Observable streams\n private _status$ = this.createBehaviorSubject<WebSocketConnectionStatus>('disconnected');\n\n private _incomingMessages$ = this.createSubject<MessageEvent>();\n\n private _errors$ = this.createSubject<Error>();\n\n constructor(\n private WebSocketConstructor: WebSocketAdapter | NodeSocketAdapter,\n private endpoint: string,\n private outgoingMessages$: Observable<string | ArrayBuffer | Blob>,\n options: WebSocketControllerOptions = {}\n ) {\n super();\n this.reconnectDelayMin =\n options.reconnectDelayMin ?? WebSocketController.DEFAULT_RECONNECT_DELAY_MIN_MS;\n this.reconnectDelayMax =\n options.reconnectDelayMax ?? WebSocketController.DEFAULT_RECONNECT_DELAY_MAX_MS;\n this.connectionTimeout =\n options.connectionTimeout ?? WebSocketController.DEFAULT_CONNECTION_TIMEOUT_MS;\n this.currentReconnectDelay = this.reconnectDelayMin;\n\n // Subscribe to send$ to handle message sending\n this.subscriptions.push(\n this.outgoingMessages$.subscribe((data) => {\n this.send(data);\n })\n );\n }\n\n public get status$(): Observable<WebSocketConnectionStatus> {\n return this._status$.asObservable();\n }\n public get incomingMessages$(): Observable<MessageEvent> {\n return this._incomingMessages$.asObservable();\n }\n public get errors$(): Observable<Error> {\n return this._errors$.asObservable();\n }\n public connect(): void {\n if (this._status$.value === 'connecting' || this._status$.value === 'connected') {\n return;\n }\n\n this.shouldReconnect = true;\n this._status$.next('connecting');\n this.createWebSocket();\n }\n\n public disconnect(): void {\n this.shouldReconnect = false;\n this.clearReconnectTimer();\n this.clearConnectionTimeout();\n\n const currentStatus = this._status$.value;\n\n if (\n currentStatus === 'connected' ||\n currentStatus === 'connecting' ||\n currentStatus === 'reconnecting'\n ) {\n if (this.socket) {\n this._status$.next('disconnecting');\n this.socket.close();\n } else {\n this._status$.next('disconnected');\n }\n } else {\n this._status$.next('disconnected');\n }\n }\n\n reconnect(): void {\n if (this.shouldReconnect) {\n this._status$.next('reconnecting');\n this.scheduleReconnection();\n } else {\n this._status$.next('disconnected');\n }\n }\n\n public send(data: string | ArrayBuffer | Blob): void {\n if (\n this._status$.value === 'connected' &&\n this.socket?.readyState === 1 // WebSocket.OPEN\n ) {\n try {\n logger.debug(\n `[WebSocketConnectionManager] Sending message:\\n${JSON.stringify(\n JSON.parse(data as string),\n null,\n 2\n )}`\n );\n } catch {\n logger.warn(\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-base-to-string\n `[WebSocketConnectionManager] Sending non-JSON message:\\n${data}`\n );\n }\n this.socket.send(data);\n } else {\n this.messageQueue.push(data);\n }\n }\n\n private createWebSocket(): void {\n try {\n this.socket = new this.WebSocketConstructor(this.endpoint);\n this.setupWebSocketListeners();\n this.startConnectionTimeout();\n } catch (error) {\n const err =\n error instanceof Error ? error : new UnexpectedError('Failed to create WebSocket');\n this._errors$.next(err);\n this.handleConnectionError();\n }\n }\n\n private setupWebSocketListeners(): void {\n if (!this.socket) return;\n\n this.socket.addEventListener('open', () => this.handleOpen());\n // @ts-expect-error -- Ignore ---\n this.socket.addEventListener('close', (event: CloseEvent) => this.handleClose(event));\n this.socket.addEventListener('error', () => this.handleError());\n // @ts-expect-error -- Ignore ---\n this.socket.addEventListener('message', (event: MessageEvent) => this.handleMessage(event));\n }\n\n private handleOpen(): void {\n this.clearConnectionTimeout();\n this._status$.next('connected');\n this.currentReconnectDelay = this.reconnectDelayMin;\n this.flushMessageQueue();\n }\n\n private handleClose(_event: CloseEvent): void {\n this.clearConnectionTimeout();\n\n if (this.shouldReconnect) {\n this._status$.next('reconnecting');\n this.scheduleReconnection();\n } else {\n this._status$.next('disconnected');\n }\n }\n\n private handleError(): void {\n const error = new WebSocketConnectionError('WebSocket connection error');\n this._errors$.next(error);\n this.handleConnectionError();\n }\n\n private handleMessage(event: MessageEvent): void {\n try {\n logger.debug(\n `[WebSocketConnectionManager] Received message:\\n${JSON.stringify(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n JSON.parse(event.data),\n null,\n 2\n )}`\n );\n } catch {\n logger.warn(`[WebSocketConnectionManager] Received non-JSON message:\\n${event.data}`);\n }\n this._incomingMessages$.next(event);\n }\n\n private handleConnectionError(): void {\n this.reconnect();\n }\n\n private scheduleReconnection(): void {\n this.clearReconnectTimer();\n\n this.reconnectTimer = setTimeout(() => {\n if (this.shouldReconnect) {\n this._status$.next('connecting');\n this.createWebSocket();\n this.increaseReconnectDelay();\n }\n }, this.currentReconnectDelay);\n }\n\n private increaseReconnectDelay(): void {\n this.currentReconnectDelay = Math.min(this.currentReconnectDelay * 2, this.reconnectDelayMax);\n }\n\n private startConnectionTimeout(): void {\n this.clearConnectionTimeout();\n\n this.connectionTimeoutTimer = setTimeout(() => {\n if (this._status$.value === 'connecting') {\n const error = new WebSocketTimeoutError('WebSocket connection timeout');\n this._errors$.next(error);\n\n if (this.socket) {\n this.socket.close();\n }\n }\n }, this.connectionTimeout);\n }\n\n private clearConnectionTimeout(): void {\n if (this.connectionTimeoutTimer) {\n clearTimeout(this.connectionTimeoutTimer);\n this.connectionTimeoutTimer = undefined;\n }\n }\n\n private clearReconnectTimer(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n }\n\n private flushMessageQueue(): void {\n while (this.messageQueue.length > 0 && this.socket?.readyState === 1) {\n const message = this.messageQueue.shift();\n if (message !== undefined) {\n this.socket.send(message);\n }\n }\n }\n}\n","// =============================================================================\n// CLIENT/SERVER METHOD TYPE GUARDS\n// =============================================================================\n// This file contains type guards for client requests, server responses,\n// and method params/results.\n\nimport { hasProperty, isJSONRPCRequest, isJSONRPCResponse, isObject } from './base.guards';\n\nimport type { JSONRPCRequest, TypeGuard } from '../types/base';\nimport type { SignalwirePingParams, SignalwirePingRequest } from '../types/events';\nimport type {\n CallLayoutListRequest,\n CallLayoutListResponse,\n CallMuteParams,\n CallMuteRequest,\n CallMuteResponse,\n CallTargetParams,\n EmptyResponse,\n SignalwireConnectParams,\n SignalwireConnectRequest,\n SignalwireConnectResponse,\n SignalwirePingResponse,\n WebrtcVertoParams,\n WebrtcVertoRequest,\n WebrtcVertoResponse\n} from '../types/methods';\n\n// =============================================================================\n// CLIENT REQUEST TYPE GUARDS\n// =============================================================================\n\nexport function isSignalwireConnectRequest(value: unknown): value is SignalwireConnectRequest {\n return isJSONRPCRequest(value) && value.method === 'signalwire.connect';\n}\n\nexport function isSignalwirePingRequest(value: unknown): value is SignalwirePingRequest {\n return isJSONRPCRequest(value) && value.method === 'signalwire.ping';\n}\n\nexport function isWebrtcVertoRequest(value: unknown): value is WebrtcVertoRequest {\n return isJSONRPCRequest(value) && value.method === 'webrtc.verto';\n}\n\nexport function isCallLayoutListRequest(value: unknown): value is CallLayoutListRequest {\n return isJSONRPCRequest(value) && value.method === 'call.layout.list';\n}\n\nexport function isCallMuteRequest(value: unknown): value is CallMuteRequest {\n return isJSONRPCRequest(value) && value.method === 'call.mute';\n}\n\n// =============================================================================\n// RESPONSE TYPE GUARDS\n// =============================================================================\n\nexport function isSignalwireConnectResponse(value: unknown): value is SignalwireConnectResponse {\n return (\n isJSONRPCResponse(value) &&\n isObject(value.result) &&\n hasProperty(value.result, 'identity') &&\n hasProperty(value.result, 'authorization') &&\n hasProperty(value.result, 'protocol')\n );\n}\n\nexport function isSignalwirePingResponse(value: unknown): value is SignalwirePingResponse {\n return (\n isJSONRPCResponse(value) && isObject(value.result) && hasProperty(value.result, 'timestamp')\n );\n}\n\nexport function isWebrtcVertoResponse(value: unknown): value is WebrtcVertoResponse {\n return (\n isJSONRPCResponse(value) &&\n isObject(value.result) &&\n hasProperty(value.result, 'node_id') &&\n hasProperty(value.result, 'code')\n );\n}\n\nexport function isCallLayoutListResponse(value: unknown): value is CallLayoutListResponse {\n return (\n isJSONRPCResponse(value) &&\n isObject(value.result) &&\n hasProperty(value.result, 'layouts') &&\n Array.isArray(value.result.layouts)\n );\n}\n\nexport function isCallMuteResponse(value: unknown): value is CallMuteResponse {\n return (\n isJSONRPCResponse(value) &&\n isObject(value.result) &&\n hasProperty(value.result, 'code') &&\n hasProperty(value.result, 'message') &&\n !hasProperty(value.result, 'layouts') &&\n !hasProperty(value.result, 'node_id')\n );\n}\n\nexport function isEmptyResponse(value: unknown): value is EmptyResponse {\n return (\n isJSONRPCResponse(value) && isObject(value.result) && Object.keys(value.result).length === 0\n );\n}\n\n// =============================================================================\n// PARAMS TYPE GUARDS\n// =============================================================================\n\nexport function isSignalwireConnectParams(value: unknown): value is SignalwireConnectParams {\n return (\n isObject(value) &&\n hasProperty(value, 'version') &&\n hasProperty(value, 'event_acks') &&\n hasProperty(value, 'agent') &&\n hasProperty(value, 'authentication')\n );\n}\n\nexport function isSignalwirePingParams(value: unknown): value is SignalwirePingParams {\n return isObject(value) && hasProperty(value, 'timestamp') && typeof value.timestamp === 'number';\n}\n\nexport function isWebrtcVertoParams(value: unknown): value is WebrtcVertoParams {\n return (\n isObject(value) &&\n hasProperty(value, 'message') &&\n hasProperty(value, 'callID') &&\n hasProperty(value, 'node_id')\n );\n}\n\nexport function isCallTargetParams(value: unknown): value is CallTargetParams {\n return isObject(value) && hasProperty(value, 'self') && hasProperty(value, 'target');\n}\n\nexport function isCallMuteParams(value: unknown): value is CallMuteParams {\n if (!isCallTargetParams(value)) return false;\n return 'channels' in value;\n}\n\n// =============================================================================\n// METHOD TYPE MAPPING\n// =============================================================================\n\nexport const MethodTypeMap = {\n 'signalwire.connect': isSignalwireConnectRequest,\n 'signalwire.ping': isSignalwirePingRequest,\n 'webrtc.verto': isWebrtcVertoRequest,\n 'call.layout.list': isCallLayoutListRequest,\n 'call.mute': isCallMuteRequest\n} as const;\n\nexport type MethodType = keyof typeof MethodTypeMap;\n\n/**\n * Gets the appropriate type guard for a method.\n */\nexport function getMethodGuard(method: string): TypeGuard<JSONRPCRequest> | undefined {\n return MethodTypeMap[method as MethodType];\n}\n","import {\n EMPTY,\n catchError,\n defer,\n filter,\n from,\n map,\n share,\n shareReplay,\n take,\n takeUntil,\n tap,\n timeout\n} from 'rxjs';\n\nimport { PreferencesContainer } from '../containers/PreferencesContainer';\nimport { WebSocketController } from '../controllers/WebSocketController';\nimport { MessageParseError, TransportConnectionError } from '../core/errors';\nimport { RPCEventAckResponse, RPCPingResponse } from '../core/RPCMessages';\nimport { isJSONRPCRequest, isJSONRPCResponse } from '../core/RPCMessages/guards/base.guards';\nimport { isSignalwireRequest } from '../core/RPCMessages/guards/events.guards';\nimport { isSignalwirePingRequest } from '../core/RPCMessages/guards/methods.guards';\nimport { Destroyable, PendingRPC } from '../core/utils';\nimport { getLogger } from '../utils/logger';\n\nimport type { StorageManager } from './StorageManager';\nimport type { JSONRPCRequest, JSONRPCResponse } from '../core/RPCMessages/types/base';\nimport type {\n JSONSerializable,\n WebSocketAdapter,\n NodeSocketAdapter\n} from '../core/types/common.types';\nimport type { PendingRPCOptions } from '../core/utils';\nimport type { Observable, OperatorFunction } from 'rxjs';\n\nconst logger = getLogger();\n\nexport class TransportManager extends Destroyable {\n private initialized$: Observable<boolean>;\n public protocol$ = this.createReplaySubject<string | undefined>(1);\n // Connection state tracking\n private isConnecting = false;\n private isConnected = false;\n private ackEvent = <T extends JSONRPCRequest | JSONRPCResponse>(): OperatorFunction<T, T> => {\n return tap((message) => {\n if (isSignalwireRequest(message)) {\n try {\n logger.debug('[Transport] Sending event ack', {\n eventId: message.id\n });\n this.send(RPCEventAckResponse(message.id));\n } catch (error) {\n logger.error('[Transport] Failed to send event acknowledgment:', error);\n }\n }\n });\n };\n private replySignalwirePing = <T extends JSONRPCRequest | JSONRPCResponse>(): OperatorFunction<\n T,\n T\n > => {\n return filter((message) => {\n if (isSignalwirePingRequest(message)) {\n try {\n logger.debug('[Transport] Received ping, sending pong', {\n pingId: message.id\n });\n this.send(RPCPingResponse(message.id));\n } catch (error) {\n logger.error('[Transport] Failed to send ping response:', error);\n }\n return false;\n }\n return true;\n });\n };\n private _outgoingMessages$ = this.createSubject<string | ArrayBuffer | Blob>();\n\n private _webSocketConnections!: WebSocketController;\n private _jsonRPCMessage$!: Observable<JSONRPCResponse | JSONRPCRequest>;\n private _jsonRPCResponse$!: Observable<JSONRPCResponse>;\n private _incomingEvent$!: Observable<JSONRPCRequest | JSONRPCResponse>;\n\n constructor(\n private readonly storage: StorageManager,\n private readonly protocolKey: string,\n webSocketConstructor: WebSocketAdapter | NodeSocketAdapter,\n relayHost: string,\n private readonly onError?: (error: Error) => void\n ) {\n super();\n this._webSocketConnections = new WebSocketController(\n webSocketConstructor,\n relayHost,\n this._outgoingMessages$.asObservable(),\n {\n connectionTimeout: PreferencesContainer.instance.connectionTimeout,\n reconnectDelayMin: PreferencesContainer.instance.reconnectDelayMin,\n reconnectDelayMax: PreferencesContainer.instance.reconnectDelayMax\n }\n );\n this.subscribeTo(this._webSocketConnections.errors$, (error) => {\n this.onError?.(error);\n });\n this.initialized$ = defer(() => from(this._init())).pipe(\n shareReplay(1),\n takeUntil(this.destroyed$)\n );\n\n this._jsonRPCMessage$ = this._webSocketConnections.incomingMessages$.pipe(\n map((event: MessageEvent) => {\n try {\n return JSON.parse(event.data as string) as object;\n } catch (error) {\n logger.error('[Transport] Failed to parse incoming message:', error);\n this.onError?.(new MessageParseError(error));\n return null;\n }\n }),\n filter(\n (message): message is JSONRPCResponse | JSONRPCRequest =>\n message !== null && (isJSONRPCResponse(message) || isJSONRPCRequest(message))\n ),\n catchError((error) => {\n logger.error('[Transport] Message processing error:', error);\n this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));\n return EMPTY;\n }),\n share(),\n takeUntil(this.destroyed$)\n );\n\n this._jsonRPCResponse$ = this._jsonRPCMessage$.pipe(filter(isJSONRPCResponse));\n\n this._incomingEvent$ = this._jsonRPCMessage$.pipe(\n this.ackEvent(),\n this.replySignalwirePing(),\n filter((message) => !isJSONRPCResponse(message)),\n share(),\n takeUntil(this.destroyed$)\n );\n }\n\n public async setProtocol(protocol: string | undefined): Promise<void> {\n this.protocol$.next(protocol);\n await this._updateProtocolInStorage(protocol);\n }\n public get incomingEvent$(): Observable<JSONRPCRequest | JSONRPCResponse> {\n return this._incomingEvent$;\n }\n\n public get connectionStatus$(): Observable<string> {\n return this._webSocketConnections.status$;\n }\n\n public async connect(): Promise<void> {\n // Prevent duplicate connections\n if (this.isConnecting || this.isConnected) {\n logger.warn('[Transport] Already connecting or connected');\n return Promise.resolve();\n }\n\n return new Promise<void>((resolve, reject) => {\n this.isConnecting = true;\n\n this.subscribeTo(this.initialized$, () => {\n this._webSocketConnections.connect();\n\n // Wait for actual connection\n const connectionSub = this._webSocketConnections.status$\n .pipe(\n filter((status) => status === 'connected' || status === 'disconnected'),\n take(1),\n timeout(10000) // 10 second timeout\n )\n .subscribe({\n next: (status) => {\n if (status === 'connected') {\n this.isConnecting = false;\n this.isConnected = true;\n logger.debug('[Transport] Connection established');\n resolve();\n } else {\n this.isConnecting = false;\n const error = new TransportConnectionError('Failed to connect');\n logger.error('[Transport] Connection failed');\n this.onError?.(error);\n reject(error);\n }\n },\n error: (err) => {\n this.isConnecting = false;\n logger.error('[Transport] Connection error:', err);\n this.onError?.(err instanceof Error ? err : new Error(String(err), { cause: err }));\n reject(err as Error);\n }\n });\n\n this.subscriptions.push(connectionSub);\n\n // Track disconnection\n this.subscribeTo(\n this._webSocketConnections.status$.pipe(filter((status) => status === 'disconnected')),\n () => {\n logger.debug('[Transport] Disconnected');\n this.isConnected = false;\n }\n );\n });\n });\n }\n\n public reconnect(): void {\n this._webSocketConnections.reconnect();\n }\n\n public async execute<T extends JSONRPCResponse = JSONRPCResponse>(\n request: JSONRPCRequest,\n options?: PendingRPCOptions\n ): Promise<T> {\n // Send the request through the WebSocket\n this.send(request as unknown as JSONSerializable);\n\n // Create and return a PendingRPC promise that will resolve when the matching response arrives\n return new PendingRPC<T>(request, this._jsonRPCResponse$ as Observable<T>, options).promise;\n }\n public send(message: unknown): void {\n const payload = JSON.stringify(message);\n this._outgoingMessages$.next(payload);\n }\n // request(request: HTTPRequest): Promise<HTTPResponse> {}\n public disconnect(): void {\n logger.debug('[Transport] Disconnecting');\n this.isConnected = false;\n this.isConnecting = false;\n\n // Disconnect WebSocket\n this._webSocketConnections.disconnect();\n }\n public destroy(): void {\n logger.debug('[Transport] Destroying');\n this.disconnect();\n super.destroy();\n this._webSocketConnections.destroy();\n }\n private async _loadProtocolFromStorage(): Promise<void> {\n try {\n const storedProtocol = await this.storage.getItem<string>(this.protocolKey);\n this.protocol$.next(storedProtocol ?? undefined);\n } catch (error) {\n logger.error('Failed to retrieve protocol from storage:', error);\n throw error;\n }\n }\n\n private async _updateProtocolInStorage(protocol: string | undefined): Promise<void> {\n if (!protocol) {\n try {\n await this.storage.removeItem(this.protocolKey);\n } catch (error) {\n logger.error('Failed to remove protocol from storage:', error);\n throw error;\n }\n return;\n }\n\n try {\n const storedProtocol = await this.storage.getItem<string>(this.protocolKey);\n if (!storedProtocol || storedProtocol !== protocol) {\n await this.storage.setItem(this.protocolKey, protocol);\n }\n } catch (error) {\n logger.error('Failed to update protocol in storage:', error);\n throw error;\n }\n }\n\n private async _init(): Promise<boolean> {\n await this._loadProtocolFromStorage();\n return true;\n }\n}\n","import { jwtDecode } from 'jwt-decode';\nimport { filter, firstValueFrom, of, switchMap, type Observable } from 'rxjs';\n\nimport { Destroyable } from '../behaviors/Destroyable';\nimport { DependencyContainer } from '../containers/DependencyContainer';\nimport { ClientPreferences, PreferencesContainer } from '../containers/PreferencesContainer';\nimport { Subscriber } from '../core/entities/Subscriber';\nimport { InvalidCredentialsError, UnexpectedError } from '../core/errors';\nimport { RPCExecute } from '../core/RPCMessages';\nimport { AttachManager } from '../managers/AttachManager';\nimport { ClientSessionManager, ClientSessionWrapper } from '../managers/ClientSessionManager';\nimport { ConversationsManager } from '../managers/ConversationsManager';\nimport { DirectoryManager } from '../managers/DirectoryManager';\nimport { TransportManager } from '../managers/TransportManager';\nimport { getLogger } from '../utils/logger';\n\nimport type { Address } from '../core/entities/Address';\nimport type { Directory } from '../core/entities/Directory';\nimport type { Call } from '../core/entities/types/call.types';\nimport type {\n NodeSocketAdapter,\n SDKCredential,\n WebSocketAdapter\n} from '../core/types/common.types';\nimport type { MediaOptions } from '../core/types/media.types';\nimport type { CredentialProvider, Storage } from '../dependencies/interfaces';\nimport type { DeviceController } from '../interfaces/DeviceController';\n\nconst logger = getLogger();\n\ninterface JWTHeader {\n ch?: string;\n typ?: string;\n}\n/** Options for constructing a {@link SignalWire}. */\nexport interface SignalWireOptions {\n /** Skip automatic WebSocket connection on construction. */\n skipConnection?: boolean;\n /** Skip automatic subscriber registration on construction. */\n skipRegister?: boolean;\n /** Skip monitoring media device changes. */\n skipDeviceMonitoring?: boolean;\n /** Whether to reconnect to previously attached calls. */\n reconnectAttachedCalls?: boolean;\n /** Whether to save preferences. */\n savePreferences?: boolean;\n /** Custom storage implementation for persistence. */\n storageImplementation?: Storage;\n /** Custom WebSocket constructor */\n webSocketConstructor?: WebSocketAdapter | NodeSocketAdapter;\n}\n\n/** Options for {@link SignalWire.dial}. Extends {@link MediaOptions} with dial-specific settings. */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface DialOptions extends MediaOptions {\n // Define any options for dialing here\n}\n\nconst buildOptionsFromDestination = (destination: string | Address): DialOptions => {\n if (typeof destination === 'string') {\n const queryStartIndex = destination.indexOf('?');\n if (queryStartIndex !== -1) {\n const queryString = destination.substring(queryStartIndex + 1);\n const params = new URLSearchParams(queryString);\n const channel = params.get('channel');\n\n if (channel === 'video') {\n return { audio: true, video: true };\n } else if (channel === 'audio') {\n return { audio: true, video: false };\n }\n }\n }\n\n return {};\n};\n/**\n * Main entry point for the SignalWire Browser SDK.\n *\n * Manages authentication, WebSocket transport, call creation, and media devices.\n *\n * @example\n * ```ts\n * const client = new SignalWire(credentialProvider);\n * client.isConnected$.subscribe(connected => console.log('Connected:', connected));\n * const call = await client.dial('/public/my-room');\n * ```\n */\nclass SignalWire extends Destroyable implements DeviceController {\n /** Global SDK preferences (timeouts, ICE config, media defaults). */\n public preferences = new ClientPreferences();\n private _subscriber$ = this.createBehaviorSubject<Subscriber | undefined>(undefined);\n private _directory$ = this.createBehaviorSubject<Directory | undefined>(undefined);\n private _transport!: TransportManager;\n private _clientSession!: ClientSessionManager;\n private _publicSession!: ClientSessionWrapper;\n private _deviceController!: DeviceController;\n private _attachManager?: AttachManager;\n private _isConnected$ = this.createBehaviorSubject<boolean>(false);\n private _isRegistered$ = this.createBehaviorSubject<boolean>(false);\n private _errors$ = this.createSubject<Error>();\n private _options: SignalWireOptions = {};\n private _refreshTimerId?: ReturnType<typeof setTimeout>;\n private _deps = new DependencyContainer();\n\n constructor(credentialProvider: CredentialProvider, options: SignalWireOptions = {}) {\n super();\n this._options = {\n ...PreferencesContainer.instance.defaultSignalWireOptions,\n ...options\n };\n\n // Set custom storage implementation if provided\n if (this._options.storageImplementation) {\n this._deps.storageImpl = this._options.storageImplementation;\n }\n\n if (this._options.webSocketConstructor) {\n this._deps.WebSocket = this._options.webSocketConstructor;\n }\n\n if (this._options.savePreferences) {\n this.preferences.enableSavePreferences(this._deps.storage);\n }\n\n this._deviceController = this._deps.deviceController;\n if (!this._options.skipDeviceMonitoring) {\n this._deviceController.enableDeviceMonitoring();\n }\n this.subscribeTo(this._deviceController.errors$, (error) => {\n this._errors$.next(error);\n });\n\n this.validateCredentials(credentialProvider)\n .then(() => {\n this.init().catch((error: unknown) => {\n logger.error('[SignalWire] Initialization error:', error);\n this._errors$.next(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n });\n })\n .catch((error: unknown) => {\n logger.error('[SignalWire] Initialization error:', error);\n this._errors$.next(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n });\n }\n\n private async validateCredentials(\n credentialProvider: CredentialProvider,\n credentials?: SDKCredential\n ): Promise<void> {\n const _credentials = credentials ?? (await credentialProvider.authenticate());\n if (_credentials.token) {\n try {\n const decodeHeader: JWTHeader = jwtDecode(_credentials.token, { header: true });\n this._deps.ch = decodeHeader.ch;\n } catch (error) {\n logger.error('[SignalWire] Invalid JWT token provided in credentials:', error);\n throw new InvalidCredentialsError('Invalid JWT token provided in credentials.', {\n cause: error\n });\n }\n }\n if (!_credentials.token && !_credentials.authorizationState) {\n logger.error('[SignalWire] No valid authentication credentials provided.');\n throw new InvalidCredentialsError('No valid authentication credentials provided.');\n }\n\n if (_credentials.expiry_at && _credentials.expiry_at < Date.now()) {\n logger.error('[SignalWire] Provided credentials have expired.');\n throw new InvalidCredentialsError('Provided credentials have expired.');\n }\n\n if (_credentials.expiry_at && credentialProvider.refresh) {\n const refreshFn = credentialProvider.refresh;\n const refreshInterval = Math.max(_credentials.expiry_at - Date.now() - 5000, 1000);\n this._refreshTimerId = setTimeout(async () => {\n try {\n const newCredentials = await refreshFn();\n this._deps.credential = newCredentials;\n logger.info('[SignalWire] Credentials refreshed successfully.');\n // Schedule next refresh\n this.validateCredentials(credentialProvider, newCredentials).catch((error: unknown) => {\n logger.error('[SignalWire] Credential refresh error:', error);\n this._errors$.next(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n });\n } catch (error: unknown) {\n logger.error('[SignalWire] Credential refresh failed:', error);\n this._errors$.next(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n }\n }, refreshInterval);\n }\n\n this._deps.credential = _credentials;\n }\n\n private async init() {\n // Initialize subscriber first (before transport) to fetch subscriber info\n this._subscriber$.next(new Subscriber(this._deps.http));\n\n if (!this._options.skipConnection) {\n await this.connect();\n }\n\n // Flush attached calls after connect creates the AttachManager\n if (!this._options.reconnectAttachedCalls && this._attachManager) {\n await this._attachManager.flush();\n }\n\n if (!this._options.skipRegister) {\n // eventually register after the authentication\n void this.register();\n }\n\n // eventually reconnect to attached calls after the authentication\n void this.handleAttachments();\n }\n\n private async handleAttachments() {\n if (!this._attachManager) {\n logger.error('[SignalWire] AttachManager not initialized');\n return;\n }\n if (!this._options.reconnectAttachedCalls) {\n return;\n }\n try {\n await this._attachManager.reattachCalls();\n } catch (error) {\n logger.error('[SignalWire] Failed to reattach calls:', error);\n this._errors$.next(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n }\n }\n\n /**\n * Establishes the WebSocket connection and authenticates the session.\n *\n * ## Reconnection behavior\n *\n * After a successful connection the underlying {@link WebSocketController}\n * automatically attempts to reconnect whenever the socket closes\n * unexpectedly (e.g. network change, server restart). Reconnection uses an\n * **exponential back-off** strategy:\n *\n * - First retry after `reconnectDelayMin` (default **1 s**).\n * - Each subsequent retry doubles the delay up to `reconnectDelayMax`\n * (default **30 s**).\n * - The delay resets to `reconnectDelayMin` once a connection succeeds.\n * - A per-attempt `connectionTimeout` (default **10 s**) aborts the\n * attempt and schedules the next retry if the server does not respond.\n *\n * Calling {@link disconnect} stops the reconnection loop entirely.\n *\n * ## Message handling during temporary disconnections\n *\n * While the socket is not in the `connected` state, **outgoing messages\n * are queued** in an internal buffer. Once the connection is\n * re-established the queue is flushed in order so no outgoing RPC call is\n * lost.\n *\n * **Incoming** server-to-client messages that arrive while the socket is\n * down are *not* buffered by the SDK — they are expected to be\n * re-delivered by the server after the session is re-authenticated.\n * Active RPC calls that were awaiting a response will time out\n * (default **5 s**) and reject with an `RPCTimeoutError`; callers should\n * handle this and retry if appropriate.\n *\n * The connection status can be observed via the `status$` observable on\n * the transport layer, which emits `'connecting'`, `'connected'`,\n * `'reconnecting'`, `'disconnecting'`, or `'disconnected'`.\n */\n public async connect(): Promise<void> {\n // Wait for subscriber to be fetched first to get the subscriber ID\n try {\n const subscriber = this._subscriber$.value;\n if (!subscriber) {\n throw new UnexpectedError('Subscriber not initialized before connect');\n }\n\n const fetched = await firstValueFrom(subscriber.fetched$);\n\n if (!fetched) {\n throw new UnexpectedError(\n 'Failed to fetch subscriber information - fetched$ emitted false'\n );\n }\n\n // Set the subscriber ID in the dependency container\n this._deps.subscriber = subscriber;\n } catch (error) {\n logger.error(\n `[SignalWire] Failed to fetch subscriber information: ${error instanceof Error ? error.message : 'Unknown error'}. ` +\n `This usually means the subscriber token is invalid or expired.`\n );\n throw new UnexpectedError('Error fetching subscriber information', { cause: error });\n }\n\n const errorHandler = (error: Error) => {\n this._errors$.next(error);\n };\n\n // Now initialize transport and session with subscriber ID available\n this._transport = new TransportManager(\n this._deps.storage,\n this._deps.protocolKey,\n this._deps.WebSocket,\n PreferencesContainer.instance.relayHost ?? this._deps.relayHost,\n errorHandler\n );\n\n // Create AttachManager (needed by CallFactory -> VertoManager)\n this._attachManager = new AttachManager(\n this._deps.storage,\n this._deps.deviceController,\n PreferencesContainer.instance.reconnectCallsTimeout,\n this._deps.attachedCallsKey\n );\n\n this._clientSession = new ClientSessionManager(\n this._deps.credential,\n this._transport,\n this._deps.storage,\n this._deps.authorizationStateKey,\n this._deps.deviceController,\n this._attachManager\n );\n this._publicSession = new ClientSessionWrapper(this._clientSession);\n\n this.subscribeTo(this._clientSession.errors$, (error) => {\n this._errors$.next(error);\n });\n\n await this._clientSession.connect();\n\n // Create conversationManager first to inject into DirectoryManager\n const conversationManager = new ConversationsManager(\n this._clientSession,\n this._deps.http,\n () => this._deps.getSubscriberFromAddressId(),\n errorHandler\n );\n\n // Create directory with all dependencies injected\n const directory = new DirectoryManager(\n this._deps.http,\n this._clientSession,\n conversationManager,\n errorHandler\n );\n this._directory$.next(directory);\n this._clientSession.setDirectory(directory);\n\n this._isConnected$.next(true);\n }\n\n /**\n * Observable that emits the {@link Subscriber} profile once fetched,\n * or `undefined` before authentication completes.\n *\n * @example\n * ```ts\n * client.subscriber$.subscribe(sub => {\n * if (sub) console.log('Logged in as', sub.email);\n * });\n * ```\n */\n public get subscriber$(): Observable<Subscriber | undefined> {\n return this._subscriber$.asObservable();\n }\n\n /** Current subscriber snapshot, or `undefined` if not yet authenticated. */\n public get subscriber(): Subscriber | undefined {\n return this._subscriber$.value;\n }\n\n /**\n * Observable that emits the {@link Directory} instance once the client is connected,\n * or `undefined` while disconnected. Subscribe to this to safely wait for the directory\n * to become available without risking an error.\n *\n * @example\n * ```ts\n * client.directory$.subscribe(dir => {\n * if (dir) dir.addresses$.subscribe(console.log);\n * });\n * ```\n */\n public get directory$(): Observable<Directory | undefined> {\n return this._directory$.asObservable();\n }\n\n /**\n * Current directory snapshot, or `undefined` if the client is not yet connected.\n * Prefer {@link directory$} when you need to react to the directory becoming available.\n */\n public get directory(): Directory | undefined {\n return this._directory$.value;\n }\n\n /** Observable that emits when the subscriber registration state changes. */\n public get isRegistered$(): Observable<boolean> {\n return this._isRegistered$.asObservable();\n }\n\n /** Whether the subscriber is currently registered. */\n public get isRegistered(): boolean {\n return this._isRegistered$.value;\n }\n\n /** Whether the client is currently connected. */\n public get isConnected(): boolean {\n return this._isConnected$.value;\n }\n\n /** Observable that emits when the connection state changes. */\n public get isConnected$(): Observable<boolean> {\n return this._isConnected$.asObservable();\n }\n\n /** Observable that emits `true` when the client is both connected and authenticated. */\n public get ready$(): Observable<boolean> {\n return this.cachedObservable('ready$', () =>\n this._isConnected$.pipe(\n switchMap((connected) => (connected ? this._clientSession.authenticated$ : of(false)))\n )\n );\n }\n\n /** Observable stream of errors from transport, authentication, and devices. */\n public get errors$(): Observable<Error> {\n return this._errors$.asObservable();\n }\n\n /** Disconnects the WebSocket and tears down the session. */\n public async disconnect(): Promise<void> {\n await this._clientSession.disconnect();\n this._clientSession.destroy();\n this._isConnected$.next(false);\n }\n\n private async waitAuthentication(): Promise<void> {\n // Wait for client to be ready (authenticated)\n await firstValueFrom(this.ready$.pipe(filter((ready) => ready === true)));\n }\n\n /** Registers the subscriber as online to receive inbound calls and events. */\n public async register(): Promise<void> {\n try {\n // Wait for client session to be authenticated before registering subscriber\n await this.waitAuthentication();\n await this._transport.execute(RPCExecute({ method: 'subscriber.online', params: {} }));\n this._isRegistered$.next(true);\n } catch (error) {\n logger.error('[SignalWire] Failed to register subscriber:', error);\n this._errors$.next(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n }\n }\n\n /** Unregisters the subscriber, going offline for inbound calls. */\n public async unregister(): Promise<void> {\n try {\n await this._transport.execute(RPCExecute({ method: 'subscriber.offline', params: {} }));\n this._isRegistered$.next(false);\n } catch (error) {\n logger.error('[SignalWire] Failed to unregister subscriber:', error);\n this._errors$.next(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n throw error;\n }\n }\n\n /**\n * Places an outbound call to the given destination.\n * @param destination - Address URI string or {@link Address} instance to call.\n * @param options - Media and dial options (audio/video, constraints).\n * @returns The created {@link Call} instance.\n */\n public async dial(destination: string | Address, options: DialOptions = {}): Promise<Call> {\n const computed_options = {\n ...PreferencesContainer.instance.preferredMediaOptions,\n ...buildOptionsFromDestination(destination),\n ...options\n };\n\n // Wait for client to be ready\n await this.waitAuthentication();\n\n logger.debug('[SignalWire] Dialing with options:', computed_options);\n return this._clientSession.createOutboundCall(destination, computed_options);\n }\n\n /** The underlying client session for advanced RPC operations. */\n public get session(): ClientSessionWrapper {\n return this._publicSession;\n }\n\n // DeviceController interface implementation\n\n /** Observable list of available audio input (microphone) devices. */\n public get audioInputDevices$(): Observable<MediaDeviceInfo[]> {\n return this._deviceController.audioInputDevices$;\n }\n\n /** Current snapshot of available audio input devices. */\n public get audioInputDevices(): MediaDeviceInfo[] {\n return this._deviceController.audioInputDevices;\n }\n\n /** Observable list of available audio output (speaker) devices. */\n public get audioOutputDevices$(): Observable<MediaDeviceInfo[]> {\n return this._deviceController.audioOutputDevices$;\n }\n\n /** Current snapshot of available audio output devices. */\n public get audioOutputDevices(): MediaDeviceInfo[] {\n return this._deviceController.audioOutputDevices;\n }\n\n /** Observable list of available video input (camera) devices. */\n public get videoInputDevices$(): Observable<MediaDeviceInfo[]> {\n return this._deviceController.videoInputDevices$;\n }\n\n /** Current snapshot of available video input devices. */\n public get videoInputDevices(): MediaDeviceInfo[] {\n return this._deviceController.videoInputDevices;\n }\n\n /** Observable of the currently selected audio input device. */\n public get selectedAudioInputDevice$(): Observable<MediaDeviceInfo | null> {\n return this._deviceController.selectedAudioInputDevice$;\n }\n /** Observable of the currently selected audio output device. */\n public get selectedAudioOutputDevice$(): Observable<MediaDeviceInfo | null> {\n return this._deviceController.selectedAudioOutputDevice$;\n }\n /** Observable of the currently selected video input device. */\n public get selectedVideoInputDevice$(): Observable<MediaDeviceInfo | null> {\n return this._deviceController.selectedVideoInputDevice$;\n }\n /** Currently selected audio input device, or `null` if none. */\n public get selectedAudioInputDevice(): MediaDeviceInfo | null {\n return this._deviceController.selectedAudioInputDevice;\n }\n /** Currently selected audio output device, or `null` if none. */\n public get selectedAudioOutputDevice(): MediaDeviceInfo | null {\n return this._deviceController.selectedAudioOutputDevice;\n }\n /** Currently selected video input device, or `null` if none. */\n public get selectedVideoInputDevice(): MediaDeviceInfo | null {\n return this._deviceController.selectedVideoInputDevice;\n }\n /** Media track constraints for the selected audio input device. */\n public get selectedAudioInputDeviceConstraints(): MediaTrackConstraints {\n return this._deviceController.selectedAudioInputDeviceConstraints;\n }\n /** Media track constraints for the selected video input device. */\n public get selectedVideoInputDeviceConstraints(): MediaTrackConstraints {\n return this._deviceController.selectedVideoInputDeviceConstraints;\n }\n\n /** Converts a `MediaDeviceInfo` to track constraints suitable for `getUserMedia`. */\n public deviceInfoToConstraints(deviceInfo: MediaDeviceInfo | null): MediaTrackConstraints {\n return this._deviceController.deviceInfoToConstraints(deviceInfo);\n }\n\n /** Sets the preferred audio input device. */\n public selectAudioInputDevice(device: MediaDeviceInfo | null): void {\n this._deviceController.selectAudioInputDevice(device);\n }\n\n /** Sets the preferred video input device. */\n public selectVideoInputDevice(device: MediaDeviceInfo | null): void {\n this._deviceController.selectVideoInputDevice(device);\n }\n\n /** Sets the preferred audio output device. */\n public selectAudioOutputDevice(device: MediaDeviceInfo | null): void {\n this._deviceController.selectAudioOutputDevice(device);\n }\n\n /** Starts monitoring for media device changes (connect/disconnect). */\n public enableDeviceMonitoring(): void {\n this._deviceController.enableDeviceMonitoring();\n }\n\n /** Stops monitoring for media device changes. */\n public disableDeviceMonitoring(): void {\n this._deviceController.disableDeviceMonitoring();\n }\n\n public async getDeviceCapabilities(\n deviceInfo: MediaDeviceInfo\n ): Promise<MediaTrackCapabilities | null> {\n return this._deviceController.getDeviceCapabilities(deviceInfo);\n }\n\n public async isValidDevice(deviceInfo: MediaDeviceInfo | null): Promise<boolean> {\n return this._deviceController.isValidDevice(deviceInfo);\n }\n\n public override destroy(): void {\n if (this._refreshTimerId) {\n clearTimeout(this._refreshTimerId);\n this._refreshTimerId = undefined;\n }\n super.destroy();\n }\n}\nexport { SignalWire };\n","import { RequestError, RequestTimeoutError } from '../core/errors';\nimport { getLogger } from '../utils/logger';\n\nimport type { CredentialProvider } from './interfaces';\n\nconst logger = getLogger();\n\nexport class EmbedTokenCredentialProvider implements CredentialProvider {\n constructor(\n private host: string,\n private embedToken: string\n ) {}\n\n private async fetchSAT(): Promise<string> {\n const url = `https://${this.host}/api/fabric/embeds/tokens`;\n\n const timeout = 10000; // 10 seconds\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n body: JSON.stringify({ token: this.embedToken }),\n signal: controller.signal\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) {\n const data = (await response.json()) as { token: string };\n return data.token;\n }\n\n throw new RequestError(\n `Failed to fetch SAT using embed token: ${response.status} ${response.statusText}`\n );\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error && error.name === 'AbortError') {\n throw new RequestTimeoutError(`Request timeout after ${timeout}ms`, { cause: error });\n }\n\n logger.error('[EmbedCredentialProvider] Request failed:', error);\n throw error;\n }\n }\n\n public async authenticate(): Promise<{ token: string; expiry_at: number }> {\n const sat = await this.fetchSAT();\n const expiryAt = Date.now() + 3600 * 1000;\n return { token: sat, expiry_at: expiryAt };\n }\n\n public async refresh(): Promise<{ token: string; expiry_at: number }> {\n return this.authenticate();\n }\n}\n","import { SignalWire } from '../clients/SignalWire';\nimport { DependencyError } from '../core/errors';\nimport { EmbedTokenCredentialProvider } from '../dependencies/EmbedTokenCredentialProvider';\n\nimport type { Call } from '../core/entities/types/call.types';\n\n/** Options for {@link embeddableCall}. */\nexport interface EmbeddableCallOptions {\n /** Destination URI to call. */\n to: string;\n /** Embed token for authentication. */\n embedToken: string;\n /** SignalWire host URL. */\n host: string;\n}\n\n/**\n * Creates a call using an embed token for simple, embeddable integrations.\n *\n * Handles client creation, authentication, and dialing in a single call.\n *\n * @param options - Embed token, host, and destination.\n * @returns The created {@link Call} instance.\n */\nexport async function embeddableCall(options: EmbeddableCallOptions): Promise<Call> {\n const { to, embedToken, host } = options;\n const requiredFailed = [];\n\n if (!to) {\n requiredFailed.push('to');\n }\n\n if (!embedToken) {\n requiredFailed.push('embedToken');\n }\n\n if (!host) {\n requiredFailed.push('host');\n }\n\n if (requiredFailed.length > 0) {\n return Promise.reject(\n new DependencyError(`Missing required options: ${requiredFailed.join(', ')}`)\n );\n }\n\n const credentialProvider = new EmbedTokenCredentialProvider(host, embedToken);\n const client = new SignalWire(credentialProvider);\n\n const call = await client.dial(to);\n\n return call;\n}\n","import type { CredentialProvider } from './interfaces';\nimport type { SDKCredential } from '../core/types/common.types';\n\n/**\n * Credential provider that returns a fixed set of credentials.\n *\n * Use when the token is already available (e.g. from a backend endpoint).\n *\n * @example\n * ```ts\n * const provider = new StaticCredentialProvider({ token: 'my-sat-token' });\n * const client = new SignalWire(provider);\n * ```\n */\nexport class StaticCredentialProvider implements CredentialProvider {\n constructor(private credentials: SDKCredential) {}\n\n /** Returns the static credentials. */\n public async authenticate(): Promise<SDKCredential> {\n return Promise.resolve(this.credentials);\n }\n}\n","/**\n * Public API entry point for @signalwire/js\n *\n * IMPORTANT: This file should NEVER be imported by internal modules.\n * Internal modules must import directly from source files.\n *\n * This file defines the minimal public API surface for external consumers.\n */\n\n// ============================================================================\n// Main Entry Point\n// ============================================================================\n\nexport { SignalWire } from './clients/SignalWire';\n\nexport { embeddableCall } from './utils/embeddableCall';\n\nexport { StaticCredentialProvider } from './dependencies/StaticCredentialProvider';\nexport type { CredentialProvider } from './dependencies/interfaces';\n// ============================================================================\n// Error Types (exported as values for instanceof checks)\n// ============================================================================\n\nexport {\n CallCreateError,\n CollectionFetchError,\n InvalidCredentialsError,\n MediaTrackError,\n MessageParseError,\n UnexpectedError,\n VertoPongError\n} from './core/errors';\n\n// ============================================================================\n// Domain Model Classes (exported as values for instanceof and type guards)\n// ============================================================================\n\nexport { Address } from './core/entities/Address';\nexport { WebRTCCall } from './core/entities/Call';\nexport { Participant, SelfParticipant } from './core/entities/Participant';\nexport { Subscriber } from './core/entities/Subscriber';\nexport { SelfCapabilities } from './core/capabilities';\n\n// ============================================================================\n// Domain Model Interfaces\n// ============================================================================\n\nexport type { Directory } from './core/entities/Directory';\nexport type { SessionState } from './interfaces/SessionState';\n\n// ============================================================================\n// Type Guards (exported as values for runtime checks)\n// ============================================================================\n\nexport { isSelfParticipant } from './core/entities/Participant';\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nexport { ClientPreferences } from './containers/PreferencesContainer';\n\n// ============================================================================\n// Essential Types (type-only exports)\n// ============================================================================\n\n// Client types\nexport type { SignalWireOptions, DialOptions } from './clients/SignalWire';\n\n// Call types\nexport type {\n Call,\n CallOptions,\n CallStatus,\n CallState,\n CallParticipant,\n CallSelfParticipant,\n CallAddress\n} from './core/entities/types/call.types';\n\n// Types needed by web-components\nexport type { LayoutLayer } from './core/RPCMessages/types/common';\n\n// Media types\nexport type { MediaOptions, MediaDirections, MediaDirection } from './core/types/media.types';\n\n// Conversation types\nexport type { AddressHistory, TextMessage } from './core/types/conversation.types';\n\n// Participant types\nexport type { ExecuteMethod } from './core/entities/Participant';\n\n// Common types (credentials, adapters)\nexport type { SDKCredential, WebSocketAdapter, NodeSocketAdapter } from './core/types/common.types';\n\n// Capability types\nexport type {\n OnOffCapability,\n MemberCapabilities,\n CallCapabilitiesState\n} from './core/capabilities/types';\n\n// ============================================================================\n// DO NOT EXPORT (Internal Implementation):\n// - Behaviors (Destroyable, Fetchable)\n// - Controllers (DeviceController, RTCPeerConnectionController, etc.)\n// - Managers (DirectoryManager, TransportManager, ConversationsManager, etc.)\n// - Containers (DependencyContainer, PreferencesContainer singleton)\n// - Internal utilities and helpers\n// - RPC Messages and protocol internals\n// ============================================================================\n\n// ============================================================================\n// Library Ready Event (for async/dynamic script loading)\n// ============================================================================\n\ndeclare const __VERSION__: string;\n\n/**\n * Library version from package.json, injected at build time.\n */\nexport const version: string = __VERSION__;\n\n/**\n * Flag indicating the library has been loaded and is ready to use.\n * For UMD builds: `window.SignalWire.ready`\n * For ES modules: `import { ready } from '@signalwire/js'`\n */\nexport const ready: boolean = true;\n\n/**\n * Emits 'signalwire:js:ready' event when the library is loaded.\n *\n * Scripts that might load BEFORE the library (check flag first):\n * ```js\n * if (window.SignalWire?.ready) {\n * // Library already loaded, use it directly\n * initApp();\n * } else {\n * window.addEventListener('signalwire:js:ready', () => initApp());\n * }\n * ```\n */\nconst emitReadyEvent = (): void => {\n if (typeof window !== 'undefined') {\n const event = new CustomEvent('signalwire:js:ready', {\n detail: { version: __VERSION__ }\n });\n window.dispatchEvent(event);\n }\n};\n\nemitReadyEvent();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["Subject","ReplaySubject","BehaviorSubject","ValidationError","result: Awaited<T>","logger","getLogger","baseURL: string","credential: SDKCredential","Subject","BehaviorSubject","UnexpectedError","timeout","RequestTimeoutError","headers: HTTPHeaders","logger","getLogger","STORED_NUMBER_KEYS: (keyof StoredPreferences & keyof Preferences)[]","STORED_BOOLEAN_KEYS: (keyof StoredPreferences & keyof Preferences)[]","logger","getLogger","initialDevicesState: DevicesState","initialSelectedDevicesState: SelectedDevicesState","webRTCApiProvider: WebRTCApiProvider","device","devicesByKind: DevicesState","StorageNotAvailableError","storageImpl: Storage","SerializationError","StorageWriteError","item: string | null","StorageReadError","DeserializationError","DependencyError","fromPath: string","http: HTTPRequestController","tmpMap: VertoParams","VertoByeCauseCodes: Record<VertoByeCause, string>","logger","getLogger","storage: StorageManager","deviceController: DeviceController","reconnectCallsTimeout: number","attachKey: string","timeout","DEFAULT_ON_OFF: OnOffCapability","DEFAULT_MEMBER_CAPABILITIES: MemberCapabilities","DEFAULT_CALL_CAPABILITIES: CallCapabilitiesState","logger","getLogger","initialState: Partial<ParticipantState>","executeMethod: ExecuteMethod","deviceController: DeviceController","filterNull","UnimplementedError","vertoManager: VertoManager","logger","getLogger","initialSessionState: Partial<SessionState>","webRtcCallSession: CallManager","options: WebRTCCallEventManagerOptions","filterNull","DependencyError","filterAs","mediaSectionsValidCandidates: number[]","logger","getLogger","peerConnection: RTCPeerConnection","peerConnectionControllerNegotiating$: Observable<boolean>","logger","getLogger","options: LocalStreamControllerOptions","stream: MediaStream","constraints: MediaStreamConstraints","logger","getLogger","transceiverParams: RTCRtpTransceiverInit","MediaTrackError","constraints: MediaStreamConstraints","constraintsToApply: MediaTrackConstraints","logger","getLogger","options: RTCPeerConnectionControllerOptionsPartial","filterNull","track","options","DependencyError","options: RTCOfferOptions","sender","answer: RTCSessionDescriptionInit","logger","getLogger","webRtcCallSession: WebRTCCall","attachManager: AttachManager","deviceController: DeviceController","webRTCApiProvider: WebRTCApiProvider","DependencyError","filterNull","VertoPongError","filterAs","JSONRPCError","getValueFrom","vertoMethod: VertoMethod","vertoByeOrAccepted: boolean | VertoByeParams","deviceKind: 'audio' | 'video' | 'both' | undefined","InvalidParams","rtcPeerConnController: RTCPeerConnectionController | null","removeTrack: 'audio' | 'video' | 'both' | undefined","executeMethod: ExecuteMethod","vertoManager: VertoManager","deviceController: DeviceController","logger","getLogger","clientSession: ClientSession","options: CallOptions","address?: Address","UnimplementedError","getValueFrom","filterAs","InvalidParams","sessionManager: ClientSession","deviceController: DeviceController","attachManager: AttachManager","webRTCApiProvider: WebRTCApiProvider","logger","getLogger","endpoint: string","http: HTTPRequestController","fetchController: FetchController<T>","update$: Observable<Partial<T>>","onError?: (error: Error) => void","Subject","CollectionFetchError","ReplaySubject","originalCollection: EntityCollection<O>","filter: (i: unknown) => i is O","mapper: (item: O) => T","addressId: string","conversationManager: ConversationsProvider","addressProvider: AddressProvider<Address>","DependencyError","filterNull","UnimplementedError","logger","getLogger","Observable","RPCTimeoutError","NEVER","logger","getLogger","from","UnexpectedError","credential: SDKCredential","transport: TransportManager","storage: StorageManager","authorizationStateKey: string","attachManager: AttachManager","AuthStateHandlerError","VertoInviteHandlerError","filterAs","DependencyError","error","params: RPCConnectParams","throwOnRPCError","CallCreateError","address: Address | undefined","clientSessionManager: ClientSessionManager","logger","getLogger","groupId: string","clientSession: ClientSessionManager","http: HTTPRequestController","getSubscriberAddressId: () => string","onError?: (error: Error) => void","ConversationError","filterAs","logger","getLogger","http: HTTPRequestController","conversationManager: ConversationsProvider","onError?: (error: Error) => void","filterNull","filterAs","logger","getLogger","WebSocketConstructor: WebSocketAdapter | NodeSocketAdapter","endpoint: string","outgoingMessages$: Observable<string | ArrayBuffer | Blob>","UnexpectedError","WebSocketConnectionError","WebSocketTimeoutError","logger","getLogger","storage: StorageManager","protocolKey: string","onError?: (error: Error) => void","MessageParseError","EMPTY","TransportConnectionError","logger","getLogger","decodeHeader: JWTHeader","InvalidCredentialsError","error: unknown","UnexpectedError","ready","getLogger","host: string","embedToken: string","timeout","RequestError","RequestTimeoutError","DependencyError","credentials: SDKCredential","version: string","ready: boolean"],"sources":["../src/behaviors/Destroyable.ts","../src/utils/asyncRetry.ts","../src/controllers/HTTPRequestController.ts","../src/core/constants.ts","../src/utils/time.ts","../src/containers/PreferencesContainer.ts","../src/controllers/NavigatorDeviceController.ts","../src/dependencies/DefaultLocalStorage.ts","../src/managers/StorageManager.ts","../src/containers/DependencyContainer.ts","../src/behaviors/Fetchable.ts","../src/core/entities/Subscriber.ts","../src/core/RPCMessages/helpers.ts","../src/core/RPCMessages/RPCConnect.ts","../src/core/RPCMessages/RPCPing.ts","../src/core/RPCMessages/RPCExecute.ts","../src/core/RPCMessages/VertoMessages.ts","../src/core/RPCMessages/RPCEventAck.ts","../src/managers/AttachManager.ts","../src/core/capabilities/types.ts","../src/core/capabilities/computeCapabilities.ts","../src/core/capabilities/SelfCapabilities.ts","../src/core/RPCMessages/utils.ts","../src/core/entities/Participant.ts","../src/core/RPCMessages/guards/base.guards.ts","../src/core/RPCMessages/guards/events.guards.ts","../src/managers/CallEventsManager.ts","../src/helpers/SDPHelper.ts","../src/controllers/ICEGatheringController.ts","../src/controllers/LocalStreamController.ts","../src/controllers/TransceiverController.ts","../src/controllers/RTCPeerConnectionController.ts","../src/core/RPCMessages/guards/verto.guards.ts","../src/managers/VertoManager.ts","../src/managers/ParticipantFactory.ts","../src/core/entities/Call.ts","../src/managers/CallFactory.ts","../src/behaviors/Collection.ts","../src/core/entities/Address.ts","../src/core/utils.ts","../src/managers/ClientSessionManager.ts","../src/utils/isString.ts","../src/managers/ConversationsManager.ts","../src/utils/arrays.ts","../src/utils/warnup.ts","../src/managers/DirectoryManager.ts","../src/controllers/WebSocketController.ts","../src/core/RPCMessages/guards/methods.guards.ts","../src/managers/TransportManager.ts","../src/clients/SignalWire.ts","../src/dependencies/EmbedTokenCredentialProvider.ts","../src/utils/embeddableCall.ts","../src/dependencies/StaticCredentialProvider.ts","../src/index.ts"],"sourcesContent":["import { Subject, ReplaySubject, BehaviorSubject, merge, map, skip } from 'rxjs';\n\nimport type { Observable, Subscription, Observer } from 'rxjs';\n\nexport abstract class Destroyable {\n protected subscriptions: Subscription[] = [];\n protected subjects: Subject<unknown>[] = [];\n protected _destroyed$ = new Subject<void>();\n private _observableCache?: Map<string, Observable<unknown>>;\n\n public destroy(): void {\n this._observableCache?.clear();\n this.subscriptions.forEach((sub) => sub.unsubscribe());\n this.subjects.forEach((subject) => subject.complete());\n this._destroyed$.next();\n this._destroyed$.complete();\n }\n\n protected cachedObservable<T>(key: string, factory: () => Observable<T>): Observable<T> {\n this._observableCache ??= new Map();\n let cached = this._observableCache.get(key) as Observable<T> | undefined;\n if (!cached) {\n cached = factory();\n this._observableCache.set(key, cached as Observable<unknown>);\n }\n return cached;\n }\n\n protected subscribeTo<T>(\n observable: Observable<T>,\n observerOrNext: Partial<Observer<T>> | ((value: T) => void) | undefined\n ): void {\n const subscription = observable.subscribe(observerOrNext);\n this.subscriptions.push(subscription);\n }\n\n protected createSubject<T>(): Subject<T> {\n const subject = new Subject<T>();\n this.subjects.push(subject as Subject<unknown>);\n return subject;\n }\n\n protected createReplaySubject<T>(bufferSize?: number, windowTime?: number): ReplaySubject<T> {\n const subject = new ReplaySubject<T>(bufferSize, windowTime);\n this.subjects.push(subject as Subject<unknown>);\n return subject;\n }\n\n protected createBehaviorSubject<T>(initialValue: T): BehaviorSubject<T> {\n const subject = new BehaviorSubject<T>(initialValue);\n this.subjects.push(subject as Subject<unknown>);\n return subject;\n }\n\n public get $(): Observable<this> {\n return this.cachedObservable('$', () =>\n merge(\n // skip a burst of initial values from BehaviorSubjects\n ...this.subjects.map((s) => (s instanceof BehaviorSubject ? s.pipe(skip(1)) : s))\n ).pipe(map((_) => this))\n );\n }\n\n /**\n * Observable that emits when the instance is destroyed\n */\n public get destroyed$(): Observable<void> {\n return this._destroyed$.asObservable();\n }\n}\n","import { getLogger } from './logger';\nimport { ValidationError } from '../core/errors';\n\nconst DEFAULT_MAX_RETRIES = 10;\nconst DEFAULT_INITIAL_DELAY = 100;\nconst DEFAULT_DELAY_VARIATION = 1;\n\ninterface AsyncRetryOptions<T> {\n asyncCallable: () => Promise<T>;\n maxRetries?: number;\n delayFn?: () => number;\n validator?: (promiseResult: T) => void | never;\n expectedErrorHandler?: (error: unknown) => boolean;\n}\n\ninterface DelayOptions {\n initialDelay?: number;\n variation?: number;\n delayLimit?: number;\n}\n\nexport const increasingDelay = ({\n delayLimit: upperDelayLimit = Number.MAX_SAFE_INTEGER,\n initialDelay = DEFAULT_INITIAL_DELAY,\n variation = DEFAULT_DELAY_VARIATION\n}: DelayOptions): (() => number) => {\n if (initialDelay < 0) {\n throw new ValidationError('initialDelay must be gte 0');\n }\n if (upperDelayLimit < 0) {\n throw new ValidationError('upperDelayLimit must be gte 0');\n }\n if (variation < 0) {\n throw new ValidationError('variation must be gte 0');\n }\n if (initialDelay > upperDelayLimit) {\n throw new ValidationError('initialDelay must be lte delayLimit');\n }\n\n let delay = Math.min(initialDelay, upperDelayLimit);\n return () => {\n if (delay === upperDelayLimit) {\n // stop incrementing the delay and just return upperDelayLimit\n return upperDelayLimit;\n }\n const currentDelay = delay;\n delay = Math.min(delay + variation, upperDelayLimit);\n\n return currentDelay;\n };\n};\n\nexport const decreasingDelay = ({\n delayLimit: bottomDelayLimit = 0,\n initialDelay = DEFAULT_INITIAL_DELAY,\n variation = DEFAULT_DELAY_VARIATION\n}: DelayOptions): (() => number) => {\n if (initialDelay < 0) {\n throw new ValidationError('initialDelay must be gte 0');\n }\n if (bottomDelayLimit < 0) {\n throw new ValidationError('bottomDelayLimit must be gte 0');\n }\n if (variation < 0) {\n throw new ValidationError('variation must be gte 0');\n }\n if (initialDelay < bottomDelayLimit) {\n throw new ValidationError('initialDelay must be gte delayLimit');\n }\n\n let delay = Math.max(initialDelay, bottomDelayLimit);\n\n return () => {\n if (delay === bottomDelayLimit) {\n // stop incrementing the delay and just return upperDelayLimit\n return bottomDelayLimit;\n }\n const currentDelay = delay;\n delay = Math.max(delay - variation, bottomDelayLimit);\n\n return currentDelay;\n };\n};\n\nexport const constDelay = ({\n initialDelay = DEFAULT_INITIAL_DELAY\n}: Pick<DelayOptions, 'initialDelay'>): (() => number) => {\n if (initialDelay < 0) {\n throw new ValidationError('initialDelay must be gte 0');\n }\n return () => initialDelay;\n};\n\nexport const asyncRetry = async <T>({\n asyncCallable,\n maxRetries: retries = DEFAULT_MAX_RETRIES,\n delayFn,\n validator,\n expectedErrorHandler\n}: AsyncRetryOptions<T>): Promise<T> => {\n let remainingAttempts = retries - 1; // the 1st call counts as an attempt\n let wait = 0;\n\n const promiseAttempt = async (): Promise<T> => {\n try {\n let result: Awaited<T>;\n\n // Should not defer the call when: wait <= 0\n if (wait <= 0) {\n result = await asyncCallable();\n } else {\n result = await new Promise<T>((resolve, reject) =>\n setTimeout(() => {\n asyncCallable().then(resolve).catch(reject);\n }, wait)\n );\n }\n\n if (remainingAttempts) {\n // avoid messing with the normal returns in the last attempt\n validator?.(result);\n }\n\n return result;\n } catch (error) {\n if (remainingAttempts-- > 0 && !expectedErrorHandler?.(error)) {\n wait = delayFn?.() ?? 0;\n getLogger().debug(`Retrying request: ${retries - remainingAttempts} of ${retries}`);\n return promiseAttempt();\n } else {\n throw error;\n }\n }\n };\n\n return promiseAttempt();\n};\n","import { BehaviorSubject, Subject } from 'rxjs';\n\nimport { RequestTimeoutError, UnexpectedError } from '../core/errors';\nimport { asyncRetry, increasingDelay } from '../utils/asyncRetry';\nimport { getLogger } from '../utils/logger';\n\nimport type {\n HTTPRequest,\n HTTPResponse,\n HTTPHeaders,\n SDKCredential\n} from '../core/types/common.types';\nimport type { Observable } from 'rxjs';\n\nconst logger = getLogger();\n\nexport type HTTPRequestStatus = 'idle' | 'requesting' | 'success' | 'error';\n\nexport interface HTTPRequestControllerOptions {\n maxRetries?: number;\n retryDelayMin?: number;\n retryDelayMax?: number;\n requestTimeout?: number;\n}\n\nexport const GET_PARAMS = {\n method: 'GET',\n headers: {\n Accept: 'application/json'\n }\n} as const;\n\nexport const POST_PARAMS = {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n\n 'Content-Type': 'application/json'\n }\n} as const;\n\nexport class HTTPRequestController {\n // Default configuration values\n private static readonly defaultMaxRetries = 3;\n private static readonly defaultRetryDelayMinMs = 1000;\n private static readonly defaultRetryDelayMaxMs = 30000;\n private static readonly defaultRequestTimeoutMs = 30000;\n\n // Configuration\n private readonly maxRetries: number;\n private readonly retryDelayMin: number;\n private readonly retryDelayMax: number;\n private readonly requestTimeout: number;\n private _responses$ = new Subject<HTTPResponse>();\n private _errors$ = new Subject<Error>();\n\n // Observable streams\n private _status$ = new BehaviorSubject<HTTPRequestStatus>('idle');\n\n constructor(\n private baseURL: string,\n private credential: SDKCredential,\n options: HTTPRequestControllerOptions = {}\n ) {\n this.maxRetries = options.maxRetries ?? HTTPRequestController.defaultMaxRetries;\n this.retryDelayMin = options.retryDelayMin ?? HTTPRequestController.defaultRetryDelayMinMs;\n this.retryDelayMax = options.retryDelayMax ?? HTTPRequestController.defaultRetryDelayMaxMs;\n this.requestTimeout = options.requestTimeout ?? HTTPRequestController.defaultRequestTimeoutMs;\n }\n\n public get status$(): Observable<HTTPRequestStatus> {\n return this._status$.asObservable();\n }\n\n public get status(): HTTPRequestStatus {\n return this._status$.value;\n }\n\n public get responses$(): Observable<HTTPResponse> {\n return this._responses$.asObservable();\n }\n\n public get errors$(): Observable<Error> {\n return this._errors$.asObservable();\n }\n\n public async request(request: HTTPRequest): Promise<HTTPResponse> {\n this._status$.next('requesting');\n\n try {\n const response = await this.executeWithRetry(request);\n this._status$.next('success');\n this._responses$.next(response);\n return response;\n } catch (error) {\n logger.error('[HTTPRequestController] Request error:', error);\n this._status$.next('error');\n const err =\n error instanceof Error ? error : new Error('HTTP request failed', { cause: error });\n this._errors$.next(err);\n throw err;\n }\n }\n\n private async executeWithRetry(request: HTTPRequest): Promise<HTTPResponse> {\n // Calculate variation to spread delays evenly across retry attempts\n const variation = Math.ceil(\n (this.retryDelayMax - this.retryDelayMin) / Math.max(this.maxRetries - 1, 1)\n );\n\n const delayFn = increasingDelay({\n initialDelay: this.retryDelayMin,\n variation,\n delayLimit: this.retryDelayMax\n });\n\n return asyncRetry({\n asyncCallable: async () => this.executeRequest(request),\n maxRetries: this.maxRetries,\n delayFn,\n validator: (response) => {\n // Retry on 5xx server errors\n if (response.status >= 500 && response.status < 600) {\n throw new UnexpectedError(`Server error: ${response.status} ${response.statusText}`);\n }\n }\n });\n }\n\n private async executeRequest(request: HTTPRequest): Promise<HTTPResponse> {\n const url = this.buildURL(request.url);\n const headers = this.buildHeaders(request.headers);\n const timeout = request.timeout ?? this.requestTimeout;\n\n logger.debug('[HTTPRequestController] Executing request:', {\n method: request.method,\n url,\n headers: Object.keys(headers).reduce((acc, key) => {\n // Mask Authorization header for security\n // eslint-disable-next-line no-param-reassign\n acc[key] = key === 'Authorization' ? `${headers[key].substring(0, 20)}...` : headers[key];\n return acc;\n }, {} as HTTPHeaders),\n body: request.body\n });\n // {\"from_fabric_address_id\":\"03a98611-d38f-405a-af49-fcb51e7f22ad\",\"fabric_address_ids\":[\"31c0afc2-93f3-4530-9a7d-55613d40850d\",\"03a98611-d38f-405a-af49-fcb51e7f22ad\"]}\n // {\"from_fabric_address_id\":\"060b5d3e-5df0-45d9-911e-660779e593da\",\"fabric_address_ids\":[\"31c0afc2-93f3-4530-9a7d-55613d40850d\",\"060b5d3e-5df0-45d9-911e-660779e593da\"]}\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n method: request.method,\n headers,\n body: request.body,\n signal: controller.signal\n });\n\n clearTimeout(timeoutId);\n\n const httpResponse = await this.convertResponse(response);\n\n logger.debug('[HTTPRequestController] Response received:', {\n status: response.status,\n statusText: response.statusText,\n headers: [...response.headers.entries()],\n body: httpResponse.body ? httpResponse.body.substring(0, 200) : '(empty)' // Show first 200 chars\n });\n\n return httpResponse;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error && error.name === 'AbortError') {\n throw new RequestTimeoutError(`Request timeout after ${timeout}ms`, { cause: error });\n }\n\n logger.error('[HTTPRequestController] Request failed:', error);\n throw error;\n }\n }\n\n private buildURL(url: string | URL): string {\n const urlString = typeof url === 'string' ? url : url.toString();\n\n // If URL is absolute, return as-is\n if (urlString.startsWith('http://') || urlString.startsWith('https://')) {\n return urlString;\n }\n\n // Ensure base URL doesn't end with '/' and path starts with '/'\n const base = this.baseURL.endsWith('/') ? this.baseURL.slice(0, -1) : this.baseURL;\n const path = urlString.startsWith('/') ? urlString : `/${urlString}`;\n\n return `${base}${path}`;\n }\n\n private buildHeaders(requestHeaders?: HTTPHeaders): HTTPHeaders {\n const headers: HTTPHeaders = { ...(requestHeaders ?? {}) };\n\n // Add authentication header\n if (this.credential.token) {\n headers.Authorization = `Bearer ${this.credential.token}`;\n logger.debug(\n '[HTTPRequestController] Using Bearer token auth, token length:',\n this.credential.token.length\n );\n } else {\n logger.warn('[HTTPRequestController] No credentials available for authentication');\n }\n\n return headers;\n }\n\n private async convertResponse(response: Response): Promise<HTTPResponse> {\n // Convert Headers to plain object\n const headers: HTTPHeaders = {};\n response.headers.forEach((value, key) => {\n headers[key] = value;\n });\n\n // Read response body as text\n const bodyText = await response.text();\n\n return {\n status: response.status,\n statusText: response.statusText,\n headers,\n body: bodyText,\n ok: response.ok,\n url: response.url\n };\n }\n}\n","export const INVITE_VERSION = 1000;\nexport const DEFAULT_ICE_CANDIDATE_TIMEOUT_MS = 600;\nexport const DEFAULT_ICE_GATHERING_TIMEOUT_MS = 6_000;\nexport const DEFAULT_RECONNECT_CALLS_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\nexport const DEFAULT_CONNECTION_TIMEOUT_MS = 10_000;\nexport const DEFAULT_RECONNECT_DELAY_MIN_MS = 100;\nexport const DEFAULT_RECONNECT_DELAY_MAX_MS = 3000;\nexport const DEFAULT_DEVICE_DEBOUNCE_TIME_MS = 1500;\nexport const DEFAULT_DEVICE_POLLING_INTERVAL_MS = 0; // Disabled by default\nexport const PREFERENCES_STORAGE_KEY = 'sw:preferences';\n","export function fromSecToMs(seconds: number): number {\n return seconds * 1000;\n}\n\nexport function fromMsToSec(milliseconds: number): number {\n return Math.round(milliseconds / 100) / 10;\n}\n","import {\n DEFAULT_CONNECTION_TIMEOUT_MS,\n DEFAULT_DEVICE_DEBOUNCE_TIME_MS,\n DEFAULT_DEVICE_POLLING_INTERVAL_MS,\n DEFAULT_ICE_CANDIDATE_TIMEOUT_MS,\n DEFAULT_ICE_GATHERING_TIMEOUT_MS,\n DEFAULT_RECONNECT_CALLS_TIMEOUT_MS,\n DEFAULT_RECONNECT_DELAY_MAX_MS,\n DEFAULT_RECONNECT_DELAY_MIN_MS,\n PREFERENCES_STORAGE_KEY\n} from '../core/constants';\nimport { getLogger } from '../utils/logger';\nimport { fromMsToSec, fromSecToMs } from '../utils/time';\n\nimport type { MediaOptions } from '../core/types/media.types';\nimport type { StorageManager } from '../managers/StorageManager';\n\nconst logger = getLogger();\n\nexport interface Preferences {\n connectionTimeout: number;\n reconnectDelayMin: number;\n reconnectDelayMax: number;\n reconnectCallsTimeout: number;\n relayHost?: string;\n receiveVideo: boolean;\n receiveAudio: boolean;\n preferredAudioInput: MediaDeviceInfo | null;\n preferredAudioOutput: MediaDeviceInfo | null;\n preferredVideoInput: MediaDeviceInfo | null;\n inputAudioDeviceConstraints: MediaTrackConstraints | undefined;\n inputVideoDeviceConstraints: MediaTrackConstraints | undefined;\n disableUdpIceServers: boolean;\n relayOnly: boolean;\n iceCandidateTimeout: number;\n iceGatheringTimeout: number;\n deviceDebounceTime: number;\n devicePollingInterval: number;\n iceServers?: RTCIceServer[];\n defaultSignalWireOptions: {\n skipConnection: boolean;\n skipRegister: boolean;\n reconnectAttachedCalls: boolean;\n skipDeviceMonitoring: boolean;\n savePreferences: boolean;\n };\n inviteSubscribeScreenshare: string[];\n inviteSubscribeAdditionalDevice: string[];\n inviteSubscribeMainDevice: string[];\n userVariables: Record<string, unknown>;\n readonly preferredMediaOptions: MediaOptions;\n}\nexport class PreferencesContainer implements Preferences {\n static get instance(): Preferences {\n this._instance ??= new PreferencesContainer();\n return this._instance;\n }\n\n deviceDebounceTime = DEFAULT_DEVICE_DEBOUNCE_TIME_MS;\n devicePollingInterval = DEFAULT_DEVICE_POLLING_INTERVAL_MS;\n\n reconnectCallsTimeout = DEFAULT_RECONNECT_CALLS_TIMEOUT_MS;\n // 5 minutes\n iceServers?: RTCIceServer[];\n connectionTimeout = DEFAULT_CONNECTION_TIMEOUT_MS;\n reconnectDelayMin = DEFAULT_RECONNECT_DELAY_MIN_MS;\n reconnectDelayMax = DEFAULT_RECONNECT_DELAY_MAX_MS;\n disableUdpIceServers = false;\n relayOnly = false;\n iceCandidateTimeout = DEFAULT_ICE_CANDIDATE_TIMEOUT_MS;\n iceGatheringTimeout = DEFAULT_ICE_GATHERING_TIMEOUT_MS;\n defaultSignalWireOptions = {\n skipConnection: false,\n skipRegister: false,\n reconnectAttachedCalls: false,\n skipDeviceMonitoring: false,\n savePreferences: false\n };\n relayHost?: string;\n receiveVideo = true;\n receiveAudio = true;\n preferredAudioInput: MediaDeviceInfo | null = null;\n preferredAudioOutput: MediaDeviceInfo | null = null;\n preferredVideoInput: MediaDeviceInfo | null = null;\n inviteSubscribeScreenshare: string[] = ['video.room.screenshare'];\n inviteSubscribeAdditionalDevice: string[] = [\n // FIXME verify what to subscribe to for additional devices\n ];\n inviteSubscribeMainDevice: string[] = [\n 'track',\n 'destroy',\n 'member.updated.videoMuted',\n 'layout.changed',\n 'room.subscribed',\n 'member.updated.audioMuted',\n 'media.connected',\n 'room.updated',\n 'call.joined'\n ];\n userVariables = {};\n\n private _inputAudioDeviceConstraints?: MediaTrackConstraints;\n private _inputVideoDeviceConstraints?: MediaTrackConstraints;\n private static _instance?: PreferencesContainer;\n\n private constructor() {\n // Private constructor to enforce singleton pattern\n }\n\n public get preferredMediaOptions(): MediaOptions {\n return {\n receiveVideo: this.receiveVideo,\n receiveAudio: this.receiveAudio,\n inputAudioDeviceConstraints: this.inputAudioDeviceConstraints,\n inputVideoDeviceConstraints: this.inputVideoDeviceConstraints\n };\n }\n\n get inputAudioDeviceConstraints(): MediaTrackConstraints | undefined {\n return this._inputAudioDeviceConstraints;\n }\n\n set inputAudioDeviceConstraints(value: MediaTrackConstraints | undefined) {\n this._inputAudioDeviceConstraints = value;\n }\n\n get inputVideoDeviceConstraints(): MediaTrackConstraints | undefined {\n return this._inputVideoDeviceConstraints;\n }\n\n set inputVideoDeviceConstraints(value: MediaTrackConstraints | undefined) {\n this._inputVideoDeviceConstraints = value;\n }\n}\n\n/** Serializable subset of preferences that can be persisted to storage. */\ninterface StoredPreferences {\n connectionTimeout?: number;\n reconnectCallsTimeout?: number;\n reconnectDelayMin?: number;\n reconnectDelayMax?: number;\n relayHost?: string;\n receiveVideo?: boolean;\n receiveAudio?: boolean;\n disableUdpIceServers?: boolean;\n relayOnly?: boolean;\n iceCandidateTimeout?: number;\n iceGatheringTimeout?: number;\n deviceDebounceTime?: number;\n devicePollingInterval?: number;\n iceServers?: RTCIceServer[];\n userVariables?: Record<string, unknown>;\n}\n\n/** Keys of StoredPreferences that map to number fields on PreferencesContainer. */\nconst STORED_NUMBER_KEYS: (keyof StoredPreferences & keyof Preferences)[] = [\n 'connectionTimeout',\n 'reconnectCallsTimeout',\n 'reconnectDelayMin',\n 'reconnectDelayMax',\n 'iceCandidateTimeout',\n 'iceGatheringTimeout',\n 'deviceDebounceTime',\n 'devicePollingInterval'\n];\n\n/** Keys of StoredPreferences that map to boolean fields on PreferencesContainer. */\nconst STORED_BOOLEAN_KEYS: (keyof StoredPreferences & keyof Preferences)[] = [\n 'receiveVideo',\n 'receiveAudio',\n 'disableUdpIceServers',\n 'relayOnly'\n];\n\n/** Collects the serializable preferences from the container. */\nfunction collectStoredPreferences(): StoredPreferences {\n const container = PreferencesContainer.instance;\n return {\n connectionTimeout: container.connectionTimeout,\n reconnectCallsTimeout: container.reconnectCallsTimeout,\n reconnectDelayMin: container.reconnectDelayMin,\n reconnectDelayMax: container.reconnectDelayMax,\n relayHost: container.relayHost,\n receiveVideo: container.receiveVideo,\n receiveAudio: container.receiveAudio,\n disableUdpIceServers: container.disableUdpIceServers,\n relayOnly: container.relayOnly,\n iceCandidateTimeout: container.iceCandidateTimeout,\n iceGatheringTimeout: container.iceGatheringTimeout,\n deviceDebounceTime: container.deviceDebounceTime,\n devicePollingInterval: container.devicePollingInterval,\n iceServers: container.iceServers,\n userVariables: container.userVariables\n };\n}\n\n/** Applies stored preferences to the container. */\nfunction applyStoredPreferences(stored: StoredPreferences): void {\n const container = PreferencesContainer.instance as unknown as Record<string, unknown>;\n for (const key of STORED_NUMBER_KEYS) {\n if (stored[key] !== undefined) container[key] = stored[key];\n }\n for (const key of STORED_BOOLEAN_KEYS) {\n if (stored[key] !== undefined) container[key] = stored[key];\n }\n if (stored.relayHost !== undefined) container.relayHost = stored.relayHost;\n if (stored.iceServers !== undefined) container.iceServers = stored.iceServers;\n if (stored.userVariables !== undefined) container.userVariables = stored.userVariables;\n}\n\n/**\n * Public preferences API for configuring SDK behavior.\n *\n * Exposed as {@link SignalWire.preferences}. All timeout values\n * are in seconds when accessed through this class.\n *\n * When {@link enableSavePreferences} is called, preferences are\n * automatically loaded from storage and synced back on every change.\n */\nexport class ClientPreferences {\n private _storage: StorageManager | null = null;\n\n /**\n * Enables persistence of preferences to storage.\n * Loads any previously saved preferences and syncs future changes.\n */\n public enableSavePreferences(storage: StorageManager): void {\n this._storage = storage;\n this._loadFromStorage();\n }\n\n /** WebSocket connection timeout in seconds. */\n public get connectionTimeout(): number {\n return fromMsToSec(PreferencesContainer.instance.connectionTimeout);\n }\n public set connectionTimeout(seconds: number) {\n PreferencesContainer.instance.connectionTimeout = fromSecToMs(seconds);\n this._saveToStorage();\n }\n\n /** Timeout for reconnecting to previously attached calls, in seconds. */\n public get reconnectCallsTimeout(): number {\n return fromMsToSec(PreferencesContainer.instance.reconnectCallsTimeout);\n }\n public set reconnectCallsTimeout(seconds: number) {\n PreferencesContainer.instance.reconnectCallsTimeout = fromSecToMs(seconds);\n this._saveToStorage();\n }\n\n /** Minimum reconnection backoff delay in seconds. */\n public get reconnectDelayMin(): number {\n return fromMsToSec(PreferencesContainer.instance.reconnectDelayMin);\n }\n public set reconnectDelayMin(seconds: number) {\n PreferencesContainer.instance.reconnectDelayMin = fromSecToMs(seconds);\n this._saveToStorage();\n }\n\n /** Maximum reconnection backoff delay in seconds. */\n public get reconnectDelayMax(): number {\n return fromMsToSec(PreferencesContainer.instance.reconnectDelayMax);\n }\n public set reconnectDelayMax(seconds: number) {\n PreferencesContainer.instance.reconnectDelayMax = fromSecToMs(seconds);\n this._saveToStorage();\n }\n\n /** Custom relay host URL. Empty string uses the default. */\n public get relayHost(): string {\n return PreferencesContainer.instance.relayHost ?? '';\n }\n public set relayHost(value: string) {\n PreferencesContainer.instance.relayHost = value;\n this._saveToStorage();\n }\n\n /** Whether to receive remote video by default. */\n public get receiveVideo(): boolean {\n return PreferencesContainer.instance.receiveVideo;\n }\n public set receiveVideo(value: boolean) {\n PreferencesContainer.instance.receiveVideo = value;\n this._saveToStorage();\n }\n\n /** Whether to receive remote audio by default. */\n public get receiveAudio(): boolean {\n return PreferencesContainer.instance.receiveAudio;\n }\n public set receiveAudio(value: boolean) {\n PreferencesContainer.instance.receiveAudio = value;\n this._saveToStorage();\n }\n\n /** Preferred audio input device for new calls. */\n public get preferredAudioInput(): MediaDeviceInfo | null {\n return PreferencesContainer.instance.preferredAudioInput;\n }\n public set preferredAudioInput(value: MediaDeviceInfo | null) {\n PreferencesContainer.instance.preferredAudioInput = value;\n }\n\n /** Preferred audio output device for new calls. */\n public get preferredAudioOutput(): MediaDeviceInfo | null {\n return PreferencesContainer.instance.preferredAudioOutput;\n }\n public set preferredAudioOutput(value: MediaDeviceInfo | null) {\n PreferencesContainer.instance.preferredAudioOutput = value;\n }\n\n /** Preferred video input device for new calls. */\n public get preferredVideoInput(): MediaDeviceInfo | null {\n return PreferencesContainer.instance.preferredVideoInput;\n }\n public set preferredVideoInput(value: MediaDeviceInfo | null) {\n PreferencesContainer.instance.preferredVideoInput = value;\n }\n\n /** Default audio input track constraints. */\n public get inputAudioConstraints(): MediaTrackConstraints | undefined {\n return PreferencesContainer.instance.inputAudioDeviceConstraints;\n }\n public set inputAudioConstraints(value: MediaTrackConstraints | undefined) {\n PreferencesContainer.instance.inputAudioDeviceConstraints = value;\n }\n\n /** Default video input track constraints. */\n public get inputVideoConstraints(): MediaTrackConstraints | undefined {\n return PreferencesContainer.instance.inputVideoDeviceConstraints;\n }\n public set inputVideoConstraints(value: MediaTrackConstraints | undefined) {\n PreferencesContainer.instance.inputVideoDeviceConstraints = value;\n }\n\n /** Debounce time for device change events, in seconds. */\n public get deviceDebounceTime(): number {\n return fromMsToSec(PreferencesContainer.instance.deviceDebounceTime);\n }\n public set deviceDebounceTime(seconds: number) {\n PreferencesContainer.instance.deviceDebounceTime = fromSecToMs(seconds);\n this._saveToStorage();\n }\n\n /** Polling interval for device enumeration, in seconds. */\n public get devicePollingInterval(): number {\n return fromMsToSec(PreferencesContainer.instance.devicePollingInterval);\n }\n public set devicePollingInterval(seconds: number) {\n PreferencesContainer.instance.devicePollingInterval = fromSecToMs(seconds);\n this._saveToStorage();\n }\n\n /** Whether to filter out UDP-based ICE servers. */\n public get disableUdpIceServers(): boolean {\n return PreferencesContainer.instance.disableUdpIceServers;\n }\n public set disableUdpIceServers(value: boolean) {\n PreferencesContainer.instance.disableUdpIceServers = value;\n this._saveToStorage();\n }\n\n /** Whether to force TURN relay-only ICE candidates. */\n public get relayOnly(): boolean {\n return PreferencesContainer.instance.relayOnly;\n }\n public set relayOnly(value: boolean) {\n PreferencesContainer.instance.relayOnly = value;\n this._saveToStorage();\n }\n\n /** Timeout for individual ICE candidate gathering, in seconds. */\n public get iceCandidateTimeout(): number {\n return fromMsToSec(PreferencesContainer.instance.iceCandidateTimeout);\n }\n public set iceCandidateTimeout(seconds: number) {\n PreferencesContainer.instance.iceCandidateTimeout = fromSecToMs(seconds);\n this._saveToStorage();\n }\n\n /** Timeout for the entire ICE gathering phase, in seconds. */\n public get iceGatheringTimeout(): number {\n return fromMsToSec(PreferencesContainer.instance.iceGatheringTimeout);\n }\n public set iceGatheringTimeout(seconds: number) {\n PreferencesContainer.instance.iceGatheringTimeout = fromSecToMs(seconds);\n this._saveToStorage();\n }\n\n /** Custom ICE servers for TURN/STUN configuration. */\n public get iceServers(): RTCIceServer[] | undefined {\n return PreferencesContainer.instance.iceServers;\n }\n public set iceServers(value: RTCIceServer[] | undefined) {\n PreferencesContainer.instance.iceServers = value;\n this._saveToStorage();\n }\n\n /** Custom user variables attached to calls. */\n public get userVariables(): Record<string, unknown> {\n return PreferencesContainer.instance.userVariables;\n }\n public set userVariables(value: Record<string, unknown>) {\n PreferencesContainer.instance.userVariables = value;\n this._saveToStorage();\n }\n\n /** Saves current preferences to storage (fire-and-forget). */\n private _saveToStorage(): void {\n if (!this._storage) return;\n const data = collectStoredPreferences();\n this._storage.setItem(PREFERENCES_STORAGE_KEY, data, 'local').catch((error: unknown) => {\n logger.error(`[ClientPreferences] Failed to save preferences: ${String(error)}`);\n });\n }\n\n /** Loads preferences from storage and applies them to the container. */\n private _loadFromStorage(): void {\n if (!this._storage) return;\n this._storage\n .getItem<StoredPreferences>(PREFERENCES_STORAGE_KEY, 'local')\n .then((stored) => {\n if (stored) {\n applyStoredPreferences(stored);\n }\n })\n .catch((error: unknown) => {\n logger.error(`[ClientPreferences] Failed to load preferences: ${String(error)}`);\n });\n }\n}\n","import { debounceTime, distinctUntilChanged, interval, map, takeUntil, tap } from 'rxjs';\n\nimport { Destroyable } from '../behaviors/Destroyable';\nimport { PreferencesContainer } from '../containers/PreferencesContainer';\nimport { getLogger } from '../utils/logger';\n\nimport type { WebRTCApiProvider } from '../dependencies/interfaces';\nimport type { DeviceController } from '../interfaces/DeviceController';\nimport type { Observable, Subscription } from 'rxjs';\n\nconst logger = getLogger();\n\ninterface DevicesState {\n audioinput: MediaDeviceInfo[];\n audiooutput: MediaDeviceInfo[];\n videoinput: MediaDeviceInfo[];\n}\n\ninterface SelectedDevicesState {\n audioinput: MediaDeviceInfo | null;\n audiooutput: MediaDeviceInfo | null;\n videoinput: MediaDeviceInfo | null;\n}\n\nconst initialDevicesState: DevicesState = {\n audioinput: [],\n audiooutput: [],\n videoinput: []\n};\n\nconst initialSelectedDevicesState: SelectedDevicesState = {\n audioinput: null,\n audiooutput: null,\n videoinput: null\n};\n\nconst selectDevice = (\n devices: MediaDeviceInfo[] = [],\n selected: MediaDeviceInfo | null,\n preferred: MediaDeviceInfo | null\n): MediaDeviceInfo | null => {\n const available = selected\n ? Boolean(\n devices.find(\n // if the selected device was a default device(changed), a new default device will be selected automatically\n (device) => device.deviceId === selected.deviceId || device.label === selected.label\n )\n )\n : true;\n\n if ((!selected || !available) && devices.length > 0) {\n const preferredDevice = preferred\n ? devices.find(\n (device) => device.deviceId === preferred.deviceId || device.label === preferred.label\n )\n : undefined;\n return preferredDevice ?? devices[0];\n }\n\n return selected;\n};\n\nexport class NavigatorDeviceController extends Destroyable implements DeviceController {\n private deviceChangeHandler = () => {\n logger.debug('[DeviceController] Device change detected');\n void this.enumerateDevices();\n };\n\n private _devicesPoolingSubscription?: Subscription;\n private _devicesState$ = this.createBehaviorSubject<DevicesState>(initialDevicesState);\n private _selectedDevicesState$ = this.createBehaviorSubject<SelectedDevicesState>(\n initialSelectedDevicesState\n );\n\n // Error stream\n private _errors$ = this.createSubject<Error>();\n constructor(private readonly webRTCApiProvider: WebRTCApiProvider) {\n super();\n this.init();\n }\n public get selectedAudioInputDeviceConstraints(): MediaTrackConstraints {\n return this.deviceInfoToConstraints(this.selectedAudioInputDevice);\n }\n\n public get selectedVideoInputDeviceConstraints(): MediaTrackConstraints {\n return this.deviceInfoToConstraints(this.selectedVideoInputDevice);\n }\n\n public deviceInfoToConstraints(deviceInfo: MediaDeviceInfo | null): MediaTrackConstraints {\n if (!deviceInfo?.deviceId || deviceInfo.deviceId.trim() === '') {\n return {};\n }\n const devices =\n deviceInfo.kind === 'audioinput' ? this.audioInputDevices : this.videoInputDevices;\n const device =\n devices.find((device) => device.deviceId === deviceInfo.deviceId) ??\n devices.find((device) => device.label === deviceInfo.label);\n if (device) {\n return { deviceId: { exact: device.deviceId } };\n }\n return {};\n }\n\n public get errors$(): Observable<Error> {\n return this.cachedObservable('errors$', () =>\n this._errors$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n // Observable getters for device lists by kind\n public get audioInputDevices$(): Observable<MediaDeviceInfo[]> {\n return this.cachedObservable('audioInputDevices$', () =>\n this._devicesState$.pipe(\n map((state) => state.audioinput),\n distinctUntilChanged(),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n public get audioOutputDevices$(): Observable<MediaDeviceInfo[]> {\n return this.cachedObservable('audioOutputDevices$', () =>\n this._devicesState$.pipe(\n map((state) => state.audiooutput),\n distinctUntilChanged(),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n public get videoInputDevices$(): Observable<MediaDeviceInfo[]> {\n return this.cachedObservable('videoInputDevices$', () =>\n this._devicesState$.pipe(\n map((state) => state.videoinput),\n distinctUntilChanged(),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n public get selectedAudioInputDevice$(): Observable<MediaDeviceInfo | null> {\n return this.cachedObservable('selectedAudioInputDevice$', () =>\n this._selectedDevicesState$.asObservable().pipe(\n map((state) => state.audioinput),\n distinctUntilChanged(),\n takeUntil(this.destroyed$),\n tap((info) => logger.debug('[DeviceController] Selected audio input device changed:', info))\n )\n );\n }\n\n public get selectedAudioOutputDevice$(): Observable<MediaDeviceInfo | null> {\n return this.cachedObservable('selectedAudioOutputDevice$', () =>\n this._selectedDevicesState$.asObservable().pipe(\n map((state) => state.audiooutput),\n distinctUntilChanged(),\n takeUntil(this.destroyed$),\n tap((info) =>\n logger.debug('[DeviceController] Selected audio output device changed:', info)\n )\n )\n );\n }\n\n public get selectedVideoInputDevice$(): Observable<MediaDeviceInfo | null> {\n return this.cachedObservable('selectedVideoInputDevice$', () =>\n this._selectedDevicesState$.asObservable().pipe(\n map((state) => state.videoinput),\n distinctUntilChanged(),\n takeUntil(this.destroyed$),\n tap((info) => logger.debug('[DeviceController] Selected video input device changed:', info))\n )\n );\n }\n\n // Current value getters for selected devices\n public get selectedAudioInputDevice(): MediaDeviceInfo | null {\n return this._selectedDevicesState$.value.audioinput;\n }\n\n public get selectedAudioOutputDevice(): MediaDeviceInfo | null {\n return this._selectedDevicesState$.value.audiooutput;\n }\n\n public get selectedVideoInputDevice(): MediaDeviceInfo | null {\n return this._selectedDevicesState$.value.videoinput;\n }\n\n public get audioInputDevices(): MediaDeviceInfo[] {\n return this._devicesState$.value.audioinput;\n }\n\n public get audioOutputDevices(): MediaDeviceInfo[] {\n return this._devicesState$.value.audiooutput;\n }\n\n public get videoInputDevices(): MediaDeviceInfo[] {\n return this._devicesState$.value.videoinput;\n }\n\n // Setters for selected devices\n public selectAudioInputDevice(device: MediaDeviceInfo | null): void {\n this._selectedDevicesState$.next({\n ...this._selectedDevicesState$.value,\n audioinput: device\n });\n }\n\n public selectVideoInputDevice(device: MediaDeviceInfo | null): void {\n logger.debug('[DeviceController] Setting selected video input device:', device);\n this._selectedDevicesState$.next({\n ...this._selectedDevicesState$.value,\n videoinput: device\n });\n }\n\n public selectAudioOutputDevice(device: MediaDeviceInfo | null): void {\n this._selectedDevicesState$.next({\n ...this._selectedDevicesState$.value,\n audiooutput: device\n });\n }\n\n private init(): void {\n // Subscribe to device state changes and auto-select devices\n this.subscribeTo(\n this._devicesState$.pipe(debounceTime(PreferencesContainer.instance.deviceDebounceTime)),\n (devicesState) => {\n const currentSelected = this._selectedDevicesState$.value;\n\n const newAudioInput = selectDevice(\n devicesState.audioinput,\n currentSelected.audioinput,\n PreferencesContainer.instance.preferredAudioInput\n );\n\n const newAudioOutput = selectDevice(\n devicesState.audiooutput,\n currentSelected.audiooutput,\n PreferencesContainer.instance.preferredAudioOutput\n );\n\n const newVideoInput = selectDevice(\n devicesState.videoinput,\n currentSelected.videoinput,\n PreferencesContainer.instance.preferredVideoInput\n );\n\n // Only update if something changed\n if (\n newAudioInput !== currentSelected.audioinput ||\n newAudioOutput !== currentSelected.audiooutput ||\n newVideoInput !== currentSelected.videoinput\n ) {\n this._selectedDevicesState$.next({\n audioinput: newAudioInput,\n audiooutput: newAudioOutput,\n videoinput: newVideoInput\n });\n }\n }\n );\n\n void this.enumerateDevices();\n }\n\n public enableDeviceMonitoring(): void {\n this.disableDeviceMonitoring();\n this.webRTCApiProvider.mediaDevices.addEventListener('devicechange', this.deviceChangeHandler);\n\n if (PreferencesContainer.instance.devicePollingInterval > 0) {\n this._devicesPoolingSubscription = interval(\n PreferencesContainer.instance.devicePollingInterval\n ).subscribe(() => {\n logger.debug('[DeviceController] Polling devices due to interval');\n void this.enumerateDevices();\n });\n }\n\n void this.enumerateDevices();\n }\n\n public disableDeviceMonitoring(): void {\n this.webRTCApiProvider.mediaDevices.removeEventListener(\n 'devicechange',\n this.deviceChangeHandler\n );\n if (this._devicesPoolingSubscription) {\n this._devicesPoolingSubscription.unsubscribe();\n this._devicesPoolingSubscription = undefined;\n }\n }\n\n private async enumerateDevices(): Promise<void> {\n try {\n const devices = await this.webRTCApiProvider.mediaDevices.enumerateDevices();\n\n const devicesByKind: DevicesState = devices.reduce(\n (acc, device) => {\n const kind = device.kind as keyof DevicesState;\n acc[kind].push(device);\n return acc;\n },\n {\n audioinput: [],\n audiooutput: [],\n videoinput: []\n } as DevicesState\n );\n\n // Update state in a single emission\n this._devicesState$.next(devicesByKind);\n\n logger.debug('[DeviceController] Devices enumerated:', {\n audioInputs: devicesByKind.audioinput.length,\n audioOutputs: devicesByKind.audiooutput.length,\n videoInputs: devicesByKind.videoinput.length\n });\n } catch (error) {\n logger.error('[DeviceController] Failed to enumerate devices:', error);\n this._errors$.next(error as Error);\n }\n }\n\n public async getDeviceCapabilities(\n deviceInfo: MediaDeviceInfo\n ): Promise<MediaTrackCapabilities | null> {\n if (deviceInfo.kind === 'audiooutput') {\n return null;\n }\n\n try {\n const constraints = this.deviceInfoToConstraints(deviceInfo);\n const stream = await this.webRTCApiProvider.mediaDevices.getUserMedia({\n audio: deviceInfo.kind === 'audioinput' ? constraints : false,\n video: deviceInfo.kind === 'videoinput' ? constraints : false\n });\n\n const track =\n deviceInfo.kind === 'audioinput' ? stream.getAudioTracks()[0] : stream.getVideoTracks()[0];\n\n const capabilities = track.getCapabilities();\n\n // Stop all tracks to release devices\n stream.getTracks().forEach((t) => t.stop());\n\n return capabilities;\n } catch (error) {\n logger.error('[DeviceController] Failed to get device capabilities:', error);\n this._errors$.next(error as Error);\n throw error;\n }\n }\n\n public async isValidDevice(deviceInfo: MediaDeviceInfo | null): Promise<boolean> {\n if (!deviceInfo || deviceInfo.kind === 'audiooutput') {\n return false;\n }\n try {\n const capabilities = await this.getDeviceCapabilities(deviceInfo);\n return capabilities !== null;\n } catch {\n return false;\n }\n }\n\n public destroy(): void {\n this.disableDeviceMonitoring();\n super.destroy();\n }\n}\n","import { StorageNotAvailableError } from '../core/errors';\nimport { getLogger } from '../utils/logger';\n\nimport type { Storage, StorageScope } from './interfaces';\n\nexport class DefaultLocalStorage implements Storage {\n constructor() {\n // Check if localStorage is available\n if (typeof localStorage === 'undefined') {\n throw new StorageNotAvailableError('localStorage');\n }\n if (typeof sessionStorage === 'undefined') {\n throw new StorageNotAvailableError('sessionStorage');\n }\n\n // Test if localStorage is actually accessible (some browsers block it)\n try {\n const testKey = '__storage_test__';\n localStorage.setItem(testKey, 'test');\n localStorage.removeItem(testKey);\n } catch (error) {\n getLogger().error('LocalStorage is not accessible:', error);\n throw new StorageNotAvailableError('localStorage');\n }\n }\n\n private storage(scope: StorageScope) {\n return scope === 'local' ? localStorage : sessionStorage;\n }\n\n async setItem(key: string, value: string, scope: StorageScope = 'session'): Promise<void> {\n this.storage(scope).setItem(key, value);\n return Promise.resolve();\n }\n\n async getItem(key: string, scope: StorageScope = 'session'): Promise<string | null> {\n return Promise.resolve(this.storage(scope).getItem(key));\n }\n\n async removeItem(key: string, scope: StorageScope = 'session'): Promise<void> {\n this.storage(scope).removeItem(key);\n return Promise.resolve();\n }\n}\n","import {\n SerializationError,\n StorageWriteError,\n DeserializationError,\n StorageReadError\n} from '../core/errors';\nimport { DefaultLocalStorage } from '../dependencies/DefaultLocalStorage';\n\nimport type { Storage, StorageScope } from '../dependencies/interfaces';\n\nexport class StorageManager {\n constructor(private storageImpl: Storage = new DefaultLocalStorage()) {}\n\n /**\n * Validates that a value can be safely serialized to JSON\n * @throws SerializationError if value contains non-serializable types\n */\n private serialize(value: unknown, key?: string): string | null {\n if (value === undefined || value === null) {\n // undefined is acceptable, will be stored as null\n return null;\n }\n\n try {\n return JSON.stringify(value);\n } catch (e) {\n throw new SerializationError(key ?? 'unknown', e as Error);\n }\n }\n\n /**\n * Stores a value in storage\n * @throws InvalidStorageValueError if value contains non-serializable types\n * @throws SerializationError if JSON serialization fails\n * @throws StorageWriteError if writing to storage fails\n */\n public async setItem(\n key: string,\n value: unknown,\n scope: StorageScope = 'session'\n ): Promise<void> {\n const serialized = this.serialize(value, key);\n\n try {\n await this.storageImpl.setItem(key, serialized, scope);\n } catch (error) {\n throw new StorageWriteError(key, error as Error);\n }\n }\n\n /**\n * Retrieves a value from storage\n *\n * This method distinguishes between:\n * - Storage errors (network, permission, etc.) - these are thrown\n * - JSON parse errors - these trigger onParseError and return raw string\n * - Missing keys - returns null\n *\n * @returns The parsed value, raw string (on parse error), or null\n * @throws StorageReadError\n */\n public async getItem<T = unknown>(\n key: string,\n scope: StorageScope = 'session'\n ): Promise<T | null> {\n let item: string | null;\n\n try {\n item = await this.storageImpl.getItem(key, scope);\n } catch (error) {\n throw new StorageReadError(key, error as Error);\n }\n\n if (!item) {\n return null;\n }\n\n try {\n return JSON.parse(item) as T;\n } catch (error) {\n throw new DeserializationError(key, error as Error);\n }\n }\n\n /**\n * Removes a value from storage\n * @throws Error from underlying storage implementation\n */\n public async removeItem(key: string, scope: StorageScope = 'session'): Promise<void> {\n try {\n await this.storageImpl.removeItem(key, scope);\n } catch (error) {\n throw new StorageWriteError(key, error as Error);\n }\n }\n}\n","import { HTTPRequestController } from '../controllers/HTTPRequestController';\nimport { NavigatorDeviceController } from '../controllers/NavigatorDeviceController';\nimport { DependencyError } from '../core/errors';\nimport { DefaultLocalStorage } from '../dependencies/DefaultLocalStorage';\nimport { StorageManager } from '../managers/StorageManager';\n\nimport type { Subscriber } from '../core/entities/Subscriber';\nimport type {\n NodeSocketAdapter,\n SDKCredential,\n WebSocketAdapter\n} from '../core/types/common.types';\nimport type { Storage, WebRTCApiProvider } from '../dependencies/interfaces';\nimport type { ConversationsProvider } from '../interfaces/Conversations';\nimport type { Dependency } from '../interfaces/Dependency';\nimport type { DeviceController } from '../interfaces/DeviceController';\n\nexport class DependencyContainer implements Dependency {\n private _conversationManager?: ConversationsProvider;\n\n private _subscriber?: Subscriber;\n\n private _host?: string;\n\n private _domain?: string;\n\n private _storageManager?: StorageManager;\n private _storageImpl?: Storage;\n private _webSocketConstructor?: WebSocketAdapter | NodeSocketAdapter =\n typeof WebSocket !== 'undefined' ? WebSocket : undefined;\n private _baseURL: string = this.apiHost;\n private _credential: SDKCredential = {};\n private _httpRequestController?: HTTPRequestController;\n private _deviceController?: NavigatorDeviceController;\n private _webRTCApiProvider?: WebRTCApiProvider;\n public get subscriberId(): string {\n return this.subscriber.id;\n }\n\n public get subscriber(): Subscriber {\n if (!this._subscriber) {\n throw new DependencyError('Subscriber');\n }\n return this._subscriber;\n }\n public set subscriber(subscriber: Subscriber) {\n this._subscriber = subscriber;\n }\n\n public get storage(): StorageManager {\n if (!this._storageManager) {\n // Lazily initialize storage implementation if not already set\n this._storageImpl ??= new DefaultLocalStorage();\n this._storageManager = new StorageManager(this._storageImpl);\n }\n return this._storageManager;\n }\n\n public get http(): HTTPRequestController {\n this._httpRequestController ??= new HTTPRequestController(this._baseURL, this._credential);\n return this._httpRequestController;\n }\n\n public get conversationManager(): ConversationsProvider {\n if (!this._conversationManager) {\n throw new DependencyError('ConversationsManager');\n }\n return this._conversationManager;\n }\n\n public set conversationManager(conversationManager: ConversationsProvider) {\n this._conversationManager = conversationManager;\n }\n\n public get WebSocket(): WebSocketAdapter | NodeSocketAdapter {\n if (!this._webSocketConstructor) {\n throw new DependencyError('WebSocket constructor');\n }\n return this._webSocketConstructor;\n }\n\n public set WebSocket(WebSocketConstructor: WebSocketAdapter | NodeSocketAdapter) {\n this._webSocketConstructor = WebSocketConstructor;\n }\n\n public get deviceController(): DeviceController {\n this._deviceController ??= new NavigatorDeviceController(this.webRTCApiProvider);\n return this._deviceController;\n }\n\n public get webRTCApiProvider(): WebRTCApiProvider {\n if (!this._webRTCApiProvider) {\n if (typeof RTCPeerConnection === 'undefined' || typeof navigator === 'undefined') {\n throw new DependencyError(\n 'WebRTCApiProvider: RTCPeerConnection or navigator.mediaDevices is not available. ' +\n 'Please provide a custom webRTCApiProvider in SignalWireOptions.'\n );\n }\n this._webRTCApiProvider = {\n RTCPeerConnection,\n mediaDevices: navigator.mediaDevices\n };\n }\n return this._webRTCApiProvider;\n }\n\n public set webRTCApiProvider(webRTCApiProvider: WebRTCApiProvider) {\n this._webRTCApiProvider = webRTCApiProvider;\n // Reset device controller so it picks up the new provider\n this._deviceController = undefined;\n }\n\n public get authorizationStateKey(): string {\n return `sw:${this.subscriberId}:as`;\n }\n\n public get protocolKey(): string {\n return `sw:${this.subscriberId}:pt`;\n }\n\n public get attachedCallsKey(): string {\n return `sw:${this.subscriberId}:att`;\n }\n\n public getSubscriberFromAddressId(): string {\n return this.subscriber.addresses[0]?.id ?? '';\n }\n\n public set baseURL(baseURL: string) {\n this._baseURL = baseURL;\n this._httpRequestController = undefined;\n }\n\n public get credential(): SDKCredential {\n return this._credential;\n }\n\n public set credential(credential: SDKCredential) {\n this._credential = credential;\n this._httpRequestController = undefined;\n }\n\n public set storageImpl(storageImpl: Storage) {\n this._storageImpl = storageImpl;\n this._storageManager = undefined;\n }\n\n public set ch(ch: string | undefined) {\n if (!ch) {\n return;\n }\n\n const firstDot = ch.indexOf('.');\n if (firstDot !== -1) {\n this._host = ch.substring(0, firstDot);\n this._domain = ch.substring(firstDot + 1);\n }\n }\n\n public get relayHost(): string {\n return `wss://${this._host ?? 'puc'}.${this._domain ?? 'signalwire.com'}`;\n }\n\n public get apiHost(): string {\n return `https://${this._host ?? 'fabric'}.${this._domain ?? 'signalwire.com'}`;\n }\n}\n","import { defer, from, shareReplay, takeUntil } from 'rxjs';\n\nimport { Destroyable } from './Destroyable';\n\nimport type { HTTPRequestController } from '../controllers/HTTPRequestController';\nimport type { Observable } from 'rxjs';\n\nexport abstract class Fetchable<T = unknown> extends Destroyable {\n public fetched$: Observable<boolean>;\n\n constructor(\n public fromPath: string,\n protected http: HTTPRequestController\n ) {\n super();\n this.fetched$ = defer(() => from(this.fetch())).pipe(\n shareReplay(1),\n takeUntil(this.destroyed$)\n );\n }\n\n protected abstract populateInstance(data: T): void;\n\n private async fetch(): Promise<boolean> {\n const response = await this.http.request({\n url: this.fromPath,\n method: 'GET',\n headers: {\n Accept: 'application/json'\n }\n });\n if (response.ok && response.body) {\n const data = JSON.parse(response.body) as T;\n this.populateInstance(data);\n return true;\n }\n return false;\n }\n}\n","import { Fetchable } from '../../behaviors/Fetchable';\n\nimport type { HTTPRequestController } from '../../controllers/HTTPRequestController';\nimport type { GetAddressResponse } from '../types/address.types';\nimport type { GetSubscriberInfoResponse } from '../types/subscriber.types';\n\n/** Subscriber online presence state. */\nexport type SubscriberPresence = 'online' | 'offline' | 'busy';\n\n/**\n * Authenticated subscriber profile.\n *\n * Fetched automatically when a {@link SignalWire} connects.\n * Contains identity, contact, and organization details.\n */\nexport class Subscriber extends Fetchable<GetSubscriberInfoResponse> {\n /** Unique subscriber identifier. */\n public id!: string;\n /** Subscriber email address. */\n public email!: string;\n /** First name. */\n public firstName?: string;\n /** Last name. */\n public lastName?: string;\n /** Display name shown to other participants. */\n public displayName?: string;\n /** Job title. */\n public jobTitle?: string;\n /** Time zone offset. */\n public timeZone?: number;\n /** Country code. */\n public country?: string;\n /** Region/state. */\n public region?: string;\n /** Company name. */\n public companyName?: string;\n /** Push notification key for mobile/web push. */\n public pushNotificationKey!: string;\n /** Application-level settings (display name, permission scopes). */\n public appSettings?: {\n displayName: string;\n scopes: string[];\n };\n /** Fabric addresses associated with this subscriber. */\n public addresses!: GetAddressResponse[];\n\n constructor(http: HTTPRequestController) {\n super('/api/fabric/subscriber/info', http);\n }\n\n protected populateInstance(data: GetSubscriberInfoResponse): void {\n this.id = data.id;\n this.email = data.email;\n this.firstName = data.first_name;\n this.lastName = data.last_name;\n this.displayName = data.display_name;\n this.jobTitle = data.job_title;\n this.timeZone = data.time_zone;\n this.country = data.country;\n this.region = data.region;\n this.companyName = data.company_name;\n this.pushNotificationKey = data.push_notification_key;\n this.appSettings = data.app_settings\n ? {\n displayName: data.app_settings.display_name,\n scopes: data.app_settings.scopes\n }\n : undefined;\n this.addresses = data.fabric_addresses;\n }\n}\n","import { v4 as uuid } from 'uuid';\n\nimport type { JSONRPCRequest, JSONRPCResponse } from './types/base';\n\ninterface MakeRPCRequestParams<\n T extends string = 'execute',\n P extends Record<string, unknown> = Record<string, unknown>\n> {\n id?: string;\n method: T;\n params: P;\n}\nexport const buildRPCRequest = <\n T extends string = 'execute',\n P extends Record<string, unknown> = Record<string, unknown>\n>(\n params: MakeRPCRequestParams<T, P>\n): JSONRPCRequest<P> & { method: T; params: P } => {\n return {\n jsonrpc: '2.0' as const,\n id: params.id ?? uuid(),\n ...params\n };\n};\n\ninterface MakeRPCResponseParams {\n id: string;\n result: Record<string, unknown>;\n}\nexport const makeRPCResponse = <T extends JSONRPCResponse = JSONRPCResponse>(\n params: MakeRPCResponseParams\n): T => {\n return {\n jsonrpc: '2.0' as const,\n ...params\n } as T;\n};\n","import { buildRPCRequest } from './helpers';\n\nimport type { JSONRPCRequest } from './types/base';\n\ninterface WithToken {\n token: string;\n\n jwt_token?: never;\n}\ninterface WithJWT {\n token?: never;\n\n jwt_token: string;\n}\nexport type RPCConnectAuthentication = { project?: string } & (WithToken | WithJWT);\nexport interface RPCConnectParams {\n authentication: RPCConnectAuthentication;\n version?: typeof DEFAULT_CONNECT_VERSION;\n agent?: string;\n protocol?: string;\n\n authorization_state?: string;\n contexts?: string[];\n topics?: string[];\n eventing?: string[];\n\n event_acks?: boolean;\n}\n\nexport interface Authorization {\n jti: string;\n\n project_id: string;\n\n fabric_subscriber: {\n version: number;\n\n expires_at: number;\n\n subscriber_id: string;\n\n application_id: string;\n\n project_id: string;\n\n space_id: string;\n };\n}\n\nexport interface RPCConnectResult {\n identity: string;\n authorization: Authorization;\n protocol: string;\n\n ice_servers?: RTCIceServer[];\n}\n\nexport const DEFAULT_CONNECT_VERSION = {\n major: 4,\n minor: 0,\n revision: 0\n};\n\nexport const RPCConnect = (params: RPCConnectParams): JSONRPCRequest => {\n return buildRPCRequest({\n method: 'signalwire.connect',\n params: {\n version: DEFAULT_CONNECT_VERSION,\n\n event_acks: true,\n ...params\n }\n });\n};\n","import { buildRPCRequest, makeRPCResponse } from './helpers';\n\nimport type { SignalwirePingRequest } from './types/events';\nimport type { SignalwirePingResponse } from './types/methods';\n\nexport const RPCPing = (): SignalwirePingRequest => {\n return buildRPCRequest({\n method: 'signalwire.ping',\n params: {\n timestamp: Date.now() / 1000\n }\n });\n};\n\nexport const RPCPingResponse = (id: string, timestamp?: number): SignalwirePingResponse => {\n return makeRPCResponse<SignalwirePingResponse>({\n id,\n result: {\n timestamp: timestamp ?? Date.now() / 1000\n }\n });\n};\n","import { buildRPCRequest } from './helpers';\n\nimport type { JSONRPCRequest, JSONRPCMethod } from './types/base';\n\ninterface RPCExecuteParams {\n id?: string;\n method: JSONRPCMethod;\n params: Record<string, unknown>;\n}\n\nexport const RPCExecute = ({ method, params }: RPCExecuteParams): JSONRPCRequest => {\n return buildRPCRequest({\n method,\n params\n });\n};\n","import { buildRPCRequest, makeRPCResponse } from './helpers';\n\nimport type { VertoMethod } from '../types/rpc.types';\nimport type { JSONRPCResponse } from './types/base';\nimport type { WebrtcVertoParams, WebrtcVertoRequest } from './types/methods';\nimport type { VertoByeCause } from './types/verto';\n\ntype VertoParams = Record<string, unknown>;\n\nconst tmpMap: VertoParams = {\n id: 'callID',\n destinationNumber: 'destination_number',\n remoteCallerName: 'remote_caller_id_name',\n remoteCallerNumber: 'remote_caller_id_number',\n callerName: 'caller_id_name',\n callerNumber: 'caller_id_number',\n fromCallAddressId: 'from_fabric_address_id'\n};\n\n/**\n * Translate SDK fields into verto variables\n */\n/* eslint-disable */\nconst filterVertoParams = (params: VertoParams) => {\n if (Object.prototype.hasOwnProperty.call(params, 'dialogParams')) {\n // prettier-ignore\n const { \n remoteSdp,\n localStream,\n remoteStream,\n ...dialogParams\n } = params.dialogParams as Record<string, unknown>;\n for (const key in tmpMap) {\n if (key && Object.prototype.hasOwnProperty.call(dialogParams, key)) {\n // @ts-ignore\n dialogParams[tmpMap[key]] = dialogParams[key];\n delete dialogParams[key];\n }\n }\n params.dialogParams = dialogParams;\n }\n\n return params;\n};\n\n/* eslint-enable */\n\nconst buildVertoRPCMessage = (method: VertoMethod) => {\n return (params: VertoParams = {}) => {\n return buildRPCRequest({\n method,\n params: filterVertoParams(params)\n });\n };\n};\n\nexport type VertoRPCMessage = ReturnType<ReturnType<typeof buildVertoRPCMessage>>;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type JSONRPCParams = Record<string, any>;\n\n// export interface WebrtcVertoParams extends JSONRPCParams {\n// message: JSONRPCRequest<VertoMethod>;\n// callID?: string;\n// node_id?: string;\n// subscribe?: string[];\n// }\n\nexport const WebrtcVerto = (params: WebrtcVertoParams): WebrtcVertoRequest => {\n return buildRPCRequest({\n method: 'webrtc.verto',\n params\n });\n};\n\nexport type WebrtcVertoRPCMessage = ReturnType<ReturnType<typeof buildVertoRPCMessage>>;\n\nexport const VertoInvite = buildVertoRPCMessage('verto.invite');\nexport const VertoBye = buildVertoRPCMessage('verto.bye');\nexport const VertoAttach = buildVertoRPCMessage('verto.attach');\nexport const VertoModify = buildVertoRPCMessage('verto.modify');\nexport const VertoInfo = buildVertoRPCMessage('verto.info');\nexport const VertoAnswer = buildVertoRPCMessage('verto.answer');\nexport const VertoSubscribe = buildVertoRPCMessage('verto.subscribe');\nexport const VertoPong = buildVertoRPCMessage('verto.pong');\nexport const VertoResult = (id: string, method: VertoMethod): JSONRPCResponse => {\n return makeRPCResponse({\n id,\n result: {\n method\n }\n });\n};\n\nexport interface VertoModifyResponse {\n action: string;\n callID: string;\n holdState: 'held' | 'active';\n\n node_id?: string;\n sdp?: string;\n}\n\nexport const VertoByeCauseCodes: Record<VertoByeCause, string> = {\n NORMAL_CLEARING: '16',\n\n USER_BUSY: '17',\n\n MEDIA_TIMEOUT: '804'\n} as const;\n","import { makeRPCResponse } from './helpers';\n\nimport type { JSONRPCResponse } from './types/base';\n\nexport const RPCEventAckResponse = (id: string): JSONRPCResponse =>\n makeRPCResponse({ id, result: {} });\n","import { getLogger } from '../utils/logger';\n\nimport type { StorageManager } from './StorageManager';\nimport type { Address } from '../core/entities/Address';\nimport type { Call, CallOptions } from '../core/entities/types/call.types';\nimport type { MediaDirections } from '../core/types/media.types';\nimport type { DeviceController } from '../interfaces/DeviceController';\n\nconst logger = getLogger();\ninterface AttachableCall {\n id: string;\n to?: string;\n mediaDirections: MediaDirections;\n}\n\nexport interface OutboundCallProvider {\n createOutboundCall(destination: string | Address, options?: CallOptions): Promise<Call>;\n}\n\ninterface Attachment {\n destination: string;\n mediaDirections: MediaDirections;\n audioInputDevice: MediaDeviceInfo | null;\n videoInputDevice: MediaDeviceInfo | null;\n attachedAt: number;\n}\n\nexport class AttachManager {\n private session!: OutboundCallProvider;\n constructor(\n private readonly storage: StorageManager,\n\n private readonly deviceController: DeviceController,\n private readonly reconnectCallsTimeout: number,\n private attachKey: string\n ) {}\n\n async detachAll(): Promise<void> {\n const attached = await this.readAttached();\n for (const callId of Object.keys(attached)) {\n await this.detach({ id: callId, mediaDirections: attached[callId].mediaDirections });\n }\n }\n\n public setSession(session: OutboundCallProvider): void {\n this.session = session;\n }\n\n private async readAttached(): Promise<Record<string, Attachment>> {\n try {\n return (await this.storage.getItem(this.attachKey)) ?? {};\n } catch (error) {\n logger.warn('[AttachManager] Failed to retrieve attached calls from storage', error);\n return {};\n }\n }\n\n private async writeAttached(attached: Record<string, Attachment>): Promise<void> {\n try {\n await this.storage.setItem(this.attachKey, attached);\n } catch (error) {\n logger.warn('[AttachManager] Failed to write attached calls to storage', error);\n }\n }\n\n public async attach(call: AttachableCall): Promise<void> {\n if (!call.to) {\n logger.warn('[AttachManager] Skip attach for calls with no destination');\n return;\n }\n const attachment = {\n destination: call.to,\n mediaDirections: call.mediaDirections,\n audioInputDevice:\n call.mediaDirections.audio !== 'inactive'\n ? this.deviceController.selectedAudioInputDevice\n : null,\n videoInputDevice:\n call.mediaDirections.video !== 'inactive'\n ? this.deviceController.selectedVideoInputDevice\n : null,\n attachedAt: Date.now()\n };\n const attached = await this.readAttached();\n attached[call.id] = attachment;\n await this.writeAttached(attached);\n }\n\n public async detach(call: AttachableCall): Promise<void> {\n const attached = await this.readAttached();\n delete attached[call.id];\n await this.writeAttached(attached);\n }\n\n public async flush(): Promise<void> {\n await this.writeAttached({});\n }\n\n public async reattachCalls(): Promise<void> {\n const attached = await this.readAttached();\n\n await this.detachExpired();\n\n for (const [callId, attachment] of Object.entries(attached)) {\n const { destination } = attachment;\n\n const options = this.buildCallOptions(attachment);\n\n await this.session.createOutboundCall(destination, { callId, ...options });\n }\n }\n\n private buildCallOptions(attachment: Attachment): CallOptions {\n const { audio: audioDirection, video: videoDirection } = attachment.mediaDirections;\n const { audioInputDevice, videoInputDevice } = attachment;\n const receiveAudio = audioDirection.includes('recv');\n const receiveVideo = videoDirection.includes('recv');\n const inputAudioDeviceConstraints = {\n ...{ audio: audioDirection.includes('send') },\n ...this.deviceController.deviceInfoToConstraints(audioInputDevice)\n };\n const inputVideoDeviceConstraints = {\n ...{ video: videoDirection.includes('send') },\n ...this.deviceController.deviceInfoToConstraints(videoInputDevice)\n };\n return {\n receiveAudio,\n receiveVideo,\n inputAudioDeviceConstraints,\n inputVideoDeviceConstraints,\n reattach: true\n };\n }\n\n private async detachExpired() {\n const attached = await this.readAttached();\n\n const expired = Object.entries(attached).filter(([, attachment]) => {\n const now = Date.now();\n const timeout = this.reconnectCallsTimeout;\n return now - attachment.attachedAt > timeout;\n });\n expired.forEach(([callId]) => {\n delete attached[callId];\n });\n\n if (expired.length > 0) {\n await this.writeAttached(attached);\n }\n }\n}\n","/**\n * Represents an on/off capability state\n * Both `on` and `off` can be true if the parent permission grants both\n */\nexport interface OnOffCapability {\n readonly on: boolean;\n readonly off: boolean;\n}\n\n/**\n * Member-level capabilities for self or other members\n */\nexport interface MemberCapabilities {\n readonly muteAudio: OnOffCapability;\n readonly muteVideo: OnOffCapability;\n readonly deaf: OnOffCapability;\n readonly raisehand: OnOffCapability;\n readonly microphoneVolume: boolean;\n readonly microphoneSensitivity: boolean;\n readonly speakerVolume: boolean;\n readonly position: boolean;\n readonly meta: boolean;\n readonly remove: boolean;\n readonly audioFlags: boolean;\n}\n\n/**\n * Call-level capabilities state\n */\nexport interface CallCapabilitiesState {\n readonly self: MemberCapabilities;\n readonly member: MemberCapabilities;\n readonly end: boolean;\n readonly setLayout: boolean;\n readonly sendDigit: boolean;\n readonly vmutedHide: OnOffCapability;\n readonly lock: OnOffCapability;\n readonly device: boolean;\n readonly screenshare: boolean;\n}\n\n/**\n * Default on/off state with no permissions\n */\nexport const DEFAULT_ON_OFF: OnOffCapability = {\n on: false,\n off: false\n};\n\n/**\n * Default member capabilities with no permissions\n */\nexport const DEFAULT_MEMBER_CAPABILITIES: MemberCapabilities = {\n muteAudio: DEFAULT_ON_OFF,\n muteVideo: DEFAULT_ON_OFF,\n deaf: DEFAULT_ON_OFF,\n raisehand: DEFAULT_ON_OFF,\n microphoneVolume: false,\n microphoneSensitivity: false,\n speakerVolume: false,\n position: false,\n meta: false,\n remove: false,\n audioFlags: false\n};\n\n/**\n * Default call capabilities with no permissions\n */\nexport const DEFAULT_CALL_CAPABILITIES: CallCapabilitiesState = {\n self: DEFAULT_MEMBER_CAPABILITIES,\n member: DEFAULT_MEMBER_CAPABILITIES,\n end: false,\n setLayout: false,\n sendDigit: false,\n vmutedHide: DEFAULT_ON_OFF,\n lock: DEFAULT_ON_OFF,\n device: false,\n screenshare: false\n};\n","import { DEFAULT_CALL_CAPABILITIES, DEFAULT_MEMBER_CAPABILITIES, DEFAULT_ON_OFF } from './types';\n\nimport type { CallCapabilitiesState, MemberCapabilities, OnOffCapability } from './types';\n\ntype MemberType = 'self' | 'member';\n\n/**\n * Computes an on/off capability state from filtered flags\n *\n * Logic:\n * - `on` is true if any flag does NOT end with `.off`\n * - `off` is true if any flag does NOT end with `.on`\n *\n * This means parent permissions (without .on/.off suffix) grant both on and off\n */\nfunction computeOnOffCapability(filteredFlags: string[]): OnOffCapability {\n if (filteredFlags.length === 0) {\n return DEFAULT_ON_OFF;\n }\n\n return {\n on: filteredFlags.some((flag) => !flag.endsWith('.off')),\n off: filteredFlags.some((flag) => !flag.endsWith('.on'))\n };\n}\n\n/**\n * Filters flags for a specific member capability with on/off support\n *\n * Matches:\n * - The member type itself (e.g., \"self\" grants all self capabilities)\n * - The parent capability (e.g., \"self.mute\" grants all mute capabilities)\n * - The specific capability and its on/off variants (e.g., \"self.mute.audio*\")\n */\nfunction filterMemberOnOffFlags(\n flags: string[],\n memberType: MemberType,\n parent: string,\n capability: string\n): string[] {\n return flags.filter(\n (flag) =>\n flag === memberType ||\n flag === `${memberType}.${parent}` ||\n flag.startsWith(`${memberType}.${parent}.${capability}`)\n );\n}\n\n/**\n * Checks if a boolean capability is granted\n *\n * Matches:\n * - The member type itself (e.g., \"self\" grants all self capabilities)\n * - The parent capability if provided (e.g., \"self.microphone\" grants volume and sensitivity)\n * - The specific capability (e.g., \"self.microphone.volume.set\")\n */\nfunction hasBooleanCapability(\n flags: string[],\n memberType: MemberType,\n parent: string | null,\n capability: string\n): boolean {\n return flags.some(\n (flag) =>\n flag === memberType ||\n (parent !== null && flag === `${memberType}.${parent}`) ||\n flag.startsWith(`${memberType}.${parent ? `${parent}.` : ''}${capability}`)\n );\n}\n\n/**\n * Computes member-level capabilities (self or member) from raw flags\n */\nfunction computeMemberCapabilities(flags: string[], memberType: MemberType): MemberCapabilities {\n // Filter only flags relevant to this member type\n const memberFlags = flags.filter((flag) => flag.startsWith(memberType) || flag === memberType);\n\n if (memberFlags.length === 0) {\n return DEFAULT_MEMBER_CAPABILITIES;\n }\n\n return {\n muteAudio: computeOnOffCapability(filterMemberOnOffFlags(flags, memberType, 'mute', 'audio')),\n muteVideo: computeOnOffCapability(filterMemberOnOffFlags(flags, memberType, 'mute', 'video')),\n deaf: computeOnOffCapability(\n flags.filter((flag) => flag === memberType || flag.startsWith(`${memberType}.deaf`))\n ),\n raisehand: computeOnOffCapability(\n flags.filter((flag) => flag === memberType || flag.startsWith(`${memberType}.raisehand`))\n ),\n microphoneVolume: hasBooleanCapability(flags, memberType, 'microphone', 'volume'),\n microphoneSensitivity: hasBooleanCapability(flags, memberType, 'microphone', 'sensitivity'),\n speakerVolume: hasBooleanCapability(flags, memberType, 'speaker', 'volume'),\n position: hasBooleanCapability(flags, memberType, null, 'position'),\n meta: hasBooleanCapability(flags, memberType, null, 'meta'),\n remove: hasBooleanCapability(flags, memberType, null, 'remove'),\n audioFlags: hasBooleanCapability(flags, memberType, null, 'audioflags')\n };\n}\n\n/**\n * Computes all call capabilities from raw capability strings\n *\n * This is a pure function that transforms the raw capability strings\n * from the `call.joined` event into a structured capabilities state.\n *\n * @param capabilities - Raw capability strings from the server\n * @returns Computed capabilities state\n */\nexport function computeCapabilities(capabilities: string[]): CallCapabilitiesState {\n if (capabilities.length === 0) {\n return DEFAULT_CALL_CAPABILITIES;\n }\n\n return {\n self: computeMemberCapabilities(capabilities, 'self'),\n member: computeMemberCapabilities(capabilities, 'member'),\n end: capabilities.some((cap) => cap === 'end'),\n setLayout: capabilities.some((cap) => cap.startsWith('layout')),\n sendDigit: capabilities.some((cap) => cap.startsWith('digit')),\n vmutedHide: computeOnOffCapability(capabilities.filter((flag) => flag.startsWith('vmuted'))),\n lock: computeOnOffCapability(capabilities.filter((flag) => flag.startsWith('lock'))),\n device: capabilities.some((cap) => cap === 'device'),\n screenshare: capabilities.some((cap) => cap === 'screenshare')\n };\n}\n","import { distinctUntilChanged, map } from 'rxjs';\n\nimport { computeCapabilities } from './computeCapabilities';\nimport { DEFAULT_CALL_CAPABILITIES } from './types';\nimport { Destroyable } from '../../behaviors/Destroyable';\n\nimport type { CallCapabilitiesState, MemberCapabilities, OnOffCapability } from './types';\nimport type { Observable } from 'rxjs';\n\n/**\n * SelfCapabilities manages the capability state for the self participant.\n *\n * Capabilities are received from the server via `call.joined` events and determine\n * what actions the current participant is allowed to perform.\n *\n * Each capability is exposed as both:\n * - An observable (e.g., `end$`) for reactive state management\n * - A synchronous getter (e.g., `end`) for immediate access\n *\n * Member-level capabilities are accessed via the grouped `self` / `member` accessors:\n * - `capabilities.self.muteAudio` (sync)\n * - `capabilities.self$` (observable)\n *\n * When a new `call.joined` event is received, the capabilities state is\n * completely replaced (not merged).\n */\nexport class SelfCapabilities extends Destroyable {\n private _state$ = this.createBehaviorSubject<CallCapabilitiesState>(DEFAULT_CALL_CAPABILITIES);\n\n /**\n * Updates the capabilities state from raw capability strings.\n * This completely replaces the current state.\n *\n * @param capabilities - Raw capability strings from the server\n * @internal\n */\n public updateFromRaw(capabilities: string[]): void {\n const newState = computeCapabilities(capabilities);\n this._state$.next(newState);\n }\n\n // ============================================\n // Self member capabilities\n // ============================================\n\n /** Observable for self member capabilities */\n public get self$(): Observable<MemberCapabilities> {\n return this.cachedObservable('self$', () =>\n this._state$.pipe(\n map((state) => state.self),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current self member capabilities */\n public get self(): MemberCapabilities {\n return this._state$.value.self;\n }\n\n // ============================================\n // Member capabilities (other participants)\n // ============================================\n\n /** Observable for other member capabilities */\n public get member$(): Observable<MemberCapabilities> {\n return this.cachedObservable('member$', () =>\n this._state$.pipe(\n map((state) => state.member),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current other member capabilities */\n public get member(): MemberCapabilities {\n return this._state$.value.member;\n }\n\n // ============================================\n // Call-level capabilities\n // ============================================\n\n /** Observable for end call capability */\n public get end$(): Observable<boolean> {\n return this.cachedObservable('end$', () =>\n this._state$.pipe(\n map((state) => state.end),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current end call capability */\n public get end(): boolean {\n return this._state$.value.end;\n }\n\n /** Observable for set layout capability */\n public get setLayout$(): Observable<boolean> {\n return this.cachedObservable('setLayout$', () =>\n this._state$.pipe(\n map((state) => state.setLayout),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current set layout capability */\n public get setLayout(): boolean {\n return this._state$.value.setLayout;\n }\n\n /** Observable for send digit capability */\n public get sendDigit$(): Observable<boolean> {\n return this.cachedObservable('sendDigit$', () =>\n this._state$.pipe(\n map((state) => state.sendDigit),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current send digit capability */\n public get sendDigit(): boolean {\n return this._state$.value.sendDigit;\n }\n\n /** Observable for vmuted hide capability */\n public get vmutedHide$(): Observable<OnOffCapability> {\n return this.cachedObservable('vmutedHide$', () =>\n this._state$.pipe(\n map((state) => state.vmutedHide),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current vmuted hide capability */\n public get vmutedHide(): OnOffCapability {\n return this._state$.value.vmutedHide;\n }\n\n /** Observable for lock capability */\n public get lock$(): Observable<OnOffCapability> {\n return this.cachedObservable('lock$', () =>\n this._state$.pipe(\n map((state) => state.lock),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current lock capability */\n public get lock(): OnOffCapability {\n return this._state$.value.lock;\n }\n\n /** Observable for device capability */\n public get device$(): Observable<boolean> {\n return this.cachedObservable('device$', () =>\n this._state$.pipe(\n map((state) => state.device),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current device capability */\n public get device(): boolean {\n return this._state$.value.device;\n }\n\n /** Observable for screenshare capability */\n public get screenshare$(): Observable<boolean> {\n return this.cachedObservable('screenshare$', () =>\n this._state$.pipe(\n map((state) => state.screenshare),\n distinctUntilChanged()\n )\n );\n }\n\n /** Current screenshare capability */\n public get screenshare(): boolean {\n return this._state$.value.screenshare;\n }\n\n // ============================================\n // Full state access\n // ============================================\n\n /** Observable for the full capabilities state */\n public get state$(): Observable<CallCapabilitiesState> {\n return this._state$.asObservable();\n }\n\n /** Current full capabilities state */\n public get state(): CallCapabilitiesState {\n return this._state$.value;\n }\n}\n","export function toggleDeafMethod(is: boolean): 'call.undeaf' | 'call.deaf' {\n return is ? 'call.undeaf' : 'call.deaf';\n}\n\nexport function toggleHandraiseMethod(is: boolean): 'call.lowerhand' | 'call.raisehand' {\n return is ? 'call.lowerhand' : 'call.raisehand';\n}\n","import { distinctUntilChanged, map } from 'rxjs/operators';\n\nimport { Destroyable } from '../../behaviors/Destroyable';\nimport { PreferencesContainer } from '../../containers/PreferencesContainer';\nimport { filterNull } from '../../operators/filterNull';\nimport { getLogger } from '../../utils/logger';\nimport { SelfCapabilities } from '../capabilities';\nimport { UnimplementedError } from '../errors';\nimport { toggleDeafMethod, toggleHandraiseMethod } from '../RPCMessages/utils';\n\nimport type { CallParticipant, CallSelfParticipant } from './types/call.types';\nimport type { SelectDeviceOptions } from './types/participant.types';\nimport type { DeviceController } from '../../interfaces/DeviceController';\nimport type { VertoManager } from '../../interfaces/VertoManager';\nimport type { ScreenShareStatus } from '../../managers/types/verto-manager.types';\nimport type { JSONRPCResponse } from '../RPCMessages/types/base';\nimport type { Member, LayoutLayer } from '../RPCMessages/types/common';\nimport type { VideoPosition } from '../types/call.types';\nimport type { MediaOptions } from '../types/media.types';\nimport type { Observable } from 'rxjs';\n\nconst logger = getLogger();\n\n/**\n * Callback type for executing call methods\n * Injected to avoid circular dependency with Call class\n */\nexport type ExecuteMethod = <T extends JSONRPCResponse = JSONRPCResponse>(\n target: string,\n method: string,\n args: Record<string, unknown>\n) => Promise<T>;\n\ntype ParticipantState = Member & { position: LayoutLayer };\n\nconst initialState: Partial<ParticipantState> = {};\n\n/**\n * Represents a participant in a call.\n *\n * Provides observable state (audio/video mute, hand raise, volume, etc.)\n * and control methods for the participant. See {@link SelfParticipant} for\n * the local participant with additional device control.\n */\nexport class Participant extends Destroyable implements CallParticipant {\n /** Unique member ID of this participant. */\n public readonly id!: string;\n private _state$ = this.createBehaviorSubject<Partial<ParticipantState>>(initialState);\n constructor(\n id: string,\n protected executeMethod: ExecuteMethod,\n protected deviceController: DeviceController\n ) {\n super();\n this.id = id;\n }\n /** @internal */\n public upnext(data: Partial<ParticipantState>): void {\n this._state$.next({ ...this._state$.value, ...data });\n }\n\n /** Observable of the participant's display name. */\n public get name$(): Observable<string> {\n return this.cachedObservable('name$', () =>\n this._state$.pipe(\n map((state) => state.name),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable of the participant type (e.g. `'member'`, `'screen'`). */\n public get type$(): Observable<string> {\n return this.cachedObservable('type$', () =>\n this._state$.pipe(\n map((state) => state.type),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether the participant has raised their hand. */\n public get handraised$(): Observable<boolean> {\n return this.cachedObservable('handraised$', () =>\n this._state$.pipe(\n map((state) => state.handraised),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether the participant is visible in the layout. */\n public get visible$(): Observable<boolean> {\n return this.cachedObservable('visible$', () =>\n this._state$.pipe(\n map((state) => state.visible),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether the participant's audio is muted. */\n public get audioMuted$(): Observable<boolean> {\n return this.cachedObservable('audioMuted$', () =>\n this._state$.pipe(\n map((state) => state.audio_muted),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether the participant's video is muted. */\n public get videoMuted$(): Observable<boolean> {\n return this.cachedObservable('videoMuted$', () =>\n this._state$.pipe(\n map((state) => state.video_muted),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether the participant is deafened. */\n public get deaf$(): Observable<boolean> {\n return this.cachedObservable('deaf$', () =>\n this._state$.pipe(\n map((state) => state.deaf),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable of the participant's microphone input volume. */\n public get inputVolume$(): Observable<number> {\n return this.cachedObservable('inputVolume$', () =>\n this._state$.pipe(\n map((state) => state.input_volume),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable of the participant's speaker output volume. */\n public get outputVolume$(): Observable<number> {\n return this.cachedObservable('outputVolume$', () =>\n this._state$.pipe(\n map((state) => state.output_volume),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable of the microphone input sensitivity level. */\n public get inputSensitivity$(): Observable<number> {\n return this.cachedObservable('inputSensitivity$', () =>\n this._state$.pipe(\n map((state) => state.input_sensitivity),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether echo cancellation is enabled. */\n public get echoCancellation$(): Observable<boolean> {\n return this.cachedObservable('echoCancellation$', () =>\n this._state$.pipe(\n map((state) => state.echo_cancellation),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether auto-gain control is enabled. */\n public get autoGain$(): Observable<boolean> {\n return this.cachedObservable('autoGain$', () =>\n this._state$.pipe(\n map((state) => state.auto_gain),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether noise suppression is enabled. */\n public get noiseSuppression$(): Observable<boolean> {\n return this.cachedObservable('noiseSuppression$', () =>\n this._state$.pipe(\n map((state) => state.noise_suppression),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether low-bitrate mode is active. */\n public get lowbitrate$(): Observable<boolean> {\n return this.cachedObservable('lowbitrate$', () =>\n this._state$.pipe(\n map((state) => state.lowbitrate),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether noise reduction is active. */\n public get denoise$(): Observable<boolean> {\n return this.cachedObservable('denoise$', () =>\n this._state$.pipe(\n map((state) => state.denoise),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable of custom metadata for this participant. */\n public get meta$(): Observable<Record<string, unknown>> {\n return this.cachedObservable('meta$', () =>\n this._state$.pipe(\n map((state) => state.meta),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable of the participant's subscriber ID. */\n public get subscriberId$(): Observable<string> {\n return this.cachedObservable('subscriberId$', () =>\n this._state$.pipe(\n map((state) => state.subscriber_id),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable of the participant's address ID. */\n public get addressId$(): Observable<string> {\n return this.cachedObservable('addressId$', () =>\n this._state$.pipe(\n map((state) => state.address_id),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable of the server node ID for this participant. */\n public get nodeId$(): Observable<string> {\n return this.cachedObservable('nodeId$', () =>\n this._state$.pipe(\n map((state) => state.node_id),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Observable indicating whether the participant is currently speaking. */\n public get isTalking$(): Observable<boolean> {\n return this.cachedObservable('isTalking$', () =>\n this._state$.pipe(\n map((state) => state.talking),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Whether the participant is currently speaking. */\n public get isTalking(): boolean {\n return this._state$.value.talking ?? false;\n }\n\n /** Observable of the participant's layout position. */\n public get position$(): Observable<LayoutLayer | undefined> {\n return this.cachedObservable('position$', () =>\n this._state$.pipe(\n map((state) => state.position),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n /** Current layout position. */\n public get position(): LayoutLayer | undefined {\n return this._state$.value.position;\n }\n\n /** Whether the participant is an audience member (view-only). */\n public get isAudience(): boolean {\n return this._state$.value.isAudience ?? false;\n }\n\n /** Display name of this participant. */\n public get name(): string | undefined {\n return this._state$.value.name;\n }\n\n /** Participant type (e.g. `'member'`, `'screen'`). */\n public get type(): string | undefined {\n return this._state$.value.type;\n }\n\n public get handraised(): boolean {\n return this._state$.value.handraised ?? false;\n }\n\n public get visible(): boolean {\n return this._state$.value.visible ?? false;\n }\n\n public get audioMuted(): boolean {\n return this._state$.value.audio_muted ?? false;\n }\n\n public get videoMuted(): boolean {\n return this._state$.value.video_muted ?? false;\n }\n\n public get deaf(): boolean {\n return this._state$.value.deaf ?? false;\n }\n\n public get inputVolume(): number | undefined {\n return this._state$.value.input_volume;\n }\n\n public get outputVolume(): number | undefined {\n return this._state$.value.output_volume;\n }\n\n public get inputSensitivity(): number | undefined {\n return this._state$.value.input_sensitivity;\n }\n\n public get echoCancellation(): boolean {\n return this._state$.value.echo_cancellation ?? false;\n }\n\n public get autoGain(): boolean {\n return this._state$.value.auto_gain ?? false;\n }\n\n public get noiseSuppression(): boolean {\n return this._state$.value.noise_suppression ?? false;\n }\n\n public get lowbitrate(): boolean {\n return this._state$.value.lowbitrate ?? false;\n }\n\n public get denoise(): boolean {\n return this._state$.value.denoise ?? false;\n }\n\n public get meta(): Record<string, unknown> | undefined {\n return this._state$.value.meta;\n }\n\n public get subscriberId(): string | undefined {\n return this._state$.value.subscriber_id;\n }\n\n public get addressId(): string | undefined {\n return this._state$.value.address_id;\n }\n\n public get nodeId(): string | undefined {\n return this._state$.value.node_id;\n }\n\n /** @internal */\n public get value(): Partial<Member> {\n return this._state$.value;\n }\n\n /** Toggles the deafened state (mutes/unmutes incoming audio). */\n public async toggleDeaf(): Promise<void> {\n const method = toggleDeafMethod(this.deaf);\n const params = {};\n await this.executeMethod(this.id, method, params);\n }\n\n /** Toggles the hand-raised state. */\n public async toggleHandraise(): Promise<void> {\n await this.executeMethod(this.id, toggleHandraiseMethod(this.handraised), {});\n }\n\n /** Mutes the participant's audio. */\n public async mute(): Promise<void> {\n await this.executeMethod(this.id, 'call.mute', { channels: ['audio'] });\n }\n\n /** Unmutes the participant's audio. */\n public async unmute(): Promise<void> {\n await this.executeMethod(this.id, 'call.unmute', { channels: ['audio'] });\n }\n\n /** Toggles the participant's audio mute state. */\n public async toggleMute(): Promise<void> {\n return this.audioMuted ? this.unmute() : this.mute();\n }\n\n /** Mutes the participant's video. */\n public async muteVideo(): Promise<void> {\n await this.executeMethod(this.id, 'call.mute', { channels: ['video'] });\n }\n\n /** Unmutes the participant's video. */\n public async unmuteVideo(): Promise<void> {\n await this.executeMethod(this.id, 'call.unmute', { channels: ['video'] });\n }\n\n /** Toggles the participant's video mute state. */\n public async toggleMuteVideo(): Promise<void> {\n return this.videoMuted ? this.unmuteVideo() : this.muteVideo();\n }\n\n /** Toggles echo cancellation on the audio input. */\n public async toggleEchoCancellation(): Promise<void> {\n await this.executeMethod(this.id, 'call.audioflags.set', {\n echo_cancellation: !this.echoCancellation,\n auto_gain: this.autoGain,\n noise_suppression: this.noiseSuppression\n });\n }\n\n /** Toggles automatic gain control on the audio input. */\n public async toggleAudioInputAutoGain(): Promise<void> {\n await this.executeMethod(this.id, 'call.audioflags.set', {\n echo_cancellation: this.echoCancellation,\n auto_gain: !this.autoGain,\n noise_suppression: this.noiseSuppression\n });\n }\n\n /** Toggles noise suppression on the audio input. */\n public async toggleNoiseSuppression(): Promise<void> {\n await this.executeMethod(this.id, 'call.audioflags.set', {\n echo_cancellation: this.echoCancellation,\n auto_gain: this.autoGain,\n noise_suppression: !this.noiseSuppression\n });\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n public async toggleLowbitrate(): Promise<void> {\n // NEEDS check backend implementation\n throw new UnimplementedError();\n }\n\n /** Sets the microphone input sensitivity level. */\n public async setAudioInputSensitivity(value: number): Promise<void> {\n await this.executeMethod(this.id, 'call.microphone.sensitivity.set', {\n sensitivity: value\n });\n }\n\n /** Sets the microphone input volume level. */\n public async setAudioInputVolume(value: number): Promise<void> {\n await this.executeMethod(this.id, 'call.microphone.volume.set', {\n volume: value\n });\n }\n\n /** Sets the speaker output volume level. */\n public async setAudioOutputVolume(value: number): Promise<void> {\n await this.executeMethod(this.id, 'call.speaker.volume.set', {\n volume: value\n });\n }\n\n /** Sets the participant's position in the video layout. */\n public async setPosition(value: VideoPosition): Promise<void> {\n await this.executeMethod(this.id, 'call.member.position.set', {\n position: value\n });\n }\n\n /** Removes this participant from the call. */\n public async remove(): Promise<void> {\n await this.executeMethod(this.id, 'call.member.remove', {});\n }\n\n /** Ends the call for this participant. */\n public async end(): Promise<void> {\n await this.executeMethod(this.id, 'call.end', {});\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n public async setMeta(_meta: Record<string, unknown>): Promise<void> {\n // NEEDS backend implementation\n throw new UnimplementedError();\n }\n // eslint-disable-next-line @typescript-eslint/require-await\n public async updateMeta(_meta: Record<string, unknown>): Promise<void> {\n // NEEDS backend implementation\n throw new UnimplementedError();\n }\n\n public destroy(): void {\n // Cleanup callback reference - intentionally breaking type safety for cleanup\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any\n this.executeMethod = undefined as any;\n super.destroy();\n }\n}\n\n/**\n * The local participant in a call, with additional device and media control.\n *\n * Extends {@link Participant} with screen sharing, device selection,\n * and local media stream management.\n */\nexport class SelfParticipant extends Participant implements CallSelfParticipant {\n /**\n * Capabilities for this participant.\n * Contains all capability flags as both observables and values.\n */\n public readonly capabilities: SelfCapabilities;\n\n constructor(\n id: string,\n executeMethod: ExecuteMethod,\n private vertoManager: VertoManager,\n deviceController: DeviceController\n ) {\n super(id, executeMethod, deviceController);\n this.capabilities = new SelfCapabilities();\n }\n\n public override destroy(): void {\n this.capabilities.destroy();\n super.destroy();\n }\n\n /** Starts sharing the local screen. */\n public async startScreenShare(): Promise<void> {\n try {\n await this.vertoManager.addScreenMedia();\n } catch (error) {\n logger.error('[Participant.startScreenShare] Screen share error:', error);\n }\n }\n\n /** Observable of the current screen share status. */\n public get screenShareStatus$(): Observable<ScreenShareStatus> {\n return this.vertoManager.screenShareStatus$;\n }\n\n /** Current screen share status. */\n public get screenShareStatus(): ScreenShareStatus {\n return this.vertoManager.screenShareStatus;\n }\n\n /** Stops the current screen share. */\n public async stopScreenShare(): Promise<void> {\n return this.vertoManager.removeScreenMedia();\n }\n\n /** Adds an additional media input device to the call. */\n public async addAdditionalDevice(options: MediaOptions): Promise<void> {\n try {\n await this.vertoManager.addInputDevice(options);\n } catch (error) {\n logger.error('[Participant.startScreenShare] Screen share error:', error);\n }\n }\n\n /** Removes an additional media input device by ID. */\n public async removeAdditionalDevice(id: string): Promise<void> {\n return this.vertoManager.removeInputDevices(id);\n }\n\n /** Adds or replaces the primary audio input device with optional constraints or stream. */\n public async addAudioInputDevice({\n constraints,\n stream\n }: {\n constraints?: MediaTrackConstraints;\n stream?: MediaStream;\n } = {}): Promise<void> {\n const audio = (constraints ?? stream) ? undefined : true;\n return this.vertoManager.addMainInputDevices({\n audio,\n inputAudioDeviceConstraints: constraints,\n inputAudioStream: stream\n });\n }\n\n /** Adds or replaces the primary video input device with optional constraints or stream. */\n public async addVideoInputDevice({\n constraints,\n stream\n }: {\n constraints?: MediaTrackConstraints;\n stream?: MediaStream;\n } = {}): Promise<void> {\n const video = (constraints ?? stream) ? undefined : true;\n return this.vertoManager.addMainInputDevices({\n video,\n inputVideoDeviceConstraints: constraints,\n inputVideoStream: stream\n });\n }\n\n /** Adds or replaces primary input devices (audio and/or video). */\n public async addInputDevices(options: MediaOptions = {}): Promise<void> {\n await this.vertoManager.addMainInputDevices(options);\n }\n\n /** Selects the audio input device for future calls. Optionally saves as a preference. */\n public selectAudioInputDevice(device: MediaDeviceInfo, options: SelectDeviceOptions = {}): void {\n this.deviceController.selectAudioInputDevice(device);\n if (options.savePreference) {\n PreferencesContainer.instance.preferredAudioInput = device;\n }\n }\n\n /** Updates the audio input track constraints for the active call. */\n public async setAudioInputDeviceConstraints(constraints: MediaTrackConstraints): Promise<void> {\n await this.vertoManager.updateMediaConstraints({ audio: constraints });\n }\n\n /** Updates both audio and video input track constraints for the active call. */\n public async setInputDevicesConstraints(constraints: {\n audio: MediaTrackConstraints;\n video: MediaTrackConstraints;\n }): Promise<void> {\n await this.vertoManager.updateMediaConstraints(constraints);\n }\n\n /** Selects the video input device for future calls. Optionally saves as a preference. */\n public selectVideoInputDevice(device: MediaDeviceInfo, options: SelectDeviceOptions = {}): void {\n this.deviceController.selectVideoInputDevice(device);\n if (options.savePreference) {\n PreferencesContainer.instance.preferredVideoInput = device;\n }\n }\n\n /** Updates the video input track constraints for the active call. */\n public async setVideoInputDeviceConstraints(constraints: MediaTrackConstraints): Promise<void> {\n await this.vertoManager.updateMediaConstraints({ video: constraints });\n }\n\n /** Selects the audio output device. Optionally saves as a preference. */\n public selectAudioOutputDevice(device: MediaDeviceInfo, options: SelectDeviceOptions = {}): void {\n this.deviceController.selectAudioOutputDevice(device);\n if (options.savePreference) {\n PreferencesContainer.instance.preferredAudioOutput = device;\n }\n }\n\n public async mute(): Promise<void> {\n try {\n await super.mute();\n } catch (error) {\n logger.warn(\n '[Participant.toggleAudioInput] Server Error while muting audio input, proceeding with local toggle anyway',\n error\n );\n } finally {\n this.vertoManager.muteMainAudioInputDevice();\n }\n }\n\n public async unmute(): Promise<void> {\n try {\n await super.unmute();\n } catch (error) {\n logger.warn(\n '[Participant.toggleAudioInput] Server Error while unmuting audio input, proceeding with local toggle anyway',\n error\n );\n } finally {\n await this.vertoManager.unmuteMainAudioInputDevice();\n }\n }\n\n public async muteVideo(): Promise<void> {\n try {\n await super.muteVideo();\n } catch (error) {\n logger.warn(\n '[Participant.toggleVideoInput] Server Error while muting video input, proceeding with local toggle anyway',\n error\n );\n } finally {\n this.vertoManager.muteMainVideoInputDevice();\n }\n }\n\n public async unmuteVideo(): Promise<void> {\n try {\n await super.unmuteVideo();\n } catch (error) {\n logger.warn(\n '[Participant.toggleVideoInput] Server Error while unmuting video input, proceeding with local toggle anyway',\n error\n );\n } finally {\n await this.vertoManager.unmuteMainVideoInputDevice();\n }\n }\n}\n\n/** Type guard that checks if a participant is the local {@link SelfParticipant}. */\nexport const isSelfParticipant = (participant: Participant): participant is SelfParticipant => {\n return participant instanceof SelfParticipant;\n};\n","// =============================================================================\n// BASE TYPE GUARDS\n// =============================================================================\n// This file contains type guards for base JSON-RPC types.\n\nimport type { JSONRPCRequest, JSONRPCResponse } from '../types/base';\n\n// =============================================================================\n// TYPE GUARD HELPERS\n// =============================================================================\n\nexport function isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nexport function hasProperty<T extends object, K extends string>(\n obj: T,\n key: K\n): obj is T & Record<K, unknown> {\n return key in obj;\n}\n\nexport function hasStringProperty<T extends object, K extends string>(\n obj: T,\n key: K\n): obj is T & Record<K, string> {\n return key in obj && typeof (obj as Record<string, unknown>)[key] === 'string';\n}\n\n// =============================================================================\n// BASE TYPE GUARDS\n// =============================================================================\n\nexport function isJSONRPCRequest(value: unknown): value is JSONRPCRequest {\n return (\n isObject(value) &&\n hasProperty(value, 'jsonrpc') &&\n value.jsonrpc === '2.0' &&\n hasProperty(value, 'id') &&\n typeof value.id === 'string' &&\n hasProperty(value, 'method') &&\n typeof value.method === 'string'\n );\n}\n\nexport function isJSONRPCResponse(value: unknown): value is JSONRPCResponse {\n return (\n isObject(value) &&\n hasProperty(value, 'jsonrpc') &&\n value.jsonrpc === '2.0' &&\n hasProperty(value, 'id') &&\n typeof value.id === 'string' &&\n (hasProperty(value, 'result') || hasProperty(value, 'error'))\n );\n}\n","// =============================================================================\n// SIGNALWIRE EVENT TYPE GUARDS\n// =============================================================================\n// This file contains type guards for SignalWire event types.\n\nimport { hasProperty, isJSONRPCRequest, isObject } from './base.guards';\n\nimport type { TypeGuard, ExtractParams } from '../types/base';\nimport type {\n CallConnectPayload,\n CallJoinedPayload,\n CallJoinedRequest,\n CallLeftPayload,\n CallLeftRequest,\n CallPlayPayload,\n CallPlayRequest,\n CallStatePayload,\n CallStateRequest,\n CallUpdatedPayload,\n CallUpdatedRequest,\n CallConnectRequest,\n ConversationMessagePayload,\n ConversationMessageRequest,\n ConversationMessageUpdatedPayload,\n ConversationMessageUpdatedRequest,\n LayoutChangedPayload,\n LayoutChangedRequest,\n MemberJoinedPayload,\n MemberJoinedRequest,\n MemberLeftPayload,\n MemberLeftRequest,\n MemberTalkingPayload,\n MemberTalkingRequest,\n MemberUpdatedPayload,\n MemberUpdatedRequest,\n SignalwireAuthorizationStatePayload,\n SignalwireAuthorizationStateRequest,\n SignalwireCallMetadata,\n SignalwireCallRequest,\n SignalwireEventRequestBase,\n SignalwireMetadata,\n SignalwireRequest,\n WebrtcMessagePayload,\n WebrtcMessageRequest\n} from '../types/events';\n\n// =============================================================================\n// TYPE GUARD FACTORY SYSTEM\n// =============================================================================\n\n/**\n * Registry of all SignalWire event types.\n * This is the single source of truth for event type strings.\n */\n// eslint-disable-next-line unused-imports/no-unused-vars\nconst EVENT_TYPE_REGISTRY = {\n 'signalwire.authorization.state': true,\n 'webrtc.message': true,\n 'call.joined': true,\n 'call.left': true,\n 'call.updated': true,\n 'call.state': true,\n 'call.play': true,\n 'call.connect': true,\n 'member.updated': true,\n 'member.joined': true,\n 'member.left': true,\n 'member.talking': true,\n 'layout.changed': true,\n 'conversation.message': true,\n 'conversation.message.updated': true\n} as const;\n\nexport type RegisteredEventType = keyof typeof EVENT_TYPE_REGISTRY;\n\n/**\n * Factory function to create Request-level type guards.\n */\nexport function createEventRequestGuard<T extends SignalwireEventRequestBase>(\n eventType: RegisteredEventType\n): TypeGuard<T> {\n return (value: unknown): value is T =>\n isSignalwireRequest(value) && value.params.event_type === eventType;\n}\n\n/**\n * Factory function to create Metadata-level type guards.\n */\nexport function createEventMetadataGuard<T extends SignalwireMetadata>(\n eventType: RegisteredEventType\n): TypeGuard<T> {\n return (value: unknown): value is T =>\n isSignalwireMetadata(value) && value.event_type === eventType;\n}\n\n// =============================================================================\n// SIGNALWIRE EVENT TYPE GUARDS\n// =============================================================================\n\nexport function isSignalwireRequest(value: unknown): value is SignalwireRequest {\n return (\n isJSONRPCRequest(value) &&\n value.method === 'signalwire.event' &&\n isObject(value.params) &&\n hasProperty(value.params, 'event_type')\n );\n}\n\nexport function isSignalwireCallRequest(value: unknown): value is SignalwireCallRequest {\n return (\n isSignalwireRequest(value) &&\n (isCallJoinedRequest(value) ||\n isCallLeftRequest(value) ||\n isCallUpdatedRequest(value) ||\n isCallStateRequest(value) ||\n isCallPlayRequest(value) ||\n isCallConnectRequest(value) ||\n isMemberUpdatedRequest(value) ||\n isMemberJoinedRequest(value) ||\n isMemberLeftRequest(value) ||\n isMemberTalkingRequest(value) ||\n isLayoutChangedRequest(value) ||\n isWebrtcMessageRequest(value) ||\n isConversationMessageRequest(value) ||\n isConversationMessageUpdatedRequest(value))\n );\n}\n\n// Generated Request guards using factory pattern\nexport const isSignalwireAuthorizationStateRequest =\n createEventRequestGuard<SignalwireAuthorizationStateRequest>('signalwire.authorization.state');\n\nexport const isWebrtcMessageRequest =\n createEventRequestGuard<WebrtcMessageRequest>('webrtc.message');\n\nexport const isCallJoinedRequest = createEventRequestGuard<CallJoinedRequest>('call.joined');\n\nexport const isCallLeftRequest = createEventRequestGuard<CallLeftRequest>('call.left');\n\nexport const isCallUpdatedRequest = createEventRequestGuard<CallUpdatedRequest>('call.updated');\n\nexport const isCallStateRequest = createEventRequestGuard<CallStateRequest>('call.state');\n\nexport const isCallPlayRequest = createEventRequestGuard<CallPlayRequest>('call.play');\n\nexport const isCallConnectRequest = createEventRequestGuard<CallConnectRequest>('call.connect');\n\nexport const isMemberUpdatedRequest =\n createEventRequestGuard<MemberUpdatedRequest>('member.updated');\n\nexport const isMemberJoinedRequest = createEventRequestGuard<MemberJoinedRequest>('member.joined');\n\nexport const isMemberLeftRequest = createEventRequestGuard<MemberLeftRequest>('member.left');\n\nexport const isMemberTalkingRequest =\n createEventRequestGuard<MemberTalkingRequest>('member.talking');\n\nexport const isLayoutChangedRequest =\n createEventRequestGuard<LayoutChangedRequest>('layout.changed');\n\nexport const isConversationMessageRequest =\n createEventRequestGuard<ConversationMessageRequest>('conversation.message');\n\nexport const isConversationMessageUpdatedRequest =\n createEventRequestGuard<ConversationMessageUpdatedRequest>('conversation.message.updated');\n\n// =============================================================================\n// SIGNALWIRE EVENT METADATA TYPE GUARDS (outer wrapper with event_type)\n// =============================================================================\n\nexport function isSignalwireMetadata(value: unknown): value is SignalwireMetadata {\n return (\n isObject(value) &&\n hasProperty(value, 'event_type') &&\n typeof value.event_type === 'string' &&\n hasProperty(value, 'params')\n );\n}\n\nexport function isSignalwireCallMetadata(value: unknown): value is SignalwireCallMetadata {\n return (\n isSignalwireMetadata(value) &&\n (isCallJoinedMetadata(value) ||\n isCallLeftMetadata(value) ||\n isCallUpdatedMetadata(value) ||\n isCallStateMetadata(value) ||\n isCallPlayMetadata(value) ||\n isCallConnectMetadata(value) ||\n isMemberUpdatedMetadata(value) ||\n isMemberJoinedMetadata(value) ||\n isMemberLeftMetadata(value) ||\n isMemberTalkingMetadata(value) ||\n isLayoutChangedMetadata(value) ||\n isWebrtcMessageMetadata(value) ||\n isConversationMessageMetadata(value) ||\n isConversationMessageUpdatedMetadata(value))\n );\n}\n\n// Generated Metadata guards using factory pattern\nexport const isSignalwireAuthorizationStateMetadata = createEventMetadataGuard<\n ExtractParams<SignalwireAuthorizationStateRequest>\n>('signalwire.authorization.state');\n\nexport const isWebrtcMessageMetadata =\n createEventMetadataGuard<ExtractParams<WebrtcMessageRequest>>('webrtc.message');\n\nexport const isCallJoinedMetadata =\n createEventMetadataGuard<ExtractParams<CallJoinedRequest>>('call.joined');\n\nexport const isCallLeftMetadata =\n createEventMetadataGuard<ExtractParams<CallLeftRequest>>('call.left');\n\nexport const isCallUpdatedMetadata =\n createEventMetadataGuard<ExtractParams<CallUpdatedRequest>>('call.updated');\n\nexport const isCallStateMetadata =\n createEventMetadataGuard<ExtractParams<CallStateRequest>>('call.state');\n\nexport const isCallPlayMetadata =\n createEventMetadataGuard<ExtractParams<CallPlayRequest>>('call.play');\n\nexport const isCallConnectMetadata =\n createEventMetadataGuard<ExtractParams<CallConnectRequest>>('call.connect');\n\nexport const isMemberUpdatedMetadata =\n createEventMetadataGuard<ExtractParams<MemberUpdatedRequest>>('member.updated');\n\nexport const isMemberJoinedMetadata =\n createEventMetadataGuard<ExtractParams<MemberJoinedRequest>>('member.joined');\n\nexport const isMemberLeftMetadata =\n createEventMetadataGuard<ExtractParams<MemberLeftRequest>>('member.left');\n\nexport const isMemberTalkingMetadata =\n createEventMetadataGuard<ExtractParams<MemberTalkingRequest>>('member.talking');\n\nexport const isLayoutChangedMetadata =\n createEventMetadataGuard<ExtractParams<LayoutChangedRequest>>('layout.changed');\n\nexport const isConversationMessageMetadata =\n createEventMetadataGuard<ExtractParams<ConversationMessageRequest>>('conversation.message');\n\nexport const isConversationMessageUpdatedMetadata = createEventMetadataGuard<\n ExtractParams<ConversationMessageUpdatedRequest>\n>('conversation.message.updated');\n\n// =============================================================================\n// EVENT PAYLOAD TYPE GUARDS\n// =============================================================================\n\nexport function isSignalwireAuthorizationStatePayload(\n value: unknown\n): value is SignalwireAuthorizationStatePayload {\n return isObject(value) && hasProperty(value, 'authorization_state');\n}\n\nexport function isCallJoinedPayload(value: unknown): value is CallJoinedPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'room_session') &&\n hasProperty(value, 'call_id') &&\n hasProperty(value, 'member_id') &&\n hasProperty(value, 'capabilities')\n );\n}\n\nexport function isCallLeftPayload(value: unknown): value is CallLeftPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'room_session') &&\n hasProperty(value, 'call_id') &&\n hasProperty(value, 'reason')\n );\n}\n\nexport function isMemberUpdatedPayload(value: unknown): value is MemberUpdatedPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'member') &&\n hasProperty(value, 'room_id') &&\n hasProperty(value, 'room_session_id') &&\n !hasProperty(value, 'reason') &&\n !hasProperty((value as MemberUpdatedPayload).member, 'talking')\n );\n}\n\nexport function isMemberJoinedPayload(value: unknown): value is MemberJoinedPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'member') &&\n hasProperty(value, 'room_id') &&\n !hasProperty(value, 'reason')\n );\n}\n\nexport function isMemberLeftPayload(value: unknown): value is MemberLeftPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'member') &&\n hasProperty(value, 'room_id') &&\n hasProperty(value, 'reason')\n );\n}\n\nexport function isMemberTalkingPayload(value: unknown): value is MemberTalkingPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'member') &&\n hasProperty(value, 'room_id') &&\n hasProperty(value, 'room_session_id') &&\n !hasProperty(value, 'reason') &&\n hasProperty((value as MemberTalkingPayload).member, 'talking')\n );\n}\n\nexport function isLayoutChangedPayload(value: unknown): value is LayoutChangedPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'room_id') &&\n hasProperty(value, 'room_session_id') &&\n hasProperty(value, 'layout')\n );\n}\n\nexport function isCallUpdatedPayload(value: unknown): value is CallUpdatedPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'room_session') &&\n hasProperty(value, 'room_id') &&\n hasProperty(value, 'room_session_id')\n );\n}\n\nexport function isCallStatePayload(value: unknown): value is CallStatePayload {\n return (\n isObject(value) &&\n hasProperty(value, 'call_id') &&\n hasProperty(value, 'call_state') &&\n hasProperty(value, 'direction')\n );\n}\n\nexport function isCallPlayPayload(value: unknown): value is CallPlayPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'control_id') &&\n hasProperty(value, 'call_id') &&\n hasProperty(value, 'state')\n );\n}\n\nexport function isCallConnectPayload(value: unknown): value is CallConnectPayload {\n return (\n isObject(value) &&\n hasProperty(value, 'connect_state') &&\n hasProperty(value, 'call_id') &&\n hasProperty(value, 'segment_id')\n );\n}\n\nexport function isConversationMessagePayload(value: unknown): value is ConversationMessagePayload {\n return (\n isObject(value) &&\n hasProperty(value, 'id') &&\n hasProperty(value, 'type') &&\n hasProperty(value, 'kind') &&\n hasProperty(value, 'conversation_name')\n );\n}\n\nexport function isConversationMessageUpdatedPayload(\n value: unknown\n): value is ConversationMessageUpdatedPayload {\n return isConversationMessagePayload(value);\n}\n\nexport function isWebrtcMessageEventInnerParams(value: unknown): value is WebrtcMessagePayload {\n return (\n isObject(value) &&\n hasProperty(value, 'jsonrpc') &&\n value.jsonrpc === '2.0' &&\n hasProperty(value, 'id') &&\n hasProperty(value, 'method') &&\n typeof value.method === 'string'\n );\n}\n\n// =============================================================================\n// EVENT TYPE MAPPING\n// =============================================================================\n\nexport const EventTypeMap = {\n 'signalwire.authorization.state': isSignalwireAuthorizationStateRequest,\n 'webrtc.message': isWebrtcMessageRequest,\n 'call.joined': isCallJoinedRequest,\n 'call.left': isCallLeftRequest,\n 'call.updated': isCallUpdatedRequest,\n 'call.state': isCallStateRequest,\n 'call.play': isCallPlayRequest,\n 'call.connect': isCallConnectRequest,\n 'member.updated': isMemberUpdatedRequest,\n 'member.joined': isMemberJoinedRequest,\n 'member.left': isMemberLeftRequest,\n 'member.talking': isMemberTalkingRequest,\n 'layout.changed': isLayoutChangedRequest,\n 'conversation.message': isConversationMessageRequest,\n 'conversation.message.updated': isConversationMessageUpdatedRequest\n} as const;\n\nexport type EventType = keyof typeof EventTypeMap;\n\n/**\n * Gets the appropriate type guard for an event type.\n */\nexport function getEventGuard(eventType: string): TypeGuard<SignalwireRequest> | undefined {\n return EventTypeMap[eventType as EventType];\n}\n\n// =============================================================================\n// EVENT METADATA TYPE MAPPING\n// =============================================================================\n\nexport const EventMetadataTypeMap = {\n 'signalwire.authorization.state': isSignalwireAuthorizationStateMetadata,\n 'webrtc.message': isWebrtcMessageMetadata,\n 'call.joined': isCallJoinedMetadata,\n 'call.left': isCallLeftMetadata,\n 'call.updated': isCallUpdatedMetadata,\n 'call.state': isCallStateMetadata,\n 'call.play': isCallPlayMetadata,\n 'call.connect': isCallConnectMetadata,\n 'member.updated': isMemberUpdatedMetadata,\n 'member.joined': isMemberJoinedMetadata,\n 'member.left': isMemberLeftMetadata,\n 'member.talking': isMemberTalkingMetadata,\n 'layout.changed': isLayoutChangedMetadata,\n 'conversation.message': isConversationMessageMetadata,\n 'conversation.message.updated': isConversationMessageUpdatedMetadata\n} as const;\n\n/**\n * Gets the appropriate metadata type guard for an event type.\n */\nexport function getEventMetadataGuard(\n eventType: string\n): TypeGuard<SignalwireMetadata> | undefined {\n return EventMetadataTypeMap[eventType as EventType];\n}\n","import { distinctUntilChanged, filter, map, merge, tap } from 'rxjs';\n\nimport { Destroyable } from '../behaviors/Destroyable';\nimport { isSelfParticipant } from '../core/entities/Participant';\nimport { DependencyError } from '../core/errors';\nimport {\n isCallJoinedPayload,\n isLayoutChangedPayload\n} from '../core/RPCMessages/guards/events.guards';\nimport { filterAs } from '../operators';\nimport { filterNull } from '../operators/filterNull';\nimport { getLogger } from '../utils/logger';\n\nimport type { Participant, SelfParticipant } from '../core/entities/Participant';\nimport type {\n CallManager,\n CallParticipant,\n CallSelfParticipant,\n CallStatus\n} from '../core/entities/types/call.types';\nimport type {\n LayoutLayer,\n Member,\n RoomSession,\n Layout,\n MemberTalkingInfo\n} from '../core/RPCMessages/types/common';\nimport type { CallLayoutListResponse } from '../core/RPCMessages/types/methods';\nimport type { Observable } from 'rxjs';\n\nconst logger = getLogger();\n\ntype SessionState = RoomSession & { capabilities: string[] } & {\n layouts: string[];\n} & { layout_layers: LayoutLayer[] };\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface WebRTCCallEventManagerOptions {}\n\nconst initialSessionState: Partial<SessionState> = {};\n\nexport class CallEventsManager extends Destroyable {\n private selfId?: string;\n private originCallId?: string;\n private callIds = new Set<string>();\n private roomSessionIds = new Set<string>();\n private _status$ = this.createBehaviorSubject<CallStatus>('trying');\n\n private _participants$ = this.createBehaviorSubject<Record<string, Participant>>({});\n\n private _self$ = this.createBehaviorSubject<SelfParticipant | null>(null);\n private _sessionState$ = this.createBehaviorSubject<Partial<SessionState>>(initialSessionState);\n constructor(\n protected webRtcCallSession: CallManager,\n protected options: WebRTCCallEventManagerOptions = {}\n ) {\n super();\n this.initSubscriptions();\n }\n public get participants$(): Observable<CallParticipant[]> {\n return this.cachedObservable('participants$', () =>\n this._participants$\n .asObservable()\n .pipe(map((participantsRecord) => Object.values(participantsRecord)))\n );\n }\n\n public get self$(): Observable<CallSelfParticipant> {\n return this.cachedObservable('self$', () => this._self$.asObservable().pipe(filterNull()));\n }\n\n public get status$(): Observable<CallStatus> {\n return this._status$.asObservable();\n }\n\n public get status(): CallStatus {\n return this._status$.value;\n }\n\n // check if this call session has joined that same room session\n public isRoomSessionIdValid(roomSessionId: string): boolean {\n return this.roomSessionIds.has(roomSessionId);\n }\n\n public addCallId(callId: string): void {\n this.callIds.add(callId);\n }\n\n public isCallIdValid(callId: string): boolean {\n return this.callIds.has(callId);\n }\n\n public get recording$(): Observable<boolean> {\n return this.cachedObservable('recording$', () =>\n this._sessionState$.pipe(\n map((state) => state.recording),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get recordings$(): Observable<Record<string, unknown>[]> {\n return this.cachedObservable('recordings$', () =>\n this._sessionState$.pipe(\n map((state) => state.recordings),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get streaming$(): Observable<boolean> {\n return this.cachedObservable('streaming$', () =>\n this._sessionState$.pipe(\n map((state) => state.streaming),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get streams$(): Observable<Record<string, unknown>[]> {\n return this.cachedObservable('streams$', () =>\n this._sessionState$.pipe(\n map((state) => state.streams),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get playbacks$(): Observable<Record<string, unknown>[]> {\n return this.cachedObservable('playbacks$', () =>\n this._sessionState$.pipe(\n map((state) => state.playbacks),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get raiseHandPriority$(): Observable<boolean> {\n return this.cachedObservable('raiseHandPriority$', () =>\n this._sessionState$.pipe(\n map((state) => state.prioritize_handraise),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get locked$(): Observable<boolean> {\n return this.cachedObservable('locked$', () =>\n this._sessionState$.pipe(\n map((state) => state.locked),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get meta$(): Observable<Record<string, unknown>> {\n return this.cachedObservable('meta$', () =>\n this._sessionState$.pipe(\n map((state) => state.meta),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get capabilities$(): Observable<string[]> {\n return this.cachedObservable('capabilities$', () =>\n this._sessionState$.pipe(\n map((state) => state.capabilities),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get layout$(): Observable<string> {\n return this.cachedObservable('layout$', () =>\n this._sessionState$.pipe(\n map((state) => state.layout_name),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get layouts$(): Observable<string[]> {\n return this.cachedObservable('layouts$', () =>\n this._sessionState$.pipe(\n map((state) => state.layouts),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get layoutLayers$(): Observable<LayoutLayer[]> {\n return this.cachedObservable('layoutLayers$', () =>\n this._sessionState$.pipe(\n map((state) => state.layout_layers),\n distinctUntilChanged(),\n filterNull()\n )\n );\n }\n\n public get self(): CallSelfParticipant | null {\n return this._self$.value;\n }\n\n public get layoutLayers(): LayoutLayer[] {\n return this._sessionState$.value.layout_layers ?? [];\n }\n\n public get recording(): boolean {\n return this._sessionState$.value.recording ?? false;\n }\n\n public get streaming(): boolean {\n return this._sessionState$.value.streaming ?? false;\n }\n\n public get raiseHandPriority(): boolean {\n return this._sessionState$.value.prioritize_handraise ?? false;\n }\n\n public get locked(): boolean {\n return this._sessionState$.value.locked ?? false;\n }\n\n public get meta(): Record<string, unknown> {\n return this._sessionState$.value.meta ?? {};\n }\n\n public get layout(): string | undefined {\n return this._sessionState$.value.layout_name;\n }\n\n public get layouts(): string[] {\n return this._sessionState$.value.layouts ?? [];\n }\n\n public get capabilities(): string[] {\n return this._sessionState$.value.capabilities ?? [];\n }\n\n public isSessionEvent(id: string): boolean {\n return this.callIds.has(id) || this.roomSessionIds.has(id);\n }\n\n protected initSubscriptions(): void {\n this.subscribeTo(this.callJoinedEvent$, (callJoinedEvent) => {\n logger.debug('[CallEventsManager] Handling call.joined event for call/session IDs:', {\n callId: callJoinedEvent.call_id,\n roomSessionId: callJoinedEvent.room_session_id\n });\n this._status$.next('connected');\n\n const sessionState = callJoinedEvent.room_session;\n const { capabilities } = callJoinedEvent;\n // Don't update selfId and originCallId from nested call.joined events\n this.selfId = this.selfId ?? callJoinedEvent.member_id;\n this.originCallId = this.originCallId ?? callJoinedEvent.origin_call_id;\n this.callIds.add(callJoinedEvent.call_id);\n this.roomSessionIds.add(callJoinedEvent.room_session_id);\n\n this._sessionState$.next({\n ...this._sessionState$.value,\n recording: sessionState.recording,\n recordings: sessionState.recordings,\n streaming: sessionState.streaming,\n streams: sessionState.streams,\n playbacks: sessionState.playbacks,\n\n prioritize_handraise: sessionState.prioritize_handraise,\n locked: sessionState.locked,\n meta: sessionState.meta,\n\n capabilities\n });\n\n this.updateParticipants(sessionState.members);\n\n // Update capabilities on the self participant\n // This must happen after updateParticipants to ensure self exists\n this._self$.value?.capabilities.updateFromRaw(capabilities);\n\n this.updateLayouts();\n });\n this.subscribeTo(this.memberUpdates$, (member) => {\n logger.debug('[CallEventsManager] Handling member update event for member ID:', member);\n this.upsertParticipant(member);\n });\n this.subscribeTo(this.webRtcCallSession.memberLeft$, (memberLeftEvent) => {\n logger.debug(\n '[CallEventsManager] Handling member.left event for member ID:',\n memberLeftEvent.member.member_id\n );\n const participants = { ...this._participants$.value };\n if (memberLeftEvent.member.member_id in participants) {\n delete participants[memberLeftEvent.member.member_id];\n // in case in subscription is observing the participants collection\n this._participants$.next(participants);\n } else {\n logger.warn(\n `[CallEventsManager] Received member.left event for unknown member ID: ${memberLeftEvent.member.member_id}`\n );\n }\n });\n this.subscribeTo(this.layoutChangedEvent$, (layoutChangedEvent) => {\n logger.debug('[CallEventsManager] Handling layout.changed event:', layoutChangedEvent);\n this._sessionState$.next({\n ...this._sessionState$.value,\n\n layout_name: layoutChangedEvent.id,\n\n layout_layers: layoutChangedEvent.layers\n });\n\n this.updateParticipantPositions(layoutChangedEvent);\n });\n }\n private updateParticipantPositions(layoutChangedEvent: Layout) {\n if (\n Object.keys(this._participants$.value).length > 0 &&\n !layoutChangedEvent.layers.some((layer) => !!layer.member_id)\n ) {\n logger.warn(\n '[CallEventsManager] No layers with member_id found in layout.changed event. Nothing to update.'\n );\n }\n layoutChangedEvent.layers\n .filter((layer) => Boolean(layer.member_id))\n .map((layer) => {\n // update participant state with new position\n if (!layer.member_id) {\n throw new DependencyError('Layer member_id is required');\n }\n this._participants$.value[layer.member_id].upnext({\n position: layer\n });\n return this._participants$.value[layer.member_id];\n })\n .forEach((participant) => {\n if (isSelfParticipant(participant)) {\n this._self$.next(participant);\n }\n // update the collection observable to notify changes\n this._participants$.next({\n ...this._participants$.value,\n [participant.id]: participant\n });\n });\n }\n\n updateLayouts(): void {\n if (!this.selfId) return;\n\n this.webRtcCallSession\n .executeMethod<CallLayoutListResponse>(this.selfId, 'call.layout.list', {})\n .then((response) => {\n this._sessionState$.next({\n ...this._sessionState$.value,\n layouts: response.result.layouts\n });\n })\n .catch((error) => {\n logger.error('[CallEventsManager] Error fetching layouts:', error);\n });\n }\n\n private updateParticipants(members: Member[]) {\n members.forEach((member) => this.upsertParticipant(member));\n }\n\n private upsertParticipant(member: Member | MemberTalkingInfo) {\n if (!(member.member_id in this._participants$.value)) {\n // Pass selfId from call.joined event to ensure correct self participant identification\n const newParticipant = this.webRtcCallSession.createParticipant(\n member.member_id,\n this.selfId\n );\n\n this._participants$.next({\n ...this._participants$.value,\n [member.member_id]: newParticipant\n });\n }\n\n const participant = this._participants$.value[member.member_id];\n\n const oldValue = participant.value;\n logger.debug('[CallEventsManager] Updating participant:', member.member_id, {\n oldValue,\n newValue: member\n });\n participant.upnext({\n ...oldValue,\n ...member\n });\n\n if (isSelfParticipant(participant)) {\n this._self$.next(participant);\n }\n // in case in subscription is observing the participants collection\n this._participants$.next(this._participants$.value);\n }\n\n private get callJoinedEvent$() {\n return this.cachedObservable('callJoinedEvent$', () =>\n this.webRtcCallSession.callEvent$.pipe(\n filter(isCallJoinedPayload),\n tap((event) => {\n logger.debug('[CallEventsManager] Call joined event:', event);\n })\n )\n );\n }\n\n private get layoutChangedEvent$() {\n return this.cachedObservable('layoutChangedEvent$', () =>\n this.webRtcCallSession.callEvent$.pipe(\n filterAs(isLayoutChangedPayload, 'layout'),\n tap((event) => {\n logger.debug('[CallEventsManager] Layout changed event:', event);\n })\n )\n );\n }\n\n private get memberUpdates$() {\n return this.cachedObservable('memberUpdates$', () =>\n merge(\n this.webRtcCallSession.memberJoined$,\n this.webRtcCallSession.memberUpdated$,\n this.webRtcCallSession.memberTalking$\n ).pipe(\n map((event) => event.member),\n tap((event) => {\n logger.debug('[CallEventsManager] Member update event:', event);\n })\n )\n );\n }\n\n public override destroy(): void {\n const participants = Object.values(this._participants$.value);\n participants.forEach((participant) => {\n participant.destroy();\n });\n this._participants$.next({});\n this._self$.next(null);\n\n this.callIds.clear();\n this.roomSessionIds.clear();\n this.selfId = undefined;\n this.originCallId = undefined;\n //@ts-expect-error -- avoiding circular references\n this.webRtcCallSession = undefined;\n //@ts-expect-error -- avoiding circular references\n this.callSession = undefined;\n\n super.destroy();\n }\n}\n","/**\n * SDPHelper - Utility functions for SDP (Session Description Protocol) parsing and validation.\n *\n * This module provides helper functions to analyze and validate SDP content,\n * particularly for ICE candidate validation in WebRTC connections.\n */\n\n/**\n * Validates that an SDP string has at least one non-host ICE candidate\n * for each media section (m= line).\n *\n * Non-host candidates (srflx, prflx, relay) indicate that the SDP has\n * gathered candidates that can be used for connectivity through NAT\n * traversal mechanisms.\n *\n * @param sdp - The SDP string to validate\n * @returns true if the SDP is valid (has non-host candidates for all media sections,\n * or has no media sections), false otherwise\n *\n * @example\n * ```typescript\n * const sdp = `v=0\n * m=audio 9 UDP/TLS/RTP/SAVPF 111\n * a=candidate:1 1 UDP 1694498815 203.0.113.1 50001 typ srflx\n * m=video 9 UDP/TLS/RTP/SAVPF 96\n * a=candidate:2 1 UDP 1694498815 203.0.113.1 50002 typ relay`;\n *\n * isValidLocalDescription(sdp); // returns true\n * ```\n */\nexport function isValidLocalDescription(sdp: string): boolean {\n if (!sdp) {\n return false;\n }\n\n // Parse SDP to find media sections (m= lines)\n const lines = sdp.split('\\r\\n');\n const mediaSectionsValidCandidates: number[] = [];\n let currentSection = -1;\n\n for (const line of lines) {\n if (line.startsWith('m=')) {\n // New media section\n currentSection += 1;\n mediaSectionsValidCandidates[currentSection] = 0;\n } else if (line.startsWith('a=candidate:')) {\n const typeMatch = /\\styp\\s+(host|srflx|prflx|relay)/.exec(line);\n if (typeMatch && typeMatch[1] !== 'host') {\n // count only non-host candidates\n mediaSectionsValidCandidates[currentSection] += 1;\n }\n }\n }\n\n return (\n !mediaSectionsValidCandidates.length ||\n // Check if localDescription has at least one non-host candidate for each media section.\n mediaSectionsValidCandidates.every((count) => count > 0)\n );\n}\n","import { filter, map, withLatestFrom } from 'rxjs';\n\nimport { Destroyable } from '../behaviors/Destroyable';\nimport {\n DEFAULT_ICE_CANDIDATE_TIMEOUT_MS,\n DEFAULT_ICE_GATHERING_TIMEOUT_MS\n} from '../core/constants';\nimport { isValidLocalDescription } from '../helpers/SDPHelper';\nimport { getLogger } from '../utils/logger';\n\nimport type { Observable } from 'rxjs';\n\nconst logger = getLogger();\n\nexport interface ICEGatheringControllerOptions {\n iceCandidateTimeout?: number;\n iceGatheringTimeout?: number;\n relayOnly?: boolean;\n}\n\nexport type ICEGatheringStates = 'new' | 'gathering' | 'complete' | 'timeout';\nexport interface ICECandidateState {\n state: ICEGatheringStates;\n validSDP: boolean;\n}\n\nexport class ICEGatheringController extends Destroyable {\n private iceCandidateTimeout: number;\n private iceGatheringTimeout: number;\n private iceCandidateTimer?: ReturnType<typeof setTimeout>;\n private iceGatheringTimer?: ReturnType<typeof setTimeout>;\n private relayOnly: boolean;\n\n // Event handlers (bound to this instance)\n private onicegatheringstatechangeHandler = () => {\n const { iceGatheringState } = this.peerConnection;\n logger.debug(`[ICEGatheringController] ICE gathering state changed to: ${iceGatheringState}`);\n if (iceGatheringState === 'gathering') {\n this._iceCandidatesState.next({\n state: 'gathering',\n validSDP: false\n });\n }\n };\n\n private onicecandidateHandler = (event: RTCPeerConnectionIceEvent) => {\n logger.debug('[ICEGatheringController] ICE candidate event received:', event.candidate);\n this.removeTimer('iceCandidateTimer');\n\n if (event.candidate) {\n this.iceCandidateTimer = setTimeout(() => {\n if (this.peerConnection.iceGatheringState !== 'complete') {\n logger.warn('[ICEGatheringController] ICE candidate timeout, using current SDP');\n this.handleICECandidateTimeout();\n }\n }, this.iceCandidateTimeout);\n } else {\n logger.debug('[ICEGatheringController] ICE gathering completed: null candidate received');\n this.removeTimer('iceGatheringTimer');\n\n this.handleICEGatheringComplete();\n }\n };\n\n private _iceCandidatesState = this.createBehaviorSubject<ICECandidateState>({\n state: 'new',\n validSDP: false\n });\n constructor(\n private peerConnection: RTCPeerConnection,\n private peerConnectionControllerNegotiating$: Observable<boolean>,\n options: ICEGatheringControllerOptions = {}\n ) {\n super();\n this.iceCandidateTimeout = options.iceCandidateTimeout ?? DEFAULT_ICE_CANDIDATE_TIMEOUT_MS;\n this.iceGatheringTimeout = options.iceGatheringTimeout ?? DEFAULT_ICE_GATHERING_TIMEOUT_MS;\n this.relayOnly = options.relayOnly ?? false;\n // Setup ICE candidate handling\n this.setupEventListeners();\n this.subscribeTo(\n this.peerConnectionControllerNegotiating$.pipe(filter((isNegotiating) => isNegotiating)),\n (isNegotiating) => {\n if (isNegotiating) {\n this.setupEventListeners();\n this.iceGatheringTimer = setTimeout(() => {\n if (this.peerConnection.iceGatheringState !== 'complete') {\n logger.warn('[ICEGatheringController] ICE gathering timeout, using current SDP');\n this.handleICEGatheringTimeout();\n }\n }, this.iceGatheringTimeout);\n }\n }\n );\n }\n\n private setupEventListeners() {\n this.peerConnection.removeEventListener('icecandidate', this.onicecandidateHandler);\n this.peerConnection.addEventListener('icecandidate', this.onicecandidateHandler);\n\n // Setup ICE gathering state change handling\n this.peerConnection.removeEventListener(\n 'icegatheringstatechange',\n this.onicegatheringstatechangeHandler\n );\n this.peerConnection.addEventListener(\n 'icegatheringstatechange',\n this.onicegatheringstatechangeHandler\n );\n }\n\n public get iceCandidatesState$(): Observable<ICEGatheringStates> {\n return this._iceCandidatesState.pipe(\n withLatestFrom(this.peerConnectionControllerNegotiating$),\n filter(([_, isNegotiating]) => isNegotiating),\n map(([state, _]) => state.state)\n );\n }\n\n public get hasValidLocalDescriptionSDP(): boolean {\n const sdp = this.peerConnection.localDescription?.sdp;\n return isValidLocalDescription(sdp ?? '');\n }\n\n public get isRelayOnly(): boolean {\n return this.relayOnly;\n }\n\n public setRelayOnly(value: boolean): void {\n this.relayOnly = value;\n }\n\n private handleICEGatheringComplete(): void {\n logger.debug('[ICEGatheringController] Handling ICE gathering complete');\n\n logger.debug(\n `[ICEGatheringController] Checking ICE gathering state: ${this.peerConnection.iceGatheringState}`\n );\n\n logger.debug('[ICEGatheringController] ICE gathering complete');\n\n this._iceCandidatesState.next({\n state: 'complete',\n validSDP: this.hasValidLocalDescriptionSDP\n });\n this.stopGathering();\n }\n\n private stopGathering(): void {\n this.peerConnection.removeEventListener(\n 'icegatheringstatechange',\n this.onicegatheringstatechangeHandler\n );\n this.peerConnection.removeEventListener('icecandidate', this.onicecandidateHandler);\n this.clearAllTimers();\n }\n\n private handleICEGatheringTimeout(): void {\n this.removeTimer('iceGatheringTimer');\n\n const validSDP = this.hasValidLocalDescriptionSDP;\n if (validSDP) {\n logger.debug('[ICEGatheringController] Local SDP is valid');\n this._iceCandidatesState.next({\n state: 'timeout',\n validSDP: validSDP\n });\n this.stopGathering();\n } else {\n logger.debug('### ICE gathering timeout\\n', this.peerConnection.localDescription?.sdp);\n }\n }\n\n public handleICECandidateTimeout(): void {\n if (this.iceCandidateTimer) {\n this.removeTimer('iceCandidateTimer');\n }\n\n logger.warn('[ICEGatheringController] ICE candidate timeout');\n\n const validSDP = this.hasValidLocalDescriptionSDP;\n if (!validSDP && !this.relayOnly) {\n this.restartICEGatheringWithRelayOnly();\n } else {\n logger.debug('[ICEGatheringController] Using current SDP due to ICE candidate timeout');\n this._iceCandidatesState.next({\n state: 'timeout',\n validSDP: validSDP\n });\n this.stopGathering();\n }\n }\n\n public restartICEGatheringWithRelayOnly(): void {\n logger.debug('[ICEGatheringController] Restarting ICE gathering with relay-only candidates');\n this.relayOnly = true;\n this.peerConnection.setConfiguration({\n ...this.peerConnection.getConfiguration(),\n iceTransportPolicy: 'relay'\n });\n if (!(this.peerConnection.connectionState === 'connected')) {\n this.peerConnection.restartIce();\n }\n }\n\n public removeTimer(timer: 'iceGatheringTimer' | 'iceCandidateTimer'): void {\n if (this[timer]) {\n clearTimeout(this[timer]);\n this[timer] = undefined;\n }\n }\n\n private clearAllTimers(): void {\n logger.debug('[ICEGatheringController] Clearing all timers');\n\n this.removeTimer('iceGatheringTimer');\n this.removeTimer('iceCandidateTimer');\n }\n\n public removeEventListeners(): void {\n this.peerConnection.removeEventListener(\n 'icegatheringstatechange',\n this.onicegatheringstatechangeHandler\n );\n this.peerConnection.removeEventListener('icecandidate', this.onicecandidateHandler);\n }\n\n public destroy(): void {\n logger.debug('[ICEGatheringController] Destroying ICEGatheringController');\n this.clearAllTimers();\n this.removeEventListeners();\n super.destroy();\n }\n}\n","import { takeUntil } from 'rxjs';\n\nimport { Destroyable } from '../behaviors/Destroyable';\nimport { getLogger } from '../utils/logger';\n\nimport type { MediaOptions } from '../core/types/media.types';\nimport type { Observable } from 'rxjs';\n\nconst logger = getLogger();\n\nexport interface LocalStreamControllerOptions extends Omit<\n MediaOptions,\n 'inputAudioDeviceConstraints' | 'inputVideoDeviceConstraints'\n> {\n getUserMedia: (constraints: MediaStreamConstraints) => Promise<MediaStream>;\n getDisplayMedia: (options: DisplayMediaStreamOptions) => Promise<MediaStream>;\n propose: 'main' | 'screenshare' | 'additional-device';\n inputAudioDeviceConstraints?: MediaTrackConstraints | boolean;\n inputVideoDeviceConstraints?: MediaTrackConstraints | boolean;\n}\n\nexport class LocalStreamController extends Destroyable {\n private mediaTrackEndedHandler = (event: unknown) => {\n this._mediaTrackEnded$.next(event as MediaStreamTrack);\n };\n private _localStream$ = this.createBehaviorSubject<MediaStream | null>(null);\n private _localAudioTracks$ = this.createBehaviorSubject<MediaStreamTrack[]>([]);\n private _localVideoTracks$ = this.createBehaviorSubject<MediaStreamTrack[]>([]);\n private _mediaTrackEnded$ = this.createSubject<MediaStreamTrack>();\n\n constructor(private options: LocalStreamControllerOptions) {\n super();\n }\n\n public get localStream$(): Observable<MediaStream | null> {\n return this._localStream$.asObservable().pipe(takeUntil(this.destroyed$));\n }\n\n public get localAudioTracks$(): Observable<MediaStreamTrack[]> {\n return this._localAudioTracks$.asObservable().pipe(takeUntil(this.destroyed$));\n }\n\n public get localVideoTracks$(): Observable<MediaStreamTrack[]> {\n return this._localVideoTracks$.asObservable().pipe(takeUntil(this.destroyed$));\n }\n\n public get mediaTrackEnded$(): Observable<MediaStreamTrack> {\n return this._mediaTrackEnded$.asObservable().pipe(takeUntil(this.destroyed$));\n }\n\n public get localStream(): MediaStream | null {\n return this._localStream$.value;\n }\n\n public get localAudioTracks(): MediaStreamTrack[] {\n return this._localAudioTracks$.value;\n }\n\n public get localVideoTracks(): MediaStreamTrack[] {\n return this._localVideoTracks$.value;\n }\n\n /**\n * Build the local media stream based on the provided options.\n */\n public async buildLocalStream(): Promise<MediaStream> {\n logger.debug('[LocalStreamController] Building local media stream.');\n let stream: MediaStream;\n if (this.options.inputAudioStream ?? this.options.inputVideoStream) {\n const tracks = [\n ...(this.options.inputAudioStream?.getTracks() ?? []),\n ...(this.options.inputVideoStream?.getTracks() ?? [])\n ];\n stream = new MediaStream(tracks);\n } else if (this.options.propose === 'screenshare') {\n logger.debug(\n '[LocalStreamController] Requesting display media for screen sharing with audio:',\n Boolean(this.options.inputAudioDeviceConstraints)\n );\n stream = await this.options.getDisplayMedia({\n video: true,\n audio: Boolean(this.options.inputAudioDeviceConstraints)\n });\n logger.debug('[LocalStreamController] Screen share media obtained:', stream);\n } else {\n const constraints: MediaStreamConstraints = {\n audio: this.options.inputAudioDeviceConstraints,\n video: this.options.inputVideoDeviceConstraints\n };\n logger.debug('[LocalStreamController] Requesting user media with constraints:', constraints);\n stream = await this.options.getUserMedia(constraints);\n logger.debug('[LocalStreamController] User media obtained:', stream);\n }\n this._localStream$.next(stream);\n return stream;\n }\n\n /**\n * Add a local media track to the local stream.\n * @param track - The MediaStreamTrack to add\n * @returns The MediaStream (either existing or newly created)\n */\n public addTrack(track: MediaStreamTrack): MediaStream {\n const localStream = this._localStream$.value ?? new MediaStream();\n\n track.addEventListener('ended', this.mediaTrackEndedHandler);\n localStream.addTrack(track);\n this._localStream$.next(localStream);\n\n if (track.kind === 'video') {\n this._localVideoTracks$.next(localStream.getVideoTracks());\n } else {\n this._localAudioTracks$.next(localStream.getAudioTracks());\n }\n\n logger.debug(`[LocalStreamController] ${track.kind} track added:`, track.id);\n return localStream;\n }\n\n /**\n * Remove a local media track from the local stream.\n * @param trackId - The ID of the track to remove\n * @returns The removed track, or undefined if not found\n */\n public removeTrack(trackId: string): MediaStreamTrack | undefined {\n const stream = this._localStream$.value;\n const track = stream?.getTracks().find((t: MediaStreamTrack) => t.id === trackId);\n\n if (!track) {\n logger.debug(`[LocalStreamController] track not found: ${trackId}`);\n return undefined;\n }\n\n track.removeEventListener('ended', this.mediaTrackEndedHandler);\n stream?.removeTrack(track);\n track.stop();\n this._localStream$.next(stream);\n\n if (track.kind === 'video') {\n this._localVideoTracks$.next(stream?.getVideoTracks() ?? []);\n } else {\n this._localAudioTracks$.next(stream?.getAudioTracks() ?? []);\n }\n\n logger.debug(`[LocalStreamController] ${track.kind} track removed:`, trackId);\n return track;\n }\n\n /**\n * Get or create a local stream.\n */\n public getOrCreateLocalStream(): MediaStream {\n return this._localStream$.value ?? new MediaStream();\n }\n\n /**\n * Set the local stream directly.\n */\n public setLocalStream(stream: MediaStream | null): void {\n this._localStream$.next(stream);\n }\n\n /**\n * Add a track ended event listener to a track.\n */\n public addTrackEndedListener(track: MediaStreamTrack): void {\n track.addEventListener('ended', this.mediaTrackEndedHandler);\n }\n\n /**\n * Stop all local tracks and clean up.\n */\n public stopAllTracks(): void {\n const localStream = this._localStream$.value;\n localStream?.getTracks().forEach((track: MediaStreamTrack) => {\n logger.debug(`[LocalStreamController] Stopping local track: ${track.kind}`);\n track.removeEventListener('ended', this.mediaTrackEndedHandler);\n track.stop();\n });\n }\n\n /**\n * Clean up resources.\n */\n public override destroy(): void {\n this.stopAllTracks();\n super.destroy();\n }\n}\n","import { Destroyable } from '../behaviors/Destroyable';\nimport { MediaTrackError } from '../core/errors';\nimport { getLogger } from '../utils/logger';\n\nimport type { LocalStreamController } from './LocalStreamController';\nimport type { RTCPeerConnectionPropose } from '../core/types/call.types';\n\nconst logger = getLogger();\n\nconst getDirection = (send: boolean, recv: boolean): RTCRtpTransceiverDirection => {\n if (send && recv) {\n return 'sendrecv';\n } else if (send && !recv) {\n return 'sendonly';\n } else if (!send && recv) {\n return 'recvonly';\n }\n\n return 'inactive';\n};\n\nexport interface TransceiverControllerOptions {\n peerConnection: RTCPeerConnection;\n propose: RTCPeerConnectionPropose;\n simulcast?: boolean;\n sfu?: boolean;\n msStreamsNumber?: number;\n receiveAudio?: boolean;\n receiveVideo?: boolean;\n localStreamController: LocalStreamController;\n getInputAudioDeviceConstraints: () => MediaTrackConstraints | boolean;\n getInputVideoDeviceConstraints: () => MediaTrackConstraints | boolean;\n getUserMedia: (constraints: MediaStreamConstraints) => Promise<MediaStream>;\n onError?: (error: Error) => void;\n}\n\nexport class TransceiverController extends Destroyable {\n private peerConnection: RTCPeerConnection;\n private options: TransceiverControllerOptions;\n\n constructor(options: TransceiverControllerOptions) {\n super();\n this.peerConnection = options.peerConnection;\n this.options = options;\n }\n\n public get useAddTransceivers(): boolean {\n return typeof this.peerConnection.addTransceiver === 'function';\n }\n\n public get useAddTrack(): boolean {\n return typeof this.peerConnection.addTrack === 'function';\n }\n\n public get useAddStream(): boolean {\n return (\n // @ts-expect-error -- Ignore ---\n typeof this.peerConnection.addStream === 'function' &&\n !this.useAddTransceivers &&\n !this.useAddTrack\n );\n }\n\n private get propose(): RTCPeerConnectionPropose {\n return this.options.propose;\n }\n\n private get isAdditionalDevice(): boolean {\n return this.propose === 'additional-device';\n }\n\n private get isScreenShare(): boolean {\n return this.propose === 'screenshare';\n }\n\n private get isSimulcast(): boolean {\n return Boolean(this.options.simulcast);\n }\n\n private get isSFU(): boolean {\n return Boolean(this.options.sfu);\n }\n\n private get receiveVideo(): boolean {\n return Boolean(this.options.receiveVideo);\n }\n\n private get receiveAudio(): boolean {\n return Boolean(this.options.receiveAudio);\n }\n\n private get localStream(): MediaStream | null {\n return this.options.localStreamController.localStream;\n }\n\n private get inputAudioDeviceConstraints(): MediaTrackConstraints | boolean {\n return this.options.getInputAudioDeviceConstraints();\n }\n\n private get inputVideoDeviceConstraints(): MediaTrackConstraints | boolean {\n return this.options.getInputVideoDeviceConstraints();\n }\n\n public get audioDirection(): RTCRtpTransceiverDirection {\n if (this.isAdditionalDevice) {\n return 'sendonly';\n }\n const { localStream } = this;\n const hasAudioTrack = localStream?.getAudioTracks().some((track) => track.enabled);\n const wantsToSendAudio = Boolean(this.inputAudioDeviceConstraints);\n const wantsToReceiveAudio = Boolean(this.receiveAudio);\n const send = hasAudioTrack ?? wantsToSendAudio;\n const recv = wantsToReceiveAudio;\n return getDirection(send, recv);\n }\n\n public get videoDirection(): RTCRtpTransceiverDirection {\n if (this.isAdditionalDevice || this.isScreenShare) {\n return 'sendonly';\n }\n\n if (this.isSFU) {\n return 'recvonly';\n }\n\n const { localStream } = this;\n const hasVideoTrack = localStream?.getVideoTracks().some((track) => track.enabled);\n const wantsToSendVideo = Boolean(this.inputVideoDeviceConstraints);\n const wantsToReceiveVideo = Boolean(this.receiveVideo);\n const send = hasVideoTrack ?? wantsToSendVideo;\n const recv = wantsToReceiveVideo;\n return getDirection(send, recv);\n }\n\n private get sendEncodings(): RTCRtpEncodingParameters[] | undefined {\n if (!this.isSimulcast) {\n return undefined;\n }\n\n return ['0', '1', '2'].map((rid) => ({\n active: true,\n rid,\n scaleResolutionDownBy: Number(rid) * 6 || 1.0\n }));\n }\n\n private getConstraintsFor(kind: 'audio' | 'video'): MediaTrackConstraints {\n const constraints =\n kind === 'audio' ? this.inputAudioDeviceConstraints : this.inputVideoDeviceConstraints;\n\n // If constraints is a boolean (true/false), return empty object for track constraints\n // false case means no media of this kind is requested, but that's handled elsewhere\n return typeof constraints === 'boolean' ? {} : constraints;\n }\n\n public transceiverByKind(kind: 'audio' | 'video' | 'both'): RTCRtpTransceiver[] {\n return this.peerConnection\n .getTransceivers()\n .filter((t) => kind === 'both' || t.receiver.track.kind === kind);\n }\n\n public get audioTransceivers(): RTCRtpTransceiver[] {\n return this.transceiverByKind('audio');\n }\n\n public get videoTransceivers(): RTCRtpTransceiver[] {\n return this.transceiverByKind('video');\n }\n\n public async setupTransceiverSender(\n track: MediaStreamTrack,\n localStream: MediaStream,\n transceiver?: RTCRtpTransceiver\n ): Promise<void> {\n const isAudio = track.kind === 'audio';\n const direction = isAudio ? this.audioDirection : this.videoDirection;\n const transceiverParams: RTCRtpTransceiverInit = {\n direction,\n sendEncodings: isAudio ? undefined : this.sendEncodings,\n streams: direction === 'recvonly' ? undefined : [localStream]\n };\n logger.debug(\n `[TransceiverController] Setting up transceiver sender for local ${track.kind} track:`,\n { transceiver, transceiverParams }\n );\n if (\n transceiverParams.direction &&\n ['sendonly', 'sendrecv'].includes(transceiverParams.direction)\n ) {\n if (transceiver) {\n await transceiver.sender.replaceTrack(track);\n // eslint-disable-next-line no-param-reassign\n transceiver.direction = transceiverParams.direction;\n if (transceiverParams.streams?.some((stream) => Boolean(stream))) {\n logger.debug(\n `[TransceiverController] Setting streams for transceiver sender for local ${track.kind} track:`,\n transceiverParams.streams\n );\n transceiver.sender.setStreams(...transceiverParams.streams);\n }\n } else {\n logger.debug(\n `[TransceiverController] Adding new transceiver for local ${track.kind} track:`,\n track.id\n );\n this.peerConnection.addTransceiver(track, transceiverParams);\n }\n }\n }\n\n public stopTrackSender(\n kind: 'audio' | 'video' | 'both',\n options = { updateTransceiverDirection: false }\n ): void {\n try {\n const transceivers = this.transceiverByKind(kind);\n for (const transceiver of transceivers) {\n if (transceiver.sender.track?.readyState === 'live') {\n const trackId = transceiver.sender.track.id;\n transceiver.sender.track.stop();\n this.options.localStreamController.removeTrack(trackId);\n if (options.updateTransceiverDirection) {\n transceiver.direction = 'inactive';\n }\n }\n }\n } catch (error) {\n logger.error('[TransceiverController] stopTrackSender error', kind, error);\n this.options.onError?.(new MediaTrackError('stopTrackSender', kind, error));\n }\n }\n\n public async restoreTrackSender(kind: 'audio' | 'video' | 'both'): Promise<void> {\n try {\n logger.debug('[TransceiverController] restoreTrackSender called', kind);\n const constraints: MediaStreamConstraints = {};\n const transceivers = this.transceiverByKind(kind);\n for (const transceiver of transceivers) {\n const { track } = transceiver.sender;\n // Check if track is null, ended - all need restoration\n const needsRestore = !track || track.readyState === 'ended';\n if (needsRestore) {\n const trackKind = track?.kind ?? transceiver.receiver.track.kind;\n if (trackKind === 'audio' || trackKind === 'video') {\n constraints[trackKind] = this.getConstraintsFor(trackKind);\n }\n }\n }\n\n logger.debug('[TransceiverController] restoreTrackSender constraints:', constraints);\n\n // Don't call getUserMedia if no tracks need restoration\n if (Object.keys(constraints).length === 0) {\n logger.warn('[TransceiverController] restoreTrackSender: no tracks need restoration', kind);\n return;\n }\n\n const stream = await this.options.getUserMedia(constraints);\n const newTracks = stream.getTracks();\n\n logger.debug('[TransceiverController] restoreTrackSender new tracks:', newTracks);\n for (const newTrack of newTracks) {\n this.options.localStreamController.addTrack(newTrack);\n const trackKind = newTrack.kind as 'audio' | 'video';\n const transceiverOfKind = this.transceiverByKind(trackKind)[0];\n transceiverOfKind.direction =\n trackKind === 'audio' ? this.audioDirection : this.videoDirection;\n logger.debug(\n '[TransceiverController] restoreTrackSender setting direction for',\n trackKind,\n transceiverOfKind.direction\n );\n await transceiverOfKind.sender.replaceTrack(newTrack);\n }\n } catch (error) {\n logger.error('[TransceiverController] restoreTrackSender error', kind, error);\n this.options.onError?.(new MediaTrackError('restoreTrackSender', kind, error));\n }\n }\n\n public async replaceSenderTrack(kind: 'audio' | 'video', track: MediaStreamTrack): Promise<void> {\n const transceivers = kind === 'audio' ? this.audioTransceivers : this.videoTransceivers;\n for (const transceiver of transceivers) {\n await transceiver.sender.replaceTrack(track);\n }\n }\n\n public async setupRemoteTransceivers(type: 'offer' | 'answer'): Promise<void> {\n if (type === 'answer') {\n // remote setup was made by the offerer\n return;\n }\n\n for (const kind of ['audio', 'video']) {\n const transceivers = kind === 'audio' ? this.audioTransceivers : this.videoTransceivers;\n for (const transceiver of transceivers) {\n const direction = kind === 'audio' ? this.audioDirection : this.videoDirection;\n\n if (['inactive', 'recvonly'].includes(direction)) {\n transceiver.direction = direction;\n await transceiver.sender.replaceTrack(null);\n transceiver.sender.setStreams();\n }\n }\n }\n\n if (this.videoDirection === 'recvonly' && this.isSFU && this.useAddTransceivers) {\n const { msStreamsNumber = 5 } = this.options;\n for (let i = 0; i < Number(msStreamsNumber); i++) {\n this.peerConnection.addTransceiver('video', { direction: 'recvonly' });\n }\n }\n }\n\n public async updateSendersConstraints(\n kind: 'audio' | 'video',\n constraints?: MediaTrackConstraints\n ): Promise<void> {\n if (!constraints) {\n this.stopTrackSender(kind);\n return Promise.resolve();\n }\n\n const senders = this.peerConnection\n .getSenders()\n .filter((sender) => sender.track?.kind === kind && sender.track.readyState === 'live');\n\n for (const sender of senders) {\n const { track } = sender;\n if (track) {\n const constraintsToApply: MediaTrackConstraints = {\n ...track.getConstraints(),\n ...constraints\n };\n try {\n await track.applyConstraints(constraintsToApply);\n logger.debug(\n `[TransceiverController] Updated ${kind} sender constraints:`,\n constraintsToApply\n );\n logger.debug(\n `[TransceiverController] Updated ${kind} sender constraints:`,\n track.getConstraints()\n );\n } catch (error) {\n logger.warn(\n `[TransceiverController] Failed to apply constraints to ${kind} track ${track.id}:`,\n error\n );\n this.options.onError?.(new MediaTrackError('updateSendersConstraints', kind, error));\n }\n }\n }\n }\n\n public getMediaDirections(): {\n audio: RTCRtpTransceiverDirection;\n video: RTCRtpTransceiverDirection;\n } {\n if (this.peerConnection.connectionState === 'connected') {\n // If we are connected let's get the actual directions from the transceivers\n return this.peerConnection.getTransceivers().reduce(\n (acc, transceiver) => {\n return {\n ...acc,\n [transceiver.receiver.track.kind]: transceiver.direction\n };\n },\n { audio: 'inactive', video: 'inactive' }\n );\n }\n\n return {\n audio: this.audioDirection,\n video: this.videoDirection\n };\n }\n\n public updatePeerConnection(peerConnection: RTCPeerConnection): void {\n this.peerConnection = peerConnection;\n }\n\n public updateOptions(options: Partial<TransceiverControllerOptions>): void {\n this.options = {\n ...this.options,\n ...options\n };\n }\n}\n","/* eslint-disable max-lines */\nimport {\n auditTime,\n defer,\n exhaustMap,\n filter,\n from,\n map,\n shareReplay,\n switchMap,\n takeUntil,\n tap,\n skipWhile,\n merge\n} from 'rxjs';\nimport { v4 as uuid } from 'uuid';\n\nimport { ICEGatheringController } from './ICEGatheringController';\nimport { LocalStreamController } from './LocalStreamController';\nimport { TransceiverController } from './TransceiverController';\nimport { Destroyable } from '../behaviors/Destroyable';\nimport { PreferencesContainer } from '../containers/PreferencesContainer';\nimport { DependencyError } from '../core/errors';\nimport { isValidLocalDescription } from '../helpers/SDPHelper';\nimport { filterNull } from '../operators';\nimport { getLogger } from '../utils/logger';\n\nimport type { RTCPeerConnectionPropose, RTCPeerConnectionType } from '../core/types/call.types';\nimport type { MediaOptions } from '../core/types/media.types';\nimport type { WebRTCApiProvider } from '../dependencies/interfaces';\nimport type { DeviceController } from '../interfaces/DeviceController';\nimport type { Observable } from 'rxjs';\n\nconst logger = getLogger();\n\nexport interface RTCPeerConnectionControllerOptions extends MediaOptions {\n callId?: string;\n rtcConfiguration?: RTCConfiguration;\n simulcast?: boolean;\n sfu?: boolean;\n msStreamsNumber?: number;\n propose: RTCPeerConnectionPropose;\n iceServers?: RTCIceServer[];\n disableUdpIceServers?: boolean;\n relayOnly?: boolean;\n iceCandidateTimeout?: number;\n iceGatheringTimeout?: number;\n webRTCApiProvider?: WebRTCApiProvider;\n}\n\nexport type RTCPeerConnectionControllerOptionsPartial = Partial<RTCPeerConnectionControllerOptions>;\n\nexport interface UpdateSDPStatusParams {\n status: 'received' | 'sent' | 'failed';\n sdp?: string;\n}\n\nexport class RTCPeerConnectionController extends Destroyable {\n public readonly id: string;\n public firstSDPExchangeCompleted = false;\n public sdpInit?: RTCSessionDescriptionInit;\n private negotiationNeeded$ = this.createSubject<void>();\n private deviceController: DeviceController;\n private localStreamController: LocalStreamController;\n // Transceiver controller - initialized lazily when peerConnection is created\n private transceiverController?: TransceiverController;\n public readonly localDescription$: Observable<RTCSessionDescription | null> = defer(() =>\n from(this.init())\n ).pipe(\n switchMap(() =>\n // Wait for ICE negotiation before emitting localDescription\n this.iceGatheringController.iceCandidatesState$.pipe(\n filter((iceCandidateState) => !['new', 'gathering'].includes(iceCandidateState)),\n tap(() => {\n this.negotiationEnded();\n }),\n // Only emit when signaling state is 'have-local-offer'\n filter(() => this.shouldEmitLocalDescription),\n map(() => this.peerConnection?.localDescription),\n filterNull(),\n tap((desc) => {\n if (desc.type === 'answer') {\n // Once the answer is emitted, switch type to offer for future negotiations\n this._type = 'offer';\n }\n })\n )\n ),\n shareReplay(1),\n takeUntil(this.destroyed$)\n );\n public peerConnection?: RTCPeerConnection;\n private initPromise?: Promise<void>;\n private connectionTimeout = 3_000;\n private connectionTimer?: ReturnType<typeof setTimeout>;\n private oniceconnectionstatechangeHandler = () => {\n if (this.peerConnection) {\n const { iceConnectionState } = this.peerConnection;\n logger.debug(\n `[RTCPeerConnectionController] ICE connection state changed to: ${iceConnectionState}`\n );\n this._iceConnectionState$.next(this.peerConnection.iceConnectionState);\n }\n };\n private onconnectionstatechangeHandler = () => {\n if (this.peerConnection) {\n const { connectionState } = this.peerConnection;\n logger.debug(`[RTCPeerConnectionController] Connection state changed to: ${connectionState}`);\n if (connectionState === 'connected') {\n this.removeConnectionTimer();\n }\n this._connectionState$.next(this.peerConnection.connectionState);\n }\n };\n private onsignalingstatechangeHandler = () => {\n logger.debug(\n `[RTCPeerConnectionController] Signaling state changed to: ${this.peerConnection?.signalingState}`\n );\n };\n private onicegatheringstatechangeHandler = () => {\n if (this.peerConnection) {\n this._iceGatheringState$.next(this.peerConnection.iceGatheringState);\n }\n };\n private onnegotiationneededHandler = (event: unknown) => {\n logger.debug('[RTCPeerConnectionController] Negotiation needed event received.', event);\n this.negotiationNeeded$.next();\n };\n private updateSelectedInputDevice = async (\n kind: 'audio' | 'video',\n deviceInfo: MediaDeviceInfo | null\n ): Promise<void> => {\n try {\n const { localStream } = this;\n if (!localStream) {\n logger.warn(\n '[RTCPeerConnectionController] No local stream available to update input device.'\n );\n return;\n }\n\n logger.debug(\n `[RTCPeerConnectionController] Updating selected ${kind} input device:`,\n localStream.getTracks()\n );\n // Stop existing audio tracks\n const track = localStream.getTracks().find((track: MediaStreamTrack) => track.kind === kind);\n\n if (track) {\n this.transceiverController?.stopTrackSender(kind);\n this.localStream?.removeTrack(track);\n logger.debug(\n `[RTCPeerConnectionController] Stopped existing ${kind} track: ${track.id}`,\n localStream.getTracks()\n );\n\n if (!deviceInfo) {\n logger.debug(`[RTCPeerConnectionController] ${kind} input device selected: none`);\n return;\n }\n\n const stream = await this.getUserMedia({\n [kind]: {\n ...track.getConstraints(),\n ...this.deviceController.deviceInfoToConstraints(deviceInfo)\n }\n });\n\n const streamTrack = stream.getTracks().find((t) => t.kind === kind);\n\n if (streamTrack) {\n logger.debug(`[RTCPeerConnectionController] Adding new ${kind} track: ${streamTrack.id}`);\n this.localStream?.addTrack(streamTrack);\n await this.transceiverController?.replaceSenderTrack(kind, streamTrack);\n logger.debug(\n `[RTCPeerConnectionController] Added new ${kind} track: ${streamTrack.id}`,\n this.localStream?.getTracks()\n );\n }\n }\n\n logger.debug(\n `[RTCPeerConnectionController] ${kind} input device selected:`,\n deviceInfo?.label\n );\n } catch (error) {\n logger.error(`[RTCPeerConnectionController] Failed to select ${kind} input device:`, error);\n this._errors$.next(error as Error);\n throw error;\n }\n };\n private _isNegotiating$ = this.createBehaviorSubject<boolean>(false);\n private _iceGatheringController?: ICEGatheringController;\n private _memberId: string | null = null;\n private _type: RTCPeerConnectionType;\n // Observable state streams - exposed as public observables\n private _iceConnectionState$ = this.createReplaySubject<RTCIceConnectionState>(1);\n private _connectionState$ = this.createReplaySubject<RTCPeerConnectionState>(1);\n private _signalingState$ = this.createReplaySubject<RTCSignalingState>(1);\n private _iceGatheringState$ = this.createReplaySubject<RTCIceGatheringState>(1);\n // Error stream\n private _errors$ = this.createSubject<Error>();\n // ICE candidates stream\n private _iceCandidates$ = this.createReplaySubject<RTCIceCandidate[]>(1);\n // Initialization state\n private _initialized$ = this.createReplaySubject<boolean>(1);\n // Remote description\n private _remoteDescription$ = this.createReplaySubject<RTCSessionDescription | null>(1);\n private _remoteStream$ = this.createBehaviorSubject<MediaStream | null>(null);\n constructor(\n protected options: RTCPeerConnectionControllerOptionsPartial = {},\n remoteSessionDescription?: string,\n deviceController?: DeviceController\n ) {\n super();\n this.deviceController = deviceController ?? ({} as DeviceController);\n this.id = options.callId ?? uuid();\n this._type = remoteSessionDescription ? 'answer' : 'offer';\n\n this.sdpInit = remoteSessionDescription\n ? {\n type: 'offer',\n sdp: remoteSessionDescription\n }\n : undefined;\n this.options = {\n receiveAudio: options.receiveAudio ?? PreferencesContainer.instance.receiveAudio,\n receiveVideo: options.receiveVideo ?? PreferencesContainer.instance.receiveVideo,\n ...options\n };\n\n // Initialize the local stream controller\n this.localStreamController = new LocalStreamController({\n propose: this.propose,\n inputAudioStream: this.options.inputAudioStream,\n inputVideoStream: this.options.inputVideoStream,\n inputAudioDeviceConstraints: this.inputAudioDeviceConstraints,\n inputVideoDeviceConstraints: this.inputVideoDeviceConstraints,\n getUserMedia: async (constraints: MediaStreamConstraints) => this.getUserMedia(constraints),\n getDisplayMedia: async (options: DisplayMediaStreamOptions) => this.getDisplayMedia(options)\n });\n }\n\n private get iceGatheringController(): ICEGatheringController {\n if (!this._iceGatheringController) {\n throw new DependencyError('ICEGatheringController is not initialized');\n }\n return this._iceGatheringController;\n }\n\n private get shouldEmitLocalDescription(): boolean {\n if (!this.peerConnection) {\n return false;\n }\n\n const { localDescription, signalingState } = this.peerConnection;\n\n if (!localDescription || !isValidLocalDescription(localDescription.sdp)) {\n return false;\n }\n\n return (\n (localDescription.type === 'offer' && signalingState === 'have-local-offer') ||\n (localDescription.type === 'answer' && signalingState === 'stable')\n );\n }\n\n private removeConnectionTimer(): void {\n if (this.connectionTimer) {\n clearTimeout(this.connectionTimer);\n this.connectionTimer = undefined;\n }\n }\n\n public setMemberId(memberId: string | null): void {\n this._memberId = memberId;\n }\n\n public get memberId(): string | null {\n return this._memberId;\n }\n\n public stopTrackSender(\n kind: 'audio' | 'video' | 'both',\n options = { updateTransceiverDirection: false }\n ): void {\n this.transceiverController?.stopTrackSender(kind, options);\n }\n\n public get isNegotiating$(): Observable<boolean> {\n return this._isNegotiating$.asObservable();\n }\n\n public get isNegotiating(): boolean {\n return this._isNegotiating$.value;\n }\n\n public updateMediaDevicesOptions(options: MediaOptions): void {\n this.options = {\n ...this.options,\n ...options\n };\n }\n\n public get iceGatheringState$(): Observable<RTCIceGatheringState> {\n return this.cachedObservable('iceGatheringState$', () =>\n this._iceGatheringState$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get mediaTrackEnded$(): Observable<MediaStreamTrack> {\n return this.cachedObservable('mediaTrackEnded$', () =>\n this.localStreamController.mediaTrackEnded$.pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get errors$(): Observable<Error> {\n return this.cachedObservable('errors$', () =>\n this._errors$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get iceCandidates$(): Observable<RTCIceCandidate[]> {\n return this.cachedObservable('iceCandidates$', () =>\n this._iceCandidates$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get initialized$(): Observable<boolean> {\n return this.cachedObservable('initialized$', () =>\n this._initialized$.asObservable().pipe(\n filter((initialized) => initialized),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n public get remoteDescription$(): Observable<RTCSessionDescription | null> {\n return this.cachedObservable('remoteDescription$', () =>\n this._remoteDescription$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get localStream$(): Observable<MediaStream | null> {\n return this.cachedObservable('localStream$', () =>\n this.localStreamController.localStream$.pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get remoteStream$(): Observable<MediaStream | null> {\n return this.cachedObservable('remoteStream$', () =>\n this._remoteStream$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get localAudioTracks$(): Observable<MediaStreamTrack[]> {\n return this.cachedObservable('localAudioTracks$', () =>\n this.localStreamController.localAudioTracks$.pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get localVideoTracks$(): Observable<MediaStreamTrack[]> {\n return this.cachedObservable('localVideoTracks$', () =>\n this.localStreamController.localVideoTracks$.pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get iceConnectionState$(): Observable<RTCIceConnectionState> {\n return this.cachedObservable('iceConnectionState$', () =>\n this._iceConnectionState$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get connectionState$(): Observable<RTCPeerConnectionState> {\n return this.cachedObservable('connectionState$', () =>\n this._connectionState$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get signalingState$(): Observable<RTCSignalingState> {\n return this.cachedObservable('signalingState$', () =>\n this._signalingState$.asObservable().pipe(takeUntil(this.destroyed$))\n );\n }\n\n public get type(): RTCPeerConnectionType {\n return this._type;\n }\n\n public get propose(): RTCPeerConnectionPropose {\n return this.options.propose ?? 'main';\n }\n\n public get isAdditionalDevice(): boolean {\n return this.propose === 'additional-device';\n }\n\n public get isMainDevice(): boolean {\n return this.propose === 'main';\n }\n\n public get isScreenShare(): boolean {\n return this.propose === 'screenshare';\n }\n\n protected get iceServers(): RTCIceServer[] {\n if (!this.options.disableUdpIceServers) {\n return this.options.iceServers ?? [];\n }\n const tcpTransportParam = 'transport=tcp';\n\n // When disabling UDP, keep only URLs that explicitly specify transport=tcp\n // URLs without a transport parameter default to UDP and should be filtered out\n return (this.options.iceServers ?? []).map((server) => {\n const urls = Array.isArray(server.urls) ? server.urls : [server.urls];\n return {\n ...server,\n urls: urls.filter((url) => url.includes(tcpTransportParam))\n } as RTCIceServer;\n });\n }\n\n private get rtcConfiguration(): RTCConfiguration {\n // Destructure to exclude iceServers from options spread, since we use the filtered this.iceServers\n const { iceServers: _iceServers, ...restOptions } = this.options;\n return {\n bundlePolicy: 'max-compat',\n iceCandidatePoolSize: 10,\n iceServers: this.iceServers,\n iceTransportPolicy: this.options.relayOnly ? 'relay' : 'all',\n //@ts-expect-error -- Ignore ---\n sdpSemantics: 'unified-plan',\n ...restOptions\n };\n }\n\n public get receiveVideo(): boolean {\n return Boolean(this.options.receiveVideo);\n }\n\n public get receiveAudio(): boolean {\n return Boolean(this.options.receiveAudio);\n }\n\n public get localStream(): MediaStream | null {\n return this.localStreamController.localStream;\n }\n\n public get remoteStream(): MediaStream | null {\n return this._remoteStream$.value;\n }\n\n private get inputAudioDeviceConstraints(): MediaTrackConstraints | boolean {\n if (this.options.audio === false && !this.options.inputAudioDeviceConstraints) {\n return false;\n }\n return {\n ...this.options.inputAudioDeviceConstraints,\n ...this.deviceController.selectedAudioInputDeviceConstraints\n };\n }\n\n private get inputVideoDeviceConstraints(): MediaTrackConstraints | boolean {\n if (this.options.video === false && !this.options.inputVideoDeviceConstraints) {\n return false;\n }\n return {\n ...this.options.inputVideoDeviceConstraints,\n ...this.deviceController.selectedVideoInputDeviceConstraints\n };\n }\n\n private get WebRTCPeerConnectionConstructor(): typeof RTCPeerConnection {\n return this.options.webRTCApiProvider?.RTCPeerConnection ?? RTCPeerConnection;\n }\n\n private get offerOptions(): RTCOfferOptions {\n const options: RTCOfferOptions = {\n iceRestart: this.firstSDPExchangeCompleted ? true : undefined\n };\n switch (this.propose) {\n case 'screenshare':\n case 'additional-device':\n return {\n ...options,\n offerToReceiveAudio: false,\n offerToReceiveVideo: false\n };\n case 'main':\n default:\n return {\n ...options,\n offerToReceiveAudio: true,\n offerToReceiveVideo: Boolean(this.inputVideoDeviceConstraints)\n };\n }\n }\n\n private get answerOptions(): RTCAnswerOptions {\n // Currently no specific answer options\n return {};\n }\n\n /**\n * Initialize the RTCPeerConnection and setup event listeners.\n * Called automatically when localDescription$ is subscribed to (deferred pattern).\n * Uses Promise memoization to ensure initialization only happens once,\n * even if called concurrently.\n */\n private async init(): Promise<void> {\n this.initPromise ??= this.doInit();\n return this.initPromise;\n }\n\n /**\n * Internal initialization implementation.\n * Should only be called via init() to ensure single execution.\n */\n private async doInit(): Promise<void> {\n try {\n this.setupPeerConnection();\n\n this.subscribeTo(\n this.negotiationNeeded$.pipe(\n auditTime(0), //When updating multiple tracks, batches all the events together\n exhaustMap(async () => this.startNegotiation()) // Ignore new events while negotiation is ongoing\n ),\n {\n next: () => {\n logger.debug('[RTCPeerConnectionController] Start Negotiation completed successfully');\n },\n error: (error) => {\n logger.error('[RTCPeerConnectionController] Start Negotiation error:', error);\n this._errors$.next(error as Error);\n }\n }\n );\n\n this.subscribeTo(\n merge(\n this.deviceController.selectedAudioInputDevice$.pipe(\n map((deviceInfo) => ['audio', deviceInfo] as const)\n ),\n this.deviceController.selectedVideoInputDevice$.pipe(\n map((deviceInfo) => ['video', deviceInfo] as const)\n )\n ).pipe(\n // we only want to react to changes after the localstream is created\n // before that the device selection is handle int the localstream creation\n skipWhile(() => !this.localStreamController.localStream)\n ),\n async ([kind, deviceInfo]) => {\n logger.debug(`[RTCPeerConnectionController] Selected input device changed for:`, {\n kind,\n deviceInfo\n });\n await this.updateSelectedInputDevice(kind, deviceInfo);\n }\n );\n\n await this.setupTrackHandling();\n\n this._initialized$.next(true);\n\n // Start answer negotiation\n if (this.type === 'answer' && this.sdpInit) {\n this.setupEventListeners();\n await this.handleOfferReceived();\n }\n } catch (error) {\n logger.error('[RTCPeerConnectionController] Initialization error:', error);\n this._errors$.next(error as Error);\n this.destroy();\n }\n }\n\n private setupPeerConnection() {\n this.peerConnection = new this.WebRTCPeerConnectionConstructor(this.rtcConfiguration);\n this.peerConnection.addEventListener('negotiationneeded', this.onnegotiationneededHandler);\n this._iceGatheringController = new ICEGatheringController(\n this.peerConnection,\n this.isNegotiating$,\n {\n iceCandidateTimeout: this.options.iceCandidateTimeout,\n iceGatheringTimeout: this.options.iceGatheringTimeout,\n relayOnly: this.options.relayOnly\n }\n );\n\n // Initialize the transceiver controller\n this.transceiverController = new TransceiverController({\n peerConnection: this.peerConnection,\n propose: this.propose,\n simulcast: this.options.simulcast,\n sfu: this.options.sfu,\n msStreamsNumber: this.options.msStreamsNumber,\n receiveAudio: this.receiveAudio,\n receiveVideo: this.receiveVideo,\n localStreamController: this.localStreamController,\n getInputAudioDeviceConstraints: () => this.inputAudioDeviceConstraints,\n getInputVideoDeviceConstraints: () => this.inputVideoDeviceConstraints,\n getUserMedia: async (constraints: MediaStreamConstraints) => this.getUserMedia(constraints),\n onError: (error: Error) => {\n this._errors$.next(error);\n }\n });\n }\n\n private async startNegotiation() {\n if (this.isNegotiating) {\n logger.debug('[RTCPeerConnectionController] Negotiation already in progress, skipping.');\n return;\n }\n\n this.setupEventListeners();\n\n if (this.type === 'answer') {\n logger.debug(\n '[RTCPeerConnectionController] This is an answer type still, skipping offer creation.'\n );\n return;\n }\n\n this._isNegotiating$.next(true);\n logger.debug('[RTCPeerConnectionController] Starting negotiation.');\n\n try {\n const { offerOptions } = this;\n logger.debug('[RTCPeerConnectionController] Creating offer with options:', offerOptions);\n await this.createOffer(offerOptions);\n } catch (error) {\n logger.error('[RTCPeerConnectionController] Error during negotiation:', error);\n this._errors$.next(error as Error);\n }\n }\n\n /**\n * Create an SDP offer and set it as local description.\n */\n private async createOffer(options?: RTCOfferOptions): Promise<void> {\n if (!this.peerConnection) {\n throw new DependencyError('RTCPeerConnection is not initialized');\n }\n\n const offer = await this.peerConnection.createOffer(options);\n await this.setLocalDescription(offer);\n\n // Note: localDescription will be emitted by setupEventListeners initial emission\n // and updated when ICE gathering state changes\n }\n\n public async updateAnswerStatus({ status, sdp }: UpdateSDPStatusParams): Promise<void> {\n let readyToConnect = status !== 'failed';\n\n try {\n if (status === 'received' && sdp) {\n logger.debug('[RTCPeerConnectionController] Received answer SDP:', sdp);\n await this._setRemoteDescription({\n type: 'answer',\n sdp\n });\n }\n } catch (error) {\n logger.error('[RTCPeerConnectionController] Error updating answer status:', error);\n this._errors$.next(error as Error);\n readyToConnect = false;\n } finally {\n if (readyToConnect) {\n this.readyToConnect();\n } else {\n this.iceGatheringController.restartICEGatheringWithRelayOnly();\n }\n }\n }\n\n public async updateOfferStatus({ status, sdp }: UpdateSDPStatusParams): Promise<void> {\n switch (status) {\n case 'received':\n this._type = 'answer';\n this.sdpInit = {\n type: 'offer',\n sdp: sdp\n };\n await this.handleOfferReceived();\n break;\n case 'failed':\n logger.error('[RTCPeerConnectionController] Offer failed to be processed by remote.');\n break;\n case 'sent':\n default:\n // No action needed for sent offers\n }\n }\n\n private async handleOfferReceived() {\n if (!this.sdpInit) {\n throw new DependencyError('SDP initialization parameters are not set');\n }\n\n this._isNegotiating$.next(true);\n await this._setRemoteDescription(this.sdpInit);\n\n const { answerOptions } = this;\n logger.debug('[RTCPeerConnectionController] Creating answer with options:', answerOptions);\n await this.createAnswer(answerOptions);\n }\n\n private readyToConnect() {\n this.firstSDPExchangeCompleted = true;\n this.connectionTimer = setTimeout(() => {\n this.removeConnectionTimer();\n if (this.peerConnection?.connectionState !== 'connected') {\n logger.debug(\n '[RTCPeerConnectionController] Connection timeout, restarting ICE gathering with relay only.'\n );\n this.iceGatheringController.restartICEGatheringWithRelayOnly();\n }\n }, this.connectionTimeout);\n }\n\n private async setRemoteDescriptionBefore(sdp: string = ''): Promise<string> {\n // TODO use the options hooks\n return Promise.resolve(sdp);\n }\n protected async setLocalDescription(params: RTCSessionDescriptionInit): Promise<void> {\n const finalLocal = await this.setLocalDescriptionBefore(params.sdp);\n return this.peerConnection?.setLocalDescription({\n ...params,\n sdp: finalLocal\n });\n }\n async setLocalDescriptionBefore(sdp: string = ''): Promise<string> {\n // TODO use the options hooks\n return Promise.resolve(sdp);\n }\n /**\n * Create an SDP answer and set it as local description.\n */\n private async createAnswer(options?: RTCAnswerOptions): Promise<void> {\n if (!this.peerConnection) {\n throw new DependencyError('RTCPeerConnection is not initialized');\n }\n\n const answer = await this.peerConnection.createAnswer(options);\n await this.setLocalDescription(answer);\n // Note: localDescription will be emitted by setupEventListeners initial emission\n // and updated when ICE gathering state changes\n }\n /**\n * Setup event listeners on RTCPeerConnection for state changes.\n */\n private setupEventListeners(): void {\n if (!this.peerConnection) {\n throw new DependencyError('RTCPeerConnection is not initialized');\n }\n\n // Emit initial states from the actual RTCPeerConnection\n this._iceConnectionState$.next(this.peerConnection.iceConnectionState);\n this._connectionState$.next(this.peerConnection.connectionState);\n this._signalingState$.next(this.peerConnection.signalingState);\n this._iceGatheringState$.next(this.peerConnection.iceGatheringState);\n // Note: localDescription is NOT emitted here - it will be emitted when ICE gathering completes\n this._remoteDescription$.next(this.peerConnection.remoteDescription);\n\n this.peerConnection.removeEventListener(\n 'icegatheringstatechange',\n this.onicegatheringstatechangeHandler\n );\n this.peerConnection.addEventListener(\n 'icegatheringstatechange',\n this.onicegatheringstatechangeHandler\n );\n this.peerConnection.removeEventListener(\n 'iceconnectionstatechange',\n this.oniceconnectionstatechangeHandler\n );\n this.peerConnection.addEventListener(\n 'iceconnectionstatechange',\n this.oniceconnectionstatechangeHandler\n );\n\n // Signaling state changes\n this.peerConnection.removeEventListener(\n 'connectionstatechange',\n this.onconnectionstatechangeHandler\n );\n this.peerConnection.addEventListener(\n 'connectionstatechange',\n this.onconnectionstatechangeHandler\n );\n\n this.peerConnection.removeEventListener(\n 'signalingstatechange',\n this.onsignalingstatechangeHandler\n );\n\n this.peerConnection.addEventListener(\n 'signalingstatechange',\n this.onsignalingstatechangeHandler\n );\n }\n\n private negotiationEnded() {\n this._isNegotiating$.next(false);\n }\n\n public restarIce(): void {\n this.peerConnection?.restartIce();\n }\n /**\n * Setup track handling for remote tracks.\n */\n private async setupTrackHandling(): Promise<void> {\n if (!this.peerConnection) {\n throw new DependencyError('RTCPeerConnection is not initialized');\n }\n\n await this.setupLocalTracks();\n\n await this.setupRemoteTracks();\n }\n\n // eslint-disable-next-line complexity\n private async setupLocalTracks(): Promise<void> {\n logger.debug('[RTCPeerConnectionController] Setting up local tracks/transceivers.');\n let { localStream } = this;\n if (!localStream) {\n try {\n localStream = await this.localStreamController.buildLocalStream();\n } catch (error) {\n logger.error('[RTCPeerConnectionController] Error building local stream:', error);\n this._errors$.next(error as Error);\n }\n }\n\n if (localStream) {\n if (this.transceiverController?.useAddStream ?? false) {\n logger.warn(\n '[RTCPeerConnectionController] Using deprecated addStream API to add local stream.'\n );\n //@ts-expect-error -- Ignore -- useAddStream checked if the deprecated API should be used\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n this.peerConnection?.addStream(localStream);\n // In case the browser doesn't fire negotiationneeded automatically\n if (!this.isNegotiating) {\n logger.debug(\n '[RTCPeerConnectionController] Forcing negotiationneeded after local tracks setup.'\n );\n this.negotiationNeeded$.next();\n }\n return;\n }\n\n for (const kind of ['audio', 'video']) {\n const tracks = (\n kind === 'audio' ? localStream.getAudioTracks() : localStream.getVideoTracks()\n ).map((track, index) => ({ index, track }));\n for (const { index, track } of tracks) {\n this.localStreamController.addTrackEndedListener(track);\n if (this.transceiverController?.useAddTransceivers ?? false) {\n const transceivers =\n (kind === 'audio'\n ? this.transceiverController?.audioTransceivers\n : this.transceiverController?.videoTransceivers) ?? [];\n await this.transceiverController?.setupTransceiverSender(\n track,\n localStream,\n transceivers[index]\n );\n } else {\n logger.debug(\n `[RTCPeerConnectionController] Using addTrack for local ${kind} track:`,\n track.id\n );\n this.peerConnection?.addTrack(track, localStream);\n }\n }\n }\n }\n }\n private async getUserMedia(constraints: MediaStreamConstraints): Promise<MediaStream> {\n const mediaDevices = this.options.webRTCApiProvider?.mediaDevices ?? navigator.mediaDevices;\n return mediaDevices.getUserMedia(constraints);\n }\n\n private async getDisplayMedia(options: DisplayMediaStreamOptions): Promise<MediaStream> {\n const mediaDevices = this.options.webRTCApiProvider?.mediaDevices ?? navigator.mediaDevices;\n if (!mediaDevices.getDisplayMedia) {\n throw new DependencyError('getDisplayMedia is not supported by the current WebRTC provider');\n }\n return mediaDevices.getDisplayMedia(options);\n }\n private async setupRemoteTracks(): Promise<void> {\n if (!this.peerConnection) {\n throw new DependencyError('RTCPeerConnection is not initialized');\n }\n this.peerConnection.ontrack = (event) => {\n logger.debug('[RTCPeerConnectionController] Remote track received:', event.track.kind);\n this._remoteStream$.next(event.streams[0]);\n };\n\n await this.transceiverController?.setupRemoteTransceivers(this.type);\n }\n\n public async restoreTrackSender(kind: 'audio' | 'video' | 'both'): Promise<void> {\n await this.transceiverController?.restoreTrackSender(kind);\n }\n /**\n * Add a local media track to the peer connection.\n * @param track - The MediaStreamTrack to add\n */\n public addLocalTrack(track: MediaStreamTrack): void {\n if (!this.peerConnection) {\n const error = new DependencyError('RTCPeerConnection is not initialized');\n this._errors$.next(error);\n throw error;\n }\n\n try {\n // Add track to local stream controller\n const localStream = this.localStreamController.addTrack(track);\n\n // Add track to peer connection\n this.peerConnection.addTrack(track, localStream);\n\n logger.debug(`[RTCPeerConnectionController] ${track.kind} track added:`, track.id);\n } catch (error) {\n logger.error(`[RTCPeerConnectionController] Failed to add ${track.kind} track:`, error);\n this._errors$.next(error as Error);\n throw error;\n }\n }\n /**\n * Remove a local media track from the peer connection.\n * @param trackId - The ID of the track to remove\n */\n public removeLocalTrack(trackId: string): void {\n if (!this.peerConnection) {\n const error = new DependencyError('RTCPeerConnection is not initialized');\n this._errors$.next(error);\n throw error;\n }\n\n const sender = this.peerConnection.getSenders().find((sender) => sender.track?.id === trackId);\n if (!sender) {\n logger.debug(`[RTCPeerConnectionController] track not found: ${trackId}`);\n return;\n }\n\n try {\n // Remove sender from peer connection\n this.peerConnection.removeTrack(sender);\n\n // Remove track from local stream controller\n this.localStreamController.removeTrack(trackId);\n\n logger.debug(`[RTCPeerConnectionController] ${sender.track?.kind} track removed:`, trackId);\n } catch (error) {\n logger.error(\n `[RTCPeerConnectionController] Failed to remove ${sender.track?.kind} track:`,\n error\n );\n this._errors$.next(error as Error);\n throw error;\n }\n }\n /**\n * Replace all existing media tracks with a new media track.\n * Convenience method for single-track scenarios.\n * @param track - The MediaStreamTrack to set\n */\n public setLocalTrack(track: MediaStreamTrack): void {\n // Remove all existing media tracks\n const existingTracks = [\n ...(track.kind === 'audio'\n ? this.localStreamController.localAudioTracks\n : this.localStreamController.localVideoTracks)\n ];\n for (const existingTrack of existingTracks) {\n this.removeLocalTrack(existingTrack.id);\n }\n\n // Add the new track\n this.addLocalTrack(track);\n }\n public async updateSendersConstraints(\n kind: 'audio' | 'video',\n constraints?: MediaTrackConstraints\n ): Promise<void> {\n await this.transceiverController?.updateSendersConstraints(kind, constraints);\n }\n\n /**\n * Clean up resources and close the peer connection.\n * Completes all observables to prevent memory leaks.\n */\n public destroy(): void {\n logger.debug(\n `[RTCPeerConnectionController] Destroying RTCPeerConnectionController. ${this.propose}`\n );\n this.removeConnectionTimer();\n this._iceGatheringController?.destroy();\n this.localStreamController.destroy();\n this.transceiverController?.destroy();\n\n // Close peer connection\n if (this.peerConnection) {\n this.stopRemoteTracks();\n this.removeAllListeners();\n this.peerConnection.close();\n this.peerConnection = undefined;\n }\n\n // Call parent destroy to clean up subscriptions and complete destroyed$\n super.destroy();\n }\n private removeAllListeners() {\n if (this.peerConnection) {\n this.peerConnection.removeEventListener(\n 'icegatheringstatechange',\n this.onicegatheringstatechangeHandler\n );\n this.peerConnection.removeEventListener(\n 'iceconnectionstatechange',\n this.oniceconnectionstatechangeHandler\n );\n this.peerConnection.removeEventListener(\n 'connectionstatechange',\n this.onconnectionstatechangeHandler\n );\n this.peerConnection.removeEventListener(\n 'signalingstatechange',\n this.onsignalingstatechangeHandler\n );\n this.peerConnection.removeEventListener('negotiationneeded', this.onnegotiationneededHandler);\n }\n }\n\n private stopRemoteTracks() {\n const remoteStream = this._remoteStream$.value;\n remoteStream?.getTracks().forEach((track: MediaStreamTrack) => {\n logger.debug(`[RTCPeerConnectionController] Stopping remote track: ${track.kind}`);\n track.stop();\n });\n }\n\n public get mediaDirections(): {\n audio: RTCRtpTransceiverDirection;\n video: RTCRtpTransceiverDirection;\n } {\n return (\n this.transceiverController?.getMediaDirections() ?? {\n audio: 'inactive',\n video: 'inactive'\n }\n );\n }\n protected async _setRemoteDescription(params: RTCSessionDescriptionInit): Promise<void> {\n if (!this.peerConnection) {\n throw new DependencyError('RTCPeerConnection is not initialized');\n }\n\n const finalRemote = await this.setRemoteDescriptionBefore(params.sdp);\n\n const answer: RTCSessionDescriptionInit = {\n ...params,\n sdp: finalRemote\n };\n logger.debug('[RTCPeerConnectionController] Setting remote description:', answer);\n return this.peerConnection.setRemoteDescription(answer);\n }\n}\n","// =============================================================================\n// VERTO TYPE GUARDS\n// =============================================================================\n// This file contains type guards for Verto protocol types.\n\nimport { hasProperty, isObject } from './base.guards';\n\nimport type { TypeGuard } from '../types/base';\nimport type { WebrtcMessagePayload } from '../types/events';\nimport type {\n VertoAnswerMessage,\n VertoAnswerParams,\n VertoAnswerResultMessage,\n VertoAttachMessage,\n VertoAttachParams,\n VertoByeMessage,\n VertoByeParams,\n VertoInviteMessage,\n VertoInviteParams,\n VertoMediaParamsMessage,\n VertoMediaParamsParams,\n VertoMethodMessage,\n VertoPingMessage,\n VertoPingParams,\n VertoPongMessage,\n VertoPongParams\n} from '../types/verto';\n\n// =============================================================================\n// VERTO MESSAGE TYPE GUARDS\n// =============================================================================\n\nexport function isVertoMethodMessage(value: unknown): value is VertoMethodMessage {\n return (\n isObject(value) &&\n hasProperty(value, 'jsonrpc') &&\n value.jsonrpc === '2.0' &&\n hasProperty(value, 'id')\n );\n}\n\nexport function isVertoAnswerMessage(value: unknown): value is VertoAnswerMessage {\n if (!isVertoMethodMessage(value)) return false;\n const msg = value as unknown as Record<string, unknown>;\n return (\n msg.method === 'verto.answer' &&\n isObject(msg.params) &&\n hasProperty(msg.params, 'callID') &&\n hasProperty(msg.params, 'sdp')\n );\n}\n\nexport function isVertoMediaParamsMessage(value: unknown): value is VertoMediaParamsMessage {\n if (!isVertoMethodMessage(value)) return false;\n const msg = value as unknown as Record<string, unknown>;\n return (\n msg.method === 'verto.mediaParams' &&\n isObject(msg.params) &&\n hasProperty(msg.params, 'mediaParams')\n );\n}\n\nexport function isVertoPingMessage(value: unknown): value is VertoPingMessage {\n if (!isVertoMethodMessage(value)) return false;\n const msg = value as unknown as Record<string, unknown>;\n return msg.method === 'verto.ping';\n}\n\nexport function isVertoPongMessage(value: unknown): value is VertoPongMessage {\n if (!isVertoMethodMessage(value)) return false;\n const msg = value as unknown as Record<string, unknown>;\n return msg.method === 'verto.pong';\n}\n\nexport function isVertoInviteMessage(value: unknown): value is VertoInviteMessage {\n if (!isVertoMethodMessage(value)) return false;\n const msg = value as unknown as Record<string, unknown>;\n return (\n msg.method === 'verto.invite' &&\n isObject(msg.params) &&\n hasProperty(msg.params, 'sdp') &&\n hasProperty(msg.params, 'callID')\n );\n}\n\nexport function isVertoByeMessage(value: unknown): value is VertoByeMessage {\n if (!isVertoMethodMessage(value)) return false;\n const msg = value as unknown as Record<string, unknown>;\n return msg.method === 'verto.bye';\n}\n\nexport function isVertoAnswerResultMessage(value: unknown): value is VertoAnswerResultMessage {\n if (!isVertoMethodMessage(value)) return false;\n const msg = value as unknown as Record<string, unknown>;\n return (\n isObject(msg.result) &&\n hasProperty(msg.result, 'method') &&\n msg.result.method === 'verto.answer'\n );\n}\n\nexport function isVertoAttachMessage(value: unknown): value is VertoAttachMessage {\n if (!isVertoMethodMessage(value)) return false;\n const msg = value as unknown as Record<string, unknown>;\n return msg.method === 'verto.attach';\n}\n\n// =============================================================================\n// WEBRTC MESSAGE EVENT DATA (inner params.params) TYPE GUARDS\n// =============================================================================\n\nexport function isVertoAnswerInnerParams(value: unknown): value is WebrtcMessagePayload & {\n method: 'verto.answer';\n params: VertoAnswerParams;\n} {\n return (\n isObject(value) &&\n hasProperty(value, 'jsonrpc') &&\n value.jsonrpc === '2.0' &&\n hasProperty(value, 'method') &&\n value.method === 'verto.answer' &&\n isObject(value.params) &&\n hasProperty(value.params, 'callID') &&\n hasProperty(value.params, 'sdp')\n );\n}\n\nexport function isVertoMediaParamsInnerParams(value: unknown): value is WebrtcMessagePayload & {\n method: 'verto.mediaParams';\n params: VertoMediaParamsParams;\n} {\n return (\n isObject(value) &&\n hasProperty(value, 'jsonrpc') &&\n value.jsonrpc === '2.0' &&\n hasProperty(value, 'method') &&\n value.method === 'verto.mediaParams' &&\n isObject(value.params) &&\n hasProperty(value.params, 'mediaParams')\n );\n}\n\nexport function isVertoPingInnerParams(value: unknown): value is WebrtcMessagePayload & {\n method: 'verto.ping';\n params: VertoPingParams;\n} {\n return (\n isObject(value) &&\n hasProperty(value, 'jsonrpc') &&\n value.jsonrpc === '2.0' &&\n hasProperty(value, 'method') &&\n value.method === 'verto.ping'\n );\n}\n\n// =============================================================================\n// VERTO PARAMS TYPE GUARDS (for use with filterAs on Verto method params)\n// =============================================================================\n\nexport function isVertoAnswerParamsGuard(value: unknown): value is VertoAnswerParams {\n return (\n isObject(value) &&\n hasProperty(value, 'callID') &&\n typeof value.callID === 'string' &&\n hasProperty(value, 'sdp') &&\n typeof value.sdp === 'string'\n );\n}\n\nexport function isVertoMediaParamsParamsGuard(value: unknown): value is VertoMediaParamsParams {\n return (\n isObject(value) &&\n hasProperty(value, 'callID') &&\n typeof value.callID === 'string' &&\n hasProperty(value, 'mediaParams') &&\n isObject(value.mediaParams)\n );\n}\n\nexport function isVertoPingParamsGuard(value: unknown): value is VertoPingParams {\n return (\n isObject(value) &&\n hasProperty(value, 'callID') &&\n typeof value.callID === 'string' &&\n hasProperty(value, 'dialogParams') &&\n isObject(value.dialogParams)\n );\n}\n\nexport function isVertoPongParamsGuard(value: unknown): value is VertoPongParams {\n return isVertoPingParamsGuard(value);\n}\n\nexport function isVertoInviteParamsGuard(value: unknown): value is VertoInviteParams {\n return (\n isObject(value) &&\n hasProperty(value, 'dialogParams') &&\n isObject(value.dialogParams) &&\n hasProperty(value, 'sdp') &&\n typeof value.sdp === 'string'\n );\n}\n\nexport function isVertoByeParamsGuard(value: unknown): value is VertoByeParams {\n return isObject(value) && hasProperty(value, 'callID') && typeof value.callID === 'string';\n}\n\nexport function isVertoAttachParamsGuard(value: unknown): value is VertoAttachParams {\n return (\n isObject(value) &&\n hasProperty(value, 'callID') &&\n typeof value.callID === 'string' &&\n hasProperty(value, 'callee_id_number') &&\n typeof value.callee_id_number === 'string' &&\n hasProperty(value, 'callee_id_name') &&\n typeof value.callee_id_name === 'string' &&\n hasProperty(value, 'caller_id_number') &&\n typeof value.caller_id_number === 'string' &&\n hasProperty(value, 'caller_id_name') &&\n typeof value.caller_id_name === 'string'\n );\n}\n\n// Duplicate guards for backwards compatibility (without \"Guard\" suffix)\nexport function isVertoAnswerParams(value: unknown): value is VertoAnswerParams {\n return isVertoAnswerParamsGuard(value);\n}\n\nexport function isVertoMediaParamsParams(value: unknown): value is VertoMediaParamsParams {\n return isVertoMediaParamsParamsGuard(value);\n}\n\nexport function isVertoPingParams(value: unknown): value is VertoPingParams {\n return isVertoPingParamsGuard(value);\n}\n\nexport function isVertoPongParams(value: unknown): value is VertoPongParams {\n return isVertoPongParamsGuard(value);\n}\n\nexport function isVertoInviteParams(value: unknown): value is VertoInviteParams {\n return isVertoInviteParamsGuard(value);\n}\n\nexport function isVertoByeParams(value: unknown): value is VertoByeParams {\n return isVertoByeParamsGuard(value);\n}\n\nexport function isVertoAttachParams(value: unknown): value is VertoAttachParams {\n return isVertoAttachParamsGuard(value);\n}\n\n// =============================================================================\n// VERTO METHOD TYPE MAPPING\n// =============================================================================\n\nexport const VertoMethodTypeMap = {\n 'verto.answer': isVertoAnswerMessage,\n 'verto.mediaParams': isVertoMediaParamsMessage,\n 'verto.ping': isVertoPingMessage,\n 'verto.pong': isVertoPongMessage,\n 'verto.invite': isVertoInviteMessage,\n 'verto.bye': isVertoByeMessage\n} as const;\n\nexport type VertoMethodType = keyof typeof VertoMethodTypeMap;\n\n/**\n * Gets the appropriate type guard for a Verto method.\n */\nexport function getVertoMethodGuard(method: string): TypeGuard<VertoMethodMessage> | undefined {\n return VertoMethodTypeMap[method as VertoMethodType];\n}\n\n// =============================================================================\n// VERTO PARAMS TYPE MAPPING\n// =============================================================================\n\nexport const VertoParamsTypeMap = {\n 'verto.answer': isVertoAnswerParamsGuard,\n 'verto.mediaParams': isVertoMediaParamsParamsGuard,\n 'verto.ping': isVertoPingParamsGuard,\n 'verto.pong': isVertoPongParamsGuard,\n 'verto.invite': isVertoInviteParamsGuard,\n 'verto.attach': isVertoAttachParamsGuard,\n 'verto.bye': isVertoByeParamsGuard\n} as const;\n\n/**\n * Gets the appropriate params type guard for a Verto method.\n */\nexport function getVertoParamsGuard(\n method: string\n):\n | TypeGuard<\n | VertoAnswerParams\n | VertoMediaParamsParams\n | VertoPingParams\n | VertoPongParams\n | VertoInviteParams\n | VertoByeParams\n | VertoAttachParams\n >\n | undefined {\n return VertoParamsTypeMap[method as VertoMethodType];\n}\n","/* eslint-disable max-lines */\nimport { filter, firstValueFrom, map, merge, race, take, takeUntil, timeout } from 'rxjs';\n\nimport { Destroyable } from '../behaviors/Destroyable';\nimport { PreferencesContainer } from '../containers/PreferencesContainer';\nimport { RTCPeerConnectionController } from '../controllers/RTCPeerConnectionController';\nimport { INVITE_VERSION } from '../core/constants';\nimport { DependencyError, InvalidParams, JSONRPCError, VertoPongError } from '../core/errors';\nimport {\n VertoAnswer,\n VertoBye,\n VertoByeCauseCodes,\n VertoInfo,\n VertoInvite,\n VertoModify,\n VertoPong,\n WebrtcVerto\n} from '../core/RPCMessages';\nimport {\n isVertoAnswerInnerParams,\n isVertoAttachMessage,\n isVertoByeMessage,\n isVertoMediaParamsInnerParams,\n isVertoPingInnerParams\n} from '../core/RPCMessages/guards/verto.guards';\nimport { filterAs } from '../operators';\nimport { filterNull } from '../operators/filterNull';\nimport { getValueFrom } from '../utils/getValueFrom';\nimport { getLogger } from '../utils/logger';\n\nimport type { AttachManager } from './AttachManager';\nimport type { WebRTCCall } from '../core/entities/Call';\nimport type { VertoRPCMessage } from '../core/RPCMessages';\nimport type {\n ExecuteVertoOptions,\n ScreenShareStatus,\n SignalingStatus,\n TransferOptions,\n WebRTCVertoManagerOptions\n} from './types/verto-manager.types';\nimport type { JSONRPCResponse } from '../core/RPCMessages/types/base';\nimport type {\n VertoAnswerParams,\n VertoAttachParams,\n VertoByeCause,\n VertoByeParams,\n VertoMediaParamsParams,\n VertoPingParams\n} from '../core/RPCMessages/types/verto';\nimport type { RTCPeerConnectionPropose } from '../core/types/call.types';\nimport type { MediaOptions, MediaDirections } from '../core/types/media.types';\nimport type { VertoMethod } from '../core/types/rpc.types';\nimport type { WebRTCApiProvider } from '../dependencies/interfaces';\nimport type { DeviceController } from '../interfaces/DeviceController';\nimport type { WebRTCVerto } from '../interfaces/WebRTCVerto';\nimport type { BehaviorSubject, Observable } from 'rxjs';\n\nconst logger = getLogger();\nexport abstract class VertoManager extends Destroyable {\n protected callSession?: WebRTCCall;\n\n constructor(callSession?: WebRTCCall) {\n super();\n this.callSession = callSession;\n }\n\n public destroy(): void {\n this.callSession = undefined;\n super.destroy();\n }\n}\nexport class WebRTCVertoManager extends VertoManager implements WebRTCVerto {\n public mediaDirections$!: Observable<MediaDirections>;\n public localStream$!: Observable<MediaStream>;\n public remoteStream$!: Observable<MediaStream>;\n private readonly onError?: (error: Error) => void;\n private _rtcPeerConnections$ = this.createBehaviorSubject<RTCPeerConnectionController[]>([]);\n\n private _nodeId$: BehaviorSubject<string | null>;\n private _selfId$ = this.createBehaviorSubject<string | null>(null);\n private _signalingStatus$ = this.createBehaviorSubject<SignalingStatus | null>(null);\n private _screenShareStatus$ = this.createBehaviorSubject<ScreenShareStatus>('none');\n private _rtcPeerConnectionsMap = new Map<string, RTCPeerConnectionController>();\n private _screenShareId?: string;\n private _screenShareTimeoutMs = 50000;\n\n constructor(\n protected webRtcCallSession: WebRTCCall,\n private readonly attachManager: AttachManager,\n private readonly deviceController: DeviceController,\n private readonly webRTCApiProvider: WebRTCApiProvider,\n options: WebRTCVertoManagerOptions = {}\n ) {\n super(webRtcCallSession);\n this._nodeId$ = this.createBehaviorSubject<string | null>(options.nodeId ?? null);\n this.onError = options.onError;\n this.initSubscriptions();\n this.initMainPeerConnection();\n }\n async hold(): Promise<void> {\n const vertoModifyMessage = VertoModify({\n sessid: this.webRtcCallSession.id,\n dialogParams: {\n callID: this.webRtcCallSession.id\n },\n action: 'hold'\n });\n\n try {\n await this.executeVerto(vertoModifyMessage);\n } catch (error) {\n logger.warn(\n '[WebRTCManager] Call might already be disconnected, error sending Verto hold:',\n error\n );\n throw error;\n }\n }\n async unhold(): Promise<void> {\n const vertoModifyMessage = VertoModify({\n sessid: this.webRtcCallSession.id,\n dialogParams: {\n callID: this.webRtcCallSession.id\n },\n action: 'unhold'\n });\n try {\n await this.executeVerto(vertoModifyMessage);\n } catch (error) {\n logger.warn(\n '[WebRTCManager] Call might already be disconnected, error sending Verto unhold:',\n error\n );\n throw error;\n }\n }\n\n public get mediaDirections(): MediaDirections {\n return this.mainPeerConnection.mediaDirections;\n }\n\n public get rtcPeerConnections$(): Observable<RTCPeerConnectionController[]> {\n return this._rtcPeerConnections$.asObservable();\n }\n\n public get rtcPeerConnections(): RTCPeerConnectionController[] {\n return this._rtcPeerConnections$.value;\n }\n\n public get nodeId$(): Observable<string | null> {\n return this._nodeId$.asObservable();\n }\n\n public get selfId$(): Observable<string | null> {\n return this._selfId$.asObservable();\n }\n\n public get localStream(): MediaStream | null {\n return this._rtcPeerConnectionsMap.get(this.webRtcCallSession.id)?.localStream ?? null;\n }\n\n public get remoteStream(): MediaStream | null {\n return this._rtcPeerConnectionsMap.get(this.webRtcCallSession.id)?.remoteStream ?? null;\n }\n\n public get nodeId(): string | null {\n return this._nodeId$.value;\n }\n\n public get screenShareStatus(): ScreenShareStatus {\n return this._screenShareStatus$.value;\n }\n\n public get screenShareStatus$(): Observable<ScreenShareStatus> {\n return this._screenShareStatus$.asObservable();\n }\n\n public get mainPeerConnection(): RTCPeerConnectionController {\n const rtcPeerConnection = this._rtcPeerConnectionsMap.get(this.webRtcCallSession.id);\n if (!rtcPeerConnection) {\n throw new DependencyError('Main peer connection not found');\n }\n return rtcPeerConnection;\n }\n\n public get signalingStatus$(): Observable<SignalingStatus> {\n return this.cachedObservable('signalingStatus$', () =>\n merge(\n this._signalingStatus$.pipe(filterNull()),\n this.mainPeerConnection.connectionState$.pipe(\n filter((connectionState) =>\n ['connected', 'disconnected', 'failed'].includes(connectionState)\n )\n ) as Observable<SignalingStatus>\n )\n );\n }\n\n private initSubscriptions() {\n this.subscribeTo(this.vertoAnswer$, (event: VertoAnswerParams) => {\n logger.debug('[WebRTCManager] Received Verto answer event:', event);\n const { sdp } = event;\n const rtcPeerConnController = this._rtcPeerConnectionsMap.get(event.callID);\n void rtcPeerConnController?.updateAnswerStatus({\n status: 'received',\n sdp: sdp\n });\n });\n\n this.subscribeTo(this.vertoMediaParams$, (event: VertoMediaParamsParams) => {\n logger.debug('[WebRTCManager] Received Verto mediaParams event:', event);\n\n const { mediaParams, callID } = event;\n const rtcPeerConnController = this._rtcPeerConnectionsMap.get(callID);\n const { audio, video } = mediaParams;\n if (audio) {\n void rtcPeerConnController?.updateSendersConstraints('audio', audio);\n }\n if (video) {\n void rtcPeerConnController?.updateSendersConstraints('video', video);\n }\n });\n\n this.subscribeTo(this.vertoPing$, (vertoPing: VertoPingParams) => {\n void this.attachManager.attach(this.webRtcCallSession);\n void this.sendVertoPong(vertoPing);\n });\n }\n\n private async sendVertoPong(vertoPing: VertoPingParams) {\n try {\n const vertoPongMessage = VertoPong({\n ...vertoPing\n });\n await this.executeVerto(vertoPongMessage);\n } catch (error) {\n logger.warn('[WebRTCManager] Call might disconnect, error sending Verto pong:', error);\n this.onError?.(new VertoPongError(error));\n }\n }\n\n public async updateMediaConstraints(\n options: {\n audio?: MediaTrackConstraints;\n video?: MediaTrackConstraints;\n } = {}\n ): Promise<void> {\n const { audio, video } = options;\n try {\n if (audio) {\n await this.mainPeerConnection.updateSendersConstraints('audio', audio);\n }\n if (video) {\n await this.mainPeerConnection.updateSendersConstraints('video', video);\n }\n } catch (error) {\n logger.warn('[WebRTCManager] Error updating media constraints:', error);\n this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));\n throw error;\n }\n }\n\n public get selfId(): string | null {\n return this._selfId$.value;\n }\n\n private get vertoAnswer$() {\n return this.cachedObservable('vertoAnswer$', () =>\n this.webRtcCallSession.webrtcMessages$.pipe(\n filterAs(isVertoAnswerInnerParams, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n private get vertoMediaParams$() {\n return this.cachedObservable('vertoMediaParams$', () =>\n this.webRtcCallSession.webrtcMessages$.pipe(\n filterAs(isVertoMediaParamsInnerParams, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n private get vertoBye$() {\n return this.cachedObservable('vertoBye$', () =>\n this.webRtcCallSession.webrtcMessages$.pipe(\n filterAs(isVertoByeMessage, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n private get vertoAttach$() {\n return this.cachedObservable('vertoAttach$', () =>\n this.webRtcCallSession.webrtcMessages$.pipe(\n filterAs(isVertoAttachMessage, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n private get vertoPing$() {\n return this.cachedObservable('vertoPing$', () =>\n this.webRtcCallSession.webrtcMessages$.pipe(\n filterAs(isVertoPingInnerParams, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n private async executeVerto(\n message: VertoRPCMessage,\n optionals: ExecuteVertoOptions = {}\n ): Promise<JSONRPCResponse<unknown>> {\n const params = {\n callID: optionals.callID ?? this.webRtcCallSession.id,\n\n node_id: optionals.node_id ?? this._nodeId$.value ?? '',\n message,\n subscribe: optionals.subscribe\n };\n const webrtcVertoMessage = WebrtcVerto(params);\n\n const response = await this.webRtcCallSession.execute(webrtcVertoMessage);\n\n // Check for error at top level\n if (response.error) {\n const error = new JSONRPCError(\n response.error.code,\n response.error.message,\n response.error.data\n );\n this.onError?.(error);\n throw error;\n }\n\n // Check for nested error in result.result (webrtc.verto wraps the inner response)\n const innerResult = getValueFrom<{ error?: { code: number; message: string; data?: unknown } }>(\n response,\n 'result.result'\n );\n if (innerResult?.error) {\n const error = new JSONRPCError(\n innerResult.error.code,\n innerResult.error.message,\n innerResult.error.data\n );\n this.onError?.(error);\n throw error;\n }\n\n return response;\n }\n\n private async sendLocalDescription(\n message: VertoRPCMessage,\n rtcPeerConnController: RTCPeerConnectionController\n ): Promise<void> {\n const vertoMethod: VertoMethod = message.method;\n\n const optionalsParams = this.getSendLocalSDPOptionalParams(rtcPeerConnController, vertoMethod);\n\n try {\n const response = await this.executeVerto(message, optionalsParams);\n\n switch (vertoMethod) {\n case 'verto.invite':\n this.processInviteResponse(response, rtcPeerConnController);\n break;\n case 'verto.modify':\n await this.processModifyResponse(response, rtcPeerConnController);\n break;\n default:\n }\n } catch (error) {\n logger.error(`[WebRTCManager] Error sending Verto ${vertoMethod}:`, error);\n throw error;\n }\n }\n private async processModifyResponse(\n response: JSONRPCResponse<unknown>,\n rtcPeerConnController: RTCPeerConnectionController\n ) {\n if (!response.error) {\n const action = getValueFrom<string>(response, 'result.result.result.action');\n const sdp = getValueFrom<string>(response, 'result.result.result.sdp');\n if (action === 'updateMedia' && !!sdp) {\n try {\n await rtcPeerConnController.updateAnswerStatus({\n status: 'received',\n sdp\n });\n } catch (error) {\n logger.warn('[WebRTCManager] Error processing modify response:', error);\n this.onError?.(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n }\n }\n }\n }\n\n private processInviteResponse(\n response: JSONRPCResponse<unknown>,\n rtcPeerConnController: RTCPeerConnectionController\n ) {\n if (\n !response.error &&\n getValueFrom(response, 'result.result.result.message') === 'CALL CREATED'\n ) {\n this._nodeId$.next(getValueFrom<string>(response, 'result.node_id') ?? null);\n const memberId = getValueFrom<string>(response, 'result.result.result.memberID') ?? null;\n const callId = getValueFrom<string>(response, 'result.result.result.callID') ?? null;\n logger.debug('[WebRTCManager] Verto invite response:', { callId, memberId, response });\n\n this._selfId$.next(memberId);\n rtcPeerConnController.setMemberId(memberId);\n if (callId) {\n this.webRtcCallSession.addCallId(callId);\n }\n this._signalingStatus$.next('ringing');\n void this.attachManager.attach(this.webRtcCallSession);\n logger.info('[WebRTCManager] Verto invite successful');\n logger.debug(\n `[WebRTCManager] nodeid: ${this._nodeId$.value}, selfId: ${this._selfId$.value}`\n );\n } else {\n logger.error('[WebRTCManager] Verto invite failed:', response);\n const inviteError = response.error\n ? new JSONRPCError(response.error.code, response.error.message, response.error.data)\n : new Error('Verto invite failed: unexpected response');\n this.onError?.(inviteError);\n }\n }\n\n private get RTCPeerConnectionConfig() {\n return {\n iceServers:\n this.webRtcCallSession.clientSession.iceServers ?? PreferencesContainer.instance.iceServers,\n relayOnly:\n PreferencesContainer.instance.relayOnly ||\n PreferencesContainer.instance.disableUdpIceServers,\n disableUdpIceServers: PreferencesContainer.instance.disableUdpIceServers,\n iceCandidateTimeout: PreferencesContainer.instance.iceCandidateTimeout,\n iceGatheringTimeout: PreferencesContainer.instance.iceGatheringTimeout\n };\n }\n\n private initMainPeerConnection() {\n //if (this.webRtcCallSession.direction === 'outbound') {\n const { options } = this.webRtcCallSession;\n const rtcPeerConnController = new RTCPeerConnectionController(\n {\n propose: 'main',\n callId: this.webRtcCallSession.id,\n audio: options.audio,\n video: options.video,\n inputAudioDeviceConstraints: options.inputAudioDeviceConstraints,\n inputVideoDeviceConstraints: options.inputVideoDeviceConstraints,\n inputAudioStream: options.inputAudioStream,\n inputVideoStream: options.inputVideoStream,\n receiveAudio: options.receiveAudio,\n receiveVideo: options.receiveVideo,\n webRTCApiProvider: this.webRTCApiProvider,\n ...this.RTCPeerConnectionConfig\n },\n options.initOffer,\n this.deviceController\n );\n this.setupLocalDescriptionHandler(rtcPeerConnController);\n this.setupVertoByeHandler();\n this.setupVertoAttachHandler();\n this.initObservables(rtcPeerConnController);\n this._rtcPeerConnectionsMap.set(rtcPeerConnController.id, rtcPeerConnController);\n this._rtcPeerConnections$.next(Array.from(this._rtcPeerConnectionsMap.values()));\n this.subscribeTo(rtcPeerConnController.errors$, (error) => {\n this.onError?.(error);\n });\n //}\n }\n\n private setupVertoAttachHandler(): void {\n this.subscribeTo(this.vertoAttach$, async (vertoAttach: VertoAttachParams) => {\n logger.debug('[WebRTCManager] Received Verto attach event:', vertoAttach);\n const { callID } = vertoAttach;\n await this.attachManager.attach({\n id: callID,\n to: vertoAttach.callee_id_number,\n mediaDirections: {\n audio: 'sendrecv',\n // this might be changed in future to support video attach, but this feature was originally supposed in the non-video SDK.\n video: 'inactive'\n }\n });\n await this.attachManager.reattachCalls();\n });\n }\n\n private initObservables(rtcPeerConnController: RTCPeerConnectionController): void {\n this.mediaDirections$ = rtcPeerConnController.connectionState$.pipe(\n filter((state) => state === 'connected'),\n takeUntil(this.destroyed$),\n map(() => rtcPeerConnController.mediaDirections)\n );\n this.localStream$ = rtcPeerConnController.localStream$.pipe(\n filterNull(),\n takeUntil(this.destroyed$)\n );\n this.remoteStream$ = rtcPeerConnController.remoteStream$.pipe(\n filterNull(),\n takeUntil(this.destroyed$)\n );\n }\n private setupLocalDescriptionHandler(rtcPeerConnController: RTCPeerConnectionController): void {\n this.subscribeTo(\n // watch for local description from the RTCPeerConnection and send it to remote peer\n rtcPeerConnController.localDescription$.pipe(\n // Filter out null descriptions\n filter((description): description is RTCSessionDescription => description !== null),\n takeUntil(this.destroyed$)\n ),\n (description) => {\n const { type, sdp } = description;\n const dialogParams = this.dialogParams(rtcPeerConnController);\n const initial = !rtcPeerConnController.firstSDPExchangeCompleted;\n if (type === 'answer') {\n {\n const vertoMessageRequest = VertoAnswer({\n dialogParams,\n sdp: sdp\n });\n void this.sendLocalDescriptionOnceAccepted(vertoMessageRequest, rtcPeerConnController);\n }\n } else if (initial) {\n this._signalingStatus$.next('trying');\n const vertoMessageRequest = VertoInvite({\n dialogParams,\n sdp\n });\n void this.sendLocalDescription(vertoMessageRequest, rtcPeerConnController);\n } else {\n const vertoMessageRequest = VertoModify({\n dialogParams,\n sdp,\n action: 'updateMedia'\n });\n void this.sendLocalDescription(vertoMessageRequest, rtcPeerConnController);\n }\n }\n );\n }\n\n private setupVertoByeHandler() {\n this.subscribeTo(this.vertoBye$, () => {\n void this.attachManager.detach(this.webRtcCallSession);\n this.callSession?.destroy();\n });\n }\n\n private getSendLocalSDPOptionalParams(\n rtcPeerConnController: RTCPeerConnectionController,\n vertoMethod: VertoMethod\n ): ExecuteVertoOptions {\n let subscribe = undefined;\n const initial = !rtcPeerConnController.firstSDPExchangeCompleted;\n if (initial) {\n subscribe = [];\n if (rtcPeerConnController.isMainDevice) {\n subscribe.push(...PreferencesContainer.instance.inviteSubscribeMainDevice);\n } else if (rtcPeerConnController.isAdditionalDevice) {\n subscribe.push(...PreferencesContainer.instance.inviteSubscribeAdditionalDevice);\n } else if (rtcPeerConnController.isScreenShare) {\n subscribe.push(...PreferencesContainer.instance.inviteSubscribeScreenshare);\n }\n }\n const isInvite = vertoMethod === 'verto.invite';\n const optionalsParams = {\n callID: rtcPeerConnController.id,\n // verto.invite must never include node_id; all other methods must\n node_id: isInvite ? '' : (this._nodeId$.value ?? ''),\n subscribe\n };\n return optionalsParams;\n }\n\n async sendLocalDescriptionOnceAccepted(\n vertoMessageRequest: VertoRPCMessage,\n rtcPeerConnectionController: RTCPeerConnectionController\n ): Promise<void> {\n logger.debug('[WebRTCManager] Waiting for call to be accepted or ended before sending answer');\n const vertoByeOrAccepted: boolean | VertoByeParams = await firstValueFrom(\n race(this.vertoBye$, this.webRtcCallSession.answered$)\n );\n\n if (isVertoByeMessage(vertoByeOrAccepted)) {\n logger.info('[WebRTCManager] Call ended before answer was sent.');\n this.callSession?.destroy();\n } else if (!vertoByeOrAccepted) {\n logger.info('[WebRTCManager] Call was not accepted, sending verto.bye.');\n await this.bye('USER_BUSY');\n } else {\n logger.debug('[WebRTCManager] Call accepted, sending answer');\n try {\n this._signalingStatus$.next('connecting');\n await this.sendLocalDescription(vertoMessageRequest, rtcPeerConnectionController);\n await rtcPeerConnectionController.updateAnswerStatus({\n status: 'sent'\n });\n await this.attachManager.attach(this.webRtcCallSession);\n } catch (error) {\n logger.error('[WebRTCManager] Error sending Verto answer:', error);\n this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));\n await rtcPeerConnectionController.updateAnswerStatus({\n status: 'failed'\n });\n }\n }\n }\n\n dialogParams(rtcPeerConnectionController: RTCPeerConnectionController): Record<string, unknown> {\n const memberId = rtcPeerConnectionController.memberId ?? this._selfId$.value ?? undefined;\n const attach =\n rtcPeerConnectionController.propose === 'main' &&\n !rtcPeerConnectionController.firstSDPExchangeCompleted &&\n this.webRtcCallSession.options.reattach;\n\n return {\n id: rtcPeerConnectionController.isMainDevice\n ? this.webRtcCallSession.id\n : rtcPeerConnectionController.id,\n destinationNumber: this.webRtcCallSession.to ?? this.webRtcCallSession.from,\n attach,\n reattaching: attach,\n callerName: this.webRtcCallSession.fromName,\n callerNumber: this.webRtcCallSession.from,\n remoteCallerName: this.webRtcCallSession.toName,\n remoteCallerNumber: this.webRtcCallSession.to,\n userVariables: {\n memberCallId: this.webRtcCallSession.id,\n memberId,\n ...this.webRtcCallSession.options.userVariables,\n ...PreferencesContainer.instance.userVariables\n },\n screenShare: rtcPeerConnectionController.isScreenShare,\n additionalDevice: rtcPeerConnectionController.isAdditionalDevice,\n pingSupported: true,\n version: INVITE_VERSION\n };\n }\n\n public muteMainAudioInputDevice(): void {\n return this.mainPeerConnection.stopTrackSender('audio');\n }\n\n public muteMainVideoInputDevice(): void {\n return this.mainPeerConnection.stopTrackSender('video');\n }\n\n public async unmuteMainAudioInputDevice(): Promise<void> {\n return this.mainPeerConnection.restoreTrackSender('audio');\n }\n\n public async unmuteMainVideoInputDevice(): Promise<void> {\n return this.mainPeerConnection.restoreTrackSender('video');\n }\n\n public async addInputDevice(\n options: MediaOptions = { audio: false, video: true }\n ): Promise<string | undefined> {\n return this.initAdditionalPeerConnection('additional-device', options);\n }\n\n /**\n * Add a new input device to the main peer connection,\n * only if a device of the same kind is not present already.\n *\n * @see selectAudioInputDevice\n * @see selectVideoInputDevice\n * @param options\n */\n public async addMainInputDevices(options: MediaOptions = { audio: true }): Promise<void> {\n let deviceKind: 'audio' | 'video' | 'both' | undefined = undefined;\n\n const { mediaDirections } = this.mainPeerConnection;\n\n if (\n options.audio ??\n options.inputAudioDeviceConstraints ??\n (options.inputAudioStream && mediaDirections.audio.startsWith('send'))\n ) {\n deviceKind = 'audio';\n }\n if (\n options.video ??\n options.inputVideoDeviceConstraints ??\n (options.inputVideoStream && !mediaDirections.video.startsWith('send'))\n ) {\n deviceKind = deviceKind === 'audio' ? 'both' : 'video';\n }\n if (deviceKind) {\n this.mainPeerConnection.updateMediaDevicesOptions(options);\n await this.mainPeerConnection.restoreTrackSender(deviceKind);\n } else {\n const error = new InvalidParams('No valid device to be added');\n this.onError?.(error);\n throw error;\n }\n }\n\n public async addScreenMedia(options: MediaOptions = { audio: false }): Promise<void> {\n await this.initAdditionalPeerConnection('screenshare', options);\n }\n\n private async initAdditionalPeerConnection(\n propose: RTCPeerConnectionPropose,\n options: MediaOptions\n ): Promise<string | undefined> {\n let rtcPeerConnController: RTCPeerConnectionController | null = null;\n try {\n this._screenShareStatus$.next('starting');\n rtcPeerConnController = new RTCPeerConnectionController(\n {\n ...options,\n ...this.RTCPeerConnectionConfig,\n propose,\n webRTCApiProvider: this.webRTCApiProvider\n },\n undefined,\n this.deviceController\n );\n this.setupLocalDescriptionHandler(rtcPeerConnController);\n if (propose === 'screenshare') {\n this._screenShareId = rtcPeerConnController.id;\n }\n this._rtcPeerConnectionsMap.set(rtcPeerConnController.id, rtcPeerConnController);\n this._rtcPeerConnections$.next(Array.from(this._rtcPeerConnectionsMap.values()));\n this.subscribeTo(rtcPeerConnController.errors$, (error) => {\n this.onError?.(error);\n });\n await firstValueFrom(\n rtcPeerConnController.connectionState$.pipe(\n filter((state) => state === 'connected'),\n take(1),\n timeout(this._screenShareTimeoutMs)\n )\n );\n this._screenShareStatus$.next('started');\n logger.info('[WebRTCManager] Screen share started successfully.');\n return rtcPeerConnController.id;\n } catch (error) {\n logger.warn('[WebRTCManager] Error initializing additional peer connection:', error);\n this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));\n if (rtcPeerConnController) {\n rtcPeerConnController.destroy();\n }\n this._screenShareStatus$.next('none');\n }\n }\n\n public async removeInputDevices(id: string): Promise<void> {\n return this.removeAdditionalPeerConnection(id);\n }\n\n public removeMainInputDevice(options = { removeAudio: false, removeVideo: true }): void {\n let removeTrack: 'audio' | 'video' | 'both' | undefined = undefined;\n if (options.removeAudio) {\n removeTrack = 'audio';\n }\n if (options.removeVideo) {\n removeTrack = removeTrack === 'audio' ? 'both' : 'video';\n }\n\n if (removeTrack) {\n return this.mainPeerConnection.stopTrackSender(removeTrack, {\n updateTransceiverDirection: true\n });\n }\n }\n\n public async removeScreenMedia(): Promise<void> {\n if (!['starting', 'started'].includes(this._screenShareStatus$.value)) {\n logger.warn('[WebRTCManager] No active screen share to stop.');\n }\n if (!this._screenShareId) {\n logger.debug('[WebRTCManager] No screen share peer connection found.');\n return;\n }\n this._screenShareStatus$.next('stopping');\n await this.removeAdditionalPeerConnection(this._screenShareId);\n this._screenShareId = undefined;\n this._screenShareStatus$.next('none');\n }\n\n public async removeAdditionalPeerConnection(id: string): Promise<void> {\n const rtcPeerConnController = this._rtcPeerConnectionsMap.get(id);\n try {\n if (rtcPeerConnController) {\n await this.executeVertoBye(rtcPeerConnController);\n }\n } finally {\n rtcPeerConnController?.destroy();\n this._rtcPeerConnectionsMap.delete(id);\n this._rtcPeerConnections$.next(Array.from(this._rtcPeerConnectionsMap.values()));\n }\n }\n\n private async executeVertoBye(\n rtcPeerConnController: RTCPeerConnectionController,\n cause?: VertoByeCause\n ): Promise<void> {\n try {\n const causeParams = cause\n ? {\n cause: cause,\n cause_code: VertoByeCauseCodes[cause]\n }\n : {};\n\n await this.executeVerto(\n VertoBye({\n ...causeParams,\n dialogParams: this.dialogParams(rtcPeerConnController)\n })\n );\n } catch (error) {\n logger.warn(\n '[WebRTCManager] Call might already be disconnected, error sending Verto bye:',\n error\n );\n throw error;\n }\n }\n public async bye(cause?: VertoByeCause): Promise<void> {\n void this.attachManager.detach(this.webRtcCallSession);\n const rtcPeerConnController = this._rtcPeerConnectionsMap.get(this.webRtcCallSession.id);\n if (rtcPeerConnController) {\n await this.executeVertoBye(rtcPeerConnController, cause);\n }\n }\n\n public async sendDigits(dtmf: string): Promise<void> {\n const vertoInfoMessage = VertoInfo({\n sessid: this.webRtcCallSession.id,\n dialogParams: {\n callID: this.webRtcCallSession.id\n },\n dtmf\n });\n\n try {\n await this.executeVerto(vertoInfoMessage);\n } catch (error) {\n logger.warn('[WebRTCManager] Error sending DTMF digits:', error);\n throw error;\n }\n }\n\n public async transfer(options: TransferOptions): Promise<void> {\n const message = VertoModify({\n ...options,\n dialogParams: this.dialogParams(this.mainPeerConnection),\n action: 'transfer'\n });\n try {\n logger.debug('[WebRTCManager] Transferring call with options:', options);\n await this.executeVerto(message);\n } catch (error) {\n logger.error('[WebRTCManager] Error transferring call:', error);\n throw error;\n }\n }\n\n public destroy(): void {\n this._rtcPeerConnectionsMap.forEach((rtcPeerConnController) => {\n rtcPeerConnController.destroy();\n });\n this._rtcPeerConnectionsMap.clear();\n this._rtcPeerConnections$.complete();\n super.destroy();\n }\n}\n","import { Participant, SelfParticipant, type ExecuteMethod } from '../core/entities/Participant';\n\nimport type { DeviceController } from '../interfaces/DeviceController';\nimport type { VertoManager } from '../interfaces/VertoManager';\n\n/**\n * Factory for creating Participant instances with proper dependency injection\n * Eliminates circular dependency between Call and Participant\n */\nexport class ParticipantFactory {\n constructor(\n private executeMethod: ExecuteMethod,\n private vertoManager: VertoManager,\n private deviceController: DeviceController\n ) {}\n\n /**\n * Create a self participant (the local user in the call)\n */\n public createSelfParticipant(id: string): SelfParticipant {\n return new SelfParticipant(id, this.executeMethod, this.vertoManager, this.deviceController);\n }\n\n /**\n * Create a remote participant\n */\n public createParticipant(id: string): Participant {\n return new Participant(id, this.executeMethod, this.deviceController);\n }\n}\n","import { filter, firstValueFrom, from, map, merge, share, takeUntil, tap } from 'rxjs';\nimport { v4 as uuid } from 'uuid';\n\nimport { Destroyable } from '../../behaviors/Destroyable';\nimport { ParticipantFactory } from '../../managers/ParticipantFactory';\nimport { filterAs } from '../../operators';\nimport { getValueFrom } from '../../utils/getValueFrom';\nimport { getLogger } from '../../utils/logger';\nimport { InvalidParams, UnimplementedError } from '../errors';\nimport { buildRPCRequest } from '../RPCMessages';\nimport {\n isCallStateMetadata,\n isCallUpdatedMetadata,\n isLayoutChangedMetadata,\n isMemberJoinedMetadata,\n isMemberLeftMetadata,\n isMemberTalkingMetadata,\n isMemberUpdatedMetadata,\n isSignalwireCallMetadata,\n isWebrtcMessageMetadata\n} from '../RPCMessages/guards/events.guards';\n\nimport type { Address } from './Address';\nimport type { Participant, SelfParticipant } from './Participant';\nimport type { ClientSession } from '../../interfaces/ClientSession';\nimport type { DeviceController } from '../../interfaces/DeviceController';\nimport type { JSONRPCParams } from '../RPCMessages';\nimport type {\n CallStatus,\n CallOptions,\n CallManager,\n CallParticipant,\n CallSelfParticipant\n} from './types/call.types';\nimport type { WebRTCVerto } from '../../interfaces/WebRTCVerto';\nimport type { CallEventsManager } from '../../managers/CallEventsManager';\nimport type { TransferOptions } from '../../managers/types/verto-manager.types';\nimport type { JSONRPCRequest, JSONRPCResponse } from '../RPCMessages/types/base';\nimport type { LayoutLayer } from '../RPCMessages/types/common';\nimport type {\n CallStatePayload,\n CallUpdatedPayload,\n LayoutChangedPayload,\n MemberJoinedPayload,\n MemberLeftPayload,\n MemberTalkingPayload,\n MemberUpdatedPayload\n} from '../RPCMessages/types/events';\nimport type { CallDirection, VideoPosition } from '../types/call.types';\nimport type { MediaDirections } from '../types/media.types';\nimport type { PendingRPCOptions } from '../utils';\nimport type { Observable, BehaviorSubject } from 'rxjs';\n\nconst logger = getLogger();\n\n/**\n * Manager instances returned by initialization callback\n */\nexport interface CallManagers {\n vertoManager: WebRTCVerto;\n callEventsManager: CallEventsManager;\n}\n\n/**\n * Initialization callback that creates managers for a Call instance\n * @param call - The WebRTCCall instance being initialized\n * @returns Manager instances for the call\n */\nexport type ManagerInitializer = (call: WebRTCCall) => CallManagers;\n\n/**\n * Required initialization configuration for Call constructor.\n * Calls must be created via {@link CallFactory} which provides these dependencies.\n */\nexport interface CallInitialization {\n /**\n * Callback function that creates and wires manager instances\n */\n initializeManagers: ManagerInitializer;\n /**\n * Device controller for media device access\n */\n deviceController: DeviceController;\n}\n\n/**\n * Concrete WebRTC call implementation.\n *\n * Manages the full lifecycle of a call including signaling, media streams,\n * participants, layout, and event routing. Created via {@link SignalWire.dial}\n * or received as an inbound call.\n */\nexport class WebRTCCall extends Destroyable implements CallManager {\n /** Unique identifier for this call. */\n public readonly id: string;\n /** Destination URI this call was placed to. */\n public to?: string;\n protected readonly participantsMap = new Map<string, Participant>();\n private vertoManager!: WebRTCVerto;\n private callEventsManager!: CallEventsManager;\n private participantFactory: ParticipantFactory;\n private _errors$ = this.createSubject<Error>();\n private _status$: BehaviorSubject<CallStatus>;\n private _answered$ = this.createReplaySubject<boolean>();\n private _holdState = false;\n\n constructor(\n public clientSession: ClientSession,\n public options: CallOptions,\n initialization: CallInitialization,\n public address?: Address\n ) {\n super();\n this.id = options.callId ?? uuid();\n this.to = options.to;\n\n const managers = initialization.initializeManagers(this);\n this.vertoManager = managers.vertoManager;\n this.callEventsManager = managers.callEventsManager;\n\n if (options.initOffer) {\n this._status$ = this.createBehaviorSubject<CallStatus>('ringing');\n } else {\n this._status$ = this.createBehaviorSubject<CallStatus>('new');\n }\n\n const { deviceController } = initialization;\n\n // Create participant factory with bound executeMethod\n this.participantFactory = new ParticipantFactory(\n this.executeMethod.bind(this),\n this.vertoManager,\n deviceController\n );\n }\n\n /** Observable stream of errors from media, signaling, and peer connection layers. */\n public get errors$(): Observable<Error> {\n return this._errors$.asObservable();\n }\n\n /** @internal Push an error to the call's error stream. */\n public emitError(error: Error): void {\n this._errors$.next(error);\n }\n\n /** Whether this call is `'inbound'` or `'outbound'`. */\n public get direction(): CallDirection {\n return this.options.initOffer ? 'inbound' : 'outbound';\n }\n\n /** Observable of the address associated with this call. */\n public get address$(): Observable<Address | undefined> {\n return from([this.address]);\n }\n\n /** Display name of the caller. */\n public get fromName(): string | undefined {\n return this.options.fromName;\n }\n\n /** Address URI of the caller. */\n public get from(): string | undefined {\n return this.options.from;\n }\n\n /** Display name of the callee. */\n public get toName(): string | undefined {\n return this.options.toName;\n }\n\n /** Toggles whether incoming video is received. @throws {UnimplementedError} Not yet implemented. */\n // eslint-disable-next-line @typescript-eslint/require-await\n public async toggleIncomingVideo(): Promise<void> {\n throw new UnimplementedError();\n }\n\n /** Toggles whether incoming audio is received. @throws {UnimplementedError} Not yet implemented. */\n // eslint-disable-next-line @typescript-eslint/require-await\n public async toggleIncomingAudio(): Promise<void> {\n throw new UnimplementedError();\n }\n\n /** @internal Registers an additional call ID for event routing. */\n public addCallId(callId: string): void {\n this.callEventsManager.addCallId(callId);\n }\n\n /** List of capabilities available in the current call. */\n public get capabilities(): string[] {\n return this.callEventsManager.capabilities;\n }\n\n /** Current snapshot of all participants in the call. */\n public get participants(): CallParticipant[] {\n return Array.from(this.participantsMap.values());\n }\n\n /** The local participant, or `null` if not yet joined. */\n public get self(): CallSelfParticipant | null {\n return this.callEventsManager.self;\n }\n\n async toggleLock(): Promise<void> {\n const method = this.locked ? 'call.unlock' : 'call.lock';\n await this.executeMethod(this.selfId ?? '', method, {});\n throw new UnimplementedError();\n }\n\n async toggleHold(): Promise<void> {\n if (this._holdState) {\n await this.vertoManager.unhold();\n } else {\n await this.vertoManager.hold();\n }\n this._holdState = !this._holdState;\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async startRecording(): Promise<void> {\n // NEEDS check backend API status\n throw new UnimplementedError();\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async startStreaming(): Promise<void> {\n // V3 VIDEO\n // NEEDS check backend API status\n throw new UnimplementedError();\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async setMeta(_meta: Record<string, unknown>): Promise<void> {\n // NEEDS backend implementation\n throw new UnimplementedError();\n }\n // eslint-disable-next-line @typescript-eslint/require-await\n async updateMeta(_meta: Record<string, unknown>): Promise<void> {\n // NEEDS backend implementation\n throw new UnimplementedError();\n }\n\n /** Observable of layout layer positions for all participants. */\n public get layoutLayers$(): Observable<LayoutLayer[]> {\n return this.callEventsManager.layoutLayers$;\n }\n\n /** Current snapshot of layout layers. */\n public get layoutLayers(): LayoutLayer[] {\n return this.callEventsManager.layoutLayers;\n }\n\n /** Executes a Verto RPC method targeting a specific participant. */\n public async executeMethod<T extends JSONRPCResponse = JSONRPCResponse>(\n target: string,\n method: string,\n args: Record<string, unknown>\n ): Promise<T> {\n const params = this.buildMethodParams(target, args);\n\n const request = buildRPCRequest({\n method,\n params\n });\n\n try {\n return await this.clientSession.execute(request);\n } catch (error) {\n logger.error(`[Call] Error executing method ${method} with params`, params, error);\n throw error;\n }\n }\n\n private buildMethodParams(target: string, args: Record<string, unknown>): JSONRPCParams {\n const reference = {\n node_id: this.nodeId,\n call_id: this.id\n };\n return {\n ...args,\n self: {\n ...reference,\n member_id: this.vertoManager.selfId\n },\n target: {\n ...reference,\n member_id: target\n }\n };\n }\n\n /** Observable of the current call status (e.g. `'ringing'`, `'connected'`). */\n public get status$(): Observable<CallStatus> {\n return this.cachedObservable('status$', () =>\n merge(this._status$.asObservable(), this.vertoManager.signalingStatus$)\n );\n }\n /** Observable of the participants list, emits on join/leave/update. */\n public get participants$(): Observable<CallParticipant[]> {\n return this.callEventsManager.participants$;\n }\n /** Observable of the local (self) participant. */\n public get self$(): Observable<CallSelfParticipant> {\n return this.callEventsManager.self$;\n }\n /** Observable indicating whether the call is being recorded. */\n public get recording$(): Observable<boolean> {\n return this.callEventsManager.recording$;\n }\n\n /** Observable indicating whether the call is being streamed. */\n public get streaming$(): Observable<boolean> {\n return this.callEventsManager.streaming$;\n }\n\n /** Observable indicating whether raise-hand priority is active. */\n public get raiseHandPriority$(): Observable<boolean> {\n return this.callEventsManager.raiseHandPriority$;\n }\n\n /** Observable indicating whether the call room is locked. */\n public get locked$(): Observable<boolean> {\n return this.callEventsManager.locked$;\n }\n\n /** Observable of custom metadata associated with the call. */\n public get meta$(): Observable<Record<string, unknown>> {\n return this.callEventsManager.meta$;\n }\n\n /** Observable of the call's capability flags. */\n public get capabilities$(): Observable<string[]> {\n return this.callEventsManager.capabilities$;\n }\n\n /** Observable of the current layout name. */\n public get layout$(): Observable<string> {\n return this.callEventsManager.layout$;\n }\n\n /** Current call status. */\n public get status(): CallStatus {\n return this._status$.value;\n }\n\n /** Whether the call is currently being recorded. */\n public get recording(): boolean {\n return this.callEventsManager.recording;\n }\n\n /** Whether the call is currently being streamed. */\n public get streaming(): boolean {\n return this.callEventsManager.streaming;\n }\n\n /** Whether raise-hand priority is active. */\n public get raiseHandPriority(): boolean {\n return this.callEventsManager.raiseHandPriority;\n }\n\n /** Whether the call room is locked. */\n public get locked(): boolean {\n return this.callEventsManager.locked;\n }\n\n /** Current custom metadata of the call. */\n public get meta(): Record<string, unknown> {\n return this.callEventsManager.meta;\n }\n\n /** Current layout name, or `undefined` if not set. */\n public get layout(): string | undefined {\n return this.callEventsManager.layout;\n }\n\n /** Observable of available layout names. */\n public get layouts$(): Observable<string[]> {\n return this.callEventsManager.layouts$;\n }\n\n /** Current snapshot of available layout names. */\n public get layouts(): string[] {\n return this.callEventsManager.layouts;\n }\n\n /** Observable of the local media stream (camera/microphone). */\n public get localStream$(): Observable<MediaStream> {\n return this.vertoManager.localStream$;\n }\n /** Current local media stream, or `null` if not available. */\n public get localStream(): MediaStream | null {\n return this.vertoManager.localStream;\n }\n /** Observable of the remote media stream from the far end. */\n public get remoteStream$(): Observable<MediaStream> {\n return this.vertoManager.remoteStream$;\n }\n /** Current remote media stream, or `null` if not available. */\n public get remoteStream(): MediaStream | null {\n return this.vertoManager.remoteStream;\n }\n\n /** @internal */\n public createParticipant(\n memberId: string,\n selfId?: string | null\n ): Participant | SelfParticipant {\n // Use provided selfId (from call.joined event) or fall back to vertoManager.selfId\n const effectiveSelfId = selfId ?? this.vertoManager.selfId;\n if (memberId === effectiveSelfId) {\n return this.participantFactory.createSelfParticipant(memberId);\n }\n return this.participantFactory.createParticipant(memberId);\n }\n\n /** Observable of the current audio/video send/receive directions. */\n public get mediaDirections$(): Observable<MediaDirections> {\n return this.vertoManager.mediaDirections$;\n }\n\n /** Current audio/video send/receive directions. */\n public get mediaDirections(): MediaDirections {\n return this.vertoManager.mediaDirections;\n }\n\n protected get participantsId$(): Observable<string[]> {\n return this.cachedObservable('participantsId$', () =>\n this.participants$.pipe(\n map((participants) => participants.map((participant) => participant.id))\n )\n );\n }\n\n /** Executes a raw JSON-RPC request on the client session. */\n public async execute<T extends JSONRPCResponse = JSONRPCResponse>(\n request: JSONRPCRequest,\n options?: PendingRPCOptions\n ): Promise<T> {\n return this.clientSession.execute(request, options);\n }\n\n /** Observable of the local participant's member ID. */\n public get selfId$(): Observable<string | null> {\n return this.vertoManager.selfId$;\n }\n\n /** Local participant's member ID, or `null` if not joined. */\n public get selfId(): string | null {\n return this.vertoManager.selfId;\n }\n\n /** Observable of the server node ID handling this call. */\n public get nodeId$(): Observable<string | null> {\n return this.vertoManager.nodeId$;\n }\n\n /** Server node ID handling this call, or `null`. */\n public get nodeId(): string | null {\n return this.vertoManager.nodeId;\n }\n\n private isCallSessionEvent(event: unknown): event is Event {\n try {\n logger.debug('[Call] Checking if event is for this call session:', event);\n const callId =\n getValueFrom<string>(event, 'params.params.callID') ??\n getValueFrom<string>(event, 'params.call_id');\n const roomSessionId = getValueFrom<string>(event, 'params.room_session_id');\n logger.debug(\n `[Call] Extracted session identifiers callID: ${callId} and roomSessionID: ${roomSessionId} from event:`\n );\n return (\n callId === this.id ||\n (!!callId && this.callEventsManager.isCallIdValid(callId)) ||\n (!!roomSessionId && this.callEventsManager.isRoomSessionIdValid(roomSessionId))\n );\n } catch (error) {\n logger.error('[Call] Error checking if event is for this call session:', error);\n return false;\n }\n }\n\n private get callSessionEvents$() {\n return this.cachedObservable('callSessionEvents$', () =>\n this.clientSession.signalingEvent$.pipe(\n filter((event) => this.isCallSessionEvent(event)),\n tap((event) => logger.debug('[Call] Received call session event:', event)),\n takeUntil(this.destroyed$),\n share()\n )\n );\n }\n\n /** Observable of call-updated events. */\n public get callUpdated$(): Observable<CallUpdatedPayload> {\n return this.cachedObservable('callUpdated$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isCallUpdatedMetadata, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n /** Observable of member-joined events. */\n public get memberJoined$(): Observable<MemberJoinedPayload> {\n return this.cachedObservable('memberJoined$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isMemberJoinedMetadata, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Observable of member-left events. */\n public get memberLeft$(): Observable<MemberLeftPayload> {\n return this.cachedObservable('memberLeft$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isMemberLeftMetadata, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n /** Observable of member-updated events (mute, volume, etc.). */\n public get memberUpdated$(): Observable<MemberUpdatedPayload> {\n return this.cachedObservable('memberUpdated$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isMemberUpdatedMetadata, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Observable of member-talking events (speech start/stop). */\n public get memberTalking$(): Observable<MemberTalkingPayload> {\n return this.cachedObservable('memberTalking$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isMemberTalkingMetadata, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Observable of call state-change events. */\n public get callStates$(): Observable<CallStatePayload> {\n return this.cachedObservable('callStates$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isCallStateMetadata, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Observable of layout-changed events. */\n public get layoutUpdates$(): Observable<LayoutChangedPayload> {\n return this.cachedObservable('layoutUpdates$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isLayoutChangedMetadata, 'params'),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Underlying `RTCPeerConnection`, for advanced use cases. */\n public get rtcPeerConnection(): RTCPeerConnection | undefined {\n return this.vertoManager.mainPeerConnection.peerConnection;\n }\n /** Observable of raw signaling events as plain objects. */\n public get signalingEvent$(): Observable<Record<string, unknown>> {\n return this.cachedObservable('signalingEvent$', () =>\n this.callEvent$.pipe(\n map((event) => JSON.parse(JSON.stringify(event)) as Record<string, unknown>)\n )\n );\n }\n\n /** Observable of WebRTC-specific signaling messages. */\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n public get webrtcMessages$() {\n return this.cachedObservable('webrtcMessages$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isWebrtcMessageMetadata, 'params'),\n tap((event) => logger.debug('[Call] Event is a WebRTC message event:', event)),\n takeUntil(this.destroyed$),\n share()\n )\n );\n }\n\n /** Observable of call-level signaling events. */\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n public get callEvent$() {\n return this.cachedObservable('callEvent$', () =>\n this.callSessionEvents$.pipe(\n filterAs(isSignalwireCallMetadata, 'params'),\n tap((event) => logger.debug('[Call] Event is a call event:', event)),\n takeUntil(this.destroyed$),\n share()\n )\n );\n }\n\n /** Observable of layout-changed signaling events. */\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n public get layoutEvent$() {\n return this.cachedObservable('layoutEvent$', () =>\n this.callEvent$.pipe(filterAs(isLayoutChangedMetadata, 'params'))\n );\n }\n\n /** Hangs up the call and releases all resources. */\n async hangup(): Promise<void> {\n this._status$.next('disconnecting');\n try {\n await this.vertoManager.bye();\n } finally {\n this._status$.next('destroyed');\n this.destroy();\n }\n }\n\n /** Sends DTMF digits (e.g. `'1234#'`) on the call. */\n async sendDigits(dtmf: string): Promise<void> {\n return this.vertoManager.sendDigits(dtmf);\n }\n\n /** Accepts an inbound call. */\n public answer(): void {\n this._answered$.next(true);\n }\n\n /** Rejects an inbound call. */\n public reject(): void {\n this._answered$.next(false);\n }\n\n /** Observable that emits `true` when answered, `false` when rejected. */\n public get answered$(): Observable<boolean> {\n return this._answered$.asObservable();\n }\n\n /**\n * Sets the call layout and participant positions.\n * @param layout - Layout name (must be one of {@link layouts}).\n * @param positions - Map of member IDs to video positions.\n */\n async setLayout(layout: string, positions: Record<string, VideoPosition>): Promise<void> {\n if (!this.layouts.includes(layout)) {\n throw new InvalidParams(\n `Layout ${layout} is not available in the current call layouts: ${this.layouts.join(', ')}`\n );\n }\n\n const selfId = await firstValueFrom(\n this.selfId$.pipe(filter((id): id is string => id !== null))\n );\n\n await this.executeMethod(selfId, 'call.layout.set', {\n layout,\n positions\n });\n }\n\n /** Transfers the call to other participants. */\n public async transfer(options: TransferOptions): Promise<void> {\n return this.vertoManager.transfer(options);\n }\n\n /** Destroys the call, releasing all resources and subscriptions. */\n public destroy(): void {\n this.vertoManager.destroy();\n this.callEventsManager.destroy();\n this.participantsMap.clear();\n super.destroy();\n }\n}\n","import { CallEventsManager } from './CallEventsManager';\nimport { WebRTCVertoManager } from './VertoManager';\nimport { WebRTCCall } from '../core/entities/Call';\n\nimport type { AttachManager } from './AttachManager';\nimport type { Address } from '../core/entities/Address';\nimport type { CallOptions } from '../core/entities/types/call.types';\nimport type { WebRTCApiProvider } from '../dependencies/interfaces';\nimport type { ClientSession } from '../interfaces/ClientSession';\nimport type { DeviceController } from '../interfaces/DeviceController';\n\n/**\n * Factory for creating WebRTCCall instances with proper manager wiring.\n * Eliminates circular dependencies by centralizing Call and Manager creation.\n */\nexport class CallFactory {\n constructor(\n private sessionManager: ClientSession,\n private deviceController: DeviceController,\n private attachManager: AttachManager,\n private webRTCApiProvider: WebRTCApiProvider\n ) {}\n\n /**\n * Create a new WebRTCCall with properly initialized managers\n */\n createCall(address: Address | undefined, options: CallOptions): WebRTCCall {\n const call = new WebRTCCall(\n this.sessionManager,\n options,\n {\n initializeManagers: (callInstance: WebRTCCall) => {\n const vertoManager = new WebRTCVertoManager(\n callInstance,\n this.attachManager,\n this.deviceController,\n this.webRTCApiProvider,\n {\n nodeId: options.nodeId,\n onError: (error: Error) => {\n callInstance.emitError(error);\n }\n }\n );\n\n const callEventsManager = new CallEventsManager(callInstance);\n\n return {\n vertoManager,\n callEventsManager\n };\n },\n deviceController: this.deviceController\n },\n address\n );\n\n return call;\n }\n}\n","import {\n defer,\n distinctUntilChanged,\n filter,\n from,\n map,\n ReplaySubject,\n shareReplay,\n Subject,\n takeUntil,\n skip,\n pipe\n} from 'rxjs';\n\nimport { Destroyable } from './Destroyable';\nimport { GET_PARAMS } from '../controllers/HTTPRequestController';\nimport { CollectionFetchError } from '../core/errors';\nimport { getLogger } from '../utils/logger';\n\nimport type {\n PaginatedResponse,\n Entity,\n FetchController,\n Collection\n} from './types/collection.types';\nimport type { HTTPRequestController } from '../controllers/HTTPRequestController';\nimport type { Observable, Subscription } from 'rxjs';\n\nconst logger = getLogger();\n\nexport class Fetcher<T extends Entity = Entity> implements FetchController<Entity> {\n private nextUrl?: string;\n public hasMore: boolean | undefined;\n public filter = (_item: Entity): _item is T => true;\n public mapper = (item: unknown): T => item as T;\n\n constructor(\n protected endpoint: string,\n params: string,\n protected http: HTTPRequestController\n ) {\n this.nextUrl = `${this.endpoint}?${params}`;\n }\n\n public async next(): Promise<T[]> {\n if (!this.nextUrl) return [];\n\n const response = await this.http.request({\n ...GET_PARAMS,\n url: this.nextUrl\n });\n if (response.ok && !!response.body) {\n const result = JSON.parse(response.body) as PaginatedResponse<T>;\n this.nextUrl = result.links.next;\n const filtered = result.data.filter(this.filter);\n return filtered.map(this.mapper);\n }\n logger.error('Failed to fetch entity');\n return [];\n }\n\n public async id(v: unknown): Promise<T | undefined> {\n const response = await this.http.request({\n ...GET_PARAMS,\n url: `${this.endpoint}/${String(v)}`\n });\n if (response.ok && !!response.body) {\n return JSON.parse(response.body) as T;\n }\n }\n}\n\nexport class EntityCollection<T extends Entity = Entity>\n extends Destroyable\n implements Collection<T>\n{\n public loading$ = this.createBehaviorSubject<boolean>(false);\n public values$ = this.createReplaySubject<T[]>(1);\n public hasMore$: Observable<boolean>;\n private collectionData = new Map<string, T>();\n private observablesRegistry = new Map<string, ReplaySubject<T>>();\n private updateSubscription: Subscription;\n private upsertData = (data: Partial<T>) => {\n if (!data.id) return;\n const existing = this.collectionData.get(data.id) ?? {};\n const updated = { ...existing, ...data } as T;\n this.collectionData.set(data.id, updated);\n this.observablesRegistry.get(data.id)?.next(updated);\n this.values$.next(Array.from(this.collectionData.values()));\n };\n\n private _destroy$ = new Subject<void>();\n constructor(\n private fetchController: FetchController<T>,\n private update$: Observable<Partial<T>>,\n private readonly onError?: (error: Error) => void\n ) {\n super();\n this.updateSubscription = this.update$.subscribe(this.upsertData);\n this.loading$.next(false);\n this.hasMore$ = defer(() => from(this.init())).pipe(shareReplay(1), takeUntil(this._destroy$));\n }\n public get loading(): boolean {\n return this.loading$.value;\n }\n\n public get hasMore(): boolean {\n return this.fetchController.hasMore ?? true;\n }\n\n public get updated$(): Observable<void> {\n return this.cachedObservable('updated$', () =>\n this.loading$.pipe(\n distinctUntilChanged(),\n skip(1), // skiping the loading === true event\n filter((loading) => !loading),\n map(() => void 0),\n takeUntil(this._destroy$)\n )\n );\n }\n\n public get values(): T[] {\n return Array.from(this.collectionData.values());\n }\n\n private async init(): Promise<boolean> {\n if (this.fetchController.hasMore === false) {\n return Promise.resolve(false);\n }\n await this.fetchMore();\n return this.fetchController.hasMore ?? true;\n }\n\n private async fetchMore(): Promise<void> {\n try {\n this.loading$.next(true);\n const datas = await this.fetchController.next();\n datas.forEach(this.upsertData);\n this.loading$.next(false);\n } catch (error) {\n logger.error(`Failed to fetch initial collection data`, error);\n this.loading$.next(false);\n this.onError?.(new CollectionFetchError('fetchMore', error));\n }\n }\n\n private async tryFetch(key: keyof FetchController<T>, value: unknown): Promise<T | undefined> {\n try {\n this.loading$.next(true);\n const data = await this.fetchController[key]?.(value);\n this.loading$.next(false);\n if (data) {\n this.upsertData(data);\n }\n return data;\n } catch (error) {\n logger.error(`Failed to fetch data for (${String(key)}:${String(value)}) :`, error);\n this.loading$.next(false);\n this.onError?.(new CollectionFetchError(`tryFetch(${String(key)})`, error));\n }\n }\n\n public get$(id: string): Observable<T> | undefined {\n if (!this.observablesRegistry.has(id)) {\n this.observablesRegistry.set(id, new ReplaySubject<T>(1));\n const data = this.collectionData.get(id);\n if (data) {\n this.observablesRegistry.get(id)?.next(data);\n } else {\n void this.tryFetch('id', id);\n }\n }\n return this.observablesRegistry.get(id)?.asObservable();\n }\n\n public async find$(key: keyof T, value: unknown): Promise<Observable<T> | undefined> {\n const data =\n Array.from(this.collectionData.values()).find((item) => item[key] === value) ??\n (await this.tryFetch(key, value));\n\n return data ? this.get$(data.id) : undefined;\n }\n\n public loadMore(): void {\n if (this.fetchController.hasMore !== false) {\n void this.fetchMore();\n }\n }\n\n public destroy(): void {\n this._destroy$.next();\n this._destroy$.complete();\n this.updateSubscription.unsubscribe();\n this.loading$.complete();\n this.observablesRegistry.forEach((subject) => subject.complete());\n }\n}\n\nexport class EntityCollectionTransformed<\n O extends Entity = Entity,\n T extends Entity = Entity\n> implements Collection<T> {\n private _values$?: Observable<T[]>;\n\n constructor(\n private originalCollection: EntityCollection<O>,\n private filter: (i: unknown) => i is O = (i): i is O => !!i,\n private mapper: (item: O) => T = (item) => item as unknown as T\n ) {}\n\n public get loading$(): Observable<boolean> {\n return this.originalCollection.loading$;\n }\n\n public get loading(): boolean {\n return this.originalCollection.loading;\n }\n public get hasMore$(): Observable<boolean> {\n return this.originalCollection.hasMore$;\n }\n public get hasMore(): boolean {\n return this.originalCollection.hasMore;\n }\n public get values(): T[] {\n return this.originalCollection.values.filter(this.filter).map(this.mapper);\n }\n public get values$(): Observable<T[]> {\n return (this._values$ ??= this.originalCollection.values$.pipe(\n map((values) => values.filter(this.filter).map(this.mapper))\n ));\n }\n\n public get$(id: string): Observable<T> | undefined {\n const original$ = this.originalCollection.get$(id);\n return !original$ ? original$ : original$.pipe(pipe(filter(this.filter), map(this.mapper)));\n }\n\n public async find$(key: keyof T, value: unknown): Promise<Observable<T> | undefined> {\n const original$ = await this.originalCollection.find$(key as keyof O, value);\n return !original$ ? original$ : original$.pipe(pipe(filter(this.filter), map(this.mapper)));\n }\n public loadMore(): void {\n this.originalCollection.loadMore();\n }\n public destroy(): void {\n this.originalCollection.destroy();\n }\n}\n","import { defer, map, shareReplay, takeUntil, type Observable } from 'rxjs';\n\nimport { EntityCollectionTransformed } from '../../behaviors/Collection';\nimport { Destroyable } from '../../behaviors/Destroyable';\nimport { filterNull } from '../../operators';\nimport { DependencyError, UnimplementedError } from '../errors';\n\nimport type { CallState } from './types/call.types';\nimport type { AddressProvider } from '../../interfaces/AddressProvider';\nimport type {\n ConversationMessageCollection,\n ConversationsProvider\n} from '../../interfaces/Conversations';\nimport type { GetAddressResponse } from '../types/address.types';\nimport type { ResourceType } from '../types/common.types';\nimport type {\n AddressHistory,\n AddressHistoryCollection,\n GetConversationMessageResponse,\n TextMessage,\n TextMessageCollection\n} from '../types/conversation.types';\n\ntype AddressState = GetAddressResponse;\n/**\n * Represents a contact or room in the directory.\n *\n * Provides identity metadata, conversation history, text messaging,\n * and activity state for an address entry.\n */\nexport class Address extends Destroyable {\n private initConversationMessages = async (): Promise<ConversationMessageCollection> => {\n this._conversationMessages =\n this._conversationMessages ??\n (await this.conversationManager.getConversationMessageCollection(this.id));\n if (this._conversationMessages.hasMore) {\n this._conversationMessages.loadMore();\n }\n return this._conversationMessages;\n };\n\n /** Observable of text messages for this address. Lazily loads conversation data. */\n public textMessages$ = defer(this.initConversationMessages).pipe(\n map(() => this.textMessage),\n shareReplay(1),\n takeUntil(this.destroyed$)\n );\n /** Observable of call history for this address. Lazily loads conversation data. */\n public history$ = defer(this.initConversationMessages).pipe(\n map(() => this.history),\n shareReplay(1),\n takeUntil(this.destroyed$)\n );\n private _conversationMessages?: ConversationMessageCollection;\n\n private _state$ = this.createBehaviorSubject<AddressState | null>(null);\n\n private _history$?: AddressHistoryCollection<Address>;\n\n private _textMessages$?: TextMessageCollection<Address>;\n\n // FIXME after presence API is available\n // this should be a dynamic view of the address existing calls,\n // independent if the user is on the call or not.\n // private _callsStates$ = this.createBehaviorSubject<CallState[]>([]);\n\n constructor(\n private readonly addressId: string,\n private conversationManager: ConversationsProvider,\n private addressProvider: AddressProvider<Address>\n ) {\n super();\n }\n\n /** @internal */\n public upnext(state: Partial<AddressState>): void {\n const update = {\n ...this._state$.value,\n ...state\n } as AddressState;\n this._state$.next(update);\n }\n\n /** @internal */\n public get state(): AddressState | null {\n return this._state$.value;\n }\n\n /** Unique address identifier. */\n public get id(): string {\n return this.addressId;\n }\n /** Address name (resource identifier). */\n public get name(): string {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.name;\n }\n\n /** ISO timestamp of when the address was created. */\n public get createdAt(): string {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.created_at;\n }\n\n /** Default communication channel URI (video for rooms, audio otherwise). */\n public get defaultChannel(): string | undefined {\n return this.type === 'room' ? this.channels.video : this.channels.audio;\n }\n\n /** Observable of the human-readable display name. */\n public get displayName$(): Observable<string> {\n return this.cachedObservable('displayName$', () =>\n this._state$.pipe(\n filterNull(),\n map((state) => state.display_name),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Human-readable display name. */\n public get displayName(): string {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.display_name;\n }\n\n /** Observable of the preview image URL. */\n public get previewUrl$(): Observable<string | undefined> {\n return this.cachedObservable('previewUrl$', () =>\n this._state$.pipe(\n filterNull(),\n map((state) => state.preview_url),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Preview image URL. */\n public get previewUrl(): string | undefined {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.preview_url;\n }\n\n /** Observable of the cover image URL. */\n public get coverUrl$(): Observable<string | undefined> {\n return this.cachedObservable('coverUrl$', () =>\n this._state$.pipe(\n filterNull(),\n shareReplay(1),\n map((state) => state.cover_url),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Cover image URL. */\n public get coverUrl(): string | undefined {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.cover_url;\n }\n\n /** Observable of the underlying resource ID. */\n public get resourceId$(): Observable<string> {\n return this.cachedObservable('resourceId$', () =>\n this._state$.pipe(\n filterNull(),\n shareReplay(1),\n map((state) => state.resource_id),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Underlying resource ID. */\n public get resourceId(): string {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.resource_id;\n }\n\n /** Observable of the resource type (e.g. `'room'`, `'subscriber'`). */\n public get type$(): Observable<ResourceType> {\n return this.cachedObservable('type$', () =>\n this._state$.pipe(\n filterNull(),\n shareReplay(1),\n map((state) => state.type),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Resource type (e.g. `'room'`, `'subscriber'`). */\n public get type(): ResourceType {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.type;\n }\n\n /** Observable of available communication channels (audio, video, messaging). */\n public get channels$(): Observable<{\n audio?: string;\n messaging?: string;\n video?: string;\n }> {\n return this.cachedObservable('channels$', () =>\n this._state$.pipe(\n filterNull(),\n shareReplay(1),\n map((state) => state.channels),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Available communication channels. */\n public get channels(): {\n audio?: string;\n messaging?: string;\n video?: string;\n } {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.channels;\n }\n\n /** Whether the address (room) is locked. */\n public get locked(): boolean {\n if (!this._state$.value) {\n throw new DependencyError('state not initialized');\n }\n return this._state$.value.locked;\n }\n\n /** Observable indicating whether the address (room) is locked. */\n public get locked$(): Observable<boolean> {\n return this.cachedObservable('locked$', () =>\n this._state$.pipe(\n filterNull(),\n shareReplay(1),\n map((state) => state.locked),\n takeUntil(this.destroyed$)\n )\n );\n }\n\n /** Sends a text message to this address. */\n public async sendText(text: string): Promise<void> {\n return this.conversationManager.sendText(text, this.id);\n }\n\n /** Collection of text messages for this address, with pagination support. */\n public get textMessage():\n | EntityCollectionTransformed<GetConversationMessageResponse, TextMessage<Address>>\n | undefined {\n if (!this._conversationMessages) {\n return;\n }\n this._textMessages$ =\n this._textMessages$ ??\n new EntityCollectionTransformed<GetConversationMessageResponse, TextMessage<Address>>(\n this._conversationMessages,\n (item): item is GetConversationMessageResponse =>\n (item as GetConversationMessageResponse).subtype === 'chat',\n (item) =>\n ({\n id: item.id,\n text: item.text,\n created: item.ts,\n fromAddress$: this.addressProvider.get$(item.from_fabric_address_id)\n }) as TextMessage<Address>\n );\n return this._textMessages$;\n }\n\n /** Collection of call history entries for this address, with pagination support. */\n public get history():\n | EntityCollectionTransformed<GetConversationMessageResponse, AddressHistory<Address>>\n | undefined {\n if (!this._conversationMessages) {\n return;\n }\n this._history$ =\n this._history$ ??\n new EntityCollectionTransformed<GetConversationMessageResponse, AddressHistory<Address>>(\n this._conversationMessages,\n (item): item is GetConversationMessageResponse =>\n (item as GetConversationMessageResponse).subtype === 'log',\n (item) =>\n ({\n id: item.id,\n kind: item.kind,\n status: item.details.status,\n started: item.details.start_time,\n ended: item.details.end_time,\n fromAddress$: this.addressProvider.get$(item.from_fabric_address_id)\n }) as AddressHistory<Address>\n );\n return this._history$;\n }\n\n /** Observable of active call states for this address. @throws {UnimplementedError} Requires presence support. */\n public get activity$(): Observable<CallState[]> {\n // NEEDS Presence\n throw new UnimplementedError();\n }\n\n /** Active call states for this address. @throws {UnimplementedError} Requires presence support. */\n public get activity(): CallState[] {\n // NEEDS Presence\n throw new UnimplementedError();\n }\n}\n","import { filter, NEVER, Observable, race, take } from 'rxjs';\nimport { v4 as uuid } from 'uuid';\n\nimport { InvalidListenerError, RPCTimeoutError } from './errors';\nimport { Destroyable } from '../behaviors/Destroyable';\nimport { getLogger } from '../utils/logger';\n\nimport type { RPCConnectResult } from './RPCMessages';\nimport type { JSONRPCRequest, JSONRPCResponse } from './RPCMessages/types/base';\n\nconst logger = getLogger();\n\nexport async function callListener<T>(\n listener: ((value: T) => void) | ((value: T) => Promise<void>),\n value: T,\n onError?: (error: unknown) => void\n): Promise<void> {\n try {\n if (typeof listener !== 'function') {\n throw new InvalidListenerError();\n }\n await listener(value);\n } catch (error) {\n if (error instanceof InvalidListenerError) {\n logger.error(error.message);\n } else {\n logger.warn('Error calling listener:', error);\n }\n onError?.(error);\n }\n}\n\nexport const isRPCConnectResult = (e: unknown): e is RPCConnectResult => {\n logger.debug('isRPCConnectResult check:', e);\n if (!e || typeof e !== 'object') return false;\n\n // Check if this is a JSON-RPC response with a result property\n\n const result = e as RPCConnectResult;\n\n const is =\n typeof result.identity === 'string' &&\n typeof result.protocol === 'string' &&\n typeof result.authorization === 'object' &&\n typeof result.authorization.jti === 'string' &&\n typeof result.authorization.project_id === 'string' &&\n typeof result.authorization.fabric_subscriber === 'object';\n\n logger.debug('isRPCConnectResult check result:', is);\n return is;\n};\n\nexport interface PendingRPCOptions {\n /**\n * Timeout in milliseconds. Defaults to 5000ms (5 seconds).\n * If the response is not received within this time, the promise will reject with RPCTimeoutError.\n */\n timeoutMs?: number;\n\n /**\n * Optional AbortSignal for cancellation support.\n * If the signal is aborted, the promise will reject with an AbortError.\n */\n signal?: AbortSignal;\n}\n\nexport class PendingRPC<T extends JSONRPCResponse = JSONRPCResponse> {\n private static readonly defaultTimeoutMs = 5000;\n private id = uuid();\n\n public readonly request: JSONRPCRequest;\n public promise: Promise<T>;\n\n constructor(request: JSONRPCRequest, responses$: Observable<T>, options?: PendingRPCOptions) {\n logger.debug(\n `[PendingRPC(${this.id}) request:${request.id}: method:${request.method}] Creating PendingRPC`\n );\n this.request = request;\n\n const timeoutMs = options?.timeoutMs ?? PendingRPC.defaultTimeoutMs;\n const signal = options?.signal;\n\n this.promise = new Promise<T>((resolve, reject) => {\n // Check if already aborted\n if (signal?.aborted) {\n reject(new DOMException('The operation was aborted', 'AbortError'));\n return;\n }\n\n // Track if promise has been settled to prevent unhandled rejections\n let isSettled = false;\n\n // Create the main response observable\n const response$ = responses$.pipe(\n filter((result) => result.id === request.id),\n take(1)\n );\n\n // Create timeout observable\n const timeout$ = new Observable<never>((subscriber) => {\n const timer = setTimeout(() => {\n subscriber.error(new RPCTimeoutError(request.id, timeoutMs));\n }, timeoutMs);\n\n return () => clearTimeout(timer);\n });\n\n // Create abort observable if signal provided\n const abort$ = signal\n ? new Observable<never>((subscriber) => {\n const abortHandler = () => {\n subscriber.error(new DOMException('The operation was aborted', 'AbortError'));\n };\n signal.addEventListener('abort', abortHandler);\n\n return () => signal.removeEventListener('abort', abortHandler);\n })\n : NEVER; // Observable that never emits\n\n // Race between response, timeout, and abort\n const subscription = race(response$, timeout$, abort$).subscribe({\n next: (response) => {\n logger.debug(\n `[PendingRPC(${this.id}) request:${request.id}] Resolving promise with response:`,\n response\n );\n isSettled = true;\n resolve(response);\n subscription.unsubscribe();\n },\n error: (error) => {\n logger.debug(\n `[PendingRPC(${this.id}) request:${request.id}] Rejecting promise with error:`,\n error\n );\n isSettled = true;\n reject(error as Error);\n subscription.unsubscribe();\n },\n complete: () => {\n logger.debug(`[PendingRPC(${this.id}) request:${request.id}] Observable completed`);\n if (!isSettled) {\n reject(new RPCTimeoutError(request.id, timeoutMs));\n }\n subscription.unsubscribe();\n }\n });\n });\n }\n\n // Make it thenable (Promise-like)\n async then<TResult1 = JSONRPCResponse, TResult2 = never>(\n onfulfilled?: ((value: JSONRPCResponse) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): Promise<TResult1 | TResult2> {\n return this.promise.then(onfulfilled, onrejected);\n }\n\n async catch<TResult = never>(\n onrejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null\n ): Promise<JSONRPCResponse | TResult> {\n return this.promise.catch(onrejected);\n }\n\n async finally(onfinally?: (() => void) | null): Promise<JSONRPCResponse> {\n return this.promise.finally(onfinally);\n }\n}\n\n// Re-export Destroyable for backward compatibility\nexport { Destroyable };\n","import {\n catchError,\n combineLatest,\n defer,\n filter,\n firstValueFrom,\n from,\n lastValueFrom,\n map,\n share,\n shareReplay,\n take,\n takeUntil,\n tap,\n timeout\n} from 'rxjs';\n\nimport { CallFactory } from './CallFactory';\nimport { Address } from '../core/entities/Address';\nimport {\n AuthStateHandlerError,\n CallCreateError,\n DependencyError,\n UnexpectedError,\n VertoInviteHandlerError\n} from '../core/errors';\nimport { RPCConnect } from '../core/RPCMessages';\nimport {\n isSignalwireAuthorizationStateMetadata,\n isSignalwireRequest,\n isWebrtcMessageMetadata\n} from '../core/RPCMessages/guards/events.guards';\nimport { isVertoInviteMessage } from '../core/RPCMessages/guards/verto.guards';\nimport { Destroyable, isRPCConnectResult } from '../core/utils';\nimport { filterAs } from '../operators/filterEventAs';\nimport { throwOnRPCError } from '../operators/throwOnRPCError';\nimport { getLogger } from '../utils/logger';\n\nimport type { AttachManager } from './AttachManager';\nimport type { StorageManager } from './StorageManager';\nimport type { TransportManager } from './TransportManager';\nimport type { WebRTCCall } from '../core/entities/Call';\nimport type { Directory } from '../core/entities/Directory';\nimport type { Call, CallOptions } from '../core/entities/types/call.types';\nimport type {\n RPCConnectParams,\n RPCConnectAuthentication,\n Authorization\n} from '../core/RPCMessages';\nimport type { JSONRPCRequest, JSONRPCResponse } from '../core/RPCMessages/types/base';\nimport type { VertoInviteParams } from '../core/RPCMessages/types/verto';\nimport type { SDKCredential, JSONSerializable } from '../core/types/common.types';\nimport type { PendingRPCOptions } from '../core/utils';\nimport type { WebRTCApiProvider } from '../dependencies/interfaces';\nimport type { DeviceController } from '../interfaces/DeviceController';\nimport type { SessionState } from '../interfaces/SessionState';\nimport type { Observable } from 'rxjs';\n\nconst logger = getLogger();\n\nconst getAddressSearchURI = (options: CallOptions): string => {\n const to = options.to?.split('?')[0];\n const from = options.from?.startsWith('subscriber://')\n ? options.from.replace('subscriber://', '')\n : options.from;\n const name = to ?? from;\n if (!name) {\n throw new UnexpectedError('Error building Address name');\n }\n return name;\n};\n\nexport class ClientSessionManager extends Destroyable implements SessionState {\n private callFactory: CallFactory;\n private callCreateTimeout = 6000;\n private readonly agent = `signalwire-typescript-sdk/1.0.0`;\n private readonly eventAcks = true;\n public initialized$: Observable<boolean>;\n public authorization$ = this.createSubject<Authorization>();\n private authorizationState$ = this.createReplaySubject<string | undefined>(1);\n private connectVersion = {\n major: 4,\n minor: 0,\n revision: 0\n };\n private _errors$ = this.createSubject<Error>();\n private _directory?: Directory;\n\n private _authenticated$ = this.createBehaviorSubject<boolean>(false);\n\n private _subscriberInfo$ = this.createBehaviorSubject<Address | null>(null);\n private _calls$ = this.createBehaviorSubject<Record<string, Call>>({});\n private _iceServers$ = this.createBehaviorSubject<RTCIceServer[]>([]);\n\n constructor(\n private credential: SDKCredential,\n private readonly transport: TransportManager,\n private readonly storage: StorageManager,\n private readonly authorizationStateKey: string,\n deviceController: DeviceController,\n private readonly attachManager: AttachManager,\n webRTCApiProvider: WebRTCApiProvider\n ) {\n super();\n attachManager.setSession(this);\n this.callFactory = new CallFactory(this, deviceController, attachManager, webRTCApiProvider);\n this.initialized$ = defer(() => from(this.init())).pipe(\n shareReplay(1),\n takeUntil(this.destroyed$)\n );\n }\n public get incomingCalls$(): Observable<Call[]> {\n return this.cachedObservable('incomingCalls$', () =>\n this.calls$.pipe(map((calls) => calls.filter((call) => call.direction === 'inbound')))\n );\n }\n\n public get incomingCalls(): Call[] {\n const calls = Object.values(this._calls$.value);\n return calls.filter((call) => call.direction === 'inbound');\n }\n\n public get subscriberInfo$(): Observable<Address | null> {\n return this._subscriberInfo$.asObservable();\n }\n\n public get subscriberInfo(): Address | null {\n return this._subscriberInfo$.value;\n }\n\n public get calls$(): Observable<Call[]> {\n return this.cachedObservable('calls$', () =>\n this._calls$.pipe(map((calls) => Object.values(calls)))\n );\n }\n\n public get calls(): Call[] {\n return Object.values(this._calls$.value);\n }\n\n public get iceServers(): RTCIceServer[] | undefined {\n return this._iceServers$.value;\n }\n\n public get errors$(): Observable<Error> {\n return this._errors$.asObservable();\n }\n\n public get authenticated$(): Observable<boolean> {\n return this._authenticated$.asObservable();\n }\n\n public get authenticated(): boolean {\n return this._authenticated$.value;\n }\n\n /**\n * Set the directory instance\n * Called by SignalWire after directory is created\n * @internal\n */\n public setDirectory(directory: Directory): void {\n this._directory = directory;\n }\n\n public async execute<T extends JSONRPCResponse = JSONRPCResponse>(\n request: JSONRPCRequest,\n options?: PendingRPCOptions\n ): Promise<T> {\n try {\n return await this.transport.execute(request, options);\n } catch (error) {\n logger.debug('[Session] Execute Error', error);\n this._errors$.next(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n throw error;\n }\n }\n\n public send(message: JSONSerializable): void {\n this.transport.send(message);\n }\n\n private async init(): Promise<boolean> {\n await this.loadAuthorizationStateFromStorage();\n this.setupMessageHandlers();\n return true;\n }\n\n private setupMessageHandlers(): void {\n logger.debug('[Session] Setting up message handlers');\n\n this.subscribeTo(this.authStateEvent$, async (authStateEvent) => {\n logger.debug('[Session] Authorization state event received:', authStateEvent);\n try {\n await this.updateAuthorizationStateInStorage(authStateEvent.authorization_state);\n } catch (error) {\n logger.error('[Session] Failed to handle authorization state update:', error);\n this._errors$.next(new AuthStateHandlerError(error));\n }\n });\n\n this.subscribeTo(\n this.transport.connectionStatus$.pipe(filter((status) => status === 'connected')),\n async () => {\n try {\n logger.debug('[Session] Connection established, initiating authentication');\n await this.authenticate();\n } catch (error) {\n this.handleAuthenticationError(error as Error).catch((err) => {\n logger.error('[Session] Error handling authentication failure:', err);\n });\n }\n }\n );\n\n this.subscribeTo(this.vertoInvite$, async (invite) => {\n logger.debug('[Session] Verto invite received:', invite);\n try {\n await this.createInboundCall(invite);\n } catch (error) {\n logger.error('[Session] Error handling Verto invite:', error);\n this._errors$.next(new VertoInviteHandlerError(error));\n }\n });\n }\n\n private async loadAuthorizationStateFromStorage(): Promise<void> {\n try {\n const storedState = await this.storage.getItem<string>(this.authorizationStateKey);\n // Always emit a value, even if undefined, so combineLatest can proceed\n this.authorizationState$.next(storedState ?? undefined);\n } catch (error) {\n logger.error('Failed to retrieve authorization state from storage:', error);\n // Emit undefined on error so authentication can proceed without stored state\n this.authorizationState$.next(undefined);\n }\n }\n\n private async updateAuthorizationStateInStorage(authorizationState?: string): Promise<void> {\n if (!authorizationState) {\n logger.debug('[Session] Removing authorization state from storage');\n try {\n await this.storage.removeItem(this.authorizationStateKey);\n } catch (error) {\n logger.error('Failed to remove authorization state from storage:', error);\n throw error;\n }\n return;\n }\n\n try {\n logger.debug('[Session] Updating authorization state in storage');\n await this.storage.setItem(this.authorizationStateKey, authorizationState);\n this.authorizationState$.next(authorizationState);\n } catch (error) {\n logger.error('Failed to retrieve authorization state from storage:', error);\n throw error;\n }\n }\n\n private get authStateEvent$() {\n return this.cachedObservable('authStateEvent$', () =>\n this.signalingEvent$.pipe(\n tap((msg) => {\n logger.debug('[Session] Received incoming message:', msg);\n }),\n filterAs(isSignalwireAuthorizationStateMetadata, 'params'),\n tap((event) => {\n logger.debug('[Session] Authorization state event received:', event.authorization_state);\n })\n )\n );\n }\n\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n public get signalingEvent$() {\n return this.cachedObservable('signalingEvent$', () =>\n this.transport.incomingEvent$.pipe(filterAs(isSignalwireRequest, 'params'), share())\n );\n }\n\n private get vertoInvite$() {\n return this.cachedObservable('vertoInvite$', () =>\n this.signalingEvent$.pipe(\n filter(isWebrtcMessageMetadata),\n filter((event) => isVertoInviteMessage(event.params)),\n map((event) => ({\n node_id: event.node_id,\n ...(event.params.params as VertoInviteParams)\n }))\n )\n );\n }\n\n private get contexts(): string[] {\n return [];\n }\n\n private get eventing(): string[] {\n return [];\n }\n\n private get topics(): string[] {\n return [];\n }\n\n private get authentication(): RPCConnectAuthentication {\n if (!this.credential.token) {\n throw new DependencyError('Credential token is undefined');\n }\n return {\n jwt_token: this.credential.token\n };\n }\n\n async connect(): Promise<void> {\n // Ensure session is initialized before proceeding\n await firstValueFrom(this.initialized$);\n\n // Now initiate the connection - the subscription above will handle authentication\n await this.transport.connect();\n }\n\n private async handleAuthenticationError(error: Error): Promise<void> {\n logger.error('Authentication error:', error);\n this._errors$.next(error);\n if (error.message === 'Requester validation failed') {\n // the server is not accepting our credentials, potentially corrupted authorizationState or protocol\n try {\n await this.cleanupStoredConnectionParams();\n } catch (error) {\n logger.error('Failed to cleanup stored connection params:', error);\n } finally {\n this.transport.reconnect();\n }\n }\n }\n\n async cleanupStoredConnectionParams(): Promise<void> {\n await this.transport.setProtocol(undefined);\n await this.updateAuthorizationStateInStorage(undefined);\n await this.attachManager.detachAll();\n }\n\n protected async updateAuthState(authorization_state: string): Promise<void> {\n try {\n await this.storage.setItem(this.authorizationStateKey, authorization_state);\n } catch (error) {\n logger.error('Failed to update authorization state in storage:', error);\n this._errors$.next(new AuthStateHandlerError(error));\n }\n }\n\n private async authenticate(): Promise<void> {\n logger.debug('[Session] Starting authentication process');\n\n const params: RPCConnectParams = {\n authentication: this.authentication,\n version: this.connectVersion,\n agent: this.agent,\n contexts: this.contexts,\n eventing: this.eventing,\n topics: this.topics,\n\n event_acks: this.eventAcks\n };\n\n const persistedParams = await firstValueFrom(\n combineLatest({\n protocol: this.transport.protocol$,\n\n authorization_state: this.authorizationState$\n }).pipe(take(1))\n );\n\n logger.debug('[Session] Persisted params:\\n', {\n protocol: persistedParams.protocol,\n authStateLength: persistedParams.authorization_state?.length\n });\n\n const rpcConnectRequest = RPCConnect({ ...params, ...persistedParams });\n\n const response = await lastValueFrom(\n from(this.transport.execute(rpcConnectRequest)).pipe(\n throwOnRPCError(),\n map((res) => res.result),\n filter(isRPCConnectResult),\n tap(() => {\n logger.debug('[Session] Response passed filter, processing authentication result');\n }),\n take(1),\n catchError((err) => {\n logger.error('[Session] Authentication RPC failed:', err);\n throw err;\n })\n )\n );\n\n logger.debug('[Session] Processing authentication result:', {\n hasProtocol: !!response.protocol,\n hasAuthorization: !!response.authorization,\n hasIceServers: !!response.ice_servers\n });\n\n if (response.protocol) {\n await this.transport.setProtocol(response.protocol);\n }\n this.authorization$.next(response.authorization);\n this._iceServers$.next(response.ice_servers ?? []);\n this._authenticated$.next(true);\n\n logger.debug('[Session] Authentication completed successfully');\n }\n\n async disconnect(): Promise<void> {\n this.transport.disconnect();\n this._authenticated$.next(false);\n await this.cleanupStoredConnectionParams();\n }\n\n private async createInboundCall(invite: VertoInviteParams & { node_id: string }): Promise<void> {\n const callSession = await this.createCall({\n nodeId: invite.node_id,\n callId: invite.callID,\n initOffer: invite.sdp,\n toName: invite.callee_id_name,\n to: invite.callee_id_number,\n fromName: invite.caller_id_name,\n from: invite.caller_id_number,\n displayDirection: invite.display_direction\n });\n\n await firstValueFrom(callSession.status$);\n\n this._calls$.next({\n [`${callSession.id}`]: callSession,\n ...this._calls$.value\n });\n }\n\n public async createOutboundCall(\n destination: string | Address,\n options: CallOptions = {}\n ): Promise<Call> {\n const destinationURI =\n destination instanceof Address ? destination.defaultChannel : destination;\n try {\n const callSession = await this.createCall({\n to: destinationURI,\n ...options\n });\n\n await firstValueFrom(\n callSession.selfId$.pipe(\n filter((id) => Boolean(id)),\n take(1),\n timeout(this.callCreateTimeout)\n )\n );\n\n this._calls$.next({\n [`${callSession.id}`]: callSession,\n ...this._calls$.value\n });\n\n return callSession;\n } catch (error) {\n logger.error('[Session] Error creating outbound call:', error);\n const callError = new CallCreateError('Call create timeout', error);\n this._errors$.next(callError);\n throw callError;\n }\n }\n\n private async createCall(options: CallOptions = {}): Promise<WebRTCCall> {\n try {\n const addressURI = getAddressSearchURI(options);\n\n // For PSTN numbers (starting with +), skip the directory lookup\n // and create the call directly with the phone number as destination.\n let address: Address | undefined;\n if (!addressURI.startsWith('+')) {\n if (!this._directory) {\n throw new DependencyError('Directory not initialized');\n }\n\n const addressId = await this._directory.findAddressIdByURI(addressURI);\n if (!addressId) {\n throw new DependencyError(`Address name: ${addressURI} not found`);\n }\n\n address = this._directory.get(addressId);\n if (!address) {\n throw new DependencyError(`Address ID: ${addressId} not found`);\n }\n }\n\n const callSession = this.callFactory.createCall(address, {\n ...options\n });\n\n callSession.status$\n .pipe(\n filter((status) => status === 'destroyed'),\n take(1)\n )\n .subscribe(() => {\n const { [`${callSession.id}`]: _, ...remainingCalls } = this._calls$.value;\n this._calls$.next(remainingCalls);\n });\n\n return callSession;\n } catch (error) {\n logger.error('[Session] Error creating call session:', error);\n throw new CallCreateError('Call create error', error);\n }\n }\n\n public destroy(): void {\n for (const call of Object.values(this._calls$.value)) {\n void call.hangup();\n }\n super.destroy();\n }\n}\n\nexport class ClientSessionWrapper implements SessionState {\n constructor(private clientSessionManager: ClientSessionManager) {}\n\n public get authenticated$(): Observable<boolean> {\n return this.clientSessionManager.authenticated$;\n }\n\n public get authenticated(): boolean {\n return this.clientSessionManager.authenticated;\n }\n\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n public get signalingEvent$() {\n return this.clientSessionManager.signalingEvent$;\n }\n\n public get iceServers(): RTCIceServer[] | undefined {\n return this.clientSessionManager.iceServers;\n }\n\n public async execute<T extends JSONRPCResponse = JSONRPCResponse>(\n request: JSONRPCRequest,\n options?: PendingRPCOptions\n ): Promise<T> {\n return this.clientSessionManager.execute(request, options);\n }\n\n public get incomingCalls$(): Observable<Call[]> {\n return this.clientSessionManager.incomingCalls$;\n }\n\n public get incomingCalls(): Call[] {\n return this.clientSessionManager.incomingCalls;\n }\n\n public get calls$(): Observable<Call[]> {\n return this.clientSessionManager.calls$;\n }\n\n public get calls(): Call[] {\n return this.clientSessionManager.calls;\n }\n}\n","export const isString = (obj: unknown): obj is string => typeof obj === 'string';\n","import { map, tap, type Observable } from 'rxjs';\n\nimport { EntityCollection, Fetcher } from '../behaviors/Collection';\nimport { POST_PARAMS } from '../controllers/HTTPRequestController';\nimport { ConversationError } from '../core/errors';\nimport { isConversationMessageMetadata } from '../core/RPCMessages/guards/events.guards';\nimport { filterAs } from '../operators/filterEventAs';\nimport { isString } from '../utils/isString';\nimport { getLogger } from '../utils/logger';\n\nimport type { ClientSessionManager } from './ClientSessionManager';\nimport type { HTTPRequestController } from '../controllers/HTTPRequestController';\nimport type {\n GetConversationMessageResponse,\n GetConversationResponse\n} from '../core/types/conversation.types';\nimport type { ConversationsProvider } from '../interfaces/Conversations';\n\nconst logger = getLogger();\n\nconst toAddressId = (groupId: string): string => {\n const [, toAddressId] = groupId.split('_');\n return toAddressId;\n};\n\nclass ConversationMessagesFetcher extends Fetcher<GetConversationMessageResponse> {\n constructor(\n public readonly groupId: string,\n http: HTTPRequestController\n ) {\n super(`/api/fabric/conversations/${groupId}/messages`, 'page_size=100', http);\n }\n}\n\nclass ConversationsFetcher extends Fetcher<GetConversationResponse> {\n filter = (item: unknown): item is GetConversationResponse =>\n !!(item as GetConversationResponse).from_fabric_address_id;\n mapper = (item: unknown) => ({\n ...(item as GetConversationResponse),\n id: (item as GetConversationResponse).group_id,\n\n address_id: toAddressId((item as GetConversationResponse).group_id)\n });\n constructor(http: HTTPRequestController) {\n super(`/api/fabric/conversations`, 'page_size=100', http);\n }\n}\n\nexport class ConversationMessageCollection extends EntityCollection<GetConversationMessageResponse> {\n constructor(\n groupId: string,\n update$: Observable<Partial<GetConversationMessageResponse>>,\n http: HTTPRequestController,\n onError?: (error: Error) => void\n ) {\n super(new ConversationMessagesFetcher(groupId, http), update$, onError);\n }\n}\n\nexport class ConversationCollection extends EntityCollection<GetConversationResponse> {\n constructor(\n update$: Observable<Partial<GetConversationResponse>>,\n http: HTTPRequestController,\n onError?: (error: Error) => void\n ) {\n super(new ConversationsFetcher(http), update$, onError);\n }\n}\n\nexport class ConversationsManager implements ConversationsProvider {\n private groupIds = new Map<string, string>();\n\n constructor(\n private clientSession: ClientSessionManager,\n private http: HTTPRequestController,\n private getSubscriberAddressId: () => string,\n private readonly onError?: (error: Error) => void\n ) {}\n private async join(addressId: string): Promise<string> {\n const subscriberFromAddressId = this.getSubscriberAddressId();\n\n try {\n const response = await this.http.request({\n ...POST_PARAMS,\n url: `/api/fabric/conversations/join`,\n body: JSON.stringify({\n from_fabric_address_id: subscriberFromAddressId,\n fabric_address_ids: [addressId, subscriberFromAddressId]\n })\n });\n\n if (response.ok && !!response.body) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const data = JSON.parse(response.body);\n /* eslint-disable @typescript-eslint/no-unsafe-member-access */\n\n if (isString(data.group_id)) {\n this.groupIds.set(addressId, data.group_id as string);\n return data.group_id as string;\n }\n /* eslint-enable @typescript-eslint/no-unsafe-member-access */\n }\n throw new ConversationError('Join Failed - Unexpected response');\n } catch (error) {\n logger.error('[ConversationsManager] Failed to join conversation:', error);\n throw error;\n }\n }\n\n public async getConversationMessageCollection(\n addressId: string\n ): Promise<ConversationMessageCollection> {\n const groupId = this.groupIds.get(addressId) ?? (await this.join(addressId));\n\n return Promise.resolve(\n new ConversationMessageCollection(\n groupId,\n this.clientSession.signalingEvent$.pipe(\n filterAs(isConversationMessageMetadata, 'params'),\n tap((event) => logger.debug('[ConversationsManager ] Conversation Event:', event)),\n // FIXME after Conversation API Fixes\n map(\n (params) =>\n ({\n ...params\n }) as Partial<GetConversationMessageResponse>\n )\n ),\n this.http,\n this.onError\n )\n );\n }\n\n public async sendText(text: string, destinationAddressId: string): Promise<void> {\n const groupId =\n this.groupIds.get(destinationAddressId) ?? (await this.join(destinationAddressId));\n const subscriberFromAddressId = this.getSubscriberAddressId();\n\n try {\n const response = await this.http.request({\n ...POST_PARAMS,\n url: '/api/fabric/messages',\n body: JSON.stringify({\n group_id: groupId,\n from_fabric_address_id: subscriberFromAddressId,\n text\n })\n });\n if (response.ok) {\n return;\n }\n throw new ConversationError('Send Text Failed - Unexpected response');\n } catch (error) {\n logger.error('[ConversationsManager] Failed to send text message:', error);\n }\n }\n}\n","export const isEmptyArray = (a?: unknown[]): boolean => {\n return (a?.length ?? 0) === 0;\n};\n","import { take } from 'rxjs';\n\nimport type { Observable } from 'rxjs';\n\nexport const warnup = (observable: Observable<unknown>): void => {\n observable.pipe(take(1)).subscribe();\n};\n","import { firstValueFrom, map, type Observable } from 'rxjs';\n\nimport { EntityCollection, Fetcher } from '../behaviors/Collection';\nimport { Destroyable } from '../behaviors/Destroyable';\nimport { GET_PARAMS } from '../controllers/HTTPRequestController';\nimport { Address } from '../core/entities/Address';\nimport { isConversationMessageUpdatedMetadata } from '../core/RPCMessages/guards/events.guards';\nimport { filterAs, filterNull } from '../operators';\nimport { isEmptyArray } from '../utils/arrays';\nimport { getLogger } from '../utils/logger';\nimport { warnup } from '../utils/warnup';\n\nimport type { ClientSessionManager } from './ClientSessionManager';\nimport type { PaginatedResponse } from '../behaviors/types/collection.types';\nimport type { HTTPRequestController } from '../controllers/HTTPRequestController';\nimport type { Directory } from '../core/entities/Directory';\nimport type { GetAddressResponse } from '../core/types/address.types';\nimport type { ConversationsProvider } from '../interfaces/Conversations';\n\nconst logger = getLogger();\n\nclass AddressFetcher extends Fetcher<GetAddressResponse> {\n constructor(http: HTTPRequestController) {\n super('/api/fabric/addresses', 'sort_by=name&sort_order=asc', http);\n }\n\n async name(name: unknown): Promise<GetAddressResponse | undefined> {\n const response = await this.http.request({\n ...GET_PARAMS,\n url: `${this.endpoint}?name=${encodeURIComponent(name as string)}`\n });\n if (response.ok && !!response.body) {\n const result = JSON.parse(response.body) as PaginatedResponse<GetAddressResponse>;\n if (!isEmptyArray(result.data)) {\n return result.data[0];\n }\n }\n logger.error('Failed to fetch addresses');\n }\n}\n\nexport class AddressStateCollection extends EntityCollection<GetAddressResponse> {\n constructor(\n update$: Observable<Partial<GetAddressResponse>>,\n http: HTTPRequestController,\n onError?: (error: Error) => void\n ) {\n super(new AddressFetcher(http), update$, onError);\n }\n}\n\nexport class DirectoryManager extends Destroyable implements Directory {\n private addNewAddress = (id: string): void => {\n const address = new Address(id, this.conversationManager, this);\n const observable = this._statesCollection.get$(id)?.pipe(\n filterNull(),\n map((data) => {\n address.upnext(data);\n return address;\n })\n );\n if (observable) {\n warnup(observable);\n this._observableRegistry.set(id, observable);\n }\n this._addressesInstances.set(id, address);\n };\n private _addresses$ = this.createBehaviorSubject<Address[]>([]);\n private _statesCollection: AddressStateCollection;\n private _addressesInstances = new Map<string, Address>();\n private _observableRegistry = new Map<string, Observable<Address>>();\n\n constructor(\n private http: HTTPRequestController,\n clientSession: ClientSessionManager,\n private conversationManager: ConversationsProvider,\n private readonly onError?: (error: Error) => void\n ) {\n super();\n this._statesCollection = new AddressStateCollection(\n clientSession.signalingEvent$.pipe(\n filterAs(isConversationMessageUpdatedMetadata, 'params'),\n // FIXME after Conversation API Fixes\n map((_) => ({}) as Partial<GetAddressResponse>)\n ),\n this.http,\n this.onError\n );\n this.initSubscriptions();\n }\n\n public get loading(): boolean {\n return this._statesCollection.loading;\n }\n\n private initSubscriptions(): void {\n this.subscribeTo(this._statesCollection.updated$, () => {\n const existing = Array.from(this._addressesInstances.values().map((address) => address.id));\n const newStates = this._statesCollection.values.filter(\n (state) => !existing.includes(state.id)\n );\n if (!isEmptyArray(newStates)) {\n newStates.forEach((state) => this.addNewAddress(state.id));\n this._addresses$.next(Array.from(this._addressesInstances.values()));\n }\n });\n }\n\n public get addresses$(): Observable<Address[]> {\n return this._addresses$.asObservable();\n }\n\n public get addresses(): Address[] {\n return this._addresses$.value;\n }\n\n public get hasMore$(): Observable<boolean> {\n return this._statesCollection.hasMore$;\n }\n\n public get loading$(): Observable<boolean> {\n return this._statesCollection.loading$;\n }\n\n public loadMore(): void {\n if (this._statesCollection.hasMore) {\n this._statesCollection.loadMore();\n }\n }\n\n public get$(id: string): Observable<Address> | undefined {\n if (!this._observableRegistry.has(id)) {\n this.addNewAddress(id);\n }\n return this._observableRegistry.get(id);\n }\n\n public get(addressId: string): Address | undefined {\n return this._addressesInstances.get(addressId);\n }\n\n public async findAddressIdByURI(name: string): Promise<string | undefined> {\n let addressId = this._addressesInstances.values().find((addr) => addr.name === name)?.id;\n if (!addressId) {\n const found$ = await this._statesCollection.find$('name', name);\n if (found$) {\n const state = await firstValueFrom(found$);\n this.addNewAddress(state.id);\n addressId = state.id;\n }\n }\n return addressId;\n }\n}\n","import { Destroyable } from '../behaviors/Destroyable';\nimport { UnexpectedError, WebSocketConnectionError, WebSocketTimeoutError } from '../core/errors';\nimport { getLogger } from '../utils/logger';\n\nimport type {\n NodeSocketAdapter,\n NodeSocketClient,\n WebSocketAdapter,\n WebSocketClient\n} from '../core/types/common.types';\nimport type { Observable } from 'rxjs';\n\nconst logger = getLogger();\n\nexport type WebSocketConnectionStatus =\n | 'disconnected'\n | 'disconnecting'\n | 'reconnecting'\n | 'connected'\n | 'connecting';\n\nexport interface WebSocketControllerOptions {\n reconnectDelayMin?: number;\n reconnectDelayMax?: number;\n connectionTimeout?: number;\n}\n\nexport class WebSocketController extends Destroyable {\n // Default configuration values\n\n private static readonly DEFAULT_RECONNECT_DELAY_MIN_MS = 1_000;\n\n private static readonly DEFAULT_RECONNECT_DELAY_MAX_MS = 30_000;\n\n private static readonly DEFAULT_CONNECTION_TIMEOUT_MS = 10_000;\n\n // Private state\n private socket?: WebSocketClient | NodeSocketClient;\n private messageQueue: (string | ArrayBuffer | Blob)[] = [];\n private reconnectTimer?: ReturnType<typeof setTimeout>;\n private connectionTimeoutTimer?: ReturnType<typeof setTimeout>;\n private currentReconnectDelay: number;\n private shouldReconnect = false;\n // Configuration\n private readonly reconnectDelayMin: number;\n private readonly reconnectDelayMax: number;\n private readonly connectionTimeout: number;\n // Observable streams\n private _status$ = this.createBehaviorSubject<WebSocketConnectionStatus>('disconnected');\n\n private _incomingMessages$ = this.createSubject<MessageEvent>();\n\n private _errors$ = this.createSubject<Error>();\n\n constructor(\n private WebSocketConstructor: WebSocketAdapter | NodeSocketAdapter,\n private endpoint: string,\n private outgoingMessages$: Observable<string | ArrayBuffer | Blob>,\n options: WebSocketControllerOptions = {}\n ) {\n super();\n this.reconnectDelayMin =\n options.reconnectDelayMin ?? WebSocketController.DEFAULT_RECONNECT_DELAY_MIN_MS;\n this.reconnectDelayMax =\n options.reconnectDelayMax ?? WebSocketController.DEFAULT_RECONNECT_DELAY_MAX_MS;\n this.connectionTimeout =\n options.connectionTimeout ?? WebSocketController.DEFAULT_CONNECTION_TIMEOUT_MS;\n this.currentReconnectDelay = this.reconnectDelayMin;\n\n // Subscribe to send$ to handle message sending\n this.subscriptions.push(\n this.outgoingMessages$.subscribe((data) => {\n this.send(data);\n })\n );\n }\n\n public get status$(): Observable<WebSocketConnectionStatus> {\n return this._status$.asObservable();\n }\n public get incomingMessages$(): Observable<MessageEvent> {\n return this._incomingMessages$.asObservable();\n }\n public get errors$(): Observable<Error> {\n return this._errors$.asObservable();\n }\n public connect(): void {\n if (this._status$.value === 'connecting' || this._status$.value === 'connected') {\n return;\n }\n\n this.shouldReconnect = true;\n this._status$.next('connecting');\n this.createWebSocket();\n }\n\n public disconnect(): void {\n this.shouldReconnect = false;\n this.clearReconnectTimer();\n this.clearConnectionTimeout();\n\n const currentStatus = this._status$.value;\n\n if (\n currentStatus === 'connected' ||\n currentStatus === 'connecting' ||\n currentStatus === 'reconnecting'\n ) {\n if (this.socket) {\n this._status$.next('disconnecting');\n this.socket.close();\n } else {\n this._status$.next('disconnected');\n }\n } else {\n this._status$.next('disconnected');\n }\n }\n\n reconnect(): void {\n if (this.shouldReconnect) {\n this._status$.next('reconnecting');\n this.scheduleReconnection();\n } else {\n this._status$.next('disconnected');\n }\n }\n\n public send(data: string | ArrayBuffer | Blob): void {\n if (\n this._status$.value === 'connected' &&\n this.socket?.readyState === 1 // WebSocket.OPEN\n ) {\n try {\n logger.debug(\n `[WebSocketConnectionManager] Sending message:\\n${JSON.stringify(\n JSON.parse(data as string),\n null,\n 2\n )}`\n );\n } catch {\n logger.warn(\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-base-to-string\n `[WebSocketConnectionManager] Sending non-JSON message:\\n${data}`\n );\n }\n this.socket.send(data);\n } else {\n this.messageQueue.push(data);\n }\n }\n\n private createWebSocket(): void {\n try {\n this.socket = new this.WebSocketConstructor(this.endpoint);\n this.setupWebSocketListeners();\n this.startConnectionTimeout();\n } catch (error) {\n const err =\n error instanceof Error ? error : new UnexpectedError('Failed to create WebSocket');\n this._errors$.next(err);\n this.handleConnectionError();\n }\n }\n\n private setupWebSocketListeners(): void {\n if (!this.socket) return;\n\n this.socket.addEventListener('open', () => this.handleOpen());\n // @ts-expect-error -- Ignore ---\n this.socket.addEventListener('close', (event: CloseEvent) => this.handleClose(event));\n this.socket.addEventListener('error', () => this.handleError());\n // @ts-expect-error -- Ignore ---\n this.socket.addEventListener('message', (event: MessageEvent) => this.handleMessage(event));\n }\n\n private handleOpen(): void {\n this.clearConnectionTimeout();\n this._status$.next('connected');\n this.currentReconnectDelay = this.reconnectDelayMin;\n this.flushMessageQueue();\n }\n\n private handleClose(_event: CloseEvent): void {\n this.clearConnectionTimeout();\n\n if (this.shouldReconnect) {\n this._status$.next('reconnecting');\n this.scheduleReconnection();\n } else {\n this._status$.next('disconnected');\n }\n }\n\n private handleError(): void {\n const error = new WebSocketConnectionError('WebSocket connection error');\n this._errors$.next(error);\n this.handleConnectionError();\n }\n\n private handleMessage(event: MessageEvent): void {\n try {\n logger.debug(\n `[WebSocketConnectionManager] Received message:\\n${JSON.stringify(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n JSON.parse(event.data),\n null,\n 2\n )}`\n );\n } catch {\n logger.warn(`[WebSocketConnectionManager] Received non-JSON message:\\n${event.data}`);\n }\n this._incomingMessages$.next(event);\n }\n\n private handleConnectionError(): void {\n this.reconnect();\n }\n\n private scheduleReconnection(): void {\n this.clearReconnectTimer();\n\n this.reconnectTimer = setTimeout(() => {\n if (this.shouldReconnect) {\n this._status$.next('connecting');\n this.createWebSocket();\n this.increaseReconnectDelay();\n }\n }, this.currentReconnectDelay);\n }\n\n private increaseReconnectDelay(): void {\n this.currentReconnectDelay = Math.min(this.currentReconnectDelay * 2, this.reconnectDelayMax);\n }\n\n private startConnectionTimeout(): void {\n this.clearConnectionTimeout();\n\n this.connectionTimeoutTimer = setTimeout(() => {\n if (this._status$.value === 'connecting') {\n const error = new WebSocketTimeoutError('WebSocket connection timeout');\n this._errors$.next(error);\n\n if (this.socket) {\n this.socket.close();\n }\n }\n }, this.connectionTimeout);\n }\n\n private clearConnectionTimeout(): void {\n if (this.connectionTimeoutTimer) {\n clearTimeout(this.connectionTimeoutTimer);\n this.connectionTimeoutTimer = undefined;\n }\n }\n\n private clearReconnectTimer(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n }\n\n private flushMessageQueue(): void {\n while (this.messageQueue.length > 0 && this.socket?.readyState === 1) {\n const message = this.messageQueue.shift();\n if (message !== undefined) {\n this.socket.send(message);\n }\n }\n }\n}\n","// =============================================================================\n// CLIENT/SERVER METHOD TYPE GUARDS\n// =============================================================================\n// This file contains type guards for client requests, server responses,\n// and method params/results.\n\nimport { hasProperty, isJSONRPCRequest, isJSONRPCResponse, isObject } from './base.guards';\n\nimport type { JSONRPCRequest, TypeGuard } from '../types/base';\nimport type { SignalwirePingParams, SignalwirePingRequest } from '../types/events';\nimport type {\n CallLayoutListRequest,\n CallLayoutListResponse,\n CallMuteParams,\n CallMuteRequest,\n CallMuteResponse,\n CallTargetParams,\n EmptyResponse,\n SignalwireConnectParams,\n SignalwireConnectRequest,\n SignalwireConnectResponse,\n SignalwirePingResponse,\n WebrtcVertoParams,\n WebrtcVertoRequest,\n WebrtcVertoResponse\n} from '../types/methods';\n\n// =============================================================================\n// CLIENT REQUEST TYPE GUARDS\n// =============================================================================\n\nexport function isSignalwireConnectRequest(value: unknown): value is SignalwireConnectRequest {\n return isJSONRPCRequest(value) && value.method === 'signalwire.connect';\n}\n\nexport function isSignalwirePingRequest(value: unknown): value is SignalwirePingRequest {\n return isJSONRPCRequest(value) && value.method === 'signalwire.ping';\n}\n\nexport function isWebrtcVertoRequest(value: unknown): value is WebrtcVertoRequest {\n return isJSONRPCRequest(value) && value.method === 'webrtc.verto';\n}\n\nexport function isCallLayoutListRequest(value: unknown): value is CallLayoutListRequest {\n return isJSONRPCRequest(value) && value.method === 'call.layout.list';\n}\n\nexport function isCallMuteRequest(value: unknown): value is CallMuteRequest {\n return isJSONRPCRequest(value) && value.method === 'call.mute';\n}\n\n// =============================================================================\n// RESPONSE TYPE GUARDS\n// =============================================================================\n\nexport function isSignalwireConnectResponse(value: unknown): value is SignalwireConnectResponse {\n return (\n isJSONRPCResponse(value) &&\n isObject(value.result) &&\n hasProperty(value.result, 'identity') &&\n hasProperty(value.result, 'authorization') &&\n hasProperty(value.result, 'protocol')\n );\n}\n\nexport function isSignalwirePingResponse(value: unknown): value is SignalwirePingResponse {\n return (\n isJSONRPCResponse(value) && isObject(value.result) && hasProperty(value.result, 'timestamp')\n );\n}\n\nexport function isWebrtcVertoResponse(value: unknown): value is WebrtcVertoResponse {\n return (\n isJSONRPCResponse(value) &&\n isObject(value.result) &&\n hasProperty(value.result, 'node_id') &&\n hasProperty(value.result, 'code')\n );\n}\n\nexport function isCallLayoutListResponse(value: unknown): value is CallLayoutListResponse {\n return (\n isJSONRPCResponse(value) &&\n isObject(value.result) &&\n hasProperty(value.result, 'layouts') &&\n Array.isArray(value.result.layouts)\n );\n}\n\nexport function isCallMuteResponse(value: unknown): value is CallMuteResponse {\n return (\n isJSONRPCResponse(value) &&\n isObject(value.result) &&\n hasProperty(value.result, 'code') &&\n hasProperty(value.result, 'message') &&\n !hasProperty(value.result, 'layouts') &&\n !hasProperty(value.result, 'node_id')\n );\n}\n\nexport function isEmptyResponse(value: unknown): value is EmptyResponse {\n return (\n isJSONRPCResponse(value) && isObject(value.result) && Object.keys(value.result).length === 0\n );\n}\n\n// =============================================================================\n// PARAMS TYPE GUARDS\n// =============================================================================\n\nexport function isSignalwireConnectParams(value: unknown): value is SignalwireConnectParams {\n return (\n isObject(value) &&\n hasProperty(value, 'version') &&\n hasProperty(value, 'event_acks') &&\n hasProperty(value, 'agent') &&\n hasProperty(value, 'authentication')\n );\n}\n\nexport function isSignalwirePingParams(value: unknown): value is SignalwirePingParams {\n return isObject(value) && hasProperty(value, 'timestamp') && typeof value.timestamp === 'number';\n}\n\nexport function isWebrtcVertoParams(value: unknown): value is WebrtcVertoParams {\n return (\n isObject(value) &&\n hasProperty(value, 'message') &&\n hasProperty(value, 'callID') &&\n hasProperty(value, 'node_id')\n );\n}\n\nexport function isCallTargetParams(value: unknown): value is CallTargetParams {\n return isObject(value) && hasProperty(value, 'self') && hasProperty(value, 'target');\n}\n\nexport function isCallMuteParams(value: unknown): value is CallMuteParams {\n if (!isCallTargetParams(value)) return false;\n return 'channels' in value;\n}\n\n// =============================================================================\n// METHOD TYPE MAPPING\n// =============================================================================\n\nexport const MethodTypeMap = {\n 'signalwire.connect': isSignalwireConnectRequest,\n 'signalwire.ping': isSignalwirePingRequest,\n 'webrtc.verto': isWebrtcVertoRequest,\n 'call.layout.list': isCallLayoutListRequest,\n 'call.mute': isCallMuteRequest\n} as const;\n\nexport type MethodType = keyof typeof MethodTypeMap;\n\n/**\n * Gets the appropriate type guard for a method.\n */\nexport function getMethodGuard(method: string): TypeGuard<JSONRPCRequest> | undefined {\n return MethodTypeMap[method as MethodType];\n}\n","import {\n EMPTY,\n catchError,\n defer,\n filter,\n from,\n map,\n share,\n shareReplay,\n take,\n takeUntil,\n tap,\n timeout\n} from 'rxjs';\n\nimport { PreferencesContainer } from '../containers/PreferencesContainer';\nimport { WebSocketController } from '../controllers/WebSocketController';\nimport { MessageParseError, TransportConnectionError } from '../core/errors';\nimport { RPCEventAckResponse, RPCPingResponse } from '../core/RPCMessages';\nimport { isJSONRPCRequest, isJSONRPCResponse } from '../core/RPCMessages/guards/base.guards';\nimport { isSignalwireRequest } from '../core/RPCMessages/guards/events.guards';\nimport { isSignalwirePingRequest } from '../core/RPCMessages/guards/methods.guards';\nimport { Destroyable, PendingRPC } from '../core/utils';\nimport { getLogger } from '../utils/logger';\n\nimport type { StorageManager } from './StorageManager';\nimport type { JSONRPCRequest, JSONRPCResponse } from '../core/RPCMessages/types/base';\nimport type {\n JSONSerializable,\n WebSocketAdapter,\n NodeSocketAdapter\n} from '../core/types/common.types';\nimport type { PendingRPCOptions } from '../core/utils';\nimport type { Observable, OperatorFunction } from 'rxjs';\n\nconst logger = getLogger();\n\nexport class TransportManager extends Destroyable {\n private initialized$: Observable<boolean>;\n public protocol$ = this.createReplaySubject<string | undefined>(1);\n // Connection state tracking\n private isConnecting = false;\n private isConnected = false;\n private ackEvent = <T extends JSONRPCRequest | JSONRPCResponse>(): OperatorFunction<T, T> => {\n return tap((message) => {\n if (isSignalwireRequest(message)) {\n try {\n logger.debug('[Transport] Sending event ack', {\n eventId: message.id\n });\n this.send(RPCEventAckResponse(message.id));\n } catch (error) {\n logger.error('[Transport] Failed to send event acknowledgment:', error);\n }\n }\n });\n };\n private replySignalwirePing = <T extends JSONRPCRequest | JSONRPCResponse>(): OperatorFunction<\n T,\n T\n > => {\n return filter((message) => {\n if (isSignalwirePingRequest(message)) {\n try {\n logger.debug('[Transport] Received ping, sending pong', {\n pingId: message.id\n });\n this.send(RPCPingResponse(message.id));\n } catch (error) {\n logger.error('[Transport] Failed to send ping response:', error);\n }\n return false;\n }\n return true;\n });\n };\n private _outgoingMessages$ = this.createSubject<string | ArrayBuffer | Blob>();\n\n private _webSocketConnections!: WebSocketController;\n private _jsonRPCMessage$!: Observable<JSONRPCResponse | JSONRPCRequest>;\n private _jsonRPCResponse$!: Observable<JSONRPCResponse>;\n private _incomingEvent$!: Observable<JSONRPCRequest | JSONRPCResponse>;\n\n constructor(\n private readonly storage: StorageManager,\n private readonly protocolKey: string,\n webSocketConstructor: WebSocketAdapter | NodeSocketAdapter,\n relayHost: string,\n private readonly onError?: (error: Error) => void\n ) {\n super();\n this._webSocketConnections = new WebSocketController(\n webSocketConstructor,\n relayHost,\n this._outgoingMessages$.asObservable(),\n {\n connectionTimeout: PreferencesContainer.instance.connectionTimeout,\n reconnectDelayMin: PreferencesContainer.instance.reconnectDelayMin,\n reconnectDelayMax: PreferencesContainer.instance.reconnectDelayMax\n }\n );\n this.subscribeTo(this._webSocketConnections.errors$, (error) => {\n this.onError?.(error);\n });\n this.initialized$ = defer(() => from(this._init())).pipe(\n shareReplay(1),\n takeUntil(this.destroyed$)\n );\n\n this._jsonRPCMessage$ = this._webSocketConnections.incomingMessages$.pipe(\n map((event: MessageEvent) => {\n try {\n return JSON.parse(event.data as string) as object;\n } catch (error) {\n logger.error('[Transport] Failed to parse incoming message:', error);\n this.onError?.(new MessageParseError(error));\n return null;\n }\n }),\n filter(\n (message): message is JSONRPCResponse | JSONRPCRequest =>\n message !== null && (isJSONRPCResponse(message) || isJSONRPCRequest(message))\n ),\n catchError((error) => {\n logger.error('[Transport] Message processing error:', error);\n this.onError?.(error instanceof Error ? error : new Error(String(error), { cause: error }));\n return EMPTY;\n }),\n share(),\n takeUntil(this.destroyed$)\n );\n\n this._jsonRPCResponse$ = this._jsonRPCMessage$.pipe(filter(isJSONRPCResponse));\n\n this._incomingEvent$ = this._jsonRPCMessage$.pipe(\n this.ackEvent(),\n this.replySignalwirePing(),\n filter((message) => !isJSONRPCResponse(message)),\n share(),\n takeUntil(this.destroyed$)\n );\n }\n\n public async setProtocol(protocol: string | undefined): Promise<void> {\n this.protocol$.next(protocol);\n await this._updateProtocolInStorage(protocol);\n }\n public get incomingEvent$(): Observable<JSONRPCRequest | JSONRPCResponse> {\n return this._incomingEvent$;\n }\n\n public get connectionStatus$(): Observable<string> {\n return this._webSocketConnections.status$;\n }\n\n public async connect(): Promise<void> {\n // Prevent duplicate connections\n if (this.isConnecting || this.isConnected) {\n logger.warn('[Transport] Already connecting or connected');\n return Promise.resolve();\n }\n\n return new Promise<void>((resolve, reject) => {\n this.isConnecting = true;\n\n this.subscribeTo(this.initialized$, () => {\n this._webSocketConnections.connect();\n\n // Wait for actual connection\n const connectionSub = this._webSocketConnections.status$\n .pipe(\n filter((status) => status === 'connected' || status === 'disconnected'),\n take(1),\n timeout(10000) // 10 second timeout\n )\n .subscribe({\n next: (status) => {\n if (status === 'connected') {\n this.isConnecting = false;\n this.isConnected = true;\n logger.debug('[Transport] Connection established');\n resolve();\n } else {\n this.isConnecting = false;\n const error = new TransportConnectionError('Failed to connect');\n logger.error('[Transport] Connection failed');\n this.onError?.(error);\n reject(error);\n }\n },\n error: (err) => {\n this.isConnecting = false;\n logger.error('[Transport] Connection error:', err);\n this.onError?.(err instanceof Error ? err : new Error(String(err), { cause: err }));\n reject(err as Error);\n }\n });\n\n this.subscriptions.push(connectionSub);\n\n // Track disconnection\n this.subscribeTo(\n this._webSocketConnections.status$.pipe(filter((status) => status === 'disconnected')),\n () => {\n logger.debug('[Transport] Disconnected');\n this.isConnected = false;\n }\n );\n });\n });\n }\n\n public reconnect(): void {\n this._webSocketConnections.reconnect();\n }\n\n public async execute<T extends JSONRPCResponse = JSONRPCResponse>(\n request: JSONRPCRequest,\n options?: PendingRPCOptions\n ): Promise<T> {\n // Send the request through the WebSocket\n this.send(request as unknown as JSONSerializable);\n\n // Create and return a PendingRPC promise that will resolve when the matching response arrives\n return new PendingRPC<T>(request, this._jsonRPCResponse$ as Observable<T>, options).promise;\n }\n public send(message: unknown): void {\n const payload = JSON.stringify(message);\n this._outgoingMessages$.next(payload);\n }\n // request(request: HTTPRequest): Promise<HTTPResponse> {}\n public disconnect(): void {\n logger.debug('[Transport] Disconnecting');\n this.isConnected = false;\n this.isConnecting = false;\n\n // Disconnect WebSocket\n this._webSocketConnections.disconnect();\n }\n public destroy(): void {\n logger.debug('[Transport] Destroying');\n this.disconnect();\n super.destroy();\n this._webSocketConnections.destroy();\n }\n private async _loadProtocolFromStorage(): Promise<void> {\n try {\n const storedProtocol = await this.storage.getItem<string>(this.protocolKey);\n this.protocol$.next(storedProtocol ?? undefined);\n } catch (error) {\n logger.error('Failed to retrieve protocol from storage:', error);\n throw error;\n }\n }\n\n private async _updateProtocolInStorage(protocol: string | undefined): Promise<void> {\n if (!protocol) {\n try {\n await this.storage.removeItem(this.protocolKey);\n } catch (error) {\n logger.error('Failed to remove protocol from storage:', error);\n throw error;\n }\n return;\n }\n\n try {\n const storedProtocol = await this.storage.getItem<string>(this.protocolKey);\n if (!storedProtocol || storedProtocol !== protocol) {\n await this.storage.setItem(this.protocolKey, protocol);\n }\n } catch (error) {\n logger.error('Failed to update protocol in storage:', error);\n throw error;\n }\n }\n\n private async _init(): Promise<boolean> {\n await this._loadProtocolFromStorage();\n return true;\n }\n}\n","import { jwtDecode } from 'jwt-decode';\nimport { filter, firstValueFrom, of, switchMap, type Observable } from 'rxjs';\n\nimport { Destroyable } from '../behaviors/Destroyable';\nimport { DependencyContainer } from '../containers/DependencyContainer';\nimport { ClientPreferences, PreferencesContainer } from '../containers/PreferencesContainer';\nimport { Subscriber } from '../core/entities/Subscriber';\nimport { InvalidCredentialsError, UnexpectedError } from '../core/errors';\nimport { RPCExecute } from '../core/RPCMessages';\nimport { AttachManager } from '../managers/AttachManager';\nimport { ClientSessionManager, ClientSessionWrapper } from '../managers/ClientSessionManager';\nimport { ConversationsManager } from '../managers/ConversationsManager';\nimport { DirectoryManager } from '../managers/DirectoryManager';\nimport { TransportManager } from '../managers/TransportManager';\nimport { getLogger } from '../utils/logger';\n\nimport type { Address } from '../core/entities/Address';\nimport type { Directory } from '../core/entities/Directory';\nimport type { Call } from '../core/entities/types/call.types';\nimport type {\n NodeSocketAdapter,\n SDKCredential,\n WebSocketAdapter\n} from '../core/types/common.types';\nimport type { MediaOptions } from '../core/types/media.types';\nimport type { CredentialProvider, Storage, WebRTCApiProvider } from '../dependencies/interfaces';\nimport type { DeviceController } from '../interfaces/DeviceController';\n\nconst logger = getLogger();\n\ninterface JWTHeader {\n ch?: string;\n typ?: string;\n}\n/** Options for constructing a {@link SignalWire}. */\nexport interface SignalWireOptions {\n /** Skip automatic WebSocket connection on construction. */\n skipConnection?: boolean;\n /** Skip automatic subscriber registration on construction. */\n skipRegister?: boolean;\n /** Skip monitoring media device changes. */\n skipDeviceMonitoring?: boolean;\n /** Whether to reconnect to previously attached calls. */\n reconnectAttachedCalls?: boolean;\n /** Whether to save preferences. */\n savePreferences?: boolean;\n /** Custom storage implementation for persistence. */\n storageImplementation?: Storage;\n /** Custom WebSocket constructor */\n webSocketConstructor?: WebSocketAdapter | NodeSocketAdapter;\n /** Custom WebRTC API provider */\n webRTCApiProvider?: WebRTCApiProvider;\n}\n\n/** Options for {@link SignalWire.dial}. Extends {@link MediaOptions} with dial-specific settings. */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface DialOptions extends MediaOptions {\n // Define any options for dialing here\n}\n\nconst buildOptionsFromDestination = (destination: string | Address): DialOptions => {\n if (typeof destination === 'string') {\n const queryStartIndex = destination.indexOf('?');\n if (queryStartIndex !== -1) {\n const queryString = destination.substring(queryStartIndex + 1);\n const params = new URLSearchParams(queryString);\n const channel = params.get('channel');\n\n if (channel === 'video') {\n return { audio: true, video: true };\n } else if (channel === 'audio') {\n return { audio: true, video: false };\n }\n }\n }\n\n return {};\n};\n/**\n * Main entry point for the SignalWire Browser SDK.\n *\n * Manages authentication, WebSocket transport, call creation, and media devices.\n *\n * @example\n * ```ts\n * const client = new SignalWire(credentialProvider);\n * client.isConnected$.subscribe(connected => console.log('Connected:', connected));\n * const call = await client.dial('/public/my-room');\n * ```\n */\nclass SignalWire extends Destroyable implements DeviceController {\n /** Global SDK preferences (timeouts, ICE config, media defaults). */\n public preferences = new ClientPreferences();\n private _subscriber$ = this.createBehaviorSubject<Subscriber | undefined>(undefined);\n private _directory$ = this.createBehaviorSubject<Directory | undefined>(undefined);\n private _transport!: TransportManager;\n private _clientSession!: ClientSessionManager;\n private _publicSession!: ClientSessionWrapper;\n private _deviceController!: DeviceController;\n private _attachManager?: AttachManager;\n private _isConnected$ = this.createBehaviorSubject<boolean>(false);\n private _isRegistered$ = this.createBehaviorSubject<boolean>(false);\n private _errors$ = this.createSubject<Error>();\n private _options: SignalWireOptions = {};\n private _refreshTimerId?: ReturnType<typeof setTimeout>;\n private _deps = new DependencyContainer();\n\n constructor(credentialProvider: CredentialProvider, options: SignalWireOptions = {}) {\n super();\n this._options = {\n ...PreferencesContainer.instance.defaultSignalWireOptions,\n ...options\n };\n\n // Set custom storage implementation if provided\n if (this._options.storageImplementation) {\n this._deps.storageImpl = this._options.storageImplementation;\n }\n\n if (this._options.webSocketConstructor) {\n this._deps.WebSocket = this._options.webSocketConstructor;\n }\n\n if (this._options.savePreferences) {\n this.preferences.enableSavePreferences(this._deps.storage);\n }\n\n if (this._options.webRTCApiProvider) {\n this._deps.webRTCApiProvider = this._options.webRTCApiProvider;\n }\n\n this._deviceController = this._deps.deviceController;\n if (!this._options.skipDeviceMonitoring) {\n this._deviceController.enableDeviceMonitoring();\n }\n\n this.subscribeTo(this._deviceController.errors$, (error) => {\n this._errors$.next(error);\n });\n\n this.validateCredentials(credentialProvider)\n .then(() => {\n this.init().catch((error: unknown) => {\n logger.error('[SignalWire] Initialization error:', error);\n this._errors$.next(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n });\n })\n .catch((error: unknown) => {\n logger.error('[SignalWire] Initialization error:', error);\n this._errors$.next(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n });\n }\n\n private async validateCredentials(\n credentialProvider: CredentialProvider,\n credentials?: SDKCredential\n ): Promise<void> {\n const _credentials = credentials ?? (await credentialProvider.authenticate());\n if (_credentials.token) {\n try {\n const decodeHeader: JWTHeader = jwtDecode(_credentials.token, { header: true });\n this._deps.ch = decodeHeader.ch;\n } catch (error) {\n logger.error('[SignalWire] Invalid JWT token provided in credentials:', error);\n throw new InvalidCredentialsError('Invalid JWT token provided in credentials.', {\n cause: error\n });\n }\n }\n if (!_credentials.token && !_credentials.authorizationState) {\n logger.error('[SignalWire] No valid authentication credentials provided.');\n throw new InvalidCredentialsError('No valid authentication credentials provided.');\n }\n\n if (_credentials.expiry_at && _credentials.expiry_at < Date.now()) {\n logger.error('[SignalWire] Provided credentials have expired.');\n throw new InvalidCredentialsError('Provided credentials have expired.');\n }\n\n if (_credentials.expiry_at && credentialProvider.refresh) {\n const refreshFn = credentialProvider.refresh;\n const refreshInterval = Math.max(_credentials.expiry_at - Date.now() - 5000, 1000);\n this._refreshTimerId = setTimeout(async () => {\n try {\n const newCredentials = await refreshFn();\n this._deps.credential = newCredentials;\n logger.info('[SignalWire] Credentials refreshed successfully.');\n // Schedule next refresh\n this.validateCredentials(credentialProvider, newCredentials).catch((error: unknown) => {\n logger.error('[SignalWire] Credential refresh error:', error);\n this._errors$.next(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n });\n } catch (error: unknown) {\n logger.error('[SignalWire] Credential refresh failed:', error);\n this._errors$.next(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n }\n }, refreshInterval);\n }\n\n this._deps.credential = _credentials;\n }\n\n private async init() {\n // Initialize subscriber first (before transport) to fetch subscriber info\n this._subscriber$.next(new Subscriber(this._deps.http));\n\n if (!this._options.skipConnection) {\n await this.connect();\n }\n\n // Flush attached calls after connect creates the AttachManager\n if (!this._options.reconnectAttachedCalls && this._attachManager) {\n await this._attachManager.flush();\n }\n\n if (!this._options.skipRegister) {\n // eventually register after the authentication\n void this.register();\n }\n\n // eventually reconnect to attached calls after the authentication\n void this.handleAttachments();\n }\n\n private async handleAttachments() {\n if (!this._attachManager) {\n logger.error('[SignalWire] AttachManager not initialized');\n return;\n }\n if (!this._options.reconnectAttachedCalls) {\n return;\n }\n try {\n await this._attachManager.reattachCalls();\n } catch (error) {\n logger.error('[SignalWire] Failed to reattach calls:', error);\n this._errors$.next(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n }\n }\n\n /**\n * Establishes the WebSocket connection and authenticates the session.\n *\n * ## Reconnection behavior\n *\n * After a successful connection the underlying {@link WebSocketController}\n * automatically attempts to reconnect whenever the socket closes\n * unexpectedly (e.g. network change, server restart). Reconnection uses an\n * **exponential back-off** strategy:\n *\n * - First retry after `reconnectDelayMin` (default **1 s**).\n * - Each subsequent retry doubles the delay up to `reconnectDelayMax`\n * (default **30 s**).\n * - The delay resets to `reconnectDelayMin` once a connection succeeds.\n * - A per-attempt `connectionTimeout` (default **10 s**) aborts the\n * attempt and schedules the next retry if the server does not respond.\n *\n * Calling {@link disconnect} stops the reconnection loop entirely.\n *\n * ## Message handling during temporary disconnections\n *\n * While the socket is not in the `connected` state, **outgoing messages\n * are queued** in an internal buffer. Once the connection is\n * re-established the queue is flushed in order so no outgoing RPC call is\n * lost.\n *\n * **Incoming** server-to-client messages that arrive while the socket is\n * down are *not* buffered by the SDK — they are expected to be\n * re-delivered by the server after the session is re-authenticated.\n * Active RPC calls that were awaiting a response will time out\n * (default **5 s**) and reject with an `RPCTimeoutError`; callers should\n * handle this and retry if appropriate.\n *\n * The connection status can be observed via the `status$` observable on\n * the transport layer, which emits `'connecting'`, `'connected'`,\n * `'reconnecting'`, `'disconnecting'`, or `'disconnected'`.\n */\n public async connect(): Promise<void> {\n // Wait for subscriber to be fetched first to get the subscriber ID\n try {\n const subscriber = this._subscriber$.value;\n if (!subscriber) {\n throw new UnexpectedError('Subscriber not initialized before connect');\n }\n\n const fetched = await firstValueFrom(subscriber.fetched$);\n\n if (!fetched) {\n throw new UnexpectedError(\n 'Failed to fetch subscriber information - fetched$ emitted false'\n );\n }\n\n // Set the subscriber ID in the dependency container\n this._deps.subscriber = subscriber;\n } catch (error) {\n logger.error(\n `[SignalWire] Failed to fetch subscriber information: ${error instanceof Error ? error.message : 'Unknown error'}. ` +\n `This usually means the subscriber token is invalid or expired.`\n );\n throw new UnexpectedError('Error fetching subscriber information', { cause: error });\n }\n\n const errorHandler = (error: Error) => {\n this._errors$.next(error);\n };\n\n // Now initialize transport and session with subscriber ID available\n this._transport = new TransportManager(\n this._deps.storage,\n this._deps.protocolKey,\n this._deps.WebSocket,\n PreferencesContainer.instance.relayHost ?? this._deps.relayHost,\n errorHandler\n );\n\n // Create AttachManager (needed by CallFactory -> VertoManager)\n this._attachManager = new AttachManager(\n this._deps.storage,\n this._deps.deviceController,\n PreferencesContainer.instance.reconnectCallsTimeout,\n this._deps.attachedCallsKey\n );\n\n this._clientSession = new ClientSessionManager(\n this._deps.credential,\n this._transport,\n this._deps.storage,\n this._deps.authorizationStateKey,\n this._deps.deviceController,\n this._attachManager,\n this._deps.webRTCApiProvider\n );\n this._publicSession = new ClientSessionWrapper(this._clientSession);\n\n this.subscribeTo(this._clientSession.errors$, (error) => {\n this._errors$.next(error);\n });\n\n await this._clientSession.connect();\n\n // Create conversationManager first to inject into DirectoryManager\n const conversationManager = new ConversationsManager(\n this._clientSession,\n this._deps.http,\n () => this._deps.getSubscriberFromAddressId(),\n errorHandler\n );\n\n // Create directory with all dependencies injected\n const directory = new DirectoryManager(\n this._deps.http,\n this._clientSession,\n conversationManager,\n errorHandler\n );\n this._directory$.next(directory);\n this._clientSession.setDirectory(directory);\n\n this._isConnected$.next(true);\n }\n\n /**\n * Observable that emits the {@link Subscriber} profile once fetched,\n * or `undefined` before authentication completes.\n *\n * @example\n * ```ts\n * client.subscriber$.subscribe(sub => {\n * if (sub) console.log('Logged in as', sub.email);\n * });\n * ```\n */\n public get subscriber$(): Observable<Subscriber | undefined> {\n return this._subscriber$.asObservable();\n }\n\n /** Current subscriber snapshot, or `undefined` if not yet authenticated. */\n public get subscriber(): Subscriber | undefined {\n return this._subscriber$.value;\n }\n\n /**\n * Observable that emits the {@link Directory} instance once the client is connected,\n * or `undefined` while disconnected. Subscribe to this to safely wait for the directory\n * to become available without risking an error.\n *\n * @example\n * ```ts\n * client.directory$.subscribe(dir => {\n * if (dir) dir.addresses$.subscribe(console.log);\n * });\n * ```\n */\n public get directory$(): Observable<Directory | undefined> {\n return this._directory$.asObservable();\n }\n\n /**\n * Current directory snapshot, or `undefined` if the client is not yet connected.\n * Prefer {@link directory$} when you need to react to the directory becoming available.\n */\n public get directory(): Directory | undefined {\n return this._directory$.value;\n }\n\n /** Observable that emits when the subscriber registration state changes. */\n public get isRegistered$(): Observable<boolean> {\n return this._isRegistered$.asObservable();\n }\n\n /** Whether the subscriber is currently registered. */\n public get isRegistered(): boolean {\n return this._isRegistered$.value;\n }\n\n /** Whether the client is currently connected. */\n public get isConnected(): boolean {\n return this._isConnected$.value;\n }\n\n /** Observable that emits when the connection state changes. */\n public get isConnected$(): Observable<boolean> {\n return this._isConnected$.asObservable();\n }\n\n /** Observable that emits `true` when the client is both connected and authenticated. */\n public get ready$(): Observable<boolean> {\n return this.cachedObservable('ready$', () =>\n this._isConnected$.pipe(\n switchMap((connected) => (connected ? this._clientSession.authenticated$ : of(false)))\n )\n );\n }\n\n /** Observable stream of errors from transport, authentication, and devices. */\n public get errors$(): Observable<Error> {\n return this._errors$.asObservable();\n }\n\n /** Disconnects the WebSocket and tears down the session. */\n public async disconnect(): Promise<void> {\n await this._clientSession.disconnect();\n this._clientSession.destroy();\n this._isConnected$.next(false);\n }\n\n private async waitAuthentication(): Promise<void> {\n // Wait for client to be ready (authenticated)\n await firstValueFrom(this.ready$.pipe(filter((ready) => ready === true)));\n }\n\n /** Registers the subscriber as online to receive inbound calls and events. */\n public async register(): Promise<void> {\n try {\n // Wait for client session to be authenticated before registering subscriber\n await this.waitAuthentication();\n await this._transport.execute(RPCExecute({ method: 'subscriber.online', params: {} }));\n this._isRegistered$.next(true);\n } catch (error) {\n logger.error('[SignalWire] Failed to register subscriber:', error);\n this._errors$.next(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n }\n }\n\n /** Unregisters the subscriber, going offline for inbound calls. */\n public async unregister(): Promise<void> {\n try {\n await this._transport.execute(RPCExecute({ method: 'subscriber.offline', params: {} }));\n this._isRegistered$.next(false);\n } catch (error) {\n logger.error('[SignalWire] Failed to unregister subscriber:', error);\n this._errors$.next(\n error instanceof Error ? error : new Error(String(error), { cause: error })\n );\n throw error;\n }\n }\n\n /**\n * Places an outbound call to the given destination.\n * @param destination - Address URI string or {@link Address} instance to call.\n * @param options - Media and dial options (audio/video, constraints).\n * @returns The created {@link Call} instance.\n */\n public async dial(destination: string | Address, options: DialOptions = {}): Promise<Call> {\n const computed_options = {\n ...PreferencesContainer.instance.preferredMediaOptions,\n ...buildOptionsFromDestination(destination),\n ...options\n };\n\n // Wait for client to be ready\n await this.waitAuthentication();\n\n logger.debug('[SignalWire] Dialing with options:', computed_options);\n return this._clientSession.createOutboundCall(destination, computed_options);\n }\n\n /** The underlying client session for advanced RPC operations. */\n public get session(): ClientSessionWrapper {\n return this._publicSession;\n }\n\n // DeviceController interface implementation\n\n /** Observable list of available audio input (microphone) devices. */\n public get audioInputDevices$(): Observable<MediaDeviceInfo[]> {\n return this._deviceController.audioInputDevices$;\n }\n\n /** Current snapshot of available audio input devices. */\n public get audioInputDevices(): MediaDeviceInfo[] {\n return this._deviceController.audioInputDevices;\n }\n\n /** Observable list of available audio output (speaker) devices. */\n public get audioOutputDevices$(): Observable<MediaDeviceInfo[]> {\n return this._deviceController.audioOutputDevices$;\n }\n\n /** Current snapshot of available audio output devices. */\n public get audioOutputDevices(): MediaDeviceInfo[] {\n return this._deviceController.audioOutputDevices;\n }\n\n /** Observable list of available video input (camera) devices. */\n public get videoInputDevices$(): Observable<MediaDeviceInfo[]> {\n return this._deviceController.videoInputDevices$;\n }\n\n /** Current snapshot of available video input devices. */\n public get videoInputDevices(): MediaDeviceInfo[] {\n return this._deviceController.videoInputDevices;\n }\n\n /** Observable of the currently selected audio input device. */\n public get selectedAudioInputDevice$(): Observable<MediaDeviceInfo | null> {\n return this._deviceController.selectedAudioInputDevice$;\n }\n /** Observable of the currently selected audio output device. */\n public get selectedAudioOutputDevice$(): Observable<MediaDeviceInfo | null> {\n return this._deviceController.selectedAudioOutputDevice$;\n }\n /** Observable of the currently selected video input device. */\n public get selectedVideoInputDevice$(): Observable<MediaDeviceInfo | null> {\n return this._deviceController.selectedVideoInputDevice$;\n }\n /** Currently selected audio input device, or `null` if none. */\n public get selectedAudioInputDevice(): MediaDeviceInfo | null {\n return this._deviceController.selectedAudioInputDevice;\n }\n /** Currently selected audio output device, or `null` if none. */\n public get selectedAudioOutputDevice(): MediaDeviceInfo | null {\n return this._deviceController.selectedAudioOutputDevice;\n }\n /** Currently selected video input device, or `null` if none. */\n public get selectedVideoInputDevice(): MediaDeviceInfo | null {\n return this._deviceController.selectedVideoInputDevice;\n }\n /** Media track constraints for the selected audio input device. */\n public get selectedAudioInputDeviceConstraints(): MediaTrackConstraints {\n return this._deviceController.selectedAudioInputDeviceConstraints;\n }\n /** Media track constraints for the selected video input device. */\n public get selectedVideoInputDeviceConstraints(): MediaTrackConstraints {\n return this._deviceController.selectedVideoInputDeviceConstraints;\n }\n\n /** Converts a `MediaDeviceInfo` to track constraints suitable for `getUserMedia`. */\n public deviceInfoToConstraints(deviceInfo: MediaDeviceInfo | null): MediaTrackConstraints {\n return this._deviceController.deviceInfoToConstraints(deviceInfo);\n }\n\n /** Sets the preferred audio input device. */\n public selectAudioInputDevice(device: MediaDeviceInfo | null): void {\n this._deviceController.selectAudioInputDevice(device);\n }\n\n /** Sets the preferred video input device. */\n public selectVideoInputDevice(device: MediaDeviceInfo | null): void {\n this._deviceController.selectVideoInputDevice(device);\n }\n\n /** Sets the preferred audio output device. */\n public selectAudioOutputDevice(device: MediaDeviceInfo | null): void {\n this._deviceController.selectAudioOutputDevice(device);\n }\n\n /** Starts monitoring for media device changes (connect/disconnect). */\n public enableDeviceMonitoring(): void {\n this._deviceController.enableDeviceMonitoring();\n }\n\n /** Stops monitoring for media device changes. */\n public disableDeviceMonitoring(): void {\n this._deviceController.disableDeviceMonitoring();\n }\n\n public async getDeviceCapabilities(\n deviceInfo: MediaDeviceInfo\n ): Promise<MediaTrackCapabilities | null> {\n return this._deviceController.getDeviceCapabilities(deviceInfo);\n }\n\n public async isValidDevice(deviceInfo: MediaDeviceInfo | null): Promise<boolean> {\n return this._deviceController.isValidDevice(deviceInfo);\n }\n\n public override destroy(): void {\n if (this._refreshTimerId) {\n clearTimeout(this._refreshTimerId);\n this._refreshTimerId = undefined;\n }\n super.destroy();\n }\n}\nexport { SignalWire };\n","import { RequestError, RequestTimeoutError } from '../core/errors';\nimport { getLogger } from '../utils/logger';\n\nimport type { CredentialProvider } from './interfaces';\n\nconst logger = getLogger();\n\nexport class EmbedTokenCredentialProvider implements CredentialProvider {\n constructor(\n private host: string,\n private embedToken: string\n ) {}\n\n private async fetchSAT(): Promise<string> {\n const url = `https://${this.host}/api/fabric/embeds/tokens`;\n\n const timeout = 10000; // 10 seconds\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n body: JSON.stringify({ token: this.embedToken }),\n signal: controller.signal\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) {\n const data = (await response.json()) as { token: string };\n return data.token;\n }\n\n throw new RequestError(\n `Failed to fetch SAT using embed token: ${response.status} ${response.statusText}`\n );\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error && error.name === 'AbortError') {\n throw new RequestTimeoutError(`Request timeout after ${timeout}ms`, { cause: error });\n }\n\n logger.error('[EmbedCredentialProvider] Request failed:', error);\n throw error;\n }\n }\n\n public async authenticate(): Promise<{ token: string; expiry_at: number }> {\n const sat = await this.fetchSAT();\n const expiryAt = Date.now() + 3600 * 1000;\n return { token: sat, expiry_at: expiryAt };\n }\n\n public async refresh(): Promise<{ token: string; expiry_at: number }> {\n return this.authenticate();\n }\n}\n","import { SignalWire } from '../clients/SignalWire';\nimport { DependencyError } from '../core/errors';\nimport { EmbedTokenCredentialProvider } from '../dependencies/EmbedTokenCredentialProvider';\n\nimport type { Call } from '../core/entities/types/call.types';\n\n/** Options for {@link embeddableCall}. */\nexport interface EmbeddableCallOptions {\n /** Destination URI to call. */\n to: string;\n /** Embed token for authentication. */\n embedToken: string;\n /** SignalWire host URL. */\n host: string;\n}\n\n/**\n * Creates a call using an embed token for simple, embeddable integrations.\n *\n * Handles client creation, authentication, and dialing in a single call.\n *\n * @param options - Embed token, host, and destination.\n * @returns The created {@link Call} instance.\n */\nexport async function embeddableCall(options: EmbeddableCallOptions): Promise<Call> {\n const { to, embedToken, host } = options;\n const requiredFailed = [];\n\n if (!to) {\n requiredFailed.push('to');\n }\n\n if (!embedToken) {\n requiredFailed.push('embedToken');\n }\n\n if (!host) {\n requiredFailed.push('host');\n }\n\n if (requiredFailed.length > 0) {\n return Promise.reject(\n new DependencyError(`Missing required options: ${requiredFailed.join(', ')}`)\n );\n }\n\n const credentialProvider = new EmbedTokenCredentialProvider(host, embedToken);\n const client = new SignalWire(credentialProvider);\n\n const call = await client.dial(to);\n\n return call;\n}\n","import type { CredentialProvider } from './interfaces';\nimport type { SDKCredential } from '../core/types/common.types';\n\n/**\n * Credential provider that returns a fixed set of credentials.\n *\n * Use when the token is already available (e.g. from a backend endpoint).\n *\n * @example\n * ```ts\n * const provider = new StaticCredentialProvider({ token: 'my-sat-token' });\n * const client = new SignalWire(provider);\n * ```\n */\nexport class StaticCredentialProvider implements CredentialProvider {\n constructor(private credentials: SDKCredential) {}\n\n /** Returns the static credentials. */\n public async authenticate(): Promise<SDKCredential> {\n return Promise.resolve(this.credentials);\n }\n}\n","/**\n * Public API entry point for @signalwire/js\n *\n * IMPORTANT: This file should NEVER be imported by internal modules.\n * Internal modules must import directly from source files.\n *\n * This file defines the minimal public API surface for external consumers.\n */\n\n// ============================================================================\n// Main Entry Point\n// ============================================================================\n\nexport { SignalWire } from './clients/SignalWire';\n\nexport { embeddableCall } from './utils/embeddableCall';\n\nexport { StaticCredentialProvider } from './dependencies/StaticCredentialProvider';\nexport type {\n CredentialProvider,\n WebRTCApiProvider,\n WebRTCMediaDevices,\n Storage\n} from './dependencies/interfaces';\n// ============================================================================\n// Error Types (exported as values for instanceof checks)\n// ============================================================================\n\nexport {\n CallCreateError,\n CollectionFetchError,\n InvalidCredentialsError,\n MediaTrackError,\n MessageParseError,\n UnexpectedError,\n VertoPongError\n} from './core/errors';\n\n// ============================================================================\n// Domain Model Classes (exported as values for instanceof and type guards)\n// ============================================================================\n\nexport { Address } from './core/entities/Address';\nexport { WebRTCCall } from './core/entities/Call';\nexport { Participant, SelfParticipant } from './core/entities/Participant';\nexport { Subscriber } from './core/entities/Subscriber';\nexport { SelfCapabilities } from './core/capabilities';\n\n// ============================================================================\n// Domain Model Interfaces\n// ============================================================================\n\nexport type { Directory } from './core/entities/Directory';\nexport type { SessionState } from './interfaces/SessionState';\n\n// ============================================================================\n// Type Guards (exported as values for runtime checks)\n// ============================================================================\n\nexport { isSelfParticipant } from './core/entities/Participant';\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nexport { ClientPreferences } from './containers/PreferencesContainer';\n\n// ============================================================================\n// Essential Types (type-only exports)\n// ============================================================================\n\n// Client types\nexport type { SignalWireOptions, DialOptions } from './clients/SignalWire';\n\n// Call types\nexport type {\n Call,\n CallOptions,\n CallStatus,\n CallState,\n CallParticipant,\n CallSelfParticipant,\n CallAddress\n} from './core/entities/types/call.types';\n\n// Types needed by web-components\nexport type { LayoutLayer } from './core/RPCMessages/types/common';\n\n// Media types\nexport type { MediaOptions, MediaDirections, MediaDirection } from './core/types/media.types';\n\n// Conversation types\nexport type { AddressHistory, TextMessage } from './core/types/conversation.types';\n\n// Participant types\nexport type { ExecuteMethod } from './core/entities/Participant';\n\n// Common types (credentials, adapters)\nexport type { SDKCredential, WebSocketAdapter, NodeSocketAdapter } from './core/types/common.types';\n\n// Capability types\nexport type {\n OnOffCapability,\n MemberCapabilities,\n CallCapabilitiesState\n} from './core/capabilities/types';\n\n// ============================================================================\n// DO NOT EXPORT (Internal Implementation):\n// - Behaviors (Destroyable, Fetchable)\n// - Controllers (DeviceController, RTCPeerConnectionController, etc.)\n// - Managers (DirectoryManager, TransportManager, ConversationsManager, etc.)\n// - Containers (DependencyContainer, PreferencesContainer singleton)\n// - Internal utilities and helpers\n// - RPC Messages and protocol internals\n// ============================================================================\n\n// ============================================================================\n// Library Ready Event (for async/dynamic script loading)\n// ============================================================================\n\ndeclare const __VERSION__: string;\n\n/**\n * Library version from package.json, injected at build time.\n */\nexport const version: string = __VERSION__;\n\n/**\n * Flag indicating the library has been loaded and is ready to use.\n * For UMD builds: `window.SignalWire.ready`\n * For ES modules: `import { ready } from '@signalwire/js'`\n */\nexport const ready: boolean = true;\n\n/**\n * Emits 'signalwire:js:ready' event when the library is loaded.\n *\n * Scripts that might load BEFORE the library (check flag first):\n * ```js\n * if (window.SignalWire?.ready) {\n * // Library already loaded, use it directly\n * initApp();\n * } else {\n * window.addEventListener('signalwire:js:ready', () => initApp());\n * }\n * ```\n */\nconst emitReadyEvent = (): void => {\n if (typeof window !== 'undefined') {\n const event = new CustomEvent('signalwire:js:ready', {\n detail: { version: __VERSION__ }\n });\n window.dispatchEvent(event);\n }\n};\n\nemitReadyEvent();\n"],"mappings":"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"}
|