@webex/contact-center 3.12.0-next.5 → 3.12.0-next.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/cc.js +161 -21
  2. package/dist/cc.js.map +1 -1
  3. package/dist/constants.js +2 -0
  4. package/dist/constants.js.map +1 -1
  5. package/dist/metrics/behavioral-events.js +26 -0
  6. package/dist/metrics/behavioral-events.js.map +1 -1
  7. package/dist/metrics/constants.js +4 -0
  8. package/dist/metrics/constants.js.map +1 -1
  9. package/dist/services/config/Util.js +1 -1
  10. package/dist/services/config/Util.js.map +1 -1
  11. package/dist/services/config/constants.js +1 -1
  12. package/dist/services/config/constants.js.map +1 -1
  13. package/dist/services/config/types.js +4 -0
  14. package/dist/services/config/types.js.map +1 -1
  15. package/dist/services/core/Err.js.map +1 -1
  16. package/dist/services/core/Utils.js +37 -9
  17. package/dist/services/core/Utils.js.map +1 -1
  18. package/dist/services/task/TaskManager.js +90 -8
  19. package/dist/services/task/TaskManager.js.map +1 -1
  20. package/dist/services/task/constants.js +3 -1
  21. package/dist/services/task/constants.js.map +1 -1
  22. package/dist/services/task/dialer.js +78 -0
  23. package/dist/services/task/dialer.js.map +1 -1
  24. package/dist/services/task/index.js +7 -2
  25. package/dist/services/task/index.js.map +1 -1
  26. package/dist/services/task/types.js +44 -0
  27. package/dist/services/task/types.js.map +1 -1
  28. package/dist/types/cc.d.ts +44 -0
  29. package/dist/types/constants.d.ts +2 -0
  30. package/dist/types/metrics/constants.d.ts +4 -0
  31. package/dist/types/services/config/types.d.ts +10 -1
  32. package/dist/types/services/core/Err.d.ts +4 -0
  33. package/dist/types/services/core/Utils.d.ts +10 -3
  34. package/dist/types/services/task/constants.d.ts +2 -0
  35. package/dist/types/services/task/dialer.d.ts +30 -0
  36. package/dist/types/services/task/types.d.ts +53 -1
  37. package/dist/webex.js +1 -1
  38. package/package.json +9 -9
  39. package/src/cc.ts +196 -22
  40. package/src/constants.ts +2 -0
  41. package/src/metrics/behavioral-events.ts +28 -0
  42. package/src/metrics/constants.ts +4 -0
  43. package/src/services/config/Util.ts +1 -1
  44. package/src/services/config/constants.ts +1 -1
  45. package/src/services/config/types.ts +6 -1
  46. package/src/services/core/Err.ts +2 -0
  47. package/src/services/core/Utils.ts +43 -8
  48. package/src/services/task/TaskManager.ts +102 -22
  49. package/src/services/task/constants.ts +2 -0
  50. package/src/services/task/dialer.ts +80 -0
  51. package/src/services/task/index.ts +7 -2
  52. package/src/services/task/types.ts +56 -0
  53. package/test/unit/spec/cc.ts +154 -20
  54. package/test/unit/spec/services/config/index.ts +3 -3
  55. package/test/unit/spec/services/core/Utils.ts +90 -7
  56. package/test/unit/spec/services/task/TaskManager.ts +238 -7
  57. package/test/unit/spec/services/task/dialer.ts +190 -0
  58. package/test/unit/spec/services/task/index.ts +21 -0
  59. package/umd/contact-center.min.js +2 -2
  60. package/umd/contact-center.min.js.map +1 -1
package/dist/cc.js CHANGED
@@ -312,7 +312,6 @@ class ContactCenter extends _webexCore.WebexPlugin {
312
312
  webex: this.$webex,
313
313
  connectionConfig: this.getConnectionConfig()
314
314
  });
315
- this.services.webSocketManager.on('message', this.handleWebsocketMessage);
316
315
  this.webCallingService = new _WebCallingService.default(this.$webex);
317
316
  this.apiAIAssistant = new _ApiAiAssistant.ApiAIAssistant(this.$webex);
