@twilio/flex-plugins-library-utils
Version:
Flex Plugins Library Utils
469 lines (398 loc) • 16 kB
text/typescript
import { Twilio } from 'twilio';
import { retryHandler } from '../../common/retryHandler';
import { PluginsUtilsMetaData } from '../../types';
import { Parameters, ApiReturnType } from '../../types';
import { isNumber, isObject, isString } from 'lodash';
import { CallInstance } from 'twilio/lib/rest/api/v2010/account/call';
import { QueueInstance } from 'twilio/lib/rest/api/v2010/account/queue';
import {
RecordingInstance as CallRecordingInstance,
RecordingListInstanceCreateOptions,
} from 'twilio/lib/rest/api/v2010/account/call/recording';
import {
RecordingInstance,
} from 'twilio/lib/rest/api/v2010/account/recording';
import { OutgoingCallerIdInstance } from 'twilio/lib/rest/api/v2010/account/outgoingCallerId';
import { RecordingInstance as ConferenceRecordingInstance } from 'twilio/lib/rest/api/v2010/account/conference/recording';
import { fetchRecording, fetchVoiceQueue, updateCall, updateCallRecordingParams, updateConferenceRecording } from './types';
import { PluginUtils } from '../../common/BaseClasses/PluginUtils';
import { HttpErrorCode } from '../../constants/statusCodes';
import { PluginUtilsErrorManager } from '../../common/PluginUtilsErrorManager';
import TwilioRecordingAPI from './Api';
import { RETRY_STRATEGY } from 'src/constants/api';
export default class ProgrammableVoiceUtils extends PluginUtils {
private config: PluginsUtilsMetaData;
private api: TwilioRecordingAPI;
/**
* Utility class for Twilio's Programmable Voice resources
* @param {Twilio} client Twilio client
* @param {TaskRouterMetaData} config.maxBackoff Twilio service backoff max timeout
* @param {TaskRouterMetaData} config.minBackoff Twilio service backoff min timeout
* @param {TaskRouterMetaData} config.retryLimit Service retry limit
* @param {TaskRouterMetaData} config.accountSid Twilio account sid
* @param {TaskRouterMetaData} config.authToken Twilio auth token
* */
constructor(client: Twilio, config: PluginsUtilsMetaData) {
super(client);
this.config = {
...config,
maxBackoff: config.maxBackoff || RETRY_STRATEGY.MAX_BACKOFF,
minBackoff: config.minBackoff || RETRY_STRATEGY.MIN_BACKOFF,
retryLimit: config.retryLimit || RETRY_STRATEGY.RETRY_LIMIT,
};
const { accountSid, authToken, region } = config;
this.api = new TwilioRecordingAPI(accountSid, authToken, region);
}
/**
* @param {string} parameters.callSid the unique call SID to fetch
* @returns {Map} The given call's properties
* @description fetches the given call SID's properties
*/
public async fetchProperties(
parameters: Parameters & { callSid: string },
): Promise<ApiReturnType & { callProperties?: CallInstance }> {
const { callSid, attempts } = parameters;
const parameterChecks = {
callSid: 'string',
};
try {
const inputError = PluginUtilsErrorManager.checkInvalidParameters<Parameters & { callSid: string }>(
parameters,
parameterChecks,
);
if (inputError) {
throw new PluginUtilsErrorManager(inputError, HttpErrorCode.BadRequest);
}
const callProperties = await this.client.calls(callSid).fetch();
return { success: true, callProperties, status: HttpErrorCode.OK };
} catch (error) {
if (error.code === HttpErrorCode.BadRequest) {
return {
success: false,
status: HttpErrorCode.BadRequest,
message: error.message,
};
}
return retryHandler<Parameters & { callSid: string }>(this.config, error,{ ...parameters , attempts: !attempts ? 0 : attempts},this.fetchProperties);
}
}
/**
* @param {string} parameters.callSid the unique call SID to fetch
* @param {string} parameters.twiml the response of twiml based on to and from arguments of event
* @returns {object} generic response object
* @description cold transfers the given call SID to the given phone number
*/
public async coldTransfer(parameters: Parameters & { callSid: string; twiml: string; }): Promise<ApiReturnType> {
const { callSid, twiml, attempts } = parameters;
const parameterChecks = {
callSid: 'string',
twiml: 'string',
};
try {
const inputError = PluginUtilsErrorManager.checkInvalidParameters<Parameters & { callSid: string; twiml: string; }>(
parameters,
parameterChecks,
);
if (inputError) {
throw new PluginUtilsErrorManager(inputError, HttpErrorCode.BadRequest);
}
await this.client.calls(callSid).update({
twiml
});
return { success: true, status: HttpErrorCode.OK };
} catch (error) {
if (error.code === HttpErrorCode.BadRequest) {
return {
success: false,
status: HttpErrorCode.BadRequest,
message: error.message,
};
}
return retryHandler<Parameters & { callSid: string; twiml: string }>(
this.config,
error,
{ ...parameters, attempts: !attempts ? 0 : attempts },
this.coldTransfer,
);
}
}
/**
* @param {string} parameters.callSid the unique call SID to fetch
* @param {object} parameters.params recording creation parameters
* @returns {Map} The new recording's properties
* @description creates recording for the given call SID
*/
public async createRecording(
parameters: Parameters & { callSid: string; params: RecordingListInstanceCreateOptions },
): Promise<ApiReturnType & { recording?: CallRecordingInstance }> {
const { callSid, params, attempts } = parameters;
const parameterChecks = {
callSid: 'string',
params: 'object',
};
try {
const inputError = PluginUtilsErrorManager.checkInvalidParameters<
Parameters & { callSid: string; params: RecordingListInstanceCreateOptions }
>(parameters, parameterChecks);
if (inputError) {
throw new PluginUtilsErrorManager(inputError, HttpErrorCode.BadRequest);
}
const recording = await this.client.calls(callSid).recordings.create(params);
return { success: true, recording, status: HttpErrorCode.OK };
} catch (error) {
if (error.code === HttpErrorCode.BadRequest) {
return {
success: false,
status: HttpErrorCode.BadRequest,
message: error.message,
};
}
return retryHandler<Parameters & { callSid: string; params: RecordingListInstanceCreateOptions }>(
this.config,
error,
{ ...parameters , attempts: !attempts ? 0 : attempts},
this.createRecording,
);
}
}
/**
* @param {string} parameters.callSid the unique call SID to update recording
* @param {string} parameters.recordingSid the unique recording SID to update
* @param {object} parameters.params recording update parameters
* @returns {Map} The recording's properties
* @description updates the given recording for the given call
*/
public async updateCallRecording(
parameters: updateCallRecordingParams,
): Promise<ApiReturnType & { recording?: CallRecordingInstance }> {
const { callSid, recordingSid, params, attempts } = parameters;
const parameterChecks = {
callSid: 'string',
recordingSid: 'string',
params: 'object',
};
try {
const inputError = PluginUtilsErrorManager.checkInvalidParameters<updateCallRecordingParams>(
parameters,
parameterChecks,
);
if (inputError) {
throw new PluginUtilsErrorManager(inputError, HttpErrorCode.BadRequest);
}
const recording = await this.client.calls(callSid).recordings(recordingSid).update(params);
return { success: true, recording, status: HttpErrorCode.OK };
} catch (error) {
if (error.code === HttpErrorCode.BadRequest) {
return {
success: false,
status: HttpErrorCode.BadRequest,
message: error.message,
};
}
return retryHandler<updateCallRecordingParams>(this.config, error,{ ...parameters , attempts: !attempts ? 0 : attempts},this.updateCallRecording);
}
}
/**
* @param {string} parameters.conferenceSid the unique conference SID to update recording
* @param {string} parameters.recordingSid the unique recording SID to update
* @param {object} parameters.params recording update parameters
* @returns {Map} The recording's properties
* @description updates the given recording for the given call
*/
public async updateConferenceRecording(
parameters: updateConferenceRecording,
): Promise<ApiReturnType & { recording?: ConferenceRecordingInstance }> {
const { conferenceSid, recordingSid, params, attempts } = parameters;
const parameterChecks = {
conferenceSid: 'string',
recordingSid: 'string',
params: 'object',
};
try {
const inputError = PluginUtilsErrorManager.checkInvalidParameters<updateConferenceRecording>(
parameters,
parameterChecks,
);
if (inputError) {
throw new PluginUtilsErrorManager(inputError, HttpErrorCode.BadRequest);
}
const recording = await this.client.conferences(conferenceSid).recordings(recordingSid).update(params);
return { success: true, recording, status: HttpErrorCode.OK };
} catch (error) {
if (error.code === HttpErrorCode.BadRequest) {
return {
success: false,
status: HttpErrorCode.BadRequest,
message: error.message,
};
}
return retryHandler<updateConferenceRecording>(this.config, error,{ ...parameters , attempts: !attempts ? 0 : attempts},this.updateConferenceRecording);
}
}
/**
* @param {string} parameters.callSid the unique call SID to update
* @param {object} parameters.params recording update parameters
* @returns {Map} The call's properties
* @description updates the given call
*/
public async updateCall(
parameters: updateCall,
): Promise<ApiReturnType & { call?: CallInstance }> {
const { callSid, params, attempts } = parameters;
const parameterChecks = {
callSid: 'string',
params: 'object',
};
try {
const inputError = PluginUtilsErrorManager.checkInvalidParameters<updateCall>(
parameters,
parameterChecks,
);
if (inputError) {
throw new PluginUtilsErrorManager(inputError, HttpErrorCode.BadRequest);
}
const call = await this.client.calls(callSid).update(params);
return { success: true, call, status: HttpErrorCode.OK };
} catch (error) {
if (error.code === HttpErrorCode.BadRequest) {
return {
success: false,
status: HttpErrorCode.BadRequest,
message: error.message,
};
}
return retryHandler<updateCall>(this.config, error,{ ...parameters , attempts: !attempts ? 0 : attempts},this.updateCall);
}
}
/**
* @param {string} parameters.queueSid the unique queue SID to fetch
* @param {object} parameters.params recording update parameters
* @returns {Map} The given queue's properties
* @description fetches the given queue SID's properties
*/
public async fetchVoiceQueue(
parameters: fetchVoiceQueue,
): Promise<ApiReturnType & { queueProperties?: QueueInstance }> {
const { queueSid, attempts } = parameters;
const parameterChecks = {
queueSid: 'string',
};
try {
const inputError = PluginUtilsErrorManager.checkInvalidParameters<fetchVoiceQueue>(
parameters,
parameterChecks,
);
if (inputError) {
throw new PluginUtilsErrorManager(inputError, HttpErrorCode.BadRequest);
}
const queueProperties = await this.client.queues(queueSid).fetch();
return { success: true, queueProperties, status: HttpErrorCode.OK };
} catch (error) {
if (error.code === HttpErrorCode.BadRequest) {
return {
success: false,
status: HttpErrorCode.BadRequest,
message: error.message,
};
}
return retryHandler<fetchVoiceQueue>(this.config, error,{ ...parameters , attempts: !attempts ? 0 : attempts},this.fetchVoiceQueue);
}
}
/**
* @param {string} parameters.recordingSid the unique recording SID to fetch
* @param {object} parameters.params recording update parameters
* @returns {Map} The given recording's properties
* @description fetches the given recording SID's properties
*/
public async fetchRecording(
parameters: fetchRecording,
): Promise<ApiReturnType & { recordingProperties?: RecordingInstance }> {
const { recordingSid,attempts } = parameters;
const parameterChecks = {
recordingSid: 'string',
};
try {
const inputError = PluginUtilsErrorManager.checkInvalidParameters<fetchRecording>(
parameters,
parameterChecks,
);
if (inputError) {
throw new PluginUtilsErrorManager(inputError, HttpErrorCode.BadRequest);
}
const recordingProperties = await this.client.recordings(recordingSid).fetch();
return { success: true, recordingProperties, status: HttpErrorCode.OK };
} catch (error) {
if (error.code === HttpErrorCode.BadRequest) {
return {
success: false,
status: HttpErrorCode.BadRequest,
message: error.message,
};
}
return retryHandler<fetchRecording>(this.config, error,{ ...parameters , attempts: !attempts ? 0 : attempts},this.fetchRecording);
}
}
/**
* @param {string} parameters.recordingSid the unique recording SID to fetch
* @param {object} parameters.params recording update parameters
* @returns {Map} The given recording's properties
* @description fetches the given recording SID's properties
*/
public async fetchRecordingMedia(
parameters: fetchRecording,
): Promise<ApiReturnType & { recording?: any , type?: string}> {
const { recordingSid, attempts } = parameters;
const parameterChecks = {
recordingSid: 'string',
};
try {
const inputError = PluginUtilsErrorManager.checkInvalidParameters<fetchRecording>(
parameters,
parameterChecks,
);
if (inputError) {
throw new PluginUtilsErrorManager(inputError, HttpErrorCode.BadRequest);
}
const { data, headers: responseHeaders } = await this.api.getRecordingMedia(recordingSid);
const recording = data;
const type = responseHeaders['content-type'];
return { success: true, recording, type, status: HttpErrorCode.OK };
} catch (error) {
if (error.code === HttpErrorCode.BadRequest) {
return {
success: false,
status: HttpErrorCode.BadRequest,
message: error.message,
};
}
return retryHandler<fetchRecording>(this.config, error,{ ...parameters , attempts: !attempts ? 0 : attempts},this.fetchRecordingMedia);
}
}
/**
* @returns {Array<PhoneNumber>} An array of outbound caller ids for the account
* @description the following method is used to robustly retrieve
* the outbound caller ids for the account
*/
public async listOutgoingCallerIds(
parameters: Parameters,
): Promise<ApiReturnType & { callerIds?: Array<OutgoingCallerIdInstance> }> {
try {
const callerIds = await this.client.outgoingCallerIds.list();
return { success: true, callerIds, status: HttpErrorCode.OK };
} catch (error) {
if (error.code === HttpErrorCode.BadRequest) {
return {
success: false,
status: HttpErrorCode.BadRequest,
message: error.message,
};
}
return retryHandler(
this.config,
error,
{ ...parameters, attempts: !parameters.attempts ? 0 : parameters.attempts },
this.fetchRecording,
);
}
}
}