@webex/contact-center 3.9.0-next.9 → 3.10.0

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 (95) hide show
  1. package/dist/cc.js +182 -47
  2. package/dist/cc.js.map +1 -1
  3. package/dist/constants.js +1 -0
  4. package/dist/constants.js.map +1 -1
  5. package/dist/index.js +9 -0
  6. package/dist/index.js.map +1 -1
  7. package/dist/logger-proxy.js +24 -1
  8. package/dist/logger-proxy.js.map +1 -1
  9. package/dist/metrics/behavioral-events.js +89 -0
  10. package/dist/metrics/behavioral-events.js.map +1 -1
  11. package/dist/metrics/constants.js +30 -2
  12. package/dist/metrics/constants.js.map +1 -1
  13. package/dist/services/AddressBook.js +271 -0
  14. package/dist/services/AddressBook.js.map +1 -0
  15. package/dist/services/EntryPoint.js +227 -0
  16. package/dist/services/EntryPoint.js.map +1 -0
  17. package/dist/services/Queue.js +261 -0
  18. package/dist/services/Queue.js.map +1 -0
  19. package/dist/services/config/constants.js +36 -2
  20. package/dist/services/config/constants.js.map +1 -1
  21. package/dist/services/config/index.js +29 -21
  22. package/dist/services/config/index.js.map +1 -1
  23. package/dist/services/config/types.js +33 -1
  24. package/dist/services/config/types.js.map +1 -1
  25. package/dist/services/core/Utils.js +42 -1
  26. package/dist/services/core/Utils.js.map +1 -1
  27. package/dist/services/task/TaskManager.js +113 -3
  28. package/dist/services/task/TaskManager.js.map +1 -1
  29. package/dist/services/task/TaskUtils.js +76 -0
  30. package/dist/services/task/TaskUtils.js.map +1 -0
  31. package/dist/services/task/constants.js +26 -1
  32. package/dist/services/task/constants.js.map +1 -1
  33. package/dist/services/task/contact.js +86 -0
  34. package/dist/services/task/contact.js.map +1 -1
  35. package/dist/services/task/index.js +241 -5
  36. package/dist/services/task/index.js.map +1 -1
  37. package/dist/services/task/types.js +14 -0
  38. package/dist/services/task/types.js.map +1 -1
  39. package/dist/types/cc.d.ts +115 -35
  40. package/dist/types/constants.d.ts +1 -0
  41. package/dist/types/index.d.ts +3 -2
  42. package/dist/types/metrics/constants.d.ts +24 -1
  43. package/dist/types/services/AddressBook.d.ts +74 -0
  44. package/dist/types/services/EntryPoint.d.ts +67 -0
  45. package/dist/types/services/Queue.d.ts +76 -0
  46. package/dist/types/services/config/constants.d.ts +35 -1
  47. package/dist/types/services/config/index.d.ts +6 -9
  48. package/dist/types/services/config/types.d.ts +79 -58
  49. package/dist/types/services/core/Utils.d.ts +14 -1
  50. package/dist/types/services/task/TaskUtils.d.ts +28 -0
  51. package/dist/types/services/task/constants.d.ts +23 -0
  52. package/dist/types/services/task/contact.d.ts +10 -0
  53. package/dist/types/services/task/index.d.ts +64 -1
  54. package/dist/types/services/task/types.d.ts +221 -19
  55. package/dist/types/types.d.ts +162 -0
  56. package/dist/types/utils/PageCache.d.ts +173 -0
  57. package/dist/types.js +17 -0
  58. package/dist/types.js.map +1 -1
  59. package/dist/utils/PageCache.js +192 -0
  60. package/dist/utils/PageCache.js.map +1 -0
  61. package/dist/webex.js +1 -1
  62. package/package.json +10 -9
  63. package/src/cc.ts +206 -52
  64. package/src/constants.ts +1 -0
  65. package/src/index.ts +16 -2
  66. package/src/logger-proxy.ts +24 -1
  67. package/src/metrics/behavioral-events.ts +94 -0
  68. package/src/metrics/constants.ts +34 -1
  69. package/src/services/AddressBook.ts +291 -0
  70. package/src/services/EntryPoint.ts +241 -0
  71. package/src/services/Queue.ts +277 -0
  72. package/src/services/config/constants.ts +42 -2
  73. package/src/services/config/index.ts +30 -30
  74. package/src/services/config/types.ts +59 -58
  75. package/src/services/core/Utils.ts +44 -0
  76. package/src/services/task/TaskManager.ts +122 -5
  77. package/src/services/task/TaskUtils.ts +81 -0
  78. package/src/services/task/constants.ts +25 -0
  79. package/src/services/task/contact.ts +80 -0
  80. package/src/services/task/index.ts +300 -4
  81. package/src/services/task/types.ts +239 -18
  82. package/src/types.ts +180 -0
  83. package/src/utils/PageCache.ts +252 -0
  84. package/test/unit/spec/cc.ts +282 -85
  85. package/test/unit/spec/metrics/behavioral-events.ts +42 -0
  86. package/test/unit/spec/services/AddressBook.ts +332 -0
  87. package/test/unit/spec/services/EntryPoint.ts +259 -0
  88. package/test/unit/spec/services/Queue.ts +323 -0
  89. package/test/unit/spec/services/config/index.ts +279 -65
  90. package/test/unit/spec/services/task/TaskManager.ts +382 -0
  91. package/test/unit/spec/services/task/TaskUtils.ts +131 -0
  92. package/test/unit/spec/services/task/contact.ts +31 -1
  93. package/test/unit/spec/services/task/index.ts +242 -8
  94. package/umd/contact-center.min.js +2 -2
  95. package/umd/contact-center.min.js.map +1 -1
