UNPKG

@signalwire/realtime-api

Version:
4 lines 330 kB
{ "version": 3, "sources": ["../src/configure/index.ts", "../src/messaging/Messaging.ts", "../src/BaseNamespace.ts", "../src/utils/internals.ts", "../src/Session.ts", "../src/ListenSubscriber.ts", "../src/messaging/workers/messagingWorker.ts", "../src/messaging/Message.ts", "../src/chat/Chat.ts", "../src/chat/BaseChat.ts", "../src/chat/workers/chatWorker.ts", "../src/pubSub/PubSub.ts", "../src/pubSub/workers/pubSubWorker.ts", "../src/task/Task.ts", "../src/task/workers/taskWorker.ts", "../src/voice/Voice.ts", "../src/voice/workers/voiceCallReceiveWorker.ts", "../src/voice/Call.ts", "../src/voice/utils.ts", "../src/voice/Playlist.ts", "../src/voice/CallPlayback/CallPlayback.ts", "../src/decoratePromise.ts", "../src/voice/CallPlayback/decoratePlaybackPromise.ts", "../src/voice/CallRecording/CallRecording.ts", "../src/voice/CallRecording/decorateRecordingPromise.ts", "../src/voice/CallPrompt/CallPrompt.ts", "../src/voice/CallPrompt/decoratePromptPromise.ts", "../src/voice/CallCollect/CallCollect.ts", "../src/voice/CallCollect/decorateCollectPromise.ts", "../src/voice/CallTap/CallTap.ts", "../src/voice/CallTap/decorateTapPromise.ts", "../src/voice/DeviceBuilder.ts", "../src/voice/CallDetect/CallDetect.ts", "../src/voice/CallDetect/decorateDetectPromise.ts", "../src/voice/workers/handlers/callStateEventsHandler.ts", "../src/voice/workers/handlers/callConnectEventsHandler.ts", "../src/voice/workers/handlers/callDialEventsHandler.ts", "../src/voice/workers/voiceCallPlayWorker.ts", "../src/voice/workers/voiceCallRecordWorker.ts", "../src/voice/workers/voiceCallCollectWorker.ts", "../src/voice/workers/voiceCallTapWorker.ts", "../src/voice/workers/voiceCallConnectWorker.ts", "../src/voice/workers/voiceCallDialWorker.ts", "../src/voice/workers/VoiceCallSendDigitWorker.ts", "../src/voice/workers/voiceCallDetectWorker.ts", "../src/video/Video.ts", "../src/video/RoomSession.ts", "../src/video/RoomSessionMember/RoomSessionMember.ts", "../src/video/methods/methods.ts", "../src/video/RoomSessionPlayback/RoomSessionPlayback.ts", "../src/video/RoomSessionPlayback/decoratePlaybackPromise.ts", "../src/video/RoomSessionRecording/RoomSessionRecording.ts", "../src/video/RoomSessionRecording/decorateRecordingPromise.ts", "../src/video/RoomSessionStream/RoomSessionStream.ts", "../src/video/RoomSessionStream/decorateStreamPromise.ts", "../src/video/BaseVideo.ts", "../src/video/workers/videoCallingWorker.ts", "../src/video/workers/videoRoomWorker.ts", "../src/video/workers/videoMemberWorker.ts", "../src/video/workers/videoLayoutWorker.ts", "../src/video/workers/videoRoomAudienceWorker.ts", "../src/video/workers/videoRecordingWorker.ts", "../src/video/workers/videoPlaybackWorker.ts", "../src/video/workers/videoStreamWorker.ts", "../src/client/createClient.ts", "../src/client/Client.ts", "../src/client/clientConnect.ts", "../src/SWClient.ts", "../src/SignalWire.ts"], "sourcesContent": ["export interface GlobalConfig {\n token?: string\n project?: string\n}\n\nlet GLOBAL_CONFIG: GlobalConfig = {}\n\nexport const getConfig = (): GlobalConfig => {\n return GLOBAL_CONFIG\n}\n\n/** @ignore */\nexport interface ConfigOptions extends GlobalConfig {\n /** @internal */\n cache?: GlobalConfig\n}\n\n/** @internal */\nexport const config = ({\n cache = GLOBAL_CONFIG,\n ...options\n}: ConfigOptions) => {\n if (cache) {\n GLOBAL_CONFIG = cache\n }\n\n Object.entries(options).forEach(([key, value]) => {\n // TODO: filter out properties\n // @ts-expect-error\n GLOBAL_CONFIG[key] = value\n })\n}\n", "import { MessagingEventNames, toExternalJSON } from '@signalwire/core'\nimport { BaseNamespace } from '../BaseNamespace'\nimport { SWClient } from '../SWClient'\nimport { Message } from './Message'\nimport { messagingWorker } from './workers'\n\ninterface MessageListenOptions {\n topics: string[]\n onMessageReceived?: (message: Message) => unknown\n onMessageUpdated?: (message: Message) => unknown\n}\n\ntype MessageListenerKeys = keyof Omit<MessageListenOptions, 'topics'>\n\ntype MessageEvents = Record<MessagingEventNames, (message: Message) => void>\n\ninterface MessageSendMethodParams {\n context?: string\n from: string\n to: string\n body?: string\n tags?: string[]\n region?: string\n media?: string[]\n}\n\ninterface MessagingSendResult {\n message: string\n code: string\n messageId: string\n}\n\ninterface MessagingSendError {\n message: string\n code: string\n errors: Record<any, any>\n}\n\nexport class Messaging extends BaseNamespace<\n MessageListenOptions,\n MessageEvents\n> {\n protected _eventMap: Record<MessageListenerKeys, MessagingEventNames> = {\n onMessageReceived: 'message.received',\n onMessageUpdated: 'message.updated',\n }\n\n constructor(options: SWClient) {\n super(options)\n\n this._client.runWorker('messagingWorker', {\n worker: messagingWorker,\n initialState: {\n messaging: this,\n },\n })\n }\n\n async send(params: MessageSendMethodParams): Promise<any> {\n const { from = '', to = '', ...rest } = params\n const sendParams = {\n ...rest,\n from_number: from,\n to_number: to,\n }\n\n try {\n const response = await this._client.execute<unknown, MessagingSendResult>(\n {\n method: 'messaging.send',\n params: sendParams,\n }\n )\n\n return toExternalJSON(response)\n } catch (error) {\n this._client.logger.error('Error sending message', error)\n throw error as MessagingSendError\n }\n }\n}\n\nexport * from './Message'\nexport type { MessagingMessageState } from '@signalwire/core'\n", "import { EventEmitter, ExecuteParams, getLogger, uuid } from '@signalwire/core'\nimport { prefixEvent } from './utils/internals'\nimport { ListenSubscriber } from './ListenSubscriber'\nimport { SWClient } from './SWClient'\n\nexport interface ListenOptions {\n topics?: string[]\n channels?: string[]\n}\n\nexport type Listeners<T> = Omit<T, 'topics' | 'channels'>\n\nexport type ListenersKeys<T> = keyof T\n\nexport class BaseNamespace<\n T extends ListenOptions,\n EventTypes extends EventEmitter.ValidEventTypes\n> extends ListenSubscriber<Listeners<T>, EventTypes> {\n constructor(options: SWClient) {\n super({ swClient: options })\n\n this.onSessionReconnect = this.onSessionReconnect.bind(this)\n this.onSessionDisconnect = this.onSessionDisconnect.bind(this)\n this._client.session.on('session.reconnecting', this.onSessionReconnect)\n this._client.session.once('session.disconnected', this.onSessionDisconnect)\n }\n\n protected onSessionReconnect() {\n this._client.session.once('session.connected', async () => {\n const resendTopics = new Set<string>()\n for (const { topics } of this._listenerMap.values()) {\n topics?.forEach((topic) => resendTopics.add(topic))\n }\n if (resendTopics.size > 0) {\n getLogger().info('Re-subscribing topics after reconnection')\n await this.addTopics([...resendTopics])\n }\n })\n }\n\n private onSessionDisconnect() {\n this._client.session.off('session.reconnecting', this.onSessionReconnect)\n this._client.destroy()\n }\n\n protected addTopics(topics: string[]) {\n const executeParams: ExecuteParams = {\n method: 'signalwire.receive',\n params: {\n contexts: topics,\n },\n }\n return this._client.execute<unknown, void>(executeParams)\n }\n\n protected removeTopics(topics: string[]) {\n const executeParams: ExecuteParams = {\n method: 'signalwire.unreceive',\n params: {\n contexts: topics,\n },\n }\n return this._client.execute<unknown, void>(executeParams)\n }\n\n public listen(listenOptions: T) {\n return new Promise<() => Promise<void>>(async (resolve, reject) => {\n try {\n const { topics } = listenOptions\n if (!Array.isArray(topics) || topics?.length < 1) {\n throw new Error(\n 'Invalid options: topics should be an array with at least one topic!'\n )\n }\n const unsub = await this.subscribe(listenOptions)\n resolve(unsub)\n } catch (error) {\n reject(error)\n }\n })\n }\n\n protected async subscribe(listenOptions: T) {\n const { topics, ...listeners } = listenOptions\n const _uuid = uuid()\n\n // Attach listeners\n this._attachListenersWithTopics(topics!, listeners as Listeners<T>)\n await this.addTopics(topics!)\n\n const unsub = () => {\n return new Promise<void>(async (resolve, reject) => {\n try {\n // Detach listeners\n this._detachListenersWithTopics(topics!, listeners as Listeners<T>)\n\n // Remove topics from the listener map\n this.removeFromListenerMap(_uuid)\n\n // Remove the topics\n const topicsToRemove = topics!.filter(\n (topic) => !this.hasOtherListeners(_uuid, topic)\n )\n if (topicsToRemove.length > 0) {\n await this.removeTopics(topicsToRemove)\n }\n\n resolve()\n } catch (error) {\n reject(error)\n }\n })\n }\n\n // Add topics to the listener map\n this.addToListenerMap(_uuid, {\n topics: new Set([...topics!]),\n listeners: listeners as Listeners<T>,\n unsub,\n })\n\n return unsub\n }\n\n protected _attachListenersWithTopics(\n topics: string[],\n listeners: Listeners<T>\n ) {\n const listenerKeys = Object.keys(listeners)\n topics.forEach((topic) => {\n listenerKeys.forEach((key) => {\n const _key = key as keyof Listeners<T>\n if (typeof listeners[_key] === 'function' && this._eventMap[_key]) {\n const event = prefixEvent(topic, this._eventMap[_key] as string)\n // @ts-expect-error\n this.on(event, listeners[_key])\n }\n })\n })\n }\n\n protected _areListenersAttached(topics: string[], listeners: Listeners<T>) {\n return topics.every((topic) =>\n Object.entries(listeners).every(([key, listener]) => {\n const event = prefixEvent(\n topic,\n this._eventMap[key as keyof Listeners<T>] as string\n )\n // @ts-expect-error\n return this.emitter.listeners(event).includes(listener)\n })\n )\n }\n\n protected _detachListenersWithTopics(\n topics: string[],\n listeners: Listeners<T>\n ) {\n const listenerKeys = Object.keys(listeners)\n topics.forEach((topic) => {\n listenerKeys.forEach((key) => {\n const _key = key as keyof Listeners<T>\n if (typeof listeners[_key] === 'function' && this._eventMap[_key]) {\n const event = prefixEvent(topic, this._eventMap[_key] as string)\n // @ts-expect-error\n this.off(event, listeners[_key])\n }\n })\n })\n }\n\n protected hasOtherListeners(uuid: string, topic: string) {\n for (const [key, listener] of this._listenerMap) {\n if (key !== uuid && listener.topics?.has(topic)) {\n return true\n }\n }\n return false\n }\n\n protected async unsubscribeAll() {\n await Promise.all(\n [...this._listenerMap.values()].map(({ unsub }) => unsub())\n )\n this._listenerMap.clear()\n }\n}\n", "import { configureStore, getEventEmitter, UserOptions } from '@signalwire/core'\nimport { getConfig } from '../configure'\nimport { Session } from '../Session'\n\nexport const setupInternals = (userOptions: {\n project: string\n token: string\n logLevel?: UserOptions['logLevel']\n}) => {\n /**\n * The emitter will be used across the entire stack so no\n * need to type it here. Typings will be provided by each\n * constructor.\n */\n const emitter = getEventEmitter<any>()\n\n const baseOptions = {\n ...userOptions,\n emitter,\n }\n\n const store = configureStore({\n userOptions: baseOptions,\n SessionConstructor: Session,\n })\n\n return { store, emitter }\n}\n\nconst getToken = (userToken?: string) => {\n const globalConfig = getConfig()\n const token = userToken || globalConfig.token || process.env.SW_TOKEN\n\n if (!token) {\n // TODO: Add error message\n throw new Error('Missing `token`')\n }\n\n return token\n}\n\nconst getProject = (userProject?: string) => {\n const globalConfig = getConfig()\n const project = userProject || globalConfig.project || process.env.SW_PROJECT\n\n if (!project) {\n // TODO: Add error message\n throw new Error('Missing `project`')\n }\n\n return project\n}\n\ninterface GetCredentialsOptions {\n token?: string\n project?: string\n}\n\nexport const getCredentials = (options?: GetCredentialsOptions) => {\n const project = getProject(options?.project)\n const token = getToken(options?.token)\n\n return { project, token }\n}\n\nexport const prefixEvent = (prefix: string, event: string) => {\n if (typeof prefix !== 'string' || typeof event !== 'string') return event\n return `${prefix}.${event}`\n}\n", "import { BaseSession, SWCloseEvent } from '@signalwire/core'\nimport WebSocket from 'ws'\n\nexport class Session extends BaseSession {\n public WebSocketConstructor = WebSocket\n public CloseEventConstructor = SWCloseEvent\n public agent = process.env.SDK_PKG_AGENT!\n}\n", "import { EventEmitter, getLogger, uuid } from '@signalwire/core'\nimport type { Client } from './client/Client'\nimport { SWClient } from './SWClient'\n\nexport type ListenersKeys<T> = keyof T\n\nexport type ListenerMapValue<T> = {\n topics?: Set<string>\n listeners: T\n unsub: () => Promise<void>\n}\n\nexport type ListenerMap<T> = Map<string, ListenerMapValue<T>>\n\nexport class ListenSubscriber<\n T extends {},\n EventTypes extends EventEmitter.ValidEventTypes\n> {\n /** @internal */\n _sw: SWClient\n\n protected _client: Client\n protected _listenerMap: ListenerMap<T> = new Map()\n protected _eventMap: Record<keyof T, keyof EventTypes>\n private _emitter = new EventEmitter<EventTypes>()\n\n constructor(options: { swClient: SWClient }) {\n this._sw = options.swClient\n this._client = options.swClient.client\n }\n\n protected get emitter() {\n return this._emitter\n }\n\n protected eventNames() {\n return this.emitter.eventNames()\n }\n\n /** @internal */\n emit<T extends EventEmitter.EventNames<EventTypes>>(\n event: T,\n ...args: EventEmitter.EventArgs<EventTypes, T>\n ) {\n return this.emitter.emit(event, ...args)\n }\n\n protected on<E extends EventEmitter.EventNames<EventTypes>>(\n event: E,\n fn: EventEmitter.EventListener<EventTypes, E>\n ) {\n return this.emitter.on(event, fn)\n }\n\n protected once<T extends EventEmitter.EventNames<EventTypes>>(\n event: T,\n fn: EventEmitter.EventListener<EventTypes, T>\n ) {\n return this.emitter.once(event, fn)\n }\n\n protected off<T extends EventEmitter.EventNames<EventTypes>>(\n event: T,\n fn?: EventEmitter.EventListener<EventTypes, T>\n ) {\n return this.emitter.off(event, fn)\n }\n\n public listen(listeners: T) {\n return new Promise<() => Promise<void>>(async (resolve, reject) => {\n try {\n if (\n !listeners ||\n listeners?.constructor !== Object ||\n Object.keys(listeners).length < 1\n ) {\n throw new Error('Invalid params!')\n }\n\n const unsub = await this.subscribe(listeners)\n resolve(unsub)\n } catch (error) {\n reject(error)\n }\n })\n }\n\n protected async subscribe(listeners: T) {\n const _uuid = uuid()\n\n // Attach listeners\n this._attachListeners(listeners)\n\n const unsub = () => {\n return new Promise<void>(async (resolve, reject) => {\n try {\n // Detach listeners\n this._detachListeners(listeners)\n\n // Remove listeners from the listener map\n this.removeFromListenerMap(_uuid)\n\n resolve()\n } catch (error) {\n reject(error)\n }\n })\n }\n\n // Add listeners to the listener map\n this.addToListenerMap(_uuid, {\n listeners,\n unsub,\n })\n\n return unsub\n }\n\n protected _attachListeners(listeners: T) {\n const listenerKeys = Object.keys(listeners) as Array<ListenersKeys<T>>\n listenerKeys.forEach((key) => {\n if (typeof listeners[key] === 'function' && this._eventMap[key]) {\n // @ts-expect-error\n this.on(this._eventMap[key], listeners[key])\n } else {\n getLogger().warn(`Unsupported listener: ${listeners[key]}`)\n }\n })\n }\n\n protected _detachListeners(listeners: T) {\n const listenerKeys = Object.keys(listeners) as Array<ListenersKeys<T>>\n listenerKeys.forEach((key) => {\n if (typeof listeners[key] === 'function' && this._eventMap[key]) {\n // @ts-expect-error\n this.off(this._eventMap[key], listeners[key])\n }\n })\n }\n\n protected addToListenerMap(id: string, value: ListenerMapValue<T>) {\n return this._listenerMap.set(id, value)\n }\n\n protected removeFromListenerMap(id: string) {\n return this._listenerMap.delete(id)\n }\n}\n", "import {\n MessagingAction,\n SDKActions,\n SDKWorker,\n SagaIterator,\n getLogger,\n sagaEffects,\n} from '@signalwire/core'\nimport type { Client } from '../../client/Client'\nimport { prefixEvent } from '../../utils/internals'\nimport { Message } from '../Messaging'\nimport { Messaging } from '../Messaging'\n\ninterface MessagingWorkerInitialState {\n messaging: Messaging\n}\n\nexport const messagingWorker: SDKWorker<Client> = function* (\n options\n): SagaIterator {\n getLogger().trace('messagingWorker started')\n const {\n channels: { swEventChannel },\n initialState,\n } = options\n\n const { messaging } = initialState as MessagingWorkerInitialState\n\n function* worker(action: MessagingAction) {\n const { payload, type } = action\n\n // @ts-expect-error\n const message = new Message(payload)\n\n switch (type) {\n case 'messaging.receive':\n messaging.emit(\n // @ts-expect-error\n prefixEvent(payload.context, 'message.received'),\n message\n )\n break\n case 'messaging.state':\n // @ts-expect-error\n messaging.emit(prefixEvent(payload.context, 'message.updated'), message)\n break\n default:\n getLogger().warn(`Unknown message event: \"${action.type}\"`)\n break\n }\n }\n\n const isMessagingEvent = (action: SDKActions) =>\n action.type.startsWith('messaging.')\n\n while (true) {\n const action: MessagingAction = yield sagaEffects.take(\n swEventChannel,\n isMessagingEvent\n )\n\n yield sagaEffects.fork(worker, action)\n }\n\n getLogger().trace('messagingWorker ended')\n}\n", "import { MessagingMessageState } from '@signalwire/core'\n\n/**\n * An object representing an SMS or MMS message.\n */\nexport interface MessageContract {\n /** The unique identifier of the message. */\n id: string\n /** The current state of the message. */\n state: MessagingMessageState\n /** The context of the message. */\n context: string\n /** The phone number the message comes from. */\n from: string\n /** The destination number of the message. */\n to: string\n /** The direction of the message: `inbound` or `outbound`. */\n direction: string\n /** Array of strings with message tags. */\n tags: string[]\n /** Body of the message */\n body: string\n /** Array of URLs media. */\n media: string[]\n /** Number of segments of the message. */\n segments: number\n /** Reason why the message was not sent. This is present only in case of failure. */\n reason?: string\n}\n\ninterface MessageOptions {\n message_id: string\n message_state: MessagingMessageState\n context: string\n from_number: string\n to_number: string\n direction: 'inbound' | 'outbound'\n tags: string[]\n body: string\n media: string[]\n segments: number\n reason?: string\n}\n\n/** @internal */\nexport class Message implements MessageContract {\n public id: string\n public state: MessagingMessageState\n public context: string\n public from: string\n public to: string\n public body: string\n public direction: 'inbound' | 'outbound'\n public media: string[]\n public segments: number\n public tags: string[]\n public reason?: string\n\n constructor(options: MessageOptions) {\n this.id = options.message_id\n this.state = options.message_state\n this.context = options.context\n this.from = options.from_number\n this.to = options.to_number\n this.body = options.body\n this.direction = options.direction\n this.media = options.media || []\n this.segments = options.segments\n this.tags = options.tags || []\n this.reason = options.reason\n }\n}\n", "import {\n ChatMember,\n ChatMessage,\n ChatEvents,\n Chat as ChatCore,\n} from '@signalwire/core'\nimport { BaseChat } from './BaseChat'\nimport { chatWorker } from './workers'\nimport { SWClient } from '../SWClient'\nimport { RealTimeChatEvents } from '../types/chat'\n\ninterface ChatListenOptions {\n channels: string[]\n onMessageReceived?: (message: ChatMessage) => unknown\n onMemberJoined?: (member: ChatMember) => unknown\n onMemberUpdated?: (member: ChatMember) => unknown\n onMemberLeft?: (member: ChatMember) => unknown\n}\n\ntype ChatListenersKeys = keyof Omit<ChatListenOptions, 'channels' | 'topics'>\n\nexport class Chat extends ChatCore.applyCommonMethods(\n BaseChat<ChatListenOptions, RealTimeChatEvents>\n) {\n protected _eventMap: Record<ChatListenersKeys, ChatEvents> = {\n onMessageReceived: 'chat.message',\n onMemberJoined: 'chat.member.joined',\n onMemberUpdated: 'chat.member.updated',\n onMemberLeft: 'chat.member.left',\n }\n\n constructor(options: SWClient) {\n super(options)\n\n this._client.runWorker('chatWorker', {\n worker: chatWorker,\n initialState: {\n chat: this,\n },\n })\n }\n}\n\nexport { ChatMember, ChatMessage } from '@signalwire/core'\nexport type {\n ChatAction,\n ChatChannel,\n ChatChannelMessageEvent,\n ChatChannelMessageEventParams,\n ChatChannelState,\n ChatEvent,\n ChatGetMembersParams,\n ChatGetMemberStateParams,\n ChatGetMessagesParams,\n ChatMemberContract,\n ChatMemberEntity,\n ChatMemberJoinedEvent,\n ChatMemberJoinedEventParams,\n ChatMemberLeftEvent,\n ChatMemberLeftEventParams,\n ChatMemberUpdatedEvent,\n ChatMemberUpdatedEventParams,\n ChatMessageContract,\n ChatMessageEntity,\n ChatSetMemberStateParams,\n InternalChatMemberEntity,\n InternalChatMessageEntity,\n InternalPubSubMessageEntity,\n MapToPubSubShape,\n MessagingAction,\n PaginationCursor,\n PubSubAction,\n PubSubChannel,\n PubSubChannelMessageEvent,\n PubSubChannelMessageEventParams,\n PubSubEvent,\n PubSubEventAction,\n PubSubPublishParams,\n} from '@signalwire/core'\n", "import {\n EventEmitter,\n ExecuteParams,\n PubSubPublishParams,\n uuid,\n getLogger,\n} from '@signalwire/core'\nimport { BaseNamespace, Listeners } from '../BaseNamespace'\n\nexport interface BaseChatListenOptions {\n channels: string[]\n}\n\nexport class BaseChat<\n T extends BaseChatListenOptions,\n EventTypes extends EventEmitter.ValidEventTypes\n> extends BaseNamespace<T, EventTypes> {\n protected override onSessionReconnect() {\n this._client.session.once('session.connected', async () => {\n const resendChannels = new Set<string>()\n const resendEvents = new Set<string>()\n\n // Iterate over all active subscriptions.\n for (const { topics, listeners } of this._listenerMap.values()) {\n topics?.forEach((channel) => resendChannels.add(channel))\n // Get the list of events for each subscription.\n Object.keys(listeners).forEach((key) => {\n const _key = key as keyof typeof this._eventMap\n if (this._eventMap[_key]) {\n resendEvents.add(String(this._eventMap[_key]))\n }\n })\n }\n if (resendChannels.size > 0) {\n getLogger().info('Re-subscribing channels after reconnection')\n await this.addChannels([...resendChannels], [...resendEvents])\n }\n })\n }\n\n public listen(listenOptions: T) {\n return new Promise<() => Promise<void>>(async (resolve, reject) => {\n try {\n const { channels } = listenOptions\n if (!Array.isArray(channels) || channels?.length < 1) {\n throw new Error(\n 'Invalid options: channels should be an array with at least one channel!'\n )\n }\n const unsub = await this.subscribe(listenOptions)\n resolve(unsub)\n } catch (error) {\n reject(error)\n }\n })\n }\n\n protected async subscribe(listenOptions: T) {\n const { channels, ...listeners } = listenOptions\n\n const _uuid = uuid()\n\n // Attach listeners\n this._attachListenersWithTopics(channels, listeners as Listeners<T>)\n\n const listenerKeys = Object.keys(listeners)\n const events: string[] = []\n listenerKeys.forEach((key) => {\n const _key = key as keyof Listeners<T>\n if (this._eventMap[_key]) events.push(this._eventMap[_key] as string)\n })\n await this.addChannels(channels, events)\n\n const unsub = () => {\n return new Promise<void>(async (resolve, reject) => {\n try {\n // Remove the channels\n const channelsToRemove = channels.filter(\n (channel) => !this.hasOtherListeners(_uuid, channel)\n )\n if (channelsToRemove.length > 0) {\n await this.removeChannels(channelsToRemove)\n }\n\n // Detach listeners\n this._detachListenersWithTopics(channels, listeners as Listeners<T>)\n\n // Remove channels from the listener map\n this.removeFromListenerMap(_uuid)\n\n resolve()\n } catch (error) {\n reject(error)\n }\n })\n }\n\n // Add channels to the listener map\n this.addToListenerMap(_uuid, {\n topics: new Set([...channels]),\n listeners: listeners as Listeners<T>,\n unsub,\n })\n\n return unsub\n }\n\n private addChannels(channels: string[], events: string[]) {\n return new Promise(async (resolve, reject) => {\n try {\n const execParams: ExecuteParams = {\n method: 'chat.subscribe',\n params: {\n channels: channels.map((channel) => ({\n name: channel,\n })),\n events,\n },\n }\n\n // @TODO: Do not subscribe if the user params are the same\n\n await this._client.execute(execParams)\n resolve(undefined)\n } catch (error) {\n reject(error)\n }\n })\n }\n\n private removeChannels(channels: string[]) {\n return new Promise(async (resolve, reject) => {\n try {\n const execParams: ExecuteParams = {\n method: 'chat.unsubscribe',\n params: {\n channels: channels.map((channel) => ({\n name: channel,\n })),\n },\n }\n\n await this._client.execute(execParams)\n resolve(undefined)\n } catch (error) {\n reject(error)\n }\n })\n }\n\n public publish(params: PubSubPublishParams) {\n return new Promise((resolve, reject) => {\n try {\n const publish = this._client.execute({\n method: 'chat.publish',\n params,\n })\n resolve(publish)\n } catch (error) {\n reject(error)\n }\n })\n }\n}\n", "import { SagaIterator } from '@redux-saga/core'\nimport {\n sagaEffects,\n SDKWorker,\n getLogger,\n ChatAction,\n toExternalJSON,\n ChatMessage,\n ChatMember,\n SDKActions,\n} from '@signalwire/core'\nimport { prefixEvent } from '../../utils/internals'\nimport type { Client } from '../../client/Client'\nimport { Chat } from '../Chat'\n\ninterface ChatWorkerInitialState {\n chat: Chat\n}\n\nexport const chatWorker: SDKWorker<Client> = function* (options): SagaIterator {\n getLogger().trace('chatWorker started')\n const {\n channels: { swEventChannel },\n initialState,\n } = options\n\n const { chat } = initialState as ChatWorkerInitialState\n\n function* worker(action: ChatAction) {\n const { type, payload } = action\n\n switch (type) {\n case 'chat.channel.message': {\n const { channel, message } = payload\n const externalJSON = toExternalJSON({\n ...message,\n channel,\n })\n const chatMessage = new ChatMessage(externalJSON)\n\n // @ts-expect-error\n chat.emit(prefixEvent(channel, 'chat.message'), chatMessage)\n break\n }\n case 'chat.member.joined':\n case 'chat.member.updated':\n case 'chat.member.left': {\n const { member, channel } = payload\n const externalJSON = toExternalJSON(member)\n const chatMember = new ChatMember(externalJSON)\n\n // @ts-expect-error\n chat.emit(prefixEvent(channel, type), chatMember)\n break\n }\n default:\n getLogger().warn(`Unknown chat event: \"${type}\"`, payload)\n break\n }\n }\n\n const isChatEvent = (action: SDKActions) => action.type.startsWith('chat.')\n\n while (true) {\n const action: ChatAction = yield sagaEffects.take(\n swEventChannel,\n isChatEvent\n )\n\n yield sagaEffects.fork(worker, action)\n }\n\n getLogger().trace('chatWorker ended')\n}\n", "import {\n PubSubMessageEventName,\n PubSubNamespace,\n PubSubMessage,\n} from '@signalwire/core'\nimport { SWClient } from '../SWClient'\nimport { pubSubWorker } from './workers'\nimport { BaseChat } from '../chat/BaseChat'\nimport { RealTimePubSubEvents } from '../types/pubSub'\n\ninterface PubSubListenOptions {\n channels: string[]\n onMessageReceived?: (message: PubSubMessage) => unknown\n}\n\ntype PubSubListenersKeys = keyof Omit<\n PubSubListenOptions,\n 'channels' | 'topics'\n>\n\nexport class PubSub extends BaseChat<\n PubSubListenOptions,\n RealTimePubSubEvents\n> {\n protected _eventMap: Record<\n PubSubListenersKeys,\n `${PubSubNamespace}.${PubSubMessageEventName}`\n > = {\n onMessageReceived: 'chat.message',\n }\n\n constructor(options: SWClient) {\n super(options)\n\n this._client.runWorker('pubSubWorker', {\n worker: pubSubWorker,\n initialState: {\n pubSub: this,\n },\n })\n }\n}\n\nexport type { PubSubMessageContract } from '@signalwire/core'\n", "import { SagaIterator } from '@redux-saga/core'\nimport {\n sagaEffects,\n PubSubEventAction,\n SDKWorker,\n getLogger,\n PubSubMessage,\n toExternalJSON,\n} from '@signalwire/core'\nimport { prefixEvent } from '../../utils/internals'\nimport type { Client } from '../../client/Client'\nimport { PubSub } from '../PubSub'\n\ninterface PubSubWorkerInitialState {\n pubSub: PubSub\n}\n\nexport const pubSubWorker: SDKWorker<Client> = function* (\n options\n): SagaIterator {\n getLogger().trace('pubSubWorker started')\n const {\n channels: { swEventChannel },\n initialState,\n } = options\n\n const { pubSub } = initialState as PubSubWorkerInitialState\n\n function* worker(action: PubSubEventAction) {\n const { type, payload } = action\n\n switch (type) {\n case 'chat.channel.message': {\n const {\n channel,\n /**\n * Since we're using the same event as `Chat`\n * the payload comes with a `member` prop. To\n * avoid confusion (since `PubSub` doesn't\n * have members) we'll remove it from the\n * payload sent to the end user.\n */\n // @ts-expect-error\n message: { member, ...restMessage },\n } = payload\n const externalJSON = toExternalJSON({\n ...restMessage,\n channel,\n })\n const pubSubMessage = new PubSubMessage(externalJSON)\n\n // @ts-expect-error\n pubSub.emit(prefixEvent(channel, 'chat.message'), pubSubMessage)\n break\n }\n default:\n getLogger().warn(`Unknown pubsub event: \"${type}\"`, payload)\n break\n }\n }\n\n const isPubSubEvent = (action: any) => action.type.startsWith('chat.')\n\n while (true) {\n const action: PubSubEventAction = yield sagaEffects.take(\n swEventChannel,\n isPubSubEvent\n )\n\n yield sagaEffects.fork(worker, action)\n }\n\n getLogger().trace('pubSubWorker ended')\n}\n", "import { request } from 'node:https'\nimport {\n TaskInboundEvent,\n TaskReceivedEventName,\n getLogger,\n} from '@signalwire/core'\nimport { SWClient } from '../SWClient'\nimport { taskWorker } from './workers'\nimport { BaseNamespace } from '../BaseNamespace'\n\nexport const PATH = '/api/relay/rest/tasks'\nconst HOST = 'relay.signalwire.com'\n\ninterface TaskListenOptions {\n topics: string[]\n onTaskReceived?: (payload: TaskInboundEvent['message']) => unknown\n}\n\ntype TaskListenersKeys = keyof Omit<TaskListenOptions, 'topics'>\n\ntype TaskEvents = Record<\n TaskReceivedEventName,\n (task: TaskInboundEvent['message']) => void\n>\n\nexport class Task extends BaseNamespace<TaskListenOptions, TaskEvents> {\n protected _eventMap: Record<TaskListenersKeys, TaskReceivedEventName> = {\n onTaskReceived: 'task.received',\n }\n\n constructor(options: SWClient) {\n super(options)\n\n this._client.runWorker('taskWorker', {\n worker: taskWorker,\n initialState: {\n task: this,\n },\n })\n }\n\n send({\n topic,\n message,\n }: {\n topic: string\n message: Record<string, unknown>\n }) {\n const { userOptions } = this._sw\n if (!userOptions.project || !userOptions.token) {\n throw new Error('Invalid options: project and token are required!')\n }\n return new Promise<void>((resolve, reject) => {\n try {\n const Authorization = `Basic ${Buffer.from(\n `${userOptions.project}:${userOptions.token}`\n ).toString('base64')}`\n\n const data = JSON.stringify({ context: topic, message })\n const options = {\n host: userOptions.host ?? HOST,\n port: 443,\n method: 'POST',\n path: PATH,\n headers: {\n Authorization,\n 'Content-Type': 'application/json',\n 'Content-Length': data.length,\n },\n }\n\n getLogger().debug('Task send -', data)\n const req = request(options, ({ statusCode }) => {\n statusCode === 204 ? resolve() : reject()\n })\n\n req.on('error', reject)\n\n req.write(data)\n req.end()\n } catch (error) {\n reject(error)\n }\n })\n }\n}\n\nexport type { TaskReceivedEventName } from '@signalwire/core'\nexport type {\n TaskClientApiEvents,\n RealTimeTaskApiEventsHandlerMapping,\n} from '../types'\n", "import {\n getLogger,\n sagaEffects,\n SagaIterator,\n SDKWorker,\n SDKActions,\n TaskAction,\n} from '@signalwire/core'\nimport { prefixEvent } from '../../utils/internals'\nimport type { Client } from '../../client/Client'\nimport { Task } from '../Task'\n\ninterface TaskWorkerInitialState {\n task: Task\n}\n\nexport const taskWorker: SDKWorker<Client> = function* (options): SagaIterator {\n getLogger().trace('taskWorker started')\n const {\n channels: { swEventChannel },\n initialState,\n } = options\n\n const { task } = initialState as TaskWorkerInitialState\n\n function* worker(action: TaskAction) {\n const { context } = action.payload\n\n // @ts-expect-error\n task.emit(prefixEvent(context, 'task.received'), action.payload.message)\n }\n\n const isTaskEvent = (action: SDKActions) =>\n action.type === 'queuing.relay.tasks'\n\n while (true) {\n const action = yield sagaEffects.take(swEventChannel, isTaskEvent)\n\n yield sagaEffects.fork(worker, action)\n }\n\n getLogger().trace('taskWorker ended')\n}\n", "import { toExternalJSON, uuid } from '@signalwire/core'\nimport type {\n ToExternalJSONResult,\n CallingCallDialFailedEventParams,\n} from '@signalwire/core'\nimport { Call } from './Call'\nimport { voiceCallReceiveWorker, voiceCallDialWorker } from './workers'\nimport { DeviceBuilder } from './DeviceBuilder'\nimport type {\n VoiceDialMethodParams,\n VoiceDialPhonelMethodParams,\n VoiceDialSipMethodParams,\n VoiceEvents,\n VoiceListeners,\n VoiceListenersEventsMapping,\n} from '../types'\nimport { toInternalDevices } from './utils'\nimport { BaseNamespace } from '../BaseNamespace'\nimport { SWClient } from '../SWClient'\n\ninterface VoiceListenOptions extends VoiceListeners {\n topics: string[]\n}\n\nexport class Voice extends BaseNamespace<VoiceListenOptions, VoiceEvents> {\n protected _eventMap: VoiceListenersEventsMapping = {\n onCallReceived: 'call.received',\n }\n\n constructor(options: SWClient) {\n super(options)\n\n this._client.runWorker('voiceCallReceiveWorker', {\n worker: voiceCallReceiveWorker,\n initialState: {\n voice: this,\n },\n })\n }\n\n dial(params: VoiceDialMethodParams) {\n return new Promise<Call>((resolve, reject) => {\n const _tag = uuid()\n\n this._client.runWorker('voiceCallDialWorker', {\n worker: voiceCallDialWorker,\n initialState: {\n voice: this,\n tag: _tag,\n listeners: params.listen,\n },\n })\n\n const resolveHandler = (call: Call) => {\n // @ts-expect-error\n this.off('dial.failed', rejectHandler)\n resolve(call)\n }\n\n const rejectHandler = (\n error: ToExternalJSONResult<CallingCallDialFailedEventParams>\n ) => {\n // @ts-expect-error\n this.off('dial.answered', resolveHandler)\n reject(toExternalJSON(error))\n }\n\n // @ts-expect-error\n this.once('dial.answered', resolveHandler)\n // @ts-expect-error\n this.once('dial.failed', rejectHandler)\n\n let executeParams: Record<string, any>\n if (params instanceof DeviceBuilder) {\n const { devices } = params\n executeParams = {\n tag: _tag,\n devices: toInternalDevices(devices),\n }\n } else if ('region' in params) {\n const { region, nodeId, devices: deviceBuilder } = params\n executeParams = {\n tag: _tag,\n region,\n node_id: nodeId,\n devices: toInternalDevices(deviceBuilder.devices),\n }\n } else {\n throw new Error('[dial] Invalid input')\n }\n\n this._client\n .execute({\n method: 'calling.dial',\n params: executeParams,\n })\n .catch((e) => {\n reject(e)\n })\n })\n }\n\n dialPhone({\n region,\n maxPricePerMinute,\n nodeId,\n listen,\n ...params\n }: VoiceDialPhonelMethodParams) {\n const devices = new DeviceBuilder().add(DeviceBuilder.Phone(params))\n return this.dial({\n maxPricePerMinute,\n region,\n nodeId,\n devices,\n listen,\n })\n }\n\n dialSip({\n region,\n maxPricePerMinute,\n nodeId,\n listen,\n ...params\n }: VoiceDialSipMethodParams) {\n const devices = new DeviceBuilder().add(DeviceBuilder.Sip(params))\n return this.dial({\n maxPricePerMinute,\n region,\n nodeId,\n devices,\n listen,\n })\n }\n}\n\nexport { Call } from './Call'\nexport { DeviceBuilder }\nexport { Playlist } from './Playlist'\nexport type { CallPlayback } from './CallPlayback'\nexport type { CallPrompt } from './CallPrompt'\nexport type { CallRecording } from './CallRecording'\nexport type { CallTap } from './CallTap'\nexport type {\n CallingCallDirection,\n CallingCallState,\n CallingCallWaitForState,\n ClientEvents,\n CollectDigitsConfig,\n CollectSpeechConfig,\n CreateVoicePlaylistParams,\n NestedArray,\n RingtoneName,\n SipCodec,\n SipHeader,\n SpeechOrDigits,\n TapDevice,\n TapDeviceRTP,\n TapDeviceWS,\n TapDirection,\n VoiceCallConnectMethodParams,\n VoiceCallConnectPhoneMethodParams,\n VoiceCallConnectSipMethodParams,\n VoiceCallContract,\n VoiceCallDetectContract,\n VoiceCallDetectDigitParams,\n VoiceCallDetectFaxParams,\n VoiceCallDetectMachineParams,\n VoiceCallDetectMethodParams,\n VoiceCallCollectContract,\n VoiceCallCollectMethodParams,\n VoiceCallDeviceParams,\n VoiceCallDialPhoneMethodParams,\n VoiceCallDialRegionParams,\n VoiceCallDialSipMethodParams,\n VoiceCallDisconnectReason,\n VoiceCallPhoneParams,\n VoiceCallPlayAudioMethodParams,\n VoiceCallPlayAudioParams,\n VoiceCallPlaybackContract,\n VoiceCallPlayParams,\n VoiceCallPlayRingtoneMethodParams,\n VoiceCallPlayRingtoneParams,\n VoiceCallPlaySilenceMethodParams,\n VoiceCallPlaySilenceParams,\n VoiceCallPlayTTSMethodParams,\n VoiceCallPlayTTSParams,\n VoiceCallPromptAudioMethodParams,\n VoiceCallPromptContract,\n VoiceCallPromptMethodParams,\n VoiceCallPromptRingtoneMethodParams,\n VoiceCallPromptTTSMethodParams,\n VoiceCallRecordingContract,\n VoiceCallRecordMethodParams,\n VoiceCallSipParams,\n VoiceCallTapAudioMethodParams,\n VoiceCallTapContract,\n VoiceCallTapMethodParams,\n VoiceDeviceBuilder,\n VoiceDialerParams,\n VoicePlaylist,\n} from '@signalwire/core'\nexport type {\n CallPlayMethodParams,\n CallPlayAudioMethodarams,\n CallPlaySilenceMethodParams,\n CallPlayRingtoneMethodParams,\n CallPlayTTSMethodParams,\n CallRecordMethodParams,\n CallRecordAudioMethodParams,\n CallPromptMethodParams,\n CallPromptAudioMethodParams,\n CallPromptRingtoneMethodParams,\n CallPromptTTSMethodParams,\n CallCollectMethodParams,\n CallTapMethodParams,\n CallTapAudioMethodParams,\n CallDetectMethodParams,\n CallDetectMachineParams,\n CallDetectFaxParams,\n CallDetectDigitParams,\n} from '../types/voice'\n", "import {\n getLogger,\n sagaEffects,\n SagaIterator,\n SDKActions,\n SDKWorker,\n VoiceCallReceiveAction,\n VoiceCallStateAction,\n} from '@signalwire/core'\nimport { prefixEvent } from '../../utils/internals'\nimport type { Client } from '../../client/index'\nimport { Call } from '../Call'\nimport { Voice } from '../Voice'\nimport { handleCallStateEvents } from './handlers'\n\ninterface VoiceCallReceiveWorkerInitialState {\n voice: Voice\n}\n\nexport const voiceCallReceiveWorker: SDKWorker<Client> = function* (\n options\n): SagaIterator {\n getLogger().trace('voiceCallReceiveWorker started')\n const {\n channels: { swEventChannel },\n instanceMap,\n initialState,\n } = options\n\n const { voice } = initialState as VoiceCallReceiveWorkerInitialState\n\n function* callReceiveWorker(action: VoiceCallReceiveAction) {\n const { get, set } = instanceMap\n const { payload } = action\n\n // Contexts is required\n if (!payload.context || !payload.context.length) {\n throw new Error('Invalid context to receive inbound call')\n }\n\n let callInstance = get<Call>(payload.call_id)\n if (!callInstance) {\n callInstance = new Call({\n voice,\n payload,\n })\n } else {\n callInstance.setPayload(payload)\n }\n\n set<Call>(payload.call_id, callInstance)\n\n // @ts-expect-error\n voice.emit(prefixEvent(payload.context, 'call.received'), callInstance)\n }\n\n function* worker(action: VoiceCallReceiveAction | VoiceCallStateAction) {\n if (action.type === 'calling.call.receive') {\n yield sagaEffects.fork(callReceiveWorker, action)\n } else {\n handleCallStateEvents({\n payload: action.payload,\n voice,\n instanceMap,\n })\n }\n }\n\n while (true) {\n const action = yield sagaEffects.take(\n swEventChannel,\n (action: SDKActions) => {\n return (\n action.type === 'calling.call.receive' ||\n (action.type === 'calling.call.state' &&\n action.payload.direction === 'inbound')\n )\n }\n )\n\n yield sagaEffects.fork(worker, action)\n }\n\n getLogger().trace('voiceCallReceiveWorker ended')\n}\n", "import {\n CallingCallConnectEventParams,\n CallingCall,\n uuid,\n VoiceCallDisconnectReason,\n toSnakeCaseKeys,\n CallingCallWaitForState,\n CallingCallState,\n VoiceCallConnectMethodParams,\n toExternalJSON,\n VoiceCallConnectPhoneMethodParams,\n VoiceCallConnectSipMethodParams,\n CallingCallConnectFailedEventParams,\n} from '@signalwire/core'\nimport { ListenSubscriber } from '../ListenSubscriber'\nimport {\n CallCollectMethodParams,\n CallDetectDigitParams,\n CallDetectFaxParams,\n CallDetectMachineParams,\n CallDetectMethodParams,\n CallPlayAudioMethodarams,\n CallPlayMethodParams,\n CallPlayRingtoneMethodParams,\n CallPlaySilenceMethodParams,\n CallPlayTTSMethodParams,\n CallPromptAudioMethodParams,\n CallPromptMethodParams,\n CallPromptRingtoneMethodParams,\n CallPromptTTSMethodParams,\n CallRecordAudioMethodParams,\n CallRecordMethodParams,\n CallTapAudioMethodParams,\n CallTapMethodParams,\n RealTimeCallEvents,\n RealTimeCallListeners,\n RealtimeCallListenersEventsMapping,\n} from '../types'\nimport { toInternalDevices, toInternalPlayParams } from './utils'\nimport {\n voiceCallCollectWorker,\n voiceCallConnectWorker,\n voiceCallDetectWorker,\n voiceCallPlayWorker,\n voiceCallRecordWorker,\n voiceCallSendDigitsWorker,\n voiceCallTapWorker,\n} from './workers'\nimport { Playlist } from './Playlist'\nimport { Voice } from './Voice'\nimport { CallPlayback, decoratePlaybackPromise } from './CallPlayback'\nimport { CallRecording, decorateRecordingPromise } from './CallRecording'\nimport { CallPrompt, decoratePromptPromise } from './CallPrompt'\nimport { CallCollect, decorateCollectPromise } from './CallCollect'\nimport { CallTap, decorateTapPromise } from './CallTap'\nimport { DeviceBuilder } from './DeviceBuilder'\nimport { CallDetect, decorateDetectPromise } from './CallDetect'\n\ninterface CallOptions {\n voice: Voice\n payload?: CallingCall\n connectPayload?: CallingCallConnectEventParams\n listeners?: RealTimeCallListeners\n}\n\nexport class Call extends ListenSubscriber<\n RealTimeCallListeners,\n RealTimeCallEvents\n> {\n private _voice: Voice\n private _context: string | undefined\n private _peer: Call | undefined\n private _payload: CallingCall | undefined\n private _connectPayload: CallingCallConnectEventParams | undefined\n protected _eventMap: RealtimeCallListenersEventsMapping = {\n onStateChanged: 'call.state',\n onPlaybackStarted: 'playback.started',\n onPlaybackUpdated: 'playback.updated',\n onPlaybackFailed: 'playback.failed',\n onPlaybackEnded: 'playback.ended',\n onRecordingStarted: 'recording.started',\n onRecordingUpdated: 'recording.updated',\n onRecordingFailed: 'recording.failed',\n onRecordingEnded: 'recording.ended',\n onPromptStarted: 'prompt.started',\n onPromptUpdated: 'prompt.updated',\n onPromptFailed: 'prompt.failed',\n onPromptEnded: 'prompt.ended',\n onCollectStarted: 'collect.started',\n onCollectInputStarted: 'collect.startOfInput',\n onCollectUpdated: 'collect.updated',\n onCollectFailed: 'collect.failed',\n onCollectEnded: 'collect.ended',\n onTapStarted: 'tap.started',\n onTapEnded: 'tap.ended',\n onDetectStarted: 'detect.started',\n onDetectUpdated: 'detect.updated',\n onDetectEnded: 'detect.ended',\n }\n\n constructor(options: CallOptions) {\n super({ swClient: options.voice._sw })\n\n this._voice = options.voice\n this._payload = options.payload\n this._context = options.payload?.context\n this._connectPayload = options.connectPayload\n\n if (options.listeners) {\n this.listen(options.listeners)\n }\n }\n\n /** Unique id for this voice call */\n get id() {\n return this._payload?.call_id\n }\n\n get callId() {\n return this._payload?.call_id\n }\n\n get state() {\n return this._payload?.call_state\n }\n\n get callState() {\n return this._payload?.call_state\n }\n\n get tag() {\n return this._payload?.tag\n }\n\n get nodeId() {\n return this._payload?.node_id\n }\n\n get device() {\n return this._payload?.device\n }\n\n /** The type of call. Only phone and sip are currently supported. */\n get type() {\n return this.device?.type ?? ''\n }\n\n /** The phone number that the call is coming from. */\n get from() {\n if (this.type === 'phone') {\n return (\n // @ts-expect-error\n (this.device?.params?.from_number || this.device?.params?.fromNumber) ??\n ''\n )\n }\n return (\n // @ts-expect-error\n this.device?.params?.from ?? ''\n )\n }\n\n /** The phone number you are attempting to call. */\n get to() {\n if (this.type === 'phone') {\n return (\n // @ts-expect-error\n (this.device?.params?.to_number || this.device?.params?.toNumber) ?? ''\n )\n }\n // @ts-expect-error\n return this.device?.params?.to ?? ''\n }\n\n get headers() {\n // @ts-expect-error\n return this.device?.params?.headers ?? []\n }\n\n get active() {\n return this.state === 'answered'\n }\n\n get connected() {\n return this.connectState === 'connected'\n }\n\n get direction() {\n return this._payload?.direction\n }\n\n get context() {\n return this._context\n }\n\n get connectState() {\n return this._connectPayload?.connect_state\n }\n\n get peer() {\n return this._peer\n }\n\n /** @internal */\n set peer(callInstance: Call | undefined) {\n this._peer = callInstance\n }\n\n /** @internal */\n setPayload(payload: CallingCall) {\n this._payload = payload\n }\n\n /** @internal */\n setConnectPayload(payload: CallingCallConnectEventParams) {\n this._connectPayload = payload\n }\n\n /**\n * Hangs up the call.\n * @param reason Optional reason for hanging u