318
317
  this.metricsManager = _MetricsManager.default.getInstance({
@@ -422,13 +421,14 @@ class ContactCenter extends _webexCore.WebexPlugin {
422
421
  * ```
423
422
  */
424
423
  async register() {
425
- _loggerProxy.default.info('Starting CC SDK registration', {
424
+ _loggerProxy.default.log('Starting CC SDK registration', {
426
425
  module: _constants.CC_FILE,
427
426
  method: _constants.METHODS.REGISTER
428
427
  });
429
428
  try {
430
429
  this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_SUCCESS, _constants4.METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_FAILED]);
431
430
  this.setupEventListeners();
431
+ this.services.webSocketManager.on('message', this.handleWebsocketMessage);
432
432
  const resp = await this.connectWebsocket();
433
433
  // Ensure 'dn' is always populated from 'defaultDn'
434
434
  resp.dn = resp.defaultDn;
@@ -616,7 +616,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
616
616
  * @private
617
617
  */
618
618
  async connectWebsocket() {
619
- _loggerProxy.default.info('Connecting to websocket', {
619
+ _loggerProxy.default.log('Connecting to websocket', {
620
620
  module: _constants.CC_FILE,
621
621
  method: _constants.METHODS.CONNECT_WEBSOCKET
622
622
  });
@@ -639,7 +639,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
639
639
  this.taskManager.setWebRtcEnabled(this.agentConfig.webRtcEnabled);
640
640
  this.apiAIAssistant.setAIFeatureFlags(this.agentConfig.aiFeature);
641
641
  if (this.agentConfig.aiFeature?.realtimeTranscripts?.enable) {
642
- _loggerProxy.default.info('Connecting to RTD websocket', {
642
+ _loggerProxy.default.log('Connecting to RTD websocket', {
643
643
  module: _constants.CC_FILE,
644
644
  method: _constants.METHODS.CONNECT_WEBSOCKET
645
645
  });
@@ -675,6 +675,11 @@ class ContactCenter extends _webexCore.WebexPlugin {
675
675
  }
676
676
  if (this.$config && this.$config.allowAutomatedRelogin) {
677
677
  await this.silentRelogin();
678
+ } else {
679
+ _loggerProxy.default.log('Skipping silent relogin: allowAutomatedRelogin is disabled', {
680
+ module: _constants.CC_FILE,
681
+ method: _constants.METHODS.CONNECT_WEBSOCKET
682
+ });
678
683
  }
679
684
  return this.agentConfig;
680
685
  } catch (error) {
@@ -715,22 +720,27 @@ class ContactCenter extends _webexCore.WebexPlugin {
715
720
  * ```
716
721
  */
717
722
  async stationLogin(data) {
718
- _loggerProxy.default.info('Starting agent station login', {
723
+ const loggerContext = {
719
724
  module: _constants.CC_FILE,
720
725
  method: _constants.METHODS.STATION_LOGIN
721
- });
726
+ };
722
727
  try {
728
+ _loggerProxy.default.log(`Starting agent station login | loginOption: ${data?.loginOption} teamId: ${data?.teamId}`, loggerContext);
723
729
  this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS, _constants4.METRIC_EVENT_NAMES.STATION_LOGIN_FAILED]);
724
730
  const dialPlanEntries = this.agentConfig?.dialPlan?.dialPlanEntity ?? [];
725
- if (data.loginOption === _types.LoginOption.AGENT_DN && !(0, _Utils.isValidDialNumber)(data.dialNumber, dialPlanEntries)) {
726
- const error = new Error('INVALID_DIAL_NUMBER');
727
- // @ts-ignore - adding custom key to the error object
728
- error.details = {
729
- data: {
730
- reason: 'INVALID_DIAL_NUMBER'
731
- }
732
- };
733
- throw error;
731
+ if (data.loginOption === _types.LoginOption.AGENT_DN) {
732
+ _loggerProxy.default.log(`Validating dial number | dialPlanEnabled: ${!!this.agentConfig?.dialPlan} | dialPlanEntryCount: ${dialPlanEntries.length}`, loggerContext);
733
+ if (!(0, _Utils.isValidDialNumber)(data.dialNumber, dialPlanEntries)) {
734
+ _loggerProxy.default.log(`Dial number validation failed | dialNumber: ${data.dialNumber} | dialPlanEntryCount: ${dialPlanEntries.length}`, loggerContext);
735
+ const error = new Error('INVALID_DIAL_NUMBER');
736
+ // @ts-ignore - adding custom key to the error object
737
+ error.details = {
738
+ data: {
739
+ reason: 'INVALID_DIAL_NUMBER'
740
+ }
741
+ };
742
+ throw error;
743
+ }
734
744
  }
735
745
  const loginResponse = await this.services.agent.stationLogin({
736
746
  data: {
@@ -1102,13 +1112,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
1102
1112
  async handleConnectionLost(msg) {
1103
1113
  if (msg.isConnectionLost) {
1104
1114
  // TODO: Emit an event saying connection is lost
1105
- _loggerProxy.default.info('event=handleConnectionLost | Connection lost', {
1115
+ _loggerProxy.default.log('event=handleConnectionLost | Connection lost', {
1106
1116
  module: _constants.CC_FILE,
1107
1117
  method: _constants.METHODS.HANDLE_CONNECTION_LOST
1108
1118
  });
1109
1119
  } else if (msg.isSocketReconnected) {
1110
1120
  // TODO: Emit an event saying connection is re-estabilished
1111
- _loggerProxy.default.info('event=handleConnectionReconnect | Connection reconnected attempting to request silent relogin', {
1121
+ _loggerProxy.default.log('event=handleConnectionReconnect | Connection reconnected attempting to request silent relogin', {
1112
1122
  module: _constants.CC_FILE,
1113
1123
  method: _constants.METHODS.HANDLE_CONNECTION_LOST
1114
1124
  });
@@ -1123,7 +1133,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
1123
1133
  * @private
1124
1134
  */
1125
1135
  async silentRelogin() {
1126
- _loggerProxy.default.info('Starting silent relogin process', {
1136
+ _loggerProxy.default.log('Starting silent relogin process', {
1127
1137
  module: _constants.CC_FILE,
1128
1138
  method: _constants.METHODS.SILENT_RELOGIN
1129
1139
  });
@@ -1145,7 +1155,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
1145
1155
  this.agentConfig.currentTeamId = reLoginResponse.data.teamId;
1146
1156
  await this.handleDeviceType(deviceType, dn);
1147
1157
  if (lastStateChangeReason === 'agent-wss-disconnect') {
1148
- _loggerProxy.default.info('event=requestAutoStateChange | Requesting state change to available on socket reconnect', {
1158
+ _loggerProxy.default.log('event=requestAutoStateChange | Requesting state change to available on socket reconnect', {
1149
1159
  module: _constants.CC_FILE,
1150
1160
  method: _constants.METHODS.SILENT_RELOGIN
1151
1161
  });
@@ -1169,8 +1179,6 @@ class ContactCenter extends _webexCore.WebexPlugin {
1169
1179
  }
1170
1180
  this.agentConfig.lastStateAuxCodeId = auxCodeId;
1171
1181
  this.agentConfig.isAgentLoggedIn = true;
1172
- // TODO: https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-626777 Implement the de-register method and close the listener there
1173
- this.services.webSocketManager.on('message', this.handleWebsocketMessage);
1174
1182
  _loggerProxy.default.log(`Silent relogin process completed successfully with login Option: ${reLoginResponse.data.deviceType} teamId: ${reLoginResponse.data.teamId}`, {
1175
1183
  module: _constants.CC_FILE,
1176
1184
  method: _constants.METHODS.SILENT_RELOGIN,
@@ -1444,6 +1452,138 @@ class ContactCenter extends _webexCore.WebexPlugin {
1444
1452
  }
1445
1453
  }
1446
1454
 
1455
+ /**
1456
+ * Skips a campaign preview contact, requesting the next contact from the campaign.
1457
+ *
1458
+ * When a campaign manager reserves a contact for an agent, the agent receives an
1459
+ * `AgentOfferCampaignReservation` event. Instead of accepting, the agent can skip the
1460
+ * preview contact to move to the next contact in the campaign.
1461
+ *
1462
+ * @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
1463
+ * @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
1464
+ * @throws {Error} If the operation fails (network error, etc.)
1465
+ *
1466
+ * @example
1467
+ * ```typescript
1468
+ * webex.cc.on('task:campaignPreviewReservation', async (task) => {
1469
+ * const { interactionId } = task.data;
1470
+ * const campaignId = task.data.interaction.callProcessingDetails.campaignId;
1471
+ *
1472
+ * const result = await webex.cc.skipPreviewContact({ interactionId, campaignId });
1473
+ * });
1474
+ * ```
1475
+ */
1476
+ async skipPreviewContact(payload) {
1477
+ const task = this.taskManager.getTask(payload.interactionId);
1478
+ if (task?.data?.interaction?.callProcessingDetails?.campaignPreviewSkipDisabled === 'true') {
1479
+ _loggerProxy.default.warn('Skip action is disabled for this campaign preview contact', {
1480
+ module: _constants.CC_FILE,
1481
+ method: _constants.METHODS.SKIP_PREVIEW_CONTACT,
1482
+ interactionId: payload.interactionId
1483
+ });
1484
+ throw new Error('Skip action is disabled for this campaign preview contact');
1485
+ }
1486
+ _loggerProxy.default.info('Skipping campaign preview contact', {
1487
+ module: _constants.CC_FILE,
1488
+ method: _constants.METHODS.SKIP_PREVIEW_CONTACT
1489
+ });
1490
+ try {
1491
+ this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_FAILED]);
1492
+ const result = await this.services.dialer.skipPreviewContact({
1493
+ data: payload
1494
+ });
1495
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_SUCCESS, {
1496
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
1497
+ interactionId: payload.interactionId,
1498
+ campaignId: payload.campaignId
1499
+ }, ['behavioral', 'business', 'operational']);
1500
+ _loggerProxy.default.log('Campaign preview contact skipped successfully', {
1501
+ module: _constants.CC_FILE,
1502
+ method: _constants.METHODS.SKIP_PREVIEW_CONTACT,
1503
+ trackingId: result.trackingId,
1504
+ interactionId: payload.interactionId
1505
+ });
1506
+ return result;
1507
+ } catch (error) {
1508
+ const failure = error.details;
1509
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_FAILED, {
1510
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
1511
+ interactionId: payload.interactionId,
1512
+ campaignId: payload.campaignId
1513
+ }, ['behavioral', 'business', 'operational']);
1514
+ const {
1515
+ error: detailedError
1516
+ } = (0, _Utils.getErrorDetails)(error, _constants.METHODS.SKIP_PREVIEW_CONTACT, _constants.CC_FILE);
1517
+ throw detailedError;
1518
+ }
1519
+ }
1520
+
1521
+ /**
1522
+ * Removes a campaign preview contact from the campaign list entirely.
1523
+ *
1524
+ * When a campaign manager reserves a contact for an agent, the agent receives an
1525
+ * `AgentOfferCampaignReservation` event. Instead of accepting or skipping, the agent can
1526
+ * remove the preview contact to permanently take it out of the campaign contact list.
1527
+ *
1528
+ * @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
1529
+ * @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
1530
+ * @throws {Error} If the operation fails (network error, etc.)
1531
+ *
1532
+ * @example
1533
+ * ```typescript
1534
+ * webex.cc.on('task:campaignPreviewReservation', async (task) => {
1535
+ * const { interactionId } = task.data;
1536
+ * const campaignId = task.data.interaction.callProcessingDetails.campaignId;
1537
+ *
1538
+ * const result = await webex.cc.removePreviewContact({ interactionId, campaignId });
1539
+ * });
1540
+ * ```
1541
+ */
1542
+ async removePreviewContact(payload) {
1543
+ const task = this.taskManager.getTask(payload.interactionId);
1544
+ if (task?.data?.interaction?.callProcessingDetails?.campaignPreviewRemoveDisabled === 'true') {
1545
+ _loggerProxy.default.warn('Remove action is disabled for this campaign preview contact', {
1546
+ module: _constants.CC_FILE,
1547
+ method: _constants.METHODS.REMOVE_PREVIEW_CONTACT,
1548
+ interactionId: payload.interactionId
1549
+ });
1550
+ throw new Error('Remove action is disabled for this campaign preview contact');
1551
+ }
1552
+ _loggerProxy.default.info('Removing campaign preview contact', {
1553
+ module: _constants.CC_FILE,
1554
+ method: _constants.METHODS.REMOVE_PREVIEW_CONTACT
1555
+ });
1556
+ try {
1557
+ this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_FAILED]);
1558
+ const result = await this.services.dialer.removePreviewContact({
1559
+ data: payload
1560
+ });
1561
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_SUCCESS, {
1562
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
1563
+ interactionId: payload.interactionId,
1564
+ campaignId: payload.campaignId
1565
+ }, ['behavioral', 'business', 'operational']);
1566
+ _loggerProxy.default.log('Campaign preview contact removed successfully', {
1567
+ module: _constants.CC_FILE,
1568
+ method: _constants.METHODS.REMOVE_PREVIEW_CONTACT,
1569
+ trackingId: result.trackingId,
1570
+ interactionId: payload.interactionId
1571
+ });
1572
+ return result;
1573
+ } catch (error) {
1574
+ const failure = error.details;
1575
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_FAILED, {
1576
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
1577
+ interactionId: payload.interactionId,
1578
+ campaignId: payload.campaignId
1579
+ }, ['behavioral', 'business', 'operational']);
1580
+ const {
1581
+ error: detailedError
1582
+ } = (0, _Utils.getErrorDetails)(error, _constants.METHODS.REMOVE_PREVIEW_CONTACT, _constants.CC_FILE);
1583
+ throw detailedError;
1584
+ }
1585
+ }
1586
+
1447
1587
  /**
1448
1588
  * Fetches outdial ANI (Automatic Number Identification) entries for an outdial ANI ID.
1449
1589
  *