interface CallOptions { to?: string; from?: string; from_name?: string; from_avatar?: string | null; isVideo?: boolean; isTransfer?: boolean; transferReason?: string; isInternal?: boolean; } type Listener = (event: T) => void; type EventMap = Record; declare class SimpleEventEmitter { private listeners; on(event: K, listener: Listener): void; on(event: string, listener: Listener): void; /** * Subscribe to an event for a single emission only. * The listener is automatically removed after first invocation. */ once(event: K, listener: Listener): void; once(event: string, listener: Listener): void; off(event: K, listener: Listener): void; off(event: string, listener: Listener): void; emit(event: K, data?: Events[K]): void; emit(event: string, data?: any): void; offAll(): void; } interface SseMessageEvent { event: string; data: any; id?: string; raw?: string; } interface SseStreamConfig { url: string; token?: string; headers?: Record; withCredentials?: boolean; maxReconnectDelay?: number; initialReconnectDelay?: number; onOpen?: () => void; onMessage?: (event: SseMessageEvent) => void; onError?: (error: unknown) => void; onConnectionStateChange?: (state: "connecting" | "connected" | "disconnected") => void; } /** * Lightweight, zero-dependency SSE Stream Client with Authorization Bearer header support. * Uses fetch() + ReadableStream on modern browsers and Node.js (18+), * with graceful fallback to EventSource (?token=...) for legacy environments. */ declare class SseStreamClient { private config; private abortController; private nativeEventSource; private reconnectTimer; private reconnectDelay; private isExplicitlyClosed; private _connected; constructor(config: SseStreamConfig); get isConnected(): boolean; /** * Start or restart the SSE connection stream */ connect(): void; private connectViaFetch; private connectViaEventSource; private scheduleReconnect; /** * Stop the SSE connection and cancel reconnect timers */ close(): void; private cleanup; } declare enum ECallState { 'INITIATED' = "INITIATED", 'TRYING' = "TRYING", 'RINGING' = "RINGING", 'ANSWERED' = "ANSWERED", 'ACTIVE' = "ACTIVE", 'ONHOLD' = "ONHOLD", 'ENDED' = "ENDED", 'ERROR' = "ERROR", 'CANCEL' = "CANCEL", 'NONE' = "NONE" } interface ITranscriptionStartedEvent { call_id: string; direction?: string; language?: string; channels?: number; provider?: string; model?: string; timestamp?: string; } interface ITranscriptionEntity { type: string; value: string; } interface ITranscriptionDialogueEvent { id?: string; call_id: string; speaker?: string; channel_index?: number; direction?: string; text: string; is_final?: boolean; speech_final?: boolean; confidence?: number; duration_ms?: number; entities?: ITranscriptionEntity[]; timestamp?: string; } interface ITranscriptionCompletedEvent { id?: string; call_id: string; workspace_id?: string; direction?: string; language?: string; provider?: string; model?: string; dialogue_count?: number; dialogues?: ITranscriptionDialogueEvent[]; full_text?: string; summary?: string | null; sentiment?: string | null; action_items?: string[]; entities?: ITranscriptionEntity[]; duration_seconds?: number; timestamp?: string; } type TranscriptionEvent = { type: 'started'; data: ITranscriptionStartedEvent; } | { type: 'dialogue'; data: ITranscriptionDialogueEvent; } | { type: 'completed'; data: ITranscriptionCompletedEvent; }; interface ICallRecordingStartedEvent { call_id: string; workspace_id?: string; record_id?: string; timestamp?: string | number; [key: string]: unknown; } interface ICallRecordingCompletedEvent { call_id: string; workspace_id?: string; record_id?: string; duration?: number; format?: string; timestamp?: string | number; [key: string]: unknown; } interface ICallRecordingReadyEvent { call_id: string; workspace_id?: string; record_id?: string; url?: string; duration?: number; format?: string; size_bytes?: number; timestamp?: string | number; [key: string]: unknown; } type CallRecordingEvent = { type: "started"; data: ICallRecordingStartedEvent; } | { type: "completed"; data: ICallRecordingCompletedEvent; }; declare class Call extends SimpleEventEmitter { callId: string | null; from: string; from_name: string; from_avatar: string | null; get avatar(): string | null; to: string; active: boolean; private client; private ws; private callSseClient; private state; private peerConnection; remoteDescription: RTCSessionDescriptionInit | null; private localStream; private remoteStream; isVideo: boolean | MediaTrackConstraints; isMuted: boolean; isCameraOff: boolean; isScreenSharing: boolean; private _cameraTrack; private _screenStream; isTransfer: boolean; transferReason?: string; isInternal: boolean; private _destroying; private currentRemoteSetupRole; constructor(client: FiretellClient, options?: CallOptions); /** * Open dedicated Native WebSocket signaling connection for this call session * and authenticate with call_token within 3s. */ connectSignaling(wsUrl: string, callToken: string): Promise; /** * Helper to send JSON event message over this call's WebSocket */ sendWsEvent(event: string, data?: Record): void; /** * Helper to extract a valid RTCSessionDescriptionInit from WS event data. * Handles object formats { type, sdp }, nested { sdp: { type, sdp } }, or raw SDP strings. */ private _extractSdpInit; /** * Process incoming WebSocket signaling messages for this call */ private _handleWsMessage; /** * Register a callback for all transcription events on this call (started, dialogue, completed). */ onTranscription(listener: (event: { type: "started" | "dialogue" | "completed"; data: ITranscriptionStartedEvent | ITranscriptionDialogueEvent | ITranscriptionCompletedEvent; }) => void): () => void; /** * Register a callback for real-time speech dialogue transcription chunks. */ onDialogue(listener: (dialogue: ITranscriptionDialogueEvent) => void): () => void; /** * Register a callback for active call recording events (started, completed). */ onRecording(listener: (event: { type: "started" | "completed"; data: ICallRecordingStartedEvent | ICallRecordingCompletedEvent; }) => void): () => void; /** * Connect dedicated per-call Server-Sent Events (SSE) stream for live transcription and telemetry. * Subscribes to `/stream?call_id=` using the call session token. */ connectCallEventStream(callToken?: string): void; /** * Process incoming Server-Sent Events for this specific call session. */ private _handleSseMessage; /** * Start an outbound call. * Initiates REST call creation, connects dedicated WS signaling, * gathers full ICE candidates, and sends call.offer. */ start(): Promise; /** * Join an existing call session (e.g. Supervision: Listen, Whisper, Barge) * using a pre-generated call_token and ws_url. */ joinSession(wsUrl: string, callToken: string, mode?: "listen" | "whisper" | "barge"): Promise; /** * Hang up this call */ hangup(): Promise; /** * Accept an incoming call. * Sets up WebRTC media, sets remote description, creates answer, * gathers full ICE, then sends call.answer over WebSocket. */ accept(): Promise; /** * Reject an incoming call */ reject(): Promise; /** * Transfer the call to another target. * Target can be: extension number (e.g. "100"), agent username, * team ID (te_...), or SIP account ID (si_...). * @param target Transfer target identifier * @param reason Optional transfer reason */ transfer(target: string, reason?: string): Promise; /** * Send a DTMF tone * @param digit Single digit: 0-9, *, #, A-D * @param duration Duration in ms (default: 250) */ sendDTMF(digit: string, duration?: number): Promise; /** * Mute the microphone. * Stops local audio tracks and notifies the server. */ mute(): Promise; /** * Unmute the microphone. * Resumes local audio tracks and notifies the server. */ unmute(): Promise; /** * Toggle mute state */ toggleMute(): Promise; /** * Mute / disable local camera video track. * Remote party will receive black frames / paused stream. */ muteVideo(): Promise; /** * Unmute / enable local camera video track. */ unmuteVideo(): Promise; /** * Toggle camera mute state */ toggleCamera(): Promise; /** * Start sharing screen via navigator.mediaDevices.getDisplayMedia. * Replaces the active video track on RTCRtpSender without renegotiating SDP. */ startScreenShare(): Promise; /** * Stop sharing screen and restore original camera video track. */ stopScreenShare(): Promise; /** * Toggle screen sharing state */ toggleScreenShare(): Promise; /** * Put the call on hold */ onhold(): Promise; /** * Resume a held call */ unhold(): Promise; /** * Update call signaling state from server notification */ setSignalState(state: ECallState, params: Record): void; /** * Get current call state */ get callState(): ECallState; /** * Whether the call is currently on hold */ get isHold(): boolean; /** * Destroy/cleanup this call instance. * Closes WebRTC PeerConnection, stops local/remote media tracks, * closes dedicated WebSocket connection, and clears event listeners. * @param sendHangup Whether to send call.hangup event to server (default: true, set to false for transfers) */ destroy(sendHangup?: boolean): Promise; /** * Set the remote SDP description on the peer connection */ setRemoteDescription(sdp: RTCSessionDescriptionInit): Promise; /** * Setup WebRTC media (getUserMedia + peerConnection) */ private _setupWebrtcMedia; /** * Wait for ICE candidates to be gathered and return full SDP. * Firetell media servers do not support Trickle ICE. */ private _getSDPFull; /** * Cleanup the peer connection and streams */ private _cleanupPeerConnection; } interface ISession { session_id: string; display_name: string; username: string; domain: string; avatar?: string; ext?: string; expires_at: number; } interface IJwtPayload { domain: string; exp: number; iss: string; aud: "agent-api" | "client-api"; sub: string; } interface IClientPhoneNumber { id: string; number: string; title?: string; country_code?: string; dial_code?: string; status: 'active' | 'inactive' | 'pending' | string; capabilities?: { voice?: boolean; sms?: boolean; }; enable_outbound?: boolean; shared_teams_id?: string[]; created_at?: string; } interface IClientPhoneNumbersResponse { data: IClientPhoneNumber[]; meta: { total: number; page: number; limit: number; total_pages: number; }; } declare const SDK_VERSION: string; /** Params for a call.ring notification */ interface ICallRingParams { call_id: string; call_token: string; ws_url?: string; from?: { number: string; name?: string; avatar?: string | null; }; to?: { number: string; name?: string; }; is_transfer?: boolean; transfer_reason?: string; is_video?: boolean; timestamp?: string; } /** Response from REST Make Call API */ interface IMakeCallResponse { call_id: string; status: string; call_token: string; ws_url: string; expires_in: number; } declare class FiretellClient { static readonly VERSION: string; readonly sdkVersion: string; private baseUrl; private jwt; private jwtPayload; private wsServers; iceServers: RTCIceServer[]; private session; private isReconnecting; private reconnectTimer; private reconnectDelay; private webRTCChecked; private sseClient; private knownCallStates; /** * Event emitter for client events * @events session, incomingCall, error, reconnected, workspace.agent.state */ events: SimpleEventEmitter<{ [x: string]: any; }>; isWebRTCSupport: boolean; connected: boolean; /** * Promise that resolves when the client is fully initialized */ readonly ready: Promise; private _resolveReady; private _rejectReady; /** * Current active calls Map */ readonly activeCalls: Map; /** * FiretellClient constructor * @param jwt Json Web Token * @param domain Workspace API domain */ constructor(jwt: string, domain: string); private _checkWorkspaceDomain; private _fetchWorkspaceMetadata; /** * Connect to Server-Sent Events (SSE) Realtime Event Stream * using SseStreamClient with Authorization Bearer header. */ private _initEventStream; /** * Call REST API POST /v1/call-center/calls to initiate call creation */ initiateCallRest(to: string, from?: string, isVideo?: boolean): Promise; /** * Helper to create a Call instance and connect its dedicated per-call WebSocket */ createCallSession(callToken: string, wsUrl: string, callId: string, options: CallOptions): Promise; /** * Initiate a new outbound call via REST API, then open native WebSocket per call. * @param call Call instance * @param sdp RTCSessionDescription (full SDP) */ makeCall(call: Call, sdp: RTCSessionDescription): Promise; /** * Initiate Call Supervision (listen / whisper / barge) via REST API. */ private _superviseCall; /** * Helper to start supervision (listen / whisper / barge) and automatically * establish the WebRTC audio session. */ startSupervision(callId: string, mode: "listen" | "whisper" | "barge", options?: CallOptions): Promise; /** * Helper to stop an active call supervision session. * Closes WebRTC call session and calls the REST API DELETE /api/v1/call-center/calls/:call_id/supervision. */ stopSupervision(callId: string): Promise; /** * Send Call Transfer request via WebSocket or REST API fallback. * Target can be: extension number, agent username, team ID (te_...), or SIP account ID (si_...). */ sendTransfer(callId: string, target: string, reason?: string): Promise; /** * Send login with username, password, domain. */ login(username: string, password: string, domain: string): Promise; /** * Fetch phone numbers (DIDs) accessible by the authenticated agent/team. * Calls GET /api/v1/call-center/phone-numbers using the agent's JWT. */ getPhoneNumbers(options?: { page?: number; limit?: number; }): Promise; getSessionInfo(): ISession | null; getJwtPayload(): IJwtPayload | null; getBaseUrl(): string; getJwt(): string; /** * Helper to generate or retrieve a unique, persistent Device ID for browser environment. * Uses localStorage when available, or falls back to random UUID. * @param storageKey Key to store device ID in localStorage (default: "firetell_device_id") * @returns Persistent unique device ID string */ static getOrCreateDeviceId(storageKey?: string): string; /** * Helper instance method to get or generate persistent browser Device ID. * @param storageKey Custom key for localStorage (default: "firetell_device_id") */ getDeviceId(storageKey?: string): string; private _cleanupSession; private _isVideoCall; private _checkWebRTCSupport; private _handleIncomingCall; logout(): void; destroy(): void; private _parseJwt; } declare enum ECallEventName { MEDIA_STATE = "mediaState", STATE = "state", LOCAL_STREAM = "localStream", REMOTE_STREAM = "remoteStream", MUTE = "mute", CAMERA = "camera", SCREEN_SHARE = "screenShare", TRANSCRIPTION = "transcription", TRANSCRIPTION_STARTED = "transcription.started", TRANSCRIPTION_DIALOGUE = "transcription.dialogue", TRANSCRIPTION_COMPLETED = "transcription.completed", RECORDING = "recording", RECORDING_STARTED = "recording.started", RECORDING_COMPLETED = "recording.completed" } declare enum EClientEventName { SESSION = "session", ERROR = "error", CALL_RING = "call.ring", CALL_OFFER = "call.offer", CALL_OFFERED = "call.offered", CALL_CREATED = "call.created", CALL_STARTED = "call.started", CALL_ANSWERED = "call.answered", CALL_ENDED = "call.ended", CALL_CANCELED = "call.canceled", CALL_HELD = "call.held", CALL_UNHELD = "call.unheld", CALL_TRANSFERRED = "call.transferred", CALL_MUTE = "call.mute", AGENT_STATE = "agent.state", AGENT_STATE_FORCED = "agent.state.forced", AGENT_CREATED = "agent.created", AGENT_UPDATED = "agent.updated", AGENT_DELETED = "agent.deleted", RECONNECTED = "reconnected", CONTACT_CREATED = "contact.created", CONTACT_UPDATED = "contact.updated", CONTACT_DELETED = "contact.deleted", TEAM_CREATED = "team.created", TEAM_UPDATED = "team.updated", TEAM_DELETED = "team.deleted", TEAM_ASSIGNED = "team.assigned", TEAM_UNASSIGNED = "team.unassigned", CONNECTION_STATE = "connection.state", CALL_RECORDING_READY = "call.recording.ready" } interface IActiveCall { call_id: string; sdp: RTCSessionDescriptionInit; media_type: string; } /** * Fallback ICE (STUN) servers used when workspace metadata is unavailable */ declare const DEFAULT_ICE_SERVERS: RTCIceServer[]; export { Call, type CallOptions, type CallRecordingEvent, DEFAULT_ICE_SERVERS, ECallEventName, ECallState, EClientEventName, FiretellClient, type IActiveCall, type ICallRecordingCompletedEvent, type ICallRecordingReadyEvent, type ICallRecordingStartedEvent, type ICallRingParams, type IClientPhoneNumber, type IClientPhoneNumbersResponse, type ISession, type ITranscriptionCompletedEvent, type ITranscriptionDialogueEvent, type ITranscriptionEntity, type ITranscriptionStartedEvent, type Listener, SDK_VERSION, SimpleEventEmitter, type SseMessageEvent, SseStreamClient, type SseStreamConfig, type TranscriptionEvent };