diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..e69de29 diff --git a/packages/adapter-ameyo/lib/assets/js/ajaxClient.ts b/packages/adapter-ameyo/lib/assets/js/ajaxClient.ts index 7c7cd97..93d68e7 100644 --- a/packages/adapter-ameyo/lib/assets/js/ajaxClient.ts +++ b/packages/adapter-ameyo/lib/assets/js/ajaxClient.ts @@ -64,94 +64,134 @@ export function parseQuerystring(url: string): Record { function extractUserCallModelUpdatedPush(rawResponse) { const parts = rawResponse .replaceAll(`Content-type: application/json ; charset: utf-8\r\n\r\n`, '') - .split("--DON'T_PANIC!_more_will_follow\r\n"); - let res = null; - for (const part of parts) { - try { - const jsonData = JSON.parse(part.trim()); - if (jsonData?.pushType === pushResponseTypes.CRMCreateNotifyPush) { - const crtObjectId = jsonData?.data?.crtObjectId; - const parsedObject = parseQuerystring(jsonData?.data?.crmURL); - let userCRTObjectId = parsedObject?.userCrtObjectId?.replace('%40', '@'); - userCRTObjectId = userCRTObjectId.replace('%40', '@'); - const phoneNumber = parsedObject?.phone; - const lan = parsedObject?.loanaccountnumber; - const callId = parsedObject?.unique_id || parsedObject?.callid; - localStorage.setItem( - 'revEngCustomerInfo', - JSON.stringify({phoneNumber, lan, crtObjectId, userCRTObjectId, callId}) - ); - sendCallStatusMessage(res); + .split("--DON'T_PANIC!_more_will_follow\r\n") + .map((part) => { + try { + return JSON.parse(part.trim()); + } catch { + return null; // Ignore parsing errors } - if (jsonData?.pushType === pushResponseTypes.UserCallModelUpdatedPush) { - res = jsonData; - sendCallStatusMessage(res); - } - if (jsonData?.pushType === pushResponseTypes.CustomerCallMemberUpdatedPush) { - const payload = jsonData?.data; - // handle for transfer call - if (payload?.isDisposing && - payload?.status === 'hungup') - sendCallStatusMessage(jsonData); - } - if (jsonData?.pushType === pushResponseTypes.UserCallMemberUpdatedPush) { - const payload = jsonData?.data; - const validStatuses = ["ringing", "connected", "hungup"]; - // handle for transfer call - if (payload?.associationType === 'transfer.association' && validStatuses.includes(payload?.status)) { - window.postMessage({ - type: MessagingType.ON_AMEYO_CALL_TRANSFER, - data: payload - }) - } - } - if (jsonData?.pushType === pushResponseTypes.UserCCRuntimeUpdatedPush) { - const payload = jsonData?.data; - //handle ameyo erroronous condition - if (payload?.isOnBreak) { - window.postMessage({ - type: MessagingType.ON_AMEYO_AGENT_ON_BREAK, - data: { - breakReason: 'ameyo is errorounous', - } - }); - } - } - if (jsonData?.pushType == pushResponseTypes.UserLoggedOffPush) { - const payload = jsonData?.data; + }) + .filter(Boolean); // Remove null values + + // Prioritize CRMCreateNotifyPush and keep the rest + const sortedParts = [ + ...parts.filter(part => part?.pushType === pushResponseTypes.CRMCreateNotifyPush), + ...parts.filter(part => part?.pushType !== pushResponseTypes.CRMCreateNotifyPush), + ]; + + sortedParts.forEach(jsonData => { + if (jsonData?.pushType === pushResponseTypes.CRMCreateNotifyPush) { + const crtObjectId = jsonData?.data?.crtObjectId; + const parsedObject = parseQuerystring(jsonData?.data?.crmURL); + let userCRTObjectId = parsedObject?.userCrtObjectId?.replace('%40', '@'); + userCRTObjectId = userCRTObjectId.replace('%40', '@'); + const phoneNumber = parsedObject?.phone; + const lan = parsedObject?.loanaccountnumber; + const callId = parsedObject?.unique_id || parsedObject?.callid; + localStorage.setItem( + 'revEngCustomerInfo', + JSON.stringify({phoneNumber, lan, crtObjectId, userCRTObjectId, callId}) + ); + } + if (jsonData?.pushType === pushResponseTypes.UserCallModelUpdatedPush) { + sendCallStatusMessage(jsonData); + } + if (jsonData?.pushType === pushResponseTypes.CustomerCallMemberUpdatedPush) { + const payload = jsonData?.data; + // handle for transfer call + if (payload?.isDisposing && + payload?.status === 'hungup') + sendCallStatusMessage(jsonData); + } + if (jsonData?.pushType === pushResponseTypes.UserCallMemberUpdatedPush) { + const payload = jsonData?.data; + const validStatuses = ["ringing", "connected", "hungup"]; + // handle for transfer call + if (payload?.associationType === 'transfer.association' && validStatuses.includes(payload?.status)) { window.postMessage({ - type: MessagingType.ON_AMEYO_FORCED_LOGOUT, - data: {} + type: MessagingType.ON_AMEYO_CALL_TRANSFER, + data: payload }) } - } catch (e) { - /* empty */ } - } + if (jsonData?.pushType === pushResponseTypes.UserCCRuntimeUpdatedPush) { + const payload = jsonData?.data; + //handle ameyo erroronous condition + if (payload?.isOnBreak) { + window.postMessage({ + type: MessagingType.ON_AMEYO_AGENT_ON_BREAK, + data: { + breakReason: 'ameyo is errorounous', + } + }); + } + } + if (jsonData?.pushType == pushResponseTypes.UserLoggedOffPush) { + const payload = jsonData?.data; + window.postMessage({ + type: MessagingType.ON_AMEYO_FORCED_LOGOUT, + data: {} + }) + } + } ) } -const sendCallStatusMessage = res => { - let message = null; - const data = JSON.parse( - localStorage.getItem('revEngCustomerInfo') || '{}' - ); - if (res?.data?.status === 'ringing') { - message = { - type: MessagingType.ON_AMEYO_CALL_INCOMING, - data - }; - } else if (res?.data?.status === 'connected') { - message = { - type: MessagingType.ON_AMEYO_CALL_ACCEPTED, - data - }; - } else if (res?.data?.status === 'hungup') { - message = { - type: MessagingType.ON_AMEYO_CALL_DISCONNECTED, - data +const sendCallStatusMessage = (res) => { + try { + const status = res?.data?.status; + + const getCustomerInfo = () => + JSON.parse(localStorage.getItem('revEngCustomerInfo') || '{}'); + + const sendConnectedMessage = (retryCount = 3) => { + /* The callId is received after the call is connected. + * Since callId is essential and cannot be null, + * this retry mechanism ensures we wait until it becomes available. */ + const data = getCustomerInfo(); + if (data?.callId) { + const message = { + type: MessagingType.ON_AMEYO_CALL_ACCEPTED, + data, + }; + window.postMessage(message); + } else if (retryCount > 0) { + setTimeout(() => sendConnectedMessage(retryCount - 1), 100); + } else { + console.warn('Unable to send ON_AMEYO_CALL_ACCEPTED: callId not found.'); + } }; + + switch (status) { + case 'ringing': { + const data = getCustomerInfo(); + const message = { + type: MessagingType.ON_AMEYO_CALL_INCOMING, + data, + }; + window.postMessage(message); + break; + } + case 'connected': { + sendConnectedMessage(); + break; + } + case 'hungup': { + const data = getCustomerInfo(); + const message = { + type: MessagingType.ON_AMEYO_CALL_DISCONNECTED, + data, + }; + window.postMessage(message); + localStorage.removeItem('revEngCustomerInfo'); + break; + } + default: + console.warn(`Unhandled call status: ${status}`); + } + } catch (error) { + console.error('Error in sendCallStatusMessage:', error); } - if (message) window.postMessage(message); }; function createRequestObject() { diff --git a/packages/adapter-ameyo/lib/main.ts b/packages/adapter-ameyo/lib/main.ts index 92404f4..9a13933 100644 --- a/packages/adapter-ameyo/lib/main.ts +++ b/packages/adapter-ameyo/lib/main.ts @@ -108,7 +108,7 @@ class AmeyoAdapter implements IAdapter { this._initializeAmeyo(); this.metricProcessor = metricProcessor; this.clickStreamProcessor = clickStreamProcessor; - this.metricProcessor.pushCounterMetric({metricName: 'initSdk', flow: "sdk_init_count"}) + this.metricProcessor?.pushCounterMetric({metricName: 'initSdk', flow: "sdk_init_count"}) } @@ -119,7 +119,7 @@ class AmeyoAdapter implements IAdapter { loadCredentials({accountName, userName, domain, password}); loadCallOptions(); sipRegister({domain: domainOnly, port}); - this.metricProcessor.pushCounterMetric({metricName: 'sipStackInitialised',flow: 'ameyo-sip-stack_init_count'}) + this.metricProcessor?.pushCounterMetric({metricName: 'sipStackInitialised',flow: 'ameyo-sip-stack_init_count'}) } @@ -136,12 +136,12 @@ class AmeyoAdapter implements IAdapter { _onListenForCorsBypassResponse = (payload: GenericObject) => { if(payload?.data?.requestKey !== RequestKeys.AMEYO_HEARTBEAT && !payload?.data?.err) { - this.metricProcessor.pushCounterMetric({ + this.metricProcessor?.pushCounterMetric({ metricName: `ameyo-api-call-count`, flow: 'api-call-count', subFlow: payload?.data?.requestKey }) - this.metricProcessor.pushHistogramMetric({ + this.metricProcessor?.pushHistogramMetric({ metricName: `ameyo-api-latency-${payload?.data?.requestKey}`, flow: 'api-latency', subFlow: payload?.data?.requestKey, @@ -150,9 +150,9 @@ class AmeyoAdapter implements IAdapter { } if(payload?.data?.err) { - this.clickStreamProcessor.sendClickStreamEvent({type: 'api-error', data: payload?.data?.err}) - this.metricProcessor.pushCounterMetric({metricName: `ameyo-api-err-count`, flow: 'api-error-count', subFlow: payload?.data?.requestKey}) - this.clickStreamProcessor.sendClickStreamEvent({type: 'api-error', err: payload?.data?.err}) + this.clickStreamProcessor?.sendClickStreamEvent({type: 'api-error', data: payload?.data?.err}) + this.metricProcessor?.pushCounterMetric({metricName: `ameyo-api-err-count`, flow: 'api-error-count', subFlow: payload?.data?.requestKey}) + this.clickStreamProcessor?.sendClickStreamEvent({type: 'api-error', err: payload?.data?.err}) } if (payload?.data?.requestKey === RequestKeys.AMEYO_LOGIN) { @@ -305,6 +305,7 @@ class AmeyoAdapter implements IAdapter { rejectCall() { sipHangUp(); + localStorage.removeItem('revEngCustomerInfo'); } disposeCall() {