@@ -75,6 +75,9 @@ describe('Task', () => {
75
75
  wrapup: jest.fn().mockResolvedValue({}),
76
76
  pauseRecording: jest.fn().mockResolvedValue({}),
77
77
  resumeRecording: jest.fn().mockResolvedValue({}),
78
+ consultConference: jest.fn().mockResolvedValue({}),
79
+ exitConference: jest.fn().mockResolvedValue({}),
80
+ conferenceTransfer: jest.fn().mockResolvedValue({}),
78
81
  };
79
82
 
80
83
  mockMetricsManager = {
@@ -214,7 +217,7 @@ describe('Task', () => {
214
217
  });
215
218
 
216
219
  describe('updateTaskData cases', () => {
217
- it('test updating the task data by overwrite', async () => {
220
+ it('updates the task data by overwrite', async () => {
218
221
  const newData = {
219
222
  type: CC_EVENTS.AGENT_CONTACT_ASSIGNED,
220
223
  agentId: '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
@@ -263,12 +266,12 @@ describe('Task', () => {
263
266
  expect(task.data).toEqual(newData);
264
267
  });
265
268
 
266
- it('test updating the task data by merging', async () => {
269
+ it('updates the task data by merging with key removal', async () => {
267
270
  const newData = {
268
- // ...taskDataMock, // Purposefully omit this to test scenario when other keys isn't present
271
+ // Purposefully omit other keys to test remove and merge behavior
269
272
  isConsulting: true, // Add a new custom key to test persistence
270
273
  interaction: {
271
- // ...taskDataMock.interaction, // Purposefully omit this to test scenario when a nested key isn't present
274
+ // Purposefully omit other interaction keys to test removal
272
275
  media: {
273
276
  '58a45567-4e61-4f4b-a580-5bc86357bef0': {
274
277
  holdTimestamp: null,
@@ -295,11 +298,12 @@ describe('Task', () => {
295
298
  },
296
299
  };
297
300
 
301
+ // The reconcileData method removes keys from oldData that are not in newData
302
+ // This means only keys present in newData will remain in the final result
298
303
  const expectedData: TaskData = {
299
- ...taskDataMock,
300
- isConsulting: true,
304
+ isConsulting: true, // New key is added
301
305
  interaction: {
302
- ...taskDataMock.interaction,
306
+ // Only the media key from newData.interaction remains
303
307
  media: {
304
308
  '58a45567-4e61-4f4b-a580-5bc86357bef0': {
305
309
  holdTimestamp: null,
@@ -332,6 +336,60 @@ describe('Task', () => {
332
336
 
333
337
  expect(task.data).toEqual(expectedData);
334
338
  });
339
+
340
+ it('updates the task data by merging and preserving existing keys', async () => {
341
+ const newData = {
342
+ ...taskDataMock, // Include all existing keys to test merge without removal
343
+ isConsulting: true, // Add a new custom key
344
+ interaction: {
345
+ ...taskDataMock.interaction, // Include existing interaction data
346
+ media: {
347
+ ...taskDataMock.interaction.media, // Include existing media
348
+ '58a45567-4e61-4f4b-a580-5bc86357bef0': {
349
+ holdTimestamp: null,
350
+ isHold: true,
351
+ mType: 'consult',
352
+ mediaMgr: 'callmm',
353
+ mediaResourceId: '58a45567-4e61-4f4b-a580-5bc86357bef0',
354
+ mediaType: 'telephony',
355
+ participants: [
356
+ 'f520d6b5-28ad-4f2f-b83e-781bb64af617',
357
+ '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
358
+ ],
359
+ },
360
+ },
361
+ },
362
+ };
363
+
364
+ const expectedData: TaskData = {
365
+ ...taskDataMock,
366
+ isConsulting: true,
367
+ interaction: {
368
+ ...taskDataMock.interaction,
369
+ media: {
370
+ ...taskDataMock.interaction.media,
371
+ '58a45567-4e61-4f4b-a580-5bc86357bef0': {
372
+ holdTimestamp: null,
373
+ isHold: true,
374
+ mType: 'consult',
375
+ mediaMgr: 'callmm',
376
+ mediaResourceId: '58a45567-4e61-4f4b-a580-5bc86357bef0',
377
+ mediaType: 'telephony',
378
+ participants: [
379
+ 'f520d6b5-28ad-4f2f-b83e-781bb64af617',
380
+ '723a8ffb-a26e-496d-b14a-ff44fb83b64f',
381
+ ],
382
+ },
383
+ },
384
+ },
385
+ };
386
+
387
+ expect(task.data).toEqual(taskDataMock);
388
+ const shouldOverwrite = false;
389
+ task.updateTaskData(newData, shouldOverwrite);
390
+
391
+ expect(task.data).toEqual(expectedData);
392
+ });
335
393
  });
336
394
 
337
395
  it('should accept a task and answer call when using BROWSER login option', async () => {
@@ -671,8 +729,8 @@ describe('Task', () => {
671
729
  expect(loggerLogSpy).toHaveBeenCalledWith(`Consult started successfully to ${consultPayload.to}`, {
672
730
  module: TASK_FILE,
673
731
  method: 'consult',
674
- trackingId: expectedResponse.trackingId,
675
732
  interactionId: task.data.interactionId,
733
+ trackingId: '1234',
676
734
  });
677
735
  expect(mockMetricsManager.trackEvent).toHaveBeenCalledWith(
678
736
  METRIC_EVENT_NAMES.TASK_CONSULT_START_SUCCESS,
@@ -1575,4 +1633,180 @@ describe('Task', () => {
1575
1633
  });
1576
1634
  });
1577
1635
  });
1636
+
1637
+ describe('Conference methods', () => {
1638
+ beforeEach(() => {
1639
+ contactMock = {
1640
+ consultConference: jest.fn(),
1641
+ exitConference: jest.fn(),
1642
+ conferenceTransfer: jest.fn(),
1643
+ };
1644
+
1645
+ // Re-setup the getDestinationAgentId spy for conference methods
1646
+ getDestinationAgentIdSpy = jest
1647
+ .spyOn(Utils, 'getDestinationAgentId')
1648
+ .mockReturnValue(taskDataMock.destAgentId);
1649
+
1650
+
1651
+ task = new Task(contactMock, webCallingService, taskDataMock, {
1652
+ wrapUpProps: { wrapUpReasonList: [] },
1653
+ autoWrapEnabled: false,
1654
+ autoWrapAfterSeconds: 0
1655
+ }, taskDataMock.agentId);
1656
+ });
1657
+
1658
+ describe('consultConference', () => {
1659
+
1660
+ it('should successfully start conference and emit event', async () => {
1661
+ const mockResponse = {
1662
+ trackingId: 'test-tracking-id',
1663
+ interactionId: taskId,
1664
+ };
1665
+ contactMock.consultConference.mockResolvedValue(mockResponse);
1666
+
1667
+
1668
+ const result = await task.consultConference();
1669
+
1670
+ expect(contactMock.consultConference).toHaveBeenCalledWith({
1671
+ interactionId: taskId,
1672
+ data: {
1673
+ agentId: taskDataMock.agentId, // From task data agent ID
1674
+ to: taskDataMock.destAgentId, // From getDestinationAgentId() using task participants
1675
+ destinationType: 'agent', // From consultation data
1676
+ },
1677
+ });
1678
+ expect(result).toEqual(mockResponse);
1679
+ expect(LoggerProxy.info).toHaveBeenCalledWith(`Initiating consult conference to ${taskDataMock.destAgentId}`, {
1680
+ module: TASK_FILE,
1681
+ method: 'consultConference',
1682
+ interactionId: taskId,
1683
+ });
1684
+ expect(LoggerProxy.log).toHaveBeenCalledWith('Consult conference started successfully', {
1685
+ module: TASK_FILE,
1686
+ method: 'consultConference',
1687
+ interactionId: taskId,
1688
+ });
1689
+ });
1690
+
1691
+ it('should handle basic validation scenarios', async () => {
1692
+ // Agent Desktop logic validates data structure but not participant availability
1693
+ // This test confirms the method works with the Agent Desktop data flow
1694
+ const mockResponse = {
1695
+ trackingId: 'test-tracking-validation',
1696
+ interactionId: taskId,
1697
+ };
1698
+ contactMock.consultConference.mockResolvedValue(mockResponse);
1699
+
1700
+ const result = await task.consultConference();
1701
+ expect(result).toEqual(mockResponse);
1702
+ });
1703
+
1704
+ it('should handle and rethrow contact method errors', async () => {
1705
+ const mockError = new Error('Conference start failed');
1706
+ contactMock.consultConference.mockRejectedValue(mockError);
1707
+ generateTaskErrorObjectSpy.mockReturnValue(mockError);
1708
+
1709
+ await expect(task.consultConference()).rejects.toThrow('Conference start failed');
1710
+ expect(LoggerProxy.error).toHaveBeenCalledWith('Failed to start consult conference', {
1711
+ module: TASK_FILE,
1712
+ method: 'consultConference',
1713
+ interactionId: taskId,
1714
+ });
1715
+ });
1716
+ });
1717
+
1718
+ describe('exitConference', () => {
1719
+ it('should successfully end conference and emit event', async () => {
1720
+ const mockResponse = {
1721
+ trackingId: 'test-tracking-id-end',
1722
+ interactionId: taskId,
1723
+ };
1724
+ contactMock.exitConference.mockResolvedValue(mockResponse);
1725
+
1726
+ const result = await task.exitConference();
1727
+
1728
+ expect(contactMock.exitConference).toHaveBeenCalledWith({
1729
+ interactionId: taskId,
1730
+ });
1731
+ expect(result).toEqual(mockResponse);
1732
+ expect(LoggerProxy.info).toHaveBeenCalledWith('Exiting consult conference', {
1733
+ module: TASK_FILE,
1734
+ method: 'exitConference',
1735
+ interactionId: taskId,
1736
+ });
1737
+ expect(LoggerProxy.log).toHaveBeenCalledWith('Consult conference exited successfully', {
1738
+ module: TASK_FILE,
1739
+ method: 'exitConference',
1740
+ interactionId: taskId,
1741
+ });
1742
+ });
1743
+
1744
+ it('should throw error for invalid interaction ID', async () => {
1745
+ task.data.interactionId = '';
1746
+
1747
+ await expect(task.exitConference()).rejects.toThrow('Error while performing exitConference');
1748
+ expect(contactMock.exitConference).not.toHaveBeenCalled();
1749
+ });
1750
+
1751
+ it('should handle and rethrow contact method errors', async () => {
1752
+ const mockError = new Error('Conference end failed');
1753
+ contactMock.exitConference.mockRejectedValue(mockError);
1754
+ generateTaskErrorObjectSpy.mockReturnValue(mockError);
1755
+
1756
+ await expect(task.exitConference()).rejects.toThrow('Conference end failed');
1757
+ expect(LoggerProxy.error).toHaveBeenCalledWith('Failed to exit consult conference', {
1758
+ module: TASK_FILE,
1759
+ method: 'exitConference',
1760
+ interactionId: taskId,
1761
+ });
1762
+ });
1763
+ });
1764
+
1765
+ describe('transferConference', () => {
1766
+ it('should successfully transfer conference', async () => {
1767
+ const mockResponse = {
1768
+ trackingId: 'test-tracking-id-transfer',
1769
+ interactionId: taskId,
1770
+ };
1771
+ contactMock.conferenceTransfer.mockResolvedValue(mockResponse);
1772
+
1773
+ const result = await task.transferConference();
1774
+
1775
+ expect(contactMock.conferenceTransfer).toHaveBeenCalledWith({
1776
+ interactionId: taskId,
1777
+ });
1778
+ expect(result).toEqual(mockResponse);
1779
+ expect(LoggerProxy.info).toHaveBeenCalledWith('Transferring conference', {
1780
+ module: TASK_FILE,
1781
+ method: 'transferConference',
1782
+ interactionId: taskId,
1783
+ });
1784
+ expect(LoggerProxy.log).toHaveBeenCalledWith('Conference transferred successfully', {
1785
+ module: TASK_FILE,
1786
+ method: 'transferConference',
1787
+ interactionId: taskId,
1788
+ });
1789
+ });
1790
+
1791
+ it('should throw error for invalid interaction ID', async () => {
1792
+ task.data.interactionId = '';
1793
+
1794
+ await expect(task.transferConference()).rejects.toThrow('Error while performing transferConference');
1795
+ expect(contactMock.conferenceTransfer).not.toHaveBeenCalled();
1796
+ });
1797
+
1798
+ it('should handle and rethrow contact method errors', async () => {
1799
+ const mockError = new Error('Conference transfer failed');
1800
+ contactMock.conferenceTransfer.mockRejectedValue(mockError);
1801
+ generateTaskErrorObjectSpy.mockReturnValue(mockError);
1802
+
1803
+ await expect(task.transferConference()).rejects.toThrow('Conference transfer failed');
1804
+ expect(LoggerProxy.error).toHaveBeenCalledWith('Failed to transfer conference', {
1805
+ module: TASK_FILE,
1806
+ method: 'transferConference',
1807
+ interactionId: taskId,
1808
+ });
1809
+ });
1810
+ });
1811
+ });
1578
1812
  });