@signalwire/realtime-api
Version:
SignalWire RealTime SDK for Node.js
1,918 lines (1,877 loc) • 158 kB
JavaScript
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