UNPKG

@signalwire/realtime-api

Version:
1,918 lines (1,877 loc) 158 kB
var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __objRest = (source, exclude) => { var target = {}; for (var prop in source) if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0) target[prop] = source[prop]; if (source != null && __getOwnPropSymbols) for (var prop of __getOwnPropSymbols(source)) { if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop)) target[prop] = source[prop]; } return target; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); // src/configure/index.ts var GLOBAL_CONFIG = {}; var getConfig = () => { return GLOBAL_CONFIG; }; var config = (_a) => { var _b = _a, { cache = GLOBAL_CONFIG } = _b, options = __objRest(_b, [ "cache" ]); if (cache) { GLOBAL_CONFIG = cache; } Object.entries(options).forEach(([key, value]) => { GLOBAL_CONFIG[key] = value; }); }; // src/messaging/Messaging.ts var Messaging_exports = {}; __export(Messaging_exports, { Message: () => Message, Messaging: () => Messaging }); import { toExternalJSON } from "@signalwire/core"; // src/BaseNamespace.ts import { getLogger as getLogger3, uuid as uuid2 } from "@signalwire/core"; // src/utils/internals.ts import { configureStore, getEventEmitter } from "@signalwire/core"; // src/Session.ts import { BaseSession, SWCloseEvent } from "@signalwire/core"; import WebSocket from "ws"; var Session = class extends BaseSession { constructor() { super(...arguments); __publicField(this, "WebSocketConstructor", WebSocket); __publicField(this, "CloseEventConstructor", SWCloseEvent); __publicField(this, "agent", "@signalwire/nodejs/realtime-api/4.1.3"); } }; // src/utils/internals.ts var setupInternals = (userOptions) => { const emitter = getEventEmitter(); const baseOptions = __spreadProps(__spreadValues({}, userOptions), { emitter }); const store = configureStore({ userOptions: baseOptions, SessionConstructor: Session }); return { store, emitter }; }; var prefixEvent = (prefix, event) => { if (typeof prefix !== "string" || typeof event !== "string") return event; return `${prefix}.${event}`; }; // src/ListenSubscriber.ts import { EventEmitter, getLogger as getLogger2, uuid } from "@signalwire/core"; var ListenSubscriber = class { constructor(options) { /** @internal */ __publicField(this, "_sw"); __publicField(this, "_client"); __publicField(this, "_listenerMap", /* @__PURE__ */ new Map()); __publicField(this, "_eventMap"); __publicField(this, "_emitter", new EventEmitter()); this._sw = options.swClient; this._client = options.swClient.client; } get emitter() { return this._emitter; } eventNames() { return this.emitter.eventNames(); } /** @internal */ emit(event, ...args) { return this.emitter.emit(event, ...args); } on(event, fn) { return this.emitter.on(event, fn); } once(event, fn) { return this.emitter.once(event, fn); } off(event, fn) { return this.emitter.off(event, fn); } listen(listeners) { return new Promise(async (resolve, reject) => { try { if (!listeners || (listeners == null ? void 0 : listeners.constructor) !== Object || Object.keys(listeners).length < 1) { throw new Error("Invalid params!"); } const unsub = await this.subscribe(listeners); resolve(unsub); } catch (error) { reject(error); } }); } async subscribe(listeners) { const _uuid = uuid(); this._attachListeners(listeners); const unsub = () => { return new Promise(async (resolve, reject) => { try { this._detachListeners(listeners); this.removeFromListenerMap(_uuid); resolve(); } catch (error) { reject(error); } }); }; this.addToListenerMap(_uuid, { listeners, unsub }); return unsub; } _attachListeners(listeners) { const listenerKeys = Object.keys(listeners); listenerKeys.forEach((key) => { if (typeof listeners[key] === "function" && this._eventMap[key]) { this.on(this._eventMap[key], listeners[key]); } else { getLogger2().warn(`Unsupported listener: ${listeners[key]}`); } }); } _detachListeners(listeners) { const listenerKeys = Object.keys(listeners); listenerKeys.forEach((key) => { if (typeof listeners[key] === "function" && this._eventMap[key]) { this.off(this._eventMap[key], listeners[key]); } }); } addToListenerMap(id, value) { return this._listenerMap.set(id, value); } removeFromListenerMap(id) { return this._listenerMap.delete(id); } }; // src/BaseNamespace.ts var BaseNamespace = class extends ListenSubscriber { constructor(options) { super({ swClient: options }); this.onSessionReconnect = this.onSessionReconnect.bind(this); this.onSessionDisconnect = this.onSessionDisconnect.bind(this); this._client.session.on("session.reconnecting", this.onSessionReconnect); this._client.session.once("session.disconnected", this.onSessionDisconnect); } onSessionReconnect() { this._client.session.once("session.connected", async () => { const resendTopics = /* @__PURE__ */ new Set(); for (const { topics } of this._listenerMap.values()) { topics == null ? void 0 : topics.forEach((topic) => resendTopics.add(topic)); } if (resendTopics.size > 0) { getLogger3().info("Re-subscribing topics after reconnection"); await this.addTopics([...resendTopics]); } }); } onSessionDisconnect() { this._client.session.off("session.reconnecting", this.onSessionReconnect); this._client.destroy(); } addTopics(topics) { const executeParams = { method: "signalwire.receive", params: { contexts: topics } }; return this._client.execute(executeParams); } removeTopics(topics) { const executeParams = { method: "signalwire.unreceive", params: { contexts: topics } }; return this._client.execute(executeParams); } listen(listenOptions) { return new Promise(async (resolve, reject) => { try { const { topics } = listenOptions; if (!Array.isArray(topics) || (topics == null ? void 0 : topics.length) < 1) { throw new Error( "Invalid options: topics should be an array with at least one topic!" ); } const unsub = await this.subscribe(listenOptions); resolve(unsub); } catch (error) { reject(error); } }); } async subscribe(listenOptions) { const _a = listenOptions, { topics } = _a, listeners = __objRest(_a, ["topics"]); const _uuid = uuid2(); this._attachListenersWithTopics(topics, listeners); await this.addTopics(topics); const unsub = () => { return new Promise(async (resolve, reject) => { try { this._detachListenersWithTopics(topics, listeners); this.removeFromListenerMap(_uuid); const topicsToRemove = topics.filter( (topic) => !this.hasOtherListeners(_uuid, topic) ); if (topicsToRemove.length > 0) { await this.removeTopics(topicsToRemove); } resolve(); } catch (error) { reject(error); } }); }; this.addToListenerMap(_uuid, { topics: /* @__PURE__ */ new Set([...topics]), listeners, unsub }); return unsub; } _attachListenersWithTopics(topics, listeners) { const listenerKeys = Object.keys(listeners); topics.forEach((topic) => { listenerKeys.forEach((key) => { const _key = key; if (typeof listeners[_key] === "function" && this._eventMap[_key]) { const event = prefixEvent(topic, this._eventMap[_key]); this.on(event, listeners[_key]); } }); }); } _areListenersAttached(topics, listeners) { return topics.every( (topic) => Object.entries(listeners).every(([key, listener]) => { const event = prefixEvent( topic, this._eventMap[key] ); return this.emitter.listeners(event).includes(listener); }) ); } _detachListenersWithTopics(topics, listeners) { const listenerKeys = Object.keys(listeners); topics.forEach((topic) => { listenerKeys.forEach((key) => { const _key = key; if (typeof listeners[_key] === "function" && this._eventMap[_key]) { const event = prefixEvent(topic, this._eventMap[_key]); this.off(event, listeners[_key]); } }); }); } hasOtherListeners(uuid7, topic) { var _a; for (const [key, listener] of this._listenerMap) { if (key !== uuid7 && ((_a = listener.topics) == null ? void 0 : _a.has(topic))) { return true; } } return false; } async unsubscribeAll() { await Promise.all( [...this._listenerMap.values()].map(({ unsub }) => unsub()) ); this._listenerMap.clear(); } }; // src/messaging/workers/messagingWorker.ts import { getLogger as getLogger4, sagaEffects } from "@signalwire/core"; var messagingWorker = function* (options) { getLogger4().trace("messagingWorker started"); const { channels: { swEventChannel }, initialState } = options; const { messaging } = initialState; function* worker(action) { const { payload, type } = action; const message = new Message(payload); switch (type) { case "messaging.receive": messaging.emit( // @ts-expect-error prefixEvent(payload.context, "message.received"), message ); break; case "messaging.state": messaging.emit(prefixEvent(payload.context, "message.updated"), message); break; default: getLogger4().warn(`Unknown message event: "${action.type}"`); break; } } const isMessagingEvent = (action) => action.type.startsWith("messaging."); while (true) { const action = yield sagaEffects.take( swEventChannel, isMessagingEvent ); yield sagaEffects.fork(worker, action); } getLogger4().trace("messagingWorker ended"); }; // src/messaging/Message.ts var Message = class { constructor(options) { __publicField(this, "id"); __publicField(this, "state"); __publicField(this, "context"); __publicField(this, "from"); __publicField(this, "to"); __publicField(this, "body"); __publicField(this, "direction"); __publicField(this, "media"); __publicField(this, "segments"); __publicField(this, "tags"); __publicField(this, "reason"); this.id = options.message_id; this.state = options.message_state; this.context = options.context; this.from = options.from_number; this.to = options.to_number; this.body = options.body; this.direction = options.direction; this.media = options.media || []; this.segments = options.segments; this.tags = options.tags || []; this.reason = options.reason; } }; // src/messaging/Messaging.ts var Messaging = class extends BaseNamespace { constructor(options) { super(options); __publicField(this, "_eventMap", { onMessageReceived: "message.received", onMessageUpdated: "message.updated" }); this._client.runWorker("messagingWorker", { worker: messagingWorker, initialState: { messaging: this } }); } async send(params) { const _a = params, { from = "", to = "" } = _a, rest = __objRest(_a, ["from", "to"]); const sendParams = __spreadProps(__spreadValues({}, rest), { from_number: from, to_number: to }); try { const response = await this._client.execute( { method: "messaging.send", params: sendParams } ); return toExternalJSON(response); } catch (error) { this._client.logger.error("Error sending message", error); throw error; } } }; // src/chat/Chat.ts var Chat_exports = {}; __export(Chat_exports, { Chat: () => Chat, ChatMember: () => ChatMember3, ChatMessage: () => ChatMessage3 }); import { Chat as ChatCore } from "@signalwire/core"; // src/chat/BaseChat.ts import { uuid as uuid3, getLogger as getLogger5 } from "@signalwire/core"; var BaseChat = class extends BaseNamespace { onSessionReconnect() { this._client.session.once("session.connected", async () => { const resendChannels = /* @__PURE__ */ new Set(); const resendEvents = /* @__PURE__ */ new Set(); for (const { topics, listeners } of this._listenerMap.values()) { topics == null ? void 0 : topics.forEach((channel) => resendChannels.add(channel)); Object.keys(listeners).forEach((key) => { const _key = key; if (this._eventMap[_key]) { resendEvents.add(String(this._eventMap[_key])); } }); } if (resendChannels.size > 0) { getLogger5().info("Re-subscribing channels after reconnection"); await this.addChannels([...resendChannels], [...resendEvents]); } }); } listen(listenOptions) { return new Promise(async (resolve, reject) => { try { const { channels } = listenOptions; if (!Array.isArray(channels) || (channels == null ? void 0 : channels.length) < 1) { throw new Error( "Invalid options: channels should be an array with at least one channel!" ); } const unsub = await this.subscribe(listenOptions); resolve(unsub); } catch (error) { reject(error); } }); } async subscribe(listenOptions) { const _a = listenOptions, { channels } = _a, listeners = __objRest(_a, ["channels"]); const _uuid = uuid3(); this._attachListenersWithTopics(channels, listeners); const listenerKeys = Object.keys(listeners); const events = []; listenerKeys.forEach((key) => { const _key = key; if (this._eventMap[_key]) events.push(this._eventMap[_key]); }); await this.addChannels(channels, events); const unsub = () => { return new Promise(async (resolve, reject) => { try { const channelsToRemove = channels.filter( (channel) => !this.hasOtherListeners(_uuid, channel) ); if (channelsToRemove.length > 0) { await this.removeChannels(channelsToRemove); } this._detachListenersWithTopics(channels, listeners); this.removeFromListenerMap(_uuid); resolve(); } catch (error) { reject(error); } }); }; this.addToListenerMap(_uuid, { topics: /* @__PURE__ */ new Set([...channels]), listeners, unsub }); return unsub; } addChannels(channels, events) { return new Promise(async (resolve, reject) => { try { const execParams = { method: "chat.subscribe", params: { channels: channels.map((channel) => ({ name: channel })), events } }; await this._client.execute(execParams); resolve(void 0); } catch (error) { reject(error); } }); } removeChannels(channels) { return new Promise(async (resolve, reject) => { try { const execParams = { method: "chat.unsubscribe", params: { channels: channels.map((channel) => ({ name: channel })) } }; await this._client.execute(execParams); resolve(void 0); } catch (error) { reject(error); } }); } publish(params) { return new Promise((resolve, reject) => { try { const publish = this._client.execute({ method: "chat.publish", params }); resolve(publish); } catch (error) { reject(error); } }); } }; // src/chat/workers/chatWorker.ts import { sagaEffects as sagaEffects2, getLogger as getLogger6, toExternalJSON as toExternalJSON2, ChatMessage, ChatMember } from "@signalwire/core"; var chatWorker = function* (options) { getLogger6().trace("chatWorker started"); const { channels: { swEventChannel }, initialState } = options; const { chat } = initialState; function* worker(action) { const { type, payload } = action; switch (type) { case "chat.channel.message": { const { channel, message } = payload; const externalJSON = toExternalJSON2(__spreadProps(__spreadValues({}, message), { channel })); const chatMessage = new ChatMessage(externalJSON); chat.emit(prefixEvent(channel, "chat.message"), chatMessage); break; } case "chat.member.joined": case "chat.member.updated": case "chat.member.left": { const { member, channel } = payload; const externalJSON = toExternalJSON2(member); const chatMember = new ChatMember(externalJSON); chat.emit(prefixEvent(channel, type), chatMember); break; } default: getLogger6().warn(`Unknown chat event: "${type}"`, payload); break; } } const isChatEvent = (action) => action.type.startsWith("chat."); while (true) { const action = yield sagaEffects2.take( swEventChannel, isChatEvent ); yield sagaEffects2.fork(worker, action); } getLogger6().trace("chatWorker ended"); }; // src/chat/Chat.ts import { ChatMember as ChatMember3, ChatMessage as ChatMessage3 } from "@signalwire/core"; var Chat = class extends ChatCore.applyCommonMethods( BaseChat ) { constructor(options) { super(options); __publicField(this, "_eventMap", { onMessageReceived: "chat.message", onMemberJoined: "chat.member.joined", onMemberUpdated: "chat.member.updated", onMemberLeft: "chat.member.left" }); this._client.runWorker("chatWorker", { worker: chatWorker, initialState: { chat: this } }); } }; // src/pubSub/PubSub.ts var PubSub_exports = {}; __export(PubSub_exports, { PubSub: () => PubSub }); // src/pubSub/workers/pubSubWorker.ts import { sagaEffects as sagaEffects3, getLogger as getLogger7, PubSubMessage, toExternalJSON as toExternalJSON3 } from "@signalwire/core"; var pubSubWorker = function* (options) { getLogger7().trace("pubSubWorker started"); const { channels: { swEventChannel }, initialState } = options; const { pubSub } = initialState; function* worker(action) { const { type, payload } = action; switch (type) { case "chat.channel.message": { const { channel, message: _a } = payload, _b = _a, { member } = _b, restMessage = __objRest(_b, ["member"]); const externalJSON = toExternalJSON3(__spreadProps(__spreadValues({}, restMessage), { channel })); const pubSubMessage = new PubSubMessage(externalJSON); pubSub.emit(prefixEvent(channel, "chat.message"), pubSubMessage); break; } default: getLogger7().warn(`Unknown pubsub event: "${type}"`, payload); break; } } const isPubSubEvent = (action) => action.type.startsWith("chat."); while (true) { const action = yield sagaEffects3.take( swEventChannel, isPubSubEvent ); yield sagaEffects3.fork(worker, action); } getLogger7().trace("pubSubWorker ended"); }; // src/pubSub/PubSub.ts var PubSub = class extends BaseChat { constructor(options) { super(options); __publicField(this, "_eventMap", { onMessageReceived: "chat.message" }); this._client.runWorker("pubSubWorker", { worker: pubSubWorker, initialState: { pubSub: this } }); } }; // src/task/Task.ts var Task_exports = {}; __export(Task_exports, { PATH: () => PATH, Task: () => Task }); import { request } from "node:https"; import { getLogger as getLogger9 } from "@signalwire/core"; // src/task/workers/taskWorker.ts import { getLogger as getLogger8, sagaEffects as sagaEffects4 } from "@signalwire/core"; var taskWorker = function* (options) { getLogger8().trace("taskWorker started"); const { channels: { swEventChannel }, initialState } = options; const { task } = initialState; function* worker(action) { const { context } = action.payload; task.emit(prefixEvent(context, "task.received"), action.payload.message); } const isTaskEvent = (action) => action.type === "queuing.relay.tasks"; while (true) { const action = yield sagaEffects4.take(swEventChannel, isTaskEvent); yield sagaEffects4.fork(worker, action); } getLogger8().trace("taskWorker ended"); }; // src/task/Task.ts var PATH = "/api/relay/rest/tasks"; var HOST = "relay.signalwire.com"; var Task = class extends BaseNamespace { constructor(options) { super(options); __publicField(this, "_eventMap", { onTaskReceived: "task.received" }); this._client.runWorker("taskWorker", { worker: taskWorker, initialState: { task: this } }); } send({ topic, message }) { const { userOptions } = this._sw; if (!userOptions.project || !userOptions.token) { throw new Error("Invalid options: project and token are required!"); } return new Promise((resolve, reject) => { var _a; try { const Authorization = `Basic ${Buffer.from( `${userOptions.project}:${userOptions.token}` ).toString("base64")}`; const data = JSON.stringify({ context: topic, message }); const options = { host: (_a = userOptions.host) != null ? _a : HOST, port: 443, method: "POST", path: PATH, headers: { Authorization, "Content-Type": "application/json", "Content-Length": data.length } }; getLogger9().debug("Task send -", data); const req = request(options, ({ statusCode }) => { statusCode === 204 ? resolve() : reject(); }); req.on("error", reject); req.write(data); req.end(); } catch (error) { reject(error); } }); } }; // src/voice/Voice.ts var Voice_exports = {}; __export(Voice_exports, { Call: () => Call, DeviceBuilder: () => DeviceBuilder, Playlist: () => Playlist, Voice: () => Voice }); import { toExternalJSON as toExternalJSON5, uuid as uuid5 } from "@signalwire/core"; // src/voice/workers/voiceCallReceiveWorker.ts import { getLogger as getLogger10, sagaEffects as sagaEffects5 } from "@signalwire/core"; // src/voice/Call.ts import { uuid as uuid4, toSnakeCaseKeys as toSnakeCaseKeys2, toExternalJSON as toExternalJSON4 } from "@signalwire/core"; // src/voice/utils.ts import { toSnakeCaseKeys } from "@signalwire/core"; var toInternalDevice = (device) => { switch (device.type) { case "sip": { const _a = device, { type } = _a, params = __objRest(_a, ["type"]); return { type, params: toSnakeCaseKeys(params) }; } case "phone": { const _b = device, { to, from, type } = _b, rest = __objRest(_b, ["to", "from", "type"]); return { type, params: toSnakeCaseKeys(__spreadProps(__spreadValues({}, rest), { to_number: to, from_number: from })) }; } } return device; }; var toInternalDevices = (params, internalDevices = []) => { params.forEach((dev, index) => { if (Array.isArray(dev)) { internalDevices[index] = toInternalDevices(dev); } else { internalDevices[index] = toInternalDevice(dev); } }); return internalDevices; }; var toInternalPlay = (media) => { const _a = media, { type } = _a, params = __objRest(_a, ["type"]); return { type, params }; }; var toInternalPlayParams = (params, result = []) => { params.forEach((media, index) => { if (Array.isArray(media)) { result[index] = toInternalPlayParams(media); } else { result[index] = toInternalPlay(media); } }); return result; }; // src/voice/Playlist.ts var Playlist = class { constructor(params = {}) { this.params = params; __publicField(this, "_media", []); } /** Default volume for the audio in the playlist. */ get volume() { var _a; return (_a = this.params) == null ? void 0 : _a.volume; } /** The media in this playlist. */ get media() { return this._media; } /** Adds a new media to the playlist*/ add(params) { this._media.push(params); return this; } /** * An audio media. * @params params - {@link VoicePlaylistAudioParams} * @returns - {@link VoiceCallPlayAudioParams} **/ static Audio(params) { return __spreadValues({ type: "audio" }, params); } /** * A TTS media. * @params params - {@link VoicePlaylistTTSParams} * @returns - {@link VoiceCallPlayTTSParams} **/ static TTS(params) { return __spreadValues({ type: "tts" }, params); } /** * A silence interval. * @params params - {@link VoicePlaylistSilenceParams} * @returns - {@link VoiceCallPlaySilenceParams} **/ static Silence(params) { return __spreadValues({ type: "silence" }, params); } /** * A ringtone media. * @params param - {@link VoicePlaylistRingtoneParams} * @returns - {@link VoiceCallPlayRingtoneParams} **/ static Ringtone(params) { return __spreadValues({ type: "ringtone" }, params); } }; // src/voice/CallPlayback/CallPlayback.ts var ENDED_STATES = ["finished", "error"]; var CallPlayback = class extends ListenSubscriber { constructor(options) { super({ swClient: options.call._sw }); __publicField(this, "_paused"); __publicField(this, "_volume"); __publicField(this, "_payload"); __publicField(this, "_eventMap", { onStarted: "playback.started", onUpdated: "playback.updated", onFailed: "playback.failed", onEnded: "playback.ended" }); this._payload = options.payload; this._paused = false; if (options.listeners) { this.listen(options.listeners); } } get id() { var _a; return (_a = this._payload) == null ? void 0 : _a.control_id.split(".")[0]; } get volume() { return this._volume; } get callId() { var _a; return (_a = this._payload) == null ? void 0 : _a.call_id; } get nodeId() { var _a; return (_a = this._payload) == null ? void 0 : _a.node_id; } get controlId() { var _a; return (_a = this._payload) == null ? void 0 : _a.control_id; } get state() { var _a; return (_a = this._payload) == null ? void 0 : _a.state; } get hasEnded() { if (ENDED_STATES.includes(this.state)) { return true; } return false; } /** @internal */ setPayload(payload) { this._payload = payload; } async pause() { if (this.hasEnded) { throw new Error("Action has ended"); } await this._client.execute({ method: "calling.play.pause", params: { node_id: this.nodeId, call_id: this.callId, control_id: this.controlId } }); return this; } async resume() { if (this.hasEnded) { throw new Error("Action has ended"); } await this._client.execute({ method: "calling.play.resume", params: { node_id: this.nodeId, call_id: this.callId, control_id: this.controlId } }); return this; } async stop() { if (this.hasEnded) { throw new Error("Action has ended"); } await this._client.execute({ method: "calling.play.stop", params: { node_id: this.nodeId, call_id: this.callId, control_id: this.controlId } }); return this; } async setVolume(volume) { if (this.hasEnded) { throw new Error("Action has ended"); } this._volume = volume; await this._client.execute({ method: "calling.play.volume", params: { node_id: this.nodeId, call_id: this.callId, control_id: this.controlId, volume } }); return this; } /** @deprecated */ waitForEnded() { return this.ended(); } ended() { return new Promise((resolve) => { const handler = () => { this.off("playback.ended", handler); this.off("playback.failed", handler); resolve(this); }; this.once("playback.ended", handler); this.once("playback.failed", handler); if (this.hasEnded) { handler(); } }); } }; // src/decoratePromise.ts function decoratePromise(options) { const { promise: innerPromise, namespace, methods: methods10, getters: getters10 } = options; const promise = new Promise((resolve, reject) => { const endedHandler = (instance) => { this.off(`${namespace}.ended`, endedHandler); resolve(instance); }; this.once(`${namespace}.ended`, endedHandler); innerPromise.catch((error) => { this.off(`${namespace}.ended`, endedHandler); reject(error); }); }); Object.defineProperties(promise, __spreadValues(__spreadValues({ onStarted: { value: function() { return new Promise((resolve, reject) => { promise.catch(reject); innerPromise.then(resolve).catch(reject); }); }, enumerable: true }, onEnded: { value: async function() { const instance = await this.onStarted(); if (instance.hasEnded) { return this; } return await promise; }, enumerable: true }, listen: { value: async function(...args) { const instance = await this.onStarted(); return instance.listen(...args); }, enumerable: true } }, methods10.reduce((acc, method) => { acc[method] = { value: async function(...args) { const instance = await this.onStarted(); return instance[method](...args); }, enumerable: true }; return acc; }, {})), getters10.reduce((acc, gettter) => { acc[gettter] = { get: async function() { const instance = await this.onStarted(); return instance[gettter]; }, enumerable: true }; return acc; }, {}))); return promise; } // src/voice/CallPlayback/decoratePlaybackPromise.ts var getters = [ "id", "volume", "callId", "nodeId", "controlId", "state" ]; var methods = ["pause", "resume", "stop", "setVolume", "ended"]; function decoratePlaybackPromise(innerPromise) { return decoratePromise.call(this, { promise: innerPromise, namespace: "playback", methods, getters }); } // src/voice/CallRecording/CallRecording.ts var ENDED_STATES2 = ["finished", "no_input"]; var CallRecording = class extends ListenSubscriber { constructor(options) { super({ swClient: options.call._sw }); __publicField(this, "_paused"); __publicField(this, "_payload"); __publicField(this, "_eventMap", { onStarted: "recording.started", onUpdated: "recording.updated", onFailed: "recording.failed", onEnded: "recording.ended" }); this._payload = options.payload; this._paused = false; if (options.listeners) { this.listen(options.listeners); } } get id() { return this._payload.control_id; } get callId() { return this._payload.call_id; } get nodeId() { return this._payload.node_id; } get controlId() { return this._payload.control_id; } get state() { return this._payload.state; } get url() { return this._payload.url; } get size() { return this._payload.size; } get duration() { return this._payload.duration; } get record() { return this._payload.record; } get hasEnded() { if (ENDED_STATES2.includes(this.state)) { return true; } return false; } /** @internal */ setPayload(payload) { this._payload = payload; } async pause(params) { if (this.hasEnded) { throw new Error("Action has ended"); } const { behavior = "silence" } = params || {}; await this._client.execute({ method: "calling.record.pause", params: { node_id: this.nodeId, call_id: this.callId, control_id: this.controlId, behavior } }); return this; } async resume() { if (this.hasEnded) { throw new Error("Action has ended"); } await this._client.execute({ method: "calling.record.resume", params: { node_id: this.nodeId, call_id: this.callId, control_id: this.controlId } }); return this; } async stop() { if (this.hasEnded) { throw new Error("Action has ended"); } await this._client.execute({ method: "calling.record.stop", params: { node_id: this.nodeId, call_id: this.callId, control_id: this.controlId } }); return this; } ended() { return new Promise((resolve) => { const handler = () => { this.off("recording.ended", handler); this.off("recording.failed", handler); resolve(this); }; this.once("recording.ended", handler); this.once("recording.failed", handler); if (this.hasEnded) { handler(); } }); } }; // src/voice/CallRecording/decorateRecordingPromise.ts var getters2 = [ "id", "callId", "nodeId", "controlId", "state", "url", "size", "duration", "record" ]; var methods2 = ["pause", "resume", "stop", "ended"]; function decorateRecordingPromise(innerPromise) { return decoratePromise.call(this, { promise: innerPromise, namespace: "recording", methods: methods2, getters: getters2 }); } // src/voice/CallPrompt/CallPrompt.ts var ENDED_STATES3 = [ "no_input", "error", "no_match", "digit", "speech" ]; var CallPrompt = class extends ListenSubscriber { constructor(options) { super({ swClient: options.call._sw }); __publicField(this, "_payload"); __publicField(this, "_eventMap", { onStarted: "prompt.started", onUpdated: "prompt.updated", onFailed: "prompt.failed", onEnded: "prompt.ended" }); this._payload = options.payload; if (options.listeners) { this.listen(options.listeners); } } get id() { var _a; return (_a = this._payload) == null ? void 0 : _a.control_id.split(".")[0]; } get controlId() { return this._payload.control_id; } get callId() { return this._payload.call_id; } get nodeId() { return this._payload.node_id; } get result() { return this._payload.result; } get type() { var _a; return (_a = this.result) == null ? void 0 : _a.type; } /** * User-friendly alias to understand the reason in case of errors * no_match | no_input | error */ get reason() { return this.type; } get digits() { var _a; if (((_a = this.result) == null ? void 0 : _a.type) === "digit") { return this.result.params.digits; } return void 0; } get speech() { var _a; if (((_a = this.result) == null ? void 0 : _a.type) === "speech") { return this.result.params.text; } return void 0; } get terminator() { var _a; if (((_a = this.result) == null ? void 0 : _a.type) === "digit") { return this.result.params.terminator; } return void 0; } get text() { var _a; if (((_a = this.result) == null ? void 0 : _a.type) === "speech") { return this.result.params.text; } return void 0; } get confidence() { var _a; if (((_a = this.result) == null ? void 0 : _a.type) === "speech") { return this.result.params.confidence; } return void 0; } get hasEnded() { var _a; if (ENDED_STATES3.includes((_a = this.result) == null ? void 0 : _a.type)) { return true; } return false; } /** @internal */ setPayload(payload) { this._payload = payload; } async stop() { if (this.hasEnded) { throw new Error("Action has ended"); } await this._client.execute({ method: "calling.play_and_collect.stop", params: { node_id: this.nodeId, call_id: this.callId, control_id: this.controlId } }); return this; } async setVolume(volume) { if (this.hasEnded) { throw new Error("Action has ended"); } await this._client.execute({ method: "calling.play_and_collect.volume", params: { node_id: this.nodeId, call_id: this.callId, control_id: this.controlId, volume } }); return this; } /** @deprecated */ waitForResult() { return this.ended(); } ended() { return new Promise((resolve) => { const handler = () => { this.off("prompt.ended", handler); this.off("prompt.failed", handler); resolve(this); }; this.once("prompt.ended", handler); this.once("prompt.failed", handler); if (this.hasEnded) { handler(); } }); } }; // src/voice/CallPrompt/decoratePromptPromise.ts var getters3 = [ "id", "controlId", "callId", "nodeId", "result", "type", "reason", "digits", "speech", "terminator", "text", "confidence" ]; var methods3 = ["stop", "setVolume", "ended"]; function decoratePromptPromise(innerPromise) { return decoratePromise.call(this, { promise: innerPromise, namespace: "prompt", methods: methods3, getters: getters3 }); } // src/voice/CallCollect/CallCollect.ts var ENDED_STATES4 = [ "error", "no_input", "no_match", "digit", "speech" ]; var CallCollect = class extends ListenSubscriber { constructor(options) { super({ swClient: options.call._sw }); __publicField(this, "_payload"); __publicField(this, "_eventMap", { onStarted: "collect.started", onInputStarted: "collect.startOfInput", onUpdated: "collect.updated", onFailed: "collect.failed", onEnded: "collect.ended" }); this._payload = options.payload; if (options.listeners) { this.listen(options.listeners); } } get id() { var _a; return (_a = this._payload) == null ? void 0 : _a.control_id.split(".")[0]; } get controlId() { return this._payload.control_id; } get callId() { return this._payload.call_id; } get nodeId() { return this._payload.node_id; } get result() { return this._payload.result; } get type() { var _a; return (_a = this.result) == null ? void 0 : _a.type; } /** * User-friendly alias to understand the reason in case of errors * no_match | no_input | error */ get reason() { return this.type; } get digits() { var _a; if (((_a = this.result) == null ? void 0 : _a.type) === "digit") { return this.result.params.digits; } return void 0; } get speech() { var _a; if (((_a = this.result) == null ? void 0 : _a.type) === "speech") { return this.result.params.text; } return void 0; } get terminator() { var _a; if (((_a = this.result) == null ? void 0 : _a.type) === "digit") { return this.result.params.terminator; } return void 0; } get text() { var _a; if (((_a = this.result) == null ? void 0 : _a.type) === "speech") { return this.result.params.text; } return void 0; } get confidence() { var _a; if (((_a = this.result) == null ? void 0 : _a.type) === "speech") { return this.result.params.confidence; } return void 0; } get state() { return this._payload.state; } get final() { return this._payload.final; } get hasEnded() { var _a; if (this.state !== "collecting" && this.final !== false && ENDED_STATES4.includes((_a = this.result) == null ? void 0 : _a.type)) { return true; } return false; } /** @internal */ setPayload(payload) { this._payload = payload; } async stop() { if (this.hasEnded) { throw new Error("Action has ended"); } await this._client.execute({ method: "calling.collect.stop", params: { node_id: this.nodeId, call_id: this.callId, control_id: this.controlId } }); return this; } async startInputTimers() { if (this.hasEnded) { throw new Error("Action has ended"); } await this._client.execute({ method: "calling.collect.start_input_timers", params: { node_id: this.nodeId, call_id: this.callId, control_id: this.controlId } }); return this; } ended() { return new Promise((resolve) => { const handler = () => { this.off("collect.ended", handler); this.off("collect.failed", handler); resolve(this); }; this.once("collect.ended", handler); this.once("collect.failed", handler); if (this.hasEnded) { handler(); } }); } }; // src/voice/CallCollect/decorateCollectPromise.ts var getters4 = [ "id", "callId", "nodeId", "controlId", "result", "type", "reason", "digits", "speech", "terminator", "text", "confidence" ]; var methods4 = ["stop", "startInputTimers", "ended"]; function decorateCollectPromise(innerPromise) { return decoratePromise.call(this, { promise: innerPromise, namespace: "collect", methods: methods4, getters: getters4 }); } // src/voice/CallTap/CallTap.ts var ENDED_STATES5 = ["finished"]; var CallTap = class extends ListenSubscriber { constructor(options) { super({ swClient: options.call._sw }); __publicField(this, "_payload"); __publicField(this, "_eventMap", { onStarted: "tap.started", onEnded: "tap.ended" }); this._payload = options.payload; if (options.listeners) { this.listen(options.listeners); } } get id() { return this._payload.control_id; } get controlId() { return this._payload.control_id; } get nodeId() { return this._payload.node_id; } get callId() { return this._payload.call_id; } get state() { return this._payload.state; } get hasEnded() { if (ENDED_STATES5.includes(this.state)) { return true; } return false; } /** @internal */ setPayload(payload) { this._payload = payload; } async stop() { if (this.hasEnded) { throw new Error("Action has ended"); } await this._client.execute({ method: "calling.tap.stop", params: { node_id: this.nodeId, call_id: this.callId, control_id: this.controlId } }); return this; } ended() { return new Promise((resolve) => { const handler = () => { this.off("tap.ended", handler); resolve(this); }; this.once("tap.ended", handler); if (this.hasEnded) { handler(); } }); } }; // src/voice/CallTap/decorateTapPromise.ts var getters5 = ["id", "callId", "nodeId", "controlId", "state"]; var methods5 = ["stop", "ended"]; function decorateTapPromise(innerPromise) { return decoratePromise.call(this, { promise: innerPromise, namespace: "tap", methods: methods5, getters: getters5 }); } // src/voice/DeviceBuilder.ts var DeviceBuilder = class { constructor() { __publicField(this, "_devices", []); } get devices() { return this._devices; } add(params) { if (Array.isArray(params)) { this._devices.push(params); } else { this._devices.push([params]); } return this; } static Phone(params) { return __spreadValues({ type: "phone" }, params); } static Sip(params) { return __spreadValues({ type: "sip" }, params); } }; // src/voice/CallDetect/CallDetect.ts var ENDED_STATES6 = ["finished", "error"]; var CallDetect = class extends ListenSubscriber { constructor(options) { super({ swClient: options.call._sw }); __publicField(this, "_waitForBeep"); __publicField(this, "_result", "UNKNOWN"); __publicField(this, "_payload"); __publicField(this, "_eventMap", { onStarted: "detect.started", onUpdated: "detect.updated", onEnded: "detect.ended" }); this._payload = options.payload; this._waitForBeep = options.payload.waitForBeep; if (options.listeners) { this.listen(options.listeners); } } get id() { return this._payload.control_id; } get controlId() { return this._payload.control_id; } get callId() { return this._payload.call_id; } get nodeId() { return this._payload.node_id; } get detect() { return this._payload.detect; } get type() { var _a; return (_a = this == null ? void 0 : this.detect) == null ? void 0 : _a.type; } get result() { return this._result; } get waitForBeep() { return this._waitForBeep; } get beep() { var _a; if (((_a = this.detect) == null ? void 0 : _a.params.event) === "MACHINE") { return Boolean(this.detect.params.beep); } return void 0; } get hasEnded() { const lastEvent = this._lastEvent(); if (lastEvent && ENDED_STATES6.includes(lastEvent)) { return true; } return false; } /** @internal */ setPayload(payload) { this._payload = payload; const lastEvent = this._lastEvent(); if (lastEvent && lastEvent !== "finished") { this._result = lastEvent; } } async stop() { if (this.hasEnded) { throw new Error("Action has ended"); } await this._client.execute({ method: "calling.detect.stop", params: { node_id: this.nodeId, call_id: this.callId, control_id: this.controlId } }); return this; } /** @deprecated */ waitForResult() { return this.ended(); } ended() { const lastEvent = this._lastEvent(); if (lastEvent && ENDED_STATES6.includes(lastEvent)) { return Promise.resolve(this); } return new Promise((resolve) => { const handler = () => { this.off("detect.ended", handler); resolve(this); }; this.once("detect.ended", handler); }); } _lastEvent() { var _a; return (_a = this.detect) == null ? void 0 : _a.params.event; } }; // src/voice/CallDetect/decorateDetectPromise.ts var getters6 = [ "id", "callId", "nodeId", "controlId", "detect", "type", "result", "waitForBeep", "beep" ]; var methods6 = ["stop", "ended"]; function decorateDetectPromise(innerPromise) { return decoratePromise.call(this, { promise: innerPromise, namespace: "detect", methods: methods6, getters: getters6 }); } // src/voice/Call.ts var Call = class extends ListenSubscriber { constructor(options) { var _a; super({ swClient: options.voice._sw }); __publicField(this, "_voice"); __publicField(this, "_context"); __publicField(this, "_peer"); __publicField(this, "_payload"); __publicField(this, "_connectPayload"); __publicField(this, "_eventMap", { onStateChanged: "call.state", onPlaybackStarted: "playback.started", onPlaybackUpdated: "playback.updated", onPlaybackFailed: "playback.failed", onPlaybackEnded: "playback.ended", onRecordingStarted: "recording.started", onRecordingUpdated: "recording.updated", onRecordingFailed: "recording.failed", onRecordingEnded: "recording.ended", onPromptStarted: "prompt.started", onPromptUpdated: "prompt.updated", onPromptFailed: "prompt.failed", onPromptEnded: "prompt.ended", onCollectStarted: "collect.started", onCollectInputStarted: "collect.startOfInput", onCollectUpdated: "collect.updated", onCollectFailed: "collect.failed", onCollectEnded: "collect.ended", onTapStarted: "tap.started", onTapEnded: "tap.ended", onDetectStarted: "detect.started", onDetectUpdated: "detect.updated", onDetectEnded: "detect.ended" }); /** * Alias for amd() */ __publicField(this, "detectAnsweringMachine", this.amd); this._voice = options.voice; this._payload = options.payload; this._context = (_a = options.payload) == null ? void 0 : _a.context; this._connectPayload = options.connectPayload; if (options.listeners) { this.listen(options.listeners); } } /** Unique id for this voice call */ get id() { var _a; return (_a = this._payload) == null ? void 0 : _a.call_id; } get callId() { var _a; return (_a = this._payload) == null ? void 0 : _a.call_id; } get state() { var _a; return (_a = this._payload) == null ? void 0 : _a.call_state; } get callState() { var _a; return (_a = this._payload) == nul