workano-js-sdk
Version:
Workano Communications SDK - A modern JavaScript SDK for WebRTC and VoIP integration.
1,308 lines (1,307 loc) • 463 kB
JavaScript
import * as __WEBPACK_EXTERNAL_MODULE_js_base64_4ca5b7bc__ from "js-base64";
import * as __WEBPACK_EXTERNAL_MODULE_moment__ from "moment";
import * as __WEBPACK_EXTERNAL_MODULE_jsrsasign__ from "jsrsasign";
import * as __WEBPACK_EXTERNAL_MODULE_sip_js_lib_api_session_state_3832d665__ from "sip.js/lib/api/session-state";
import * as __WEBPACK_EXTERNAL_MODULE_events__ from "events";
import * as __WEBPACK_EXTERNAL_MODULE_json_to_graphql_query_lib_jsonToGraphQLQuery_86e5fe4e__ from "json-to-graphql-query/lib/jsonToGraphQLQuery";
import * as __WEBPACK_EXTERNAL_MODULE_sip_js_lib_api_f9f0ade8__ from "sip.js/lib/api";
import "webrtc-adapter";
import * as __WEBPACK_EXTERNAL_MODULE_sip_js_lib_api_user_agent_state_a04f4d58__ from "sip.js/lib/api/user-agent-state";
import * as __WEBPACK_EXTERNAL_MODULE_sip_js_lib_core_messages_parser_9974076a__ from "sip.js/lib/core/messages/parser";
import * as __WEBPACK_EXTERNAL_MODULE_sip_js_lib_core_messages_methods_constants_78ac14f1__ from "sip.js/lib/core/messages/methods/constants";
import * as __WEBPACK_EXTERNAL_MODULE_sip_js_lib_grammar_uri_b7779ac2__ from "sip.js/lib/grammar/uri";
import * as __WEBPACK_EXTERNAL_MODULE_sip_js_lib_api_user_agent_8471afcd__ from "sip.js/lib/api/user-agent";
import * as __WEBPACK_EXTERNAL_MODULE_sip_js_lib_platform_web_modifiers_modifiers_2ed0685f__ from "sip.js/lib/platform/web/modifiers/modifiers";
import * as __WEBPACK_EXTERNAL_MODULE_sip_js_lib_core_dialogs_session_dialog_042454ee__ from "sip.js/lib/core/dialogs/session-dialog";
import * as __WEBPACK_EXTERNAL_MODULE_sip_js_lib_api_messager_c3a09f5d__ from "sip.js/lib/api/messager";
import * as __WEBPACK_EXTERNAL_MODULE_sip_js_lib_api_registerer_state_6e58ddd6__ from "sip.js/lib/api/registerer-state";
import * as __WEBPACK_EXTERNAL_MODULE_sip_js_lib_api_transport_state_2606bc5d__ from "sip.js/lib/api/transport-state";
import * as __WEBPACK_EXTERNAL_MODULE_sip_js_lib_platform_web_session_description_handler_peer_connection_configuration_default_48affb33__ from "sip.js/lib/platform/web/session-description-handler/peer-connection-configuration-default";
import * as __WEBPACK_EXTERNAL_MODULE_getstats__ from "getstats";
import * as __WEBPACK_EXTERNAL_MODULE_sip_js_lib_platform_web_session_description_handler_session_description_handler_fdd90ea0__ from "sip.js/lib/platform/web/session-description-handler/session-description-handler";
import * as __WEBPACK_EXTERNAL_MODULE_sdp_transform_45b84e5d__ from "sdp-transform";
import * as __WEBPACK_EXTERNAL_MODULE_reconnecting_websocket_e103ba3a__ from "reconnecting-websocket";
import "libphonenumber-js";
var __webpack_require__ = {};
(()=>{
__webpack_require__.d = function(exports, definition) {
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) Object.defineProperty(exports, key, {
enumerable: true,
get: definition[key]
});
};
})();
(()=>{
__webpack_require__.g = function() {
if ('object' == typeof globalThis) return globalThis;
try {
return this || new Function('return this')();
} catch (e) {
if ('object' == typeof window) return window;
}
}();
})();
(()=>{
__webpack_require__.o = function(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
};
})();
(()=>{
__webpack_require__.r = function(exports) {
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports, Symbol.toStringTag, {
value: 'Module'
});
Object.defineProperty(exports, '__esModule', {
value: true
});
};
})();
var WebRTCPhone_namespaceObject = {};
__webpack_require__.r(WebRTCPhone_namespaceObject);
__webpack_require__.d(WebRTCPhone_namespaceObject, {
MESSAGE_TYPE_CHAT: ()=>MESSAGE_TYPE_CHAT,
MESSAGE_TYPE_SIGNAL: ()=>MESSAGE_TYPE_SIGNAL,
ON_AUDIO_STREAM: ()=>ON_AUDIO_STREAM,
ON_CALL_ACCEPTED: ()=>ON_CALL_ACCEPTED,
ON_CALL_ANSWERED: ()=>ON_CALL_ANSWERED,
ON_CALL_CANCELED: ()=>ON_CALL_CANCELED,
ON_CALL_ENDED: ()=>ON_CALL_ENDED,
ON_CALL_ENDING: ()=>ON_CALL_ENDING,
ON_CALL_ERROR: ()=>ON_CALL_ERROR,
ON_CALL_FAILED: ()=>ON_CALL_FAILED,
ON_CALL_HELD: ()=>ON_CALL_HELD,
ON_CALL_INCOMING: ()=>ON_CALL_INCOMING,
ON_CALL_MUTED: ()=>ON_CALL_MUTED,
ON_CALL_OUTGOING: ()=>ON_CALL_OUTGOING,
ON_CALL_REJECTED: ()=>ON_CALL_REJECTED,
ON_CALL_RESUMED: ()=>ON_CALL_RESUMED,
ON_CALL_UNHELD: ()=>ON_CALL_UNHELD,
ON_CALL_UNMUTED: ()=>ON_CALL_UNMUTED,
ON_CAMERA_DISABLED: ()=>ON_CAMERA_DISABLED,
ON_CAMERA_RESUMED: ()=>ON_CAMERA_RESUMED,
ON_CHAT: ()=>ON_CHAT,
ON_DISCONNECTED: ()=>ON_DISCONNECTED,
ON_EARLY_MEDIA: ()=>ON_EARLY_MEDIA,
ON_MESSAGE: ()=>ON_MESSAGE,
ON_MESSAGE_TRACK_UPDATED: ()=>ON_MESSAGE_TRACK_UPDATED,
ON_NETWORK_STATS: ()=>ON_NETWORK_STATS,
ON_PLAY_HANGUP_SOUND: ()=>ON_PLAY_HANGUP_SOUND,
ON_PLAY_INBOUND_CALL_SIGNAL_SOUND: ()=>ON_PLAY_INBOUND_CALL_SIGNAL_SOUND,
ON_PLAY_PROGRESS_SOUND: ()=>ON_PLAY_PROGRESS_SOUND,
ON_PLAY_RING_SOUND: ()=>ON_PLAY_RING_SOUND,
ON_PROGRESS: ()=>ON_PROGRESS,
ON_REGISTERED: ()=>ON_REGISTERED,
ON_REINVITE: ()=>ON_REINVITE,
ON_REMOVE_STREAM: ()=>ON_REMOVE_STREAM,
ON_SHARE_SCREEN_ENDED: ()=>ON_SHARE_SCREEN_ENDED,
ON_SHARE_SCREEN_ENDING: ()=>ON_SHARE_SCREEN_ENDING,
ON_SHARE_SCREEN_STARTED: ()=>ON_SHARE_SCREEN_STARTED,
ON_SIGNAL: ()=>ON_SIGNAL,
ON_TERMINATE_SOUND: ()=>ON_TERMINATE_SOUND,
ON_TRACK: ()=>ON_TRACK,
ON_UNREGISTERED: ()=>ON_UNREGISTERED,
ON_USER_AGENT: ()=>ON_USER_AGENT,
ON_VIDEO_INPUT_CHANGE: ()=>ON_VIDEO_INPUT_CHANGE,
ON_VIDEO_STREAM: ()=>ON_VIDEO_STREAM,
default: ()=>WebRTCPhone,
events: ()=>WebRTCPhone_events
});
var websocket_client_namespaceObject = {};
__webpack_require__.r(websocket_client_namespaceObject);
__webpack_require__.d(websocket_client_namespaceObject, {
AGENT_PAUSED: ()=>AGENT_PAUSED,
AGENT_STATUS_UPDATE: ()=>AGENT_STATUS_UPDATE,
AGENT_UNPAUSED: ()=>AGENT_UNPAUSED,
APPLICATION_CALL_ANSWERED: ()=>APPLICATION_CALL_ANSWERED,
APPLICATION_CALL_DELETED: ()=>APPLICATION_CALL_DELETED,
APPLICATION_CALL_DTMF_RECEIVED: ()=>APPLICATION_CALL_DTMF_RECEIVED,
APPLICATION_CALL_ENTERED: ()=>APPLICATION_CALL_ENTERED,
APPLICATION_CALL_INITIATED: ()=>APPLICATION_CALL_INITIATED,
APPLICATION_CALL_UPDATED: ()=>APPLICATION_CALL_UPDATED,
APPLICATION_DESTINATION_NODE_CREATED: ()=>APPLICATION_DESTINATION_NODE_CREATED,
APPLICATION_NODE_CREATED: ()=>APPLICATION_NODE_CREATED,
APPLICATION_NODE_DELETED: ()=>APPLICATION_NODE_DELETED,
APPLICATION_NODE_UPDATED: ()=>APPLICATION_NODE_UPDATED,
APPLICATION_PLAYBACK_CREATED: ()=>APPLICATION_PLAYBACK_CREATED,
APPLICATION_PLAYBACK_DELETED: ()=>APPLICATION_PLAYBACK_DELETED,
APPLICATION_PROGRESS_STARTED: ()=>APPLICATION_PROGRESS_STARTED,
APPLICATION_PROGRESS_STOPPED: ()=>APPLICATION_PROGRESS_STOPPED,
APPLICATION_SNOOP_CREATED: ()=>APPLICATION_SNOOP_CREATED,
APPLICATION_SNOOP_DELETED: ()=>APPLICATION_SNOOP_DELETED,
APPLICATION_SNOOP_UPDATED: ()=>APPLICATION_SNOOP_UPDATED,
APPLICATION_USER_OUTGOING_CALL_CREATED: ()=>APPLICATION_USER_OUTGOING_CALL_CREATED,
AUTH_SESSION_EXPIRE_SOON: ()=>AUTH_SESSION_EXPIRE_SOON,
AUTH_USER_EXTERNAL_AUTH_ADDED: ()=>AUTH_USER_EXTERNAL_AUTH_ADDED,
AUTH_USER_EXTERNAL_AUTH_DELETED: ()=>AUTH_USER_EXTERNAL_AUTH_DELETED,
CALL_ANSWERED: ()=>CALL_ANSWERED,
CALL_CREATED: ()=>CALL_CREATED,
CALL_DTMF_CREATED: ()=>CALL_DTMF_CREATED,
CALL_ENDED: ()=>CALL_ENDED,
CALL_HELD: ()=>CALL_HELD,
CALL_LOG_USER_CREATED: ()=>CALL_LOG_USER_CREATED,
CALL_RESUMED: ()=>CALL_RESUMED,
CALL_UPDATED: ()=>CALL_UPDATED,
CHATD_PRESENCE_UPDATED: ()=>CHATD_PRESENCE_UPDATED,
CHATD_USER_ROOM_CREATED: ()=>CHATD_USER_ROOM_CREATED,
CHATD_USER_ROOM_MESSAGE_CREATED: ()=>CHATD_USER_ROOM_MESSAGE_CREATED,
CHAT_MESSAGE_RECEIVED: ()=>CHAT_MESSAGE_RECEIVED,
CHAT_MESSAGE_SENT: ()=>CHAT_MESSAGE_SENT,
CONFERENCE_ADHOC_DELETED: ()=>CONFERENCE_ADHOC_DELETED,
CONFERENCE_ADHOC_PARTICIPANT_LEFT: ()=>CONFERENCE_ADHOC_PARTICIPANT_LEFT,
CONFERENCE_USER_PARTICIPANT_JOINED: ()=>CONFERENCE_USER_PARTICIPANT_JOINED,
CONFERENCE_USER_PARTICIPANT_LEFT: ()=>CONFERENCE_USER_PARTICIPANT_LEFT,
CONFERENCE_USER_PARTICIPANT_TALK_STARTED: ()=>CONFERENCE_USER_PARTICIPANT_TALK_STARTED,
CONFERENCE_USER_PARTICIPANT_TALK_STOPPED: ()=>CONFERENCE_USER_PARTICIPANT_TALK_STOPPED,
ENDPOINT_STATUS_UPDATE: ()=>ENDPOINT_STATUS_UPDATE,
FAVORITE_ADDED: ()=>FAVORITE_ADDED,
FAVORITE_DELETED: ()=>FAVORITE_DELETED,
FAX_OUTBOUND_USER_CREATED: ()=>FAX_OUTBOUND_USER_CREATED,
FAX_OUTBOUND_USER_FAILED: ()=>FAX_OUTBOUND_USER_FAILED,
FAX_OUTBOUND_USER_SUCCEEDED: ()=>FAX_OUTBOUND_USER_SUCCEEDED,
HEARTBEAT_ENGINE_VERSION: ()=>HEARTBEAT_ENGINE_VERSION,
LINE_STATUS_UPDATED: ()=>LINE_STATUS_UPDATED,
MEETING_USER_GUEST_AUTHORIZATION_CREATED: ()=>MEETING_USER_GUEST_AUTHORIZATION_CREATED,
MEETING_USER_PARTICIPANT_JOINED: ()=>MEETING_USER_PARTICIPANT_JOINED,
MEETING_USER_PARTICIPANT_LEFT: ()=>MEETING_USER_PARTICIPANT_LEFT,
MEETING_USER_PROGRESS: ()=>MEETING_USER_PROGRESS,
SOCKET_EVENTS: ()=>SOCKET_EVENTS,
SWITCHBOARD_HELD_CALLS_UPDATED: ()=>SWITCHBOARD_HELD_CALLS_UPDATED,
SWITCHBOARD_HELD_CALL_ANSWERED: ()=>SWITCHBOARD_HELD_CALL_ANSWERED,
SWITCHBOARD_QUEUED_CALLS_UPDATED: ()=>SWITCHBOARD_QUEUED_CALLS_UPDATED,
SWITCHBOARD_QUEUED_CALL_ANSWERED: ()=>SWITCHBOARD_QUEUED_CALL_ANSWERED,
TRUNK_STATUS_UPDATED: ()=>TRUNK_STATUS_UPDATED,
USERS_FORWARDS_BUSY_UPDATED: ()=>USERS_FORWARDS_BUSY_UPDATED,
USERS_FORWARDS_NOANSWER_UPDATED: ()=>USERS_FORWARDS_NOANSWER_UPDATED,
USERS_FORWARDS_UNCONDITIONAL_UPDATED: ()=>USERS_FORWARDS_UNCONDITIONAL_UPDATED,
USERS_SERVICES_DND_UPDATED: ()=>USERS_SERVICES_DND_UPDATED,
USER_STATUS_UPDATE: ()=>USER_STATUS_UPDATE,
USER_VOICEMAIL_MESSAGE_CREATED: ()=>USER_VOICEMAIL_MESSAGE_CREATED,
USER_VOICEMAIL_MESSAGE_DELETED: ()=>USER_VOICEMAIL_MESSAGE_DELETED,
USER_VOICEMAIL_MESSAGE_UPDATED: ()=>USER_VOICEMAIL_MESSAGE_UPDATED,
default: ()=>websocket_client
});
class BadResponse extends Error {
static fromResponse(error, status) {
return new BadResponse(error.message || JSON.stringify(error), status, error.timestamp, error.error_id, error.details, error);
}
static fromText(response, status) {
return new BadResponse(response, status);
}
status;
timestamp;
errorId;
details;
error;
constructor(message, status, timestamp = null, errorId = null, details = null, error = null){
super(message);
this.timestamp = timestamp;
this.status = status;
this.errorId = errorId;
this.details = details;
this.error = error;
}
}
class ServerError extends BadResponse {
static fromResponse(error, status) {
return new ServerError(error.message || JSON.stringify(error), status, error.timestamp, error.error_id, error.details);
}
static fromText(response, status) {
return new ServerError(response, status);
}
}
const isMobile_isMobile = ()=>'undefined' != typeof navigator && 'ReactNative' === navigator.product;
const utils_isMobile = isMobile_isMobile;
const camelToUnderscore = (key)=>{
if ('string' != typeof key) throw new Error('Input is not a string');
return key.charAt(0).toLowerCase() + key.substring(1).replace(/([A-Z])/g, '_$1').toLowerCase();
};
const obfuscateToken = (token)=>{
if (!token) return token;
return token.split('-').map((part, index)=>0 === index ? part : 'xxxxxx').join('-');
};
const TRACE = 'trace';
const DEBUG = 'debug';
const INFO = 'info';
const LOG = 'log';
const WARN = 'warn';
const ERROR = 'error';
const CONSOLE_METHODS = [
INFO,
LOG,
WARN,
ERROR
];
const LOG_LEVELS = [
TRACE,
DEBUG,
INFO,
LOG,
WARN,
ERROR
];
const CATEGORY_PREFIX = 'logger-category=';
const MAX_REMOTE_RETRY = 10;
const addLevelsTo = (instance, withMethods = false)=>{
instance.TRACE = TRACE;
instance.DEBUG = DEBUG;
instance.INFO = INFO;
instance.LOG = LOG;
instance.WARN = WARN;
instance.ERROR = ERROR;
if (withMethods) {
instance.trace = (...args)=>instance.apply(null, [
TRACE,
...args
]);
instance.debug = (...args)=>instance.apply(null, [
DEBUG,
...args
]);
instance.info = (...args)=>instance.apply(null, [
INFO,
...args
]);
instance.log = (...args)=>instance.apply(null, [
LOG,
...args
]);
instance.warn = (...args)=>instance.apply(null, [
WARN,
...args
]);
instance.error = (...args)=>instance.apply(null, [
ERROR,
...args
]);
}
return instance;
};
const safeStringify = (object)=>{
const result = '{"message": "Not parsable JSON"}';
try {
return JSON.stringify(object);
} catch (e) {}
return result;
};
class IssueReporter_IssueReporter {
TRACE;
INFO;
LOG;
WARN;
ERROR;
oldConsoleMethods;
enabled;
remoteClientConfiguration;
buffer;
bufferTimeout;
_boundProcessBuffer;
_boundParseLoggerBody;
_callback;
constructor(){
addLevelsTo(this);
this.oldConsoleMethods = null;
this.enabled = false;
this.remoteClientConfiguration = null;
this.buffer = [];
this.bufferTimeout = null;
this._boundProcessBuffer = this._processBuffer.bind(this);
this._boundParseLoggerBody = this._parseLoggerBody.bind(this);
this._callback = null;
}
init() {
this._catchConsole();
}
setCallback(cb) {
this._callback = cb;
}
configureRemoteClient(configuration = {
tag: 'wazo-sdk',
host: null,
port: null,
level: null,
extra: {}
}) {
this.remoteClientConfiguration = configuration;
}
enable() {
if (!this.oldConsoleMethods) this.init();
this.enabled = true;
}
disable() {
this.enabled = false;
}
loggerFor(category) {
const logger = (level, ...args)=>{
this.log.apply(this, [
level,
this._makeCategory(category),
...args
]);
};
return addLevelsTo(logger, true);
}
removeSlashes(str) {
return str.replace(/"/g, "'").replace(/\\/g, '');
}
obfuscateHeaderToken(headers) {
const newHeaders = {
...headers
};
if ('X-Auth-Token' in newHeaders) newHeaders['X-Auth-Token'] = obfuscateToken(newHeaders['X-Auth-Token']);
return newHeaders;
}
log(level, ...args) {
if (!this.enabled) return;
let category = null;
let skipSendToRemote = false;
let extra = {};
if (0 === args[0].indexOf(CATEGORY_PREFIX)) {
category = args[0].split('=')[1];
args.splice(0, 1);
}
const lastArg = args[args.length - 1];
if (lastArg && ('object' == typeof lastArg && Object.keys(lastArg).length || lastArg instanceof Error)) {
extra = lastArg instanceof Error ? {
errorMessage: lastArg.message,
errorStack: lastArg.stack,
errorType: lastArg.constructor.name,
skipSendToRemote: lastArg.skipSendToRemote
} : lastArg;
args.splice(1, 1);
}
if (extra.skipSendToRemote) {
skipSendToRemote = true;
delete extra.skipSendToRemote;
}
const date = (0, __WEBPACK_EXTERNAL_MODULE_moment__["default"])().format('YYYY-MM-DD HH:mm:ss.SSS');
const message = args.join(', ');
let consoleMessage = message;
if (Object.keys(extra).length) {
const parsedExtra = safeStringify(extra);
consoleMessage = `${consoleMessage} (${parsedExtra})`;
}
if (category) consoleMessage = `[${category}] ${consoleMessage}`;
const consoleLevel = utils_isMobile() && 'error' === level ? WARN : level;
const oldMethod = this.oldConsoleMethods?.[consoleLevel] || this.oldConsoleMethods?.log;
oldMethod.apply(oldMethod, [
date,
consoleMessage
]);
if (this._callback) this._callback(level, consoleMessage);
if (!skipSendToRemote) this._sendToRemoteLogger(level, {
date,
message,
category,
...extra
});
}
logRequest(url, options, response, start) {
if (!this.enabled) return;
const { status } = response;
const duration = +new Date() - +start;
let level = TRACE;
if (status >= 400 && status < 500) level = WARN;
else if (status >= 500) level = ERROR;
this.log(level, this._makeCategory('http'), url, {
status,
body: this.removeSlashes(JSON.stringify(options.body)),
method: options.method,
headers: this.obfuscateHeaderToken(options.headers),
duration
});
}
getLogs() {
console.warn('IssueReporter\'s logs aren\'t stored anymore. Please use fluentd to store them');
return [];
}
getParsedLogs() {
console.warn('IssueReporter\'s logs aren\'t stored anymore. Please use fluentd to store them');
return [];
}
getReport() {
return this.getParsedLogs().join('\r\n');
}
_catchConsole() {
this.oldConsoleMethods = {};
CONSOLE_METHODS.forEach((methodName)=>{
if (this.oldConsoleMethods) this.oldConsoleMethods[methodName] = console[methodName];
const parent = 'undefined' != typeof window ? window : __webpack_require__.g;
parent.console[methodName] = (...args)=>{
try {
this.log(methodName, args.join(' '));
if (this.oldConsoleMethods) this.oldConsoleMethods[methodName].apply(null, args);
} catch (e) {}
};
});
}
_sendToRemoteLogger(level, payload = {}) {
if (!this.remoteClientConfiguration) return;
const { level: minLevel, bufferSize } = this.remoteClientConfiguration;
if (!minLevel || this._isLevelAbove(minLevel, level)) return;
payload.level = level;
if (bufferSize > 0) return this._addToBuffer(payload);
this._sendDebugToGrafana(payload);
}
_parseLoggerBody(payload) {
const { level } = payload;
const { maxMessageSize, extra } = this.remoteClientConfiguration || {};
delete payload.level;
if (maxMessageSize && 'string' == typeof payload.message && payload.message.length > maxMessageSize) payload.message = `${payload.message.substr(0, maxMessageSize)}...`;
return safeStringify({
level,
...payload,
...extra
});
}
_addToBuffer(payload) {
if (this.bufferTimeout) {
clearTimeout(this.bufferTimeout);
this.bufferTimeout = null;
}
this.buffer.push(payload);
const { bufferSize, bufferTimeout } = this.remoteClientConfiguration;
if (this.buffer.length > bufferSize) return this._processBuffer();
if (bufferTimeout > 0) this.bufferTimeout = setTimeout(this._boundProcessBuffer, bufferTimeout);
}
_processBuffer() {
this._sendDebugToGrafana(this.buffer);
this.buffer = [];
if (this.bufferTimeout) {
clearTimeout(this.bufferTimeout);
this.bufferTimeout = null;
}
}
_computeRetryDelay(attempt, initial = 1000, maxWait = 50000) {
const base = 1.5;
const wait = Math.min(initial * base ** attempt, maxWait);
const jitterWait = Math.max(initial, Math.random() * wait);
return jitterWait;
}
_sendDebugToGrafana(payload, retry = 0) {
if (!this.remoteClientConfiguration || retry >= MAX_REMOTE_RETRY) return;
const { tag, host, port } = this.remoteClientConfiguration;
const isSecure = 443 === +port;
const url = `http${isSecure ? 's' : ''}://${host}${isSecure ? '' : `:${port}`}/${tag}`;
const body = Array.isArray(payload) ? `[${payload.map(this._boundParseLoggerBody).join(',')}]` : this._parseLoggerBody(payload);
fetch(url, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body
}).catch((e)=>{
e.skipSendToRemote = true;
this.log('error', this._makeCategory('grafana'), 'Sending log to grafana, error', e);
const wait = this._computeRetryDelay(retry, 1000, 50000);
setTimeout(()=>{
if (Array.isArray(payload)) payload = payload.map((message)=>this._writeRetryCount(message, retry + 1));
else if (payload && 'object' == typeof payload) payload = this._writeRetryCount(payload, retry + 1);
this._sendDebugToGrafana(payload, retry + 1);
}, wait);
});
}
_writeRetryCount(message, count) {
if (message && 'object' == typeof message) message._retry = count;
return message;
}
_isLevelAbove(level1, level2) {
const index1 = LOG_LEVELS.indexOf(level1);
const index2 = LOG_LEVELS.indexOf(level2);
if (-1 === index1 || -1 === index2) return false;
return index1 > index2;
}
_makeCategory(category) {
return `${CATEGORY_PREFIX}${category}`;
}
}
const IssueReporter = new IssueReporter_IssueReporter();
const methods = [
'head',
'get',
'post',
'put',
'delete',
'options'
];
const api_requester_logger = IssueReporter ? IssueReporter.loggerFor('api') : console;
const REQUEST_TIMEOUT_MS = 300000;
class ApiRequester {
server;
agent;
clientId;
token;
tenant;
fetchOptions;
refreshTokenCallback;
refreshTokenPromise;
shouldLogErrors;
requestTimeout;
head;
get;
post;
put;
delete;
options;
static successResponseParser(response) {
return 204 === response.status || 201 === response.status || 200 === response.status;
}
static defaultParser(response) {
return response.json().then((data)=>({
...data,
_headers: response.headers
}));
}
static getQueryString(obj) {
return Object.keys(obj).filter((key)=>obj[key]).map((key)=>`${key}=${encodeURIComponent(obj[key])}`).join('&');
}
static base64Encode(str) {
if ('undefined' != typeof btoa) try {
return btoa(str);
} catch (error) {}
return __WEBPACK_EXTERNAL_MODULE_js_base64_4ca5b7bc__.Base64.encode(str);
}
constructor({ server, refreshTokenCallback, clientId, agent = null, token = null, fetchOptions, requestTimeout = REQUEST_TIMEOUT_MS }){
this.server = server;
this.agent = agent;
this.clientId = clientId;
this.refreshTokenCallback = refreshTokenCallback;
this.refreshTokenPromise = null;
this.fetchOptions = fetchOptions || {};
this.requestTimeout = requestTimeout || REQUEST_TIMEOUT_MS;
if (token) this.token = token;
this.shouldLogErrors = true;
methods.forEach((method)=>{
this[method] = function(...args) {
args.splice(1, 0, method);
return this.call.call(this, ...args);
};
});
}
setRequestTimeout(requestTimeout) {
this.requestTimeout = requestTimeout;
}
setTenant(tenant) {
this.tenant = tenant;
}
setToken(token) {
this.token = token;
}
setFetchOptions(options) {
this.fetchOptions = options;
}
disableErrorLogging() {
this.shouldLogErrors = false;
}
enableErrorLogging() {
this.shouldLogErrors = true;
}
async call(path, method = 'get', body = null, headers = null, parse = ApiRequester.defaultParser, firstCall = true) {
const url = this.computeUrl(method, path, body);
const newHeaders = this.getHeaders(headers);
let newBody = 'get' === method ? null : body;
if (newBody && 'application/json' === newHeaders['Content-Type']) newBody = JSON.stringify(newBody);
const isHead = 'head' === method;
const hasEmptyResponse = 'delete' === method || isHead;
const newParse = hasEmptyResponse && parse === ApiRequester.defaultParser ? ApiRequester.successResponseParser : parse;
const fetchOptions = {
...this.fetchOptions || {}
};
const controller = new AbortController();
const extraHeaders = fetchOptions.headers || {};
delete fetchOptions.headers;
const options = {
method,
body: newBody,
signal: controller ? controller.signal : null,
headers: {
...this.getHeaders(headers),
...extraHeaders
},
agent: this.agent,
...fetchOptions
};
if (this.refreshTokenPromise) {
api_requester_logger.info('A token is already refreshing, waiting ...', {
url
});
await this.refreshTokenPromise;
}
const start = new Date();
const requestPromise = fetch(url, options).then((response)=>{
const contentType = response.headers.get('content-type') || '';
const isJson = -1 !== contentType.indexOf('application/json');
IssueReporter.logRequest(url, options, response, start);
if (isHead && response.status >= 500 || !isHead && response.status >= 400) {
const promise = isJson ? response.json() : response.text();
const exceptionClass = response.status >= 500 ? ServerError : BadResponse;
return promise.then(async (err)=>{
if (firstCall && this._checkTokenExpired(response, err)) {
api_requester_logger.warn('token expired', {
error: err.reason
});
return this._replayWithNewToken(err, path, method, body, headers, parse);
}
const error = 'string' == typeof err ? exceptionClass.fromText(err, response.status) : exceptionClass.fromResponse(err, response.status);
if (this.shouldLogErrors) api_requester_logger.error('API error', error);
throw error;
});
}
return newParse(response, isJson);
}).catch((error)=>{
if (this.shouldLogErrors) api_requester_logger.error('Fetch failed', {
url,
options,
message: error.message,
stack: error.stack
});
throw error;
});
const requestTimeout = new Promise((resolve, reject)=>{
setTimeout(()=>{
controller.abort();
reject(new Error(`Request timed out after ${this.requestTimeout} ms`));
}, this.requestTimeout);
});
return Promise.race([
requestPromise,
requestTimeout
]);
}
_checkTokenExpired(response, err) {
const isTokenNotFound = 404 === response.status && this._isTokenNotFound(err);
return 401 === response.status || isTokenNotFound;
}
_isTokenNotFound(err) {
return err && err.reason && 'No such token' === err.reason[0];
}
_replayWithNewToken(err, path, method, body = null, headers = null, parse) {
const isTokenNotFound = this._isTokenNotFound(err);
let newPath = path;
api_requester_logger.info('refreshing token', {
inProgress: !!this.refreshTokenPromise
});
this.refreshTokenPromise = this.refreshTokenPromise || this.refreshTokenCallback();
return this.refreshTokenPromise?.then(()=>{
this.refreshTokenPromise = null;
api_requester_logger.info('token refreshed', {
isTokenNotFound
});
if (isTokenNotFound) {
const pathParts = path.split('/');
pathParts.pop();
pathParts.push(this.token);
newPath = pathParts.join('/');
}
return this.call(newPath, method, body, headers, parse, false);
}).catch((e)=>{
this.refreshTokenPromise = null;
throw e;
});
}
getHeaders(header) {
if (header instanceof Object) return header;
return {
'X-Auth-Token': this.token,
...this.tenant ? {
'Wazo-Tenant': this.tenant
} : null,
Accept: 'application/json',
'Content-Type': 'application/json'
};
}
computeUrl(method, path, body) {
const url = `${this.baseUrl}/${path}`;
return 'get' === method && body && Object.keys(body).length ? `${url}?${ApiRequester.getQueryString(body)}` : url;
}
get baseUrl() {
return `https://${this.server}/api`;
}
}
const swarmPublicKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmkXOuNfY8u5xoTiIhkb8
djnbIwG/Wrz3vpo8BZir8L5e1a1nSy740qBjP7ZINBQoALDhFfmdOfJnCyEGiHuz
ZW6jbG6C3PryE3Bu6GKwqSmD6k3q4Zk27fpwYAnNl+rWhYYM563rJZBda/INyHNN
pK7M1mixWi7gNdjjXwoEXSSBx+VpYMkY6LiAB2mvHXTY9M1qI14dvgGoQISZQoKi
NMTRCg5UP2ic0Dd9nSz/XpcOxGfa+0fwIl1F7RC1tJXOqvkGGPTOV4LLfg/Yta3h
nUPX9EZZDIX6vO/0IBV1LzjSl2A1bYFYAjJfowv3i1CpvONBOClHjSY5t9Y8MH6p
BwIDAQAB
-----END PUBLIC KEY-----`;
const pubkey = swarmPublicKey;
const new_from = (instance, ToClass)=>{
const args = {};
Object.getOwnPropertyNames(instance).forEach((prop)=>{
args[prop] = instance[prop];
});
return new ToClass(args);
};
class Line {
type;
id;
extensions;
endpointCustom;
endpointSccp;
endpointSip;
static parse(plain) {
return new Line({
id: plain.id,
extensions: plain.extensions,
endpointCustom: plain.endpoint_custom || null,
endpointSccp: plain.endpoint_sccp || null,
endpointSip: plain.endpoint_sip || null
});
}
static newFrom(profile) {
return new_from(profile, Line);
}
is(line) {
return !!line && this.id === line.id;
}
hasExtension(extension) {
if (!this.extensions) return false;
return this.extensions.some((ext)=>ext.exten === extension);
}
constructor({ id, extensions, endpointCustom, endpointSccp, endpointSip } = {}){
this.id = id;
this.extensions = extensions;
this.endpointCustom = endpointCustom || null;
this.endpointSccp = endpointSccp || null;
this.endpointSip = endpointSip || null;
this.type = 'Line';
}
}
const FORWARD_KEYS = {
BUSY: 'busy',
NO_ANSWER: 'noanswer',
UNCONDITIONAL: 'unconditional'
};
class ForwardOption {
destination;
enabled;
key;
static parse(plain, key) {
return new ForwardOption({
destination: plain.destination || '',
enabled: plain.enabled,
key
});
}
static newFrom(profile) {
return new_from(profile, ForwardOption);
}
constructor({ destination, enabled, key } = {}){
this.destination = destination;
this.enabled = enabled;
this.key = key;
}
setDestination(number) {
this.destination = number;
return this;
}
setEnabled(enabled) {
this.enabled = enabled;
return this;
}
is(other) {
return this.key === other.key;
}
}
class Incall {
id;
extensions;
extension;
type = 'Incall';
constructor({ id, extensions } = {}){
this.id = id;
this.extensions = extensions;
this.extension = extensions?.[0]?.exten;
}
static parse(plain) {
return new Incall({
id: plain.id,
extensions: plain.extensions
});
}
static newFrom(profile) {
return new_from(profile, Incall);
}
hasExtension(extension) {
if (!this.extensions) return false;
return this.extensions.some((ext)=>ext.exten === extension);
}
}
const STATE = {
AVAILABLE: 'available',
UNAVAILABLE: 'unavailable',
INVISIBLE: 'invisible',
DISCONNECTED: 'disconnected',
AWAY: 'away'
};
const LINE_STATE = {
AVAILABLE: 'available',
HOLDING: 'holding',
RINGING: 'ringing',
TALKING: 'talking',
UNAVAILABLE: 'unavailable',
PROGRESSING: 'progressing'
};
class Profile {
id;
firstName;
lastName;
email;
lines;
sipLines;
incalls;
username;
mobileNumber;
forwards;
doNotDisturb;
onlineCallRecordEnabled;
state;
ringSeconds;
voicemail;
status;
subscriptionType;
agent;
switchboards;
callPickupTargetUsers;
static parse(plain) {
return new Profile({
id: plain.uuid,
firstName: plain.firstName || plain.firstname || '',
lastName: plain.lastName || plain.lastname || '',
email: plain.email,
lines: plain.lines.map((line)=>Line.parse(line)),
incalls: plain.incalls,
username: plain.username,
mobileNumber: plain.mobile_phone_number || '',
ringSeconds: plain.ring_seconds,
forwards: [
ForwardOption.parse(plain.forwards.unconditional, FORWARD_KEYS.UNCONDITIONAL),
ForwardOption.parse(plain.forwards.noanswer, FORWARD_KEYS.NO_ANSWER),
ForwardOption.parse(plain.forwards.busy, FORWARD_KEYS.BUSY)
],
doNotDisturb: plain.services.dnd.enabled,
subscriptionType: plain.subscription_type,
voicemail: plain.voicemail,
switchboards: plain.switchboards || [],
agent: plain.agent,
status: '',
callPickupTargetUsers: plain.call_pickup_target_users || [],
onlineCallRecordEnabled: plain.online_call_record_enabled
});
}
static newFrom(profile) {
return new_from(profile, Profile);
}
constructor({ id, firstName, lastName, email, lines, username, mobileNumber, forwards, doNotDisturb, state, subscriptionType, voicemail, switchboards, agent, status, ringSeconds, sipLines, callPickupTargetUsers, onlineCallRecordEnabled, incalls }){
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.lines = lines;
this.username = username;
this.mobileNumber = mobileNumber;
this.forwards = forwards;
this.doNotDisturb = doNotDisturb;
this.state = state;
this.voicemail = voicemail;
this.subscriptionType = subscriptionType;
this.switchboards = switchboards;
this.agent = agent;
this.status = status;
this.callPickupTargetUsers = callPickupTargetUsers;
this.onlineCallRecordEnabled = onlineCallRecordEnabled;
this.ringSeconds = ringSeconds;
this.sipLines = sipLines || [];
this.incalls = incalls?.map(Incall.parse) || [];
}
static getLinesState(lines) {
let result = LINE_STATE.UNAVAILABLE;
for (const line of lines){
if (line.state === LINE_STATE.RINGING) {
result = LINE_STATE.RINGING;
break;
}
if (line.state === LINE_STATE.TALKING) {
result = LINE_STATE.TALKING;
break;
}
if (line.state === LINE_STATE.AVAILABLE) result = LINE_STATE.AVAILABLE;
}
return result;
}
hasId(id) {
return id === this.id;
}
setMobileNumber(number) {
this.mobileNumber = number;
return this;
}
setForwardOption(forwardOption) {
const updatedForwardOptions = this.forwards.slice();
const index = updatedForwardOptions.findIndex((forward)=>forward.is(forwardOption));
updatedForwardOptions.splice(index, 1, forwardOption);
this.forwards = updatedForwardOptions;
return this;
}
setDoNotDisturb(enabled) {
this.doNotDisturb = enabled;
return this;
}
setState(state) {
this.state = state;
return this;
}
}
const BACKEND = {
OFFICE365: 'office365',
PERSONAL: 'personal',
GOOGLE: 'google',
WAZO: 'wazo',
CONFERENCE: 'conference',
PHONEBOOK: 'phonebook'
};
const SOURCE_MOBILE = 'mobile';
class Contact {
static BACKEND = BACKEND;
type;
id;
uuid;
name;
firstName;
lastName;
external;
number;
numbers;
favorited;
email;
emails;
entreprise;
birthday;
address;
note;
endpointId;
personal;
state;
lineState;
previousPresential;
lastActivity;
mobile;
source;
sourceId;
status;
backend;
personalStatus;
sessions;
connected;
doNotDisturb;
ringing;
lines;
static merge(oldContacts, newContacts) {
return newContacts.map((current)=>{
const old = oldContacts.find((contact)=>contact && contact.is(current));
return old ? current.merge(old) : current;
});
}
static sortContacts(a, b) {
const aNames = a.separateName();
const bNames = b.separateName();
const aLastName = aNames.lastName;
const bLastName = bNames.lastName;
if (aLastName === bLastName) return aNames.firstName.localeCompare(bNames.firstName);
return aLastName.localeCompare(bLastName);
}
static parseMany(response, offset = 0, limit = null) {
if (!response || !response.results || 0 === limit) return [];
const results = null !== limit && limit > 0 ? response.results.slice(offset, limit) : offset > 0 ? response.results.slice(offset) : response.results;
return results.map((r)=>Contact.parse(r, response.column_types));
}
static manyGraphQlWithNumbersParser(numbers) {
return (response)=>{
if (!response.data || !response.data.me || !response.data.me.contacts) return [];
return response.data.me.contacts.edges.map((edge, i)=>{
if (!edge.node) return null;
const { email } = edge.node;
const name = edge.node.firstname && edge.node.lastname ? `${edge.node.firstname || ''} ${edge.node.lastname || ''}` : edge.node.wazoReverse;
return new Contact({
name,
firstName: edge.node.firstname,
lastName: edge.node.lastname,
number: numbers[i],
numbers: [
{
label: 'primary',
number: numbers[i]
}
],
backend: edge.node.wazoBackend,
source: edge.node.wazoSourceName,
sourceId: edge.node.wazoSourceEntryId || '',
email: email || '',
emails: email ? [
{
label: 'primary',
email
}
] : [],
uuid: edge.node.userUuid
});
}).filter((contact)=>!!contact);
};
}
static fetchNumbers(plain, columns) {
const numberColumns = columns.map((e, index)=>({
index,
columnName: e
})).filter((e)=>'number' === e.columnName || 'callable' === e.columnName).map((e)=>e.index);
return plain.column_values.filter((e, index)=>numberColumns.some((i)=>i === index) && null !== e);
}
static parse(plain, columns) {
const numbers = Contact.fetchNumbers(plain, columns);
const email = plain.column_values[columns.indexOf('email')];
return new Contact({
name: plain.column_values[columns.indexOf('name')],
firstName: plain.column_values[columns.indexOf('firstname')],
lastName: plain.column_values[columns.indexOf('lastname')],
number: numbers.length ? numbers[0] : '',
numbers: numbers.map((number, i)=>({
label: 0 === i ? 'primary' : 'secondary',
number
})),
favorited: plain.column_values[columns.indexOf('favorite')],
email: email || '',
emails: email ? [
{
label: 'primary',
email
}
] : [],
entreprise: plain.column_values[columns.indexOf('entreprise')] || '',
birthday: plain.column_values[columns.indexOf('birthday')] || '',
address: plain.column_values[columns.indexOf('address')] || '',
note: plain.column_values[columns.indexOf('note')] || '',
endpointId: plain.relations.endpoint_id,
personal: plain.column_values[columns.indexOf('personal')],
source: plain.source,
sourceId: plain.relations.source_entry_id || '',
uuid: plain.relations.user_uuid,
backend: plain.backend || ''
});
}
static parseManyPersonal(results) {
return results.map((r)=>Contact.parsePersonal(r));
}
static parsePersonal(plain) {
return new Contact({
name: `${plain.firstName || plain.firstname || ''} ${plain.lastName || plain.lastname || ''}`,
firstName: plain.firstName || plain.firstname,
lastName: plain.lastName || plain.lastname,
number: plain.number || '',
numbers: plain.number ? [
{
label: 'primary',
number: plain.number
}
] : [],
email: plain.email || '',
emails: plain.email ? [
{
label: 'primary',
email: plain.email
}
] : [],
source: 'personal',
uuid: plain.id,
id: plain.id,
sourceId: plain.id || '',
entreprise: plain.entreprise || '',
birthday: plain.birthday || '',
address: plain.address || '',
note: plain.note || '',
favorited: plain.favorited,
personal: true,
backend: plain.backend || BACKEND.PERSONAL
});
}
static parseMobile(plain) {
let address = '';
if (plain.postalAddresses.length) {
const postalAddress = plain.postalAddresses[0];
address = `${postalAddress.street} ${postalAddress.city} ${postalAddress.postCode} ${postalAddress.country}`;
}
const firstName = plain.givenName || '';
const lastName = plain.familyName || '';
const companyName = plain.company || '';
const isCompanyAccount = !firstName && !lastName;
const name = isCompanyAccount ? companyName : `${firstName} ${lastName}`;
return new Contact({
name,
firstName,
lastName,
number: plain.phoneNumbers.length ? plain.phoneNumbers[0].number : '',
numbers: [
...new Map(plain.phoneNumbers.map((item)=>[
item.number,
item
])).values()
].map((item, idx)=>({
label: 0 === idx ? 'primary' : 'secondary',
number: item.number
})),
email: plain.emailAddresses.length ? plain.emailAddresses[0].email : '',
emails: plain.emailAddresses.length ? [
{
label: 'primary',
email: plain.emailAddresses[0].email
}
] : [],
source: SOURCE_MOBILE,
sourceId: plain.recordID || '',
birthday: plain.birthday ? `${plain.birthday.year}-${plain.birthday.month}-${plain.birthday.day}` : '',
address,
note: plain.note || '',
favorited: false,
personal: true
});
}
static parseManyOffice365(response, source) {
return response.map((r)=>Contact.parseOffice365(r, source));
}
static parseOffice365(single, source) {
const emails = [];
const numbers = [];
if (single.emailAddresses) single.emailAddresses.map((email)=>emails.push({
email: email.address
}));
if (single.businessPhones) single.businessPhones.map((phone)=>numbers.push({
label: 'business',
number: phone
}));
if (single.mobilePhone) numbers.push({
label: 'mobile',
number: single.mobilePhone
});
if (single.homePhones) single.homePhones.map((phone)=>numbers.push({
label: 'home',
number: phone
}));
return new Contact({
sourceId: single.id || '',
name: single.displayName || '',
firstName: single.givenName,
lastName: single.surname,
number: numbers.length ? numbers[0].number : '',
numbers,
emails,
source: source.name,
backend: BACKEND.OFFICE365
});
}
static parseManyGoogle(response, source) {
return response.map((r)=>Contact.parseGoogle(r, source));
}
static parseGoogle(single, source) {
const emails = [];
const numbers = [];
if (single.emails) single.emails.forEach((email)=>'object' == typeof email ? {
email: email.address,
label: email.label
} : {
email
});
if (single.numbers_by_label) Object.keys(single.numbers_by_label).forEach((label)=>numbers.push({
label,
number: single.numbers_by_label[label]
}));
else if (single.numbers) single.numbers.forEach((phone)=>numbers.push({
number: phone
}));
return new Contact({
sourceId: single.id || '',
name: single.name || '',
firstName: single.lastname || '',
lastName: single.firstname || '',
number: numbers.length ? numbers[0].number : '',
numbers,
emails,
source: source.name,
backend: BACKEND.GOOGLE
});
}
static parseManyWazo(response, source) {
return response.map((r)=>Contact.parseWazo(r, source));
}
static parseWazo(single, source) {
const emails = [];
const numbers = [];
if (single.email) emails.push({
label: 'email',
email: single.email
});
if (single.exten) numbers.push({
label: 'exten',
number: single.exten
});
if (single.mobile_phone_number) numbers.push({
label: 'mobile',
number: single.mobile_phone_number
});
return new Contact({
uuid: single.uuid,
sourceId: String(single.id) || '',
name: `${single.firstname}${single.lastname ? ` ${single.lastname}` : ''}`,
firstName: single.firstname,
lastName: single.lastname,
number: numbers.length ? numbers[0].number : '',
numbers,
emails,
source: source.name,
backend: BACKEND.WAZO
});
}
static parseManyConference(response, source) {
return response.map((r)=>Contact.parseConference(r, source));
}
static parseConference(single, source) {
const numbers = [];
let firstNumber = '';
if (single && single.extensions && single.extensions.length > 0 && single.extensions[0].exten) {
firstNumber = single.extensions[0].exten;
numbers.push({
label: 'exten',
number: firstNumber
});
}
return new Contact({
sourceId: String(single.id),
name: single.name,
number: firstNumber,
numbers,
source: source.name,
backend: BACKEND.CONFERENCE
});
}
static newFrom(contact) {
return new_from(contact, Contact);
}
constructor({ id, uuid, name, firstName, lastName, external, number, numbers, email, emails, source, sourceId, entreprise, birthday, address, note, state, lineState, lastActivity, mobile, status, endpointId, personal, favorited, backend, personalStatus, sessions, connected, doNotDisturb, ringing, previousPresential, lines } = {}){
this.id = id;
this.uuid = uuid;
this.name = name || '';
this.firstName = firstName || '';
this.lastName = lastName || '';
this.external = external || false;
this.number = number;
this.numbers = numbers;
this.email = email;
this.emails = emails;
this.source = source;
this.sourceId = sourceId;
this.entreprise = entreprise;
this.birthday = birthday;
this.address = address;
this.note = note;
this.state = state;
this.lineState = lineState;