@webex/contact-center 3.12.0-next.8 → 3.12.0-next.80

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 (205) hide show
  1. package/AGENTS.md +438 -0
  2. package/ai-docs/README.md +131 -0
  3. package/ai-docs/RULES.md +455 -0
  4. package/ai-docs/patterns/event-driven-patterns.md +485 -0
  5. package/ai-docs/patterns/testing-patterns.md +480 -0
  6. package/ai-docs/patterns/typescript-patterns.md +365 -0
  7. package/ai-docs/templates/README.md +102 -0
  8. package/ai-docs/templates/documentation/create-agents-md.md +240 -0
  9. package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
  10. package/ai-docs/templates/existing-service/bug-fix.md +254 -0
  11. package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
  12. package/ai-docs/templates/new-method/00-master.md +80 -0
  13. package/ai-docs/templates/new-method/01-requirements.md +232 -0
  14. package/ai-docs/templates/new-method/02-implementation.md +295 -0
  15. package/ai-docs/templates/new-method/03-tests.md +201 -0
  16. package/ai-docs/templates/new-method/04-validation.md +141 -0
  17. package/ai-docs/templates/new-service/00-master.md +109 -0
  18. package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
  19. package/ai-docs/templates/new-service/02-code-generation.md +346 -0
  20. package/ai-docs/templates/new-service/03-integration.md +178 -0
  21. package/ai-docs/templates/new-service/04-test-generation.md +205 -0
  22. package/ai-docs/templates/new-service/05-validation.md +145 -0
  23. package/dist/cc.js +265 -29
  24. package/dist/cc.js.map +1 -1
  25. package/dist/config.js +6 -0
  26. package/dist/config.js.map +1 -1
  27. package/dist/constants.js +16 -1
  28. package/dist/constants.js.map +1 -1
  29. package/dist/index.js +20 -5
  30. package/dist/index.js.map +1 -1
  31. package/dist/metrics/behavioral-events.js +101 -0
  32. package/dist/metrics/behavioral-events.js.map +1 -1
  33. package/dist/metrics/constants.js +23 -4
  34. package/dist/metrics/constants.js.map +1 -1
  35. package/dist/services/ApiAiAssistant.js +74 -3
  36. package/dist/services/ApiAiAssistant.js.map +1 -1
  37. package/dist/services/UserPreference.js +427 -0
  38. package/dist/services/UserPreference.js.map +1 -0
  39. package/dist/services/config/Util.js +3 -3
  40. package/dist/services/config/Util.js.map +1 -1
  41. package/dist/services/config/constants.js +23 -2
  42. package/dist/services/config/constants.js.map +1 -1
  43. package/dist/services/config/types.js +49 -9
  44. package/dist/services/config/types.js.map +1 -1
  45. package/dist/services/core/Err.js.map +1 -1
  46. package/dist/services/core/Utils.js +107 -32
  47. package/dist/services/core/Utils.js.map +1 -1
  48. package/dist/services/core/websocket/WebSocketManager.js +2 -1
  49. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  50. package/dist/services/core/websocket/types.js.map +1 -1
  51. package/dist/services/index.js +1 -1
  52. package/dist/services/index.js.map +1 -1
  53. package/dist/services/task/Task.js +688 -0
  54. package/dist/services/task/Task.js.map +1 -0
  55. package/dist/services/task/TaskFactory.js +45 -0
  56. package/dist/services/task/TaskFactory.js.map +1 -0
  57. package/dist/services/task/TaskManager.js +725 -526
  58. package/dist/services/task/TaskManager.js.map +1 -1
  59. package/dist/services/task/TaskUtils.js +162 -26
  60. package/dist/services/task/TaskUtils.js.map +1 -1
  61. package/dist/services/task/constants.js +9 -2
  62. package/dist/services/task/constants.js.map +1 -1
  63. package/dist/services/task/dialer.js +78 -0
  64. package/dist/services/task/dialer.js.map +1 -1
  65. package/dist/services/task/digital/Digital.js +77 -0
  66. package/dist/services/task/digital/Digital.js.map +1 -0
  67. package/dist/services/task/state-machine/TaskStateMachine.js +837 -0
  68. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
  69. package/dist/services/task/state-machine/actions.js +543 -0
  70. package/dist/services/task/state-machine/actions.js.map +1 -0
  71. package/dist/services/task/state-machine/constants.js +161 -0
  72. package/dist/services/task/state-machine/constants.js.map +1 -0
  73. package/dist/services/task/state-machine/guards.js +340 -0
  74. package/dist/services/task/state-machine/guards.js.map +1 -0
  75. package/dist/services/task/state-machine/index.js +53 -0
  76. package/dist/services/task/state-machine/index.js.map +1 -0
  77. package/dist/services/task/state-machine/types.js +54 -0
  78. package/dist/services/task/state-machine/types.js.map +1 -0
  79. package/dist/services/task/state-machine/uiControlsComputer.js +553 -0
  80. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
  81. package/dist/services/task/taskDataNormalizer.js +99 -0
  82. package/dist/services/task/taskDataNormalizer.js.map +1 -0
  83. package/dist/services/task/types.js +212 -4
  84. package/dist/services/task/types.js.map +1 -1
  85. package/dist/services/task/voice/Voice.js +1042 -0
  86. package/dist/services/task/voice/Voice.js.map +1 -0
  87. package/dist/services/task/voice/WebRTC.js +149 -0
  88. package/dist/services/task/voice/WebRTC.js.map +1 -0
  89. package/dist/types/cc.d.ts +94 -1
  90. package/dist/types/config.d.ts +6 -0
  91. package/dist/types/constants.d.ts +16 -1
  92. package/dist/types/index.d.ts +21 -6
  93. package/dist/types/metrics/constants.d.ts +19 -1
  94. package/dist/types/services/ApiAiAssistant.d.ts +11 -3
  95. package/dist/types/services/UserPreference.d.ts +118 -0
  96. package/dist/types/services/config/constants.d.ts +21 -0
  97. package/dist/types/services/config/types.d.ts +171 -10
  98. package/dist/types/services/core/Err.d.ts +4 -0
  99. package/dist/types/services/core/Utils.d.ts +33 -13
  100. package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -0
  101. package/dist/types/services/core/websocket/types.d.ts +1 -1
  102. package/dist/types/services/index.d.ts +1 -1
  103. package/dist/types/services/task/Task.d.ts +157 -0
  104. package/dist/types/services/task/TaskFactory.d.ts +12 -0
  105. package/dist/types/services/task/TaskUtils.d.ts +46 -2
  106. package/dist/types/services/task/constants.d.ts +7 -0
  107. package/dist/types/services/task/dialer.d.ts +30 -0
  108. package/dist/types/services/task/digital/Digital.d.ts +22 -0
  109. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1144 -0
  110. package/dist/types/services/task/state-machine/actions.d.ts +10 -0
  111. package/dist/types/services/task/state-machine/constants.d.ts +107 -0
  112. package/dist/types/services/task/state-machine/guards.d.ts +90 -0
  113. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  114. package/dist/types/services/task/state-machine/types.d.ts +267 -0
  115. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  116. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  117. package/dist/types/services/task/types.d.ts +603 -66
  118. package/dist/types/services/task/voice/Voice.d.ts +184 -0
  119. package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
  120. package/dist/types/types.d.ts +94 -0
  121. package/dist/types/webex.d.ts +1 -0
  122. package/dist/types.js +85 -0
  123. package/dist/types.js.map +1 -1
  124. package/dist/webex.js +14 -2
  125. package/dist/webex.js.map +1 -1
  126. package/package.json +15 -12
  127. package/src/cc.ts +329 -30
  128. package/src/config.ts +6 -0
  129. package/src/constants.ts +16 -1
  130. package/src/index.ts +23 -5
  131. package/src/metrics/ai-docs/AGENTS.md +348 -0
  132. package/src/metrics/ai-docs/ARCHITECTURE.md +336 -0
  133. package/src/metrics/behavioral-events.ts +106 -0
  134. package/src/metrics/constants.ts +23 -4
  135. package/src/services/ApiAiAssistant.ts +104 -3
  136. package/src/services/UserPreference.ts +509 -0
  137. package/src/services/agent/ai-docs/AGENTS.md +238 -0
  138. package/src/services/agent/ai-docs/ARCHITECTURE.md +302 -0
  139. package/src/services/ai-docs/AGENTS.md +384 -0
  140. package/src/services/config/Util.ts +3 -3
  141. package/src/services/config/ai-docs/AGENTS.md +253 -0
  142. package/src/services/config/ai-docs/ARCHITECTURE.md +424 -0
  143. package/src/services/config/constants.ts +25 -1
  144. package/src/services/config/types.ts +174 -11
  145. package/src/services/core/Err.ts +2 -0
  146. package/src/services/core/Utils.ts +123 -37
  147. package/src/services/core/ai-docs/AGENTS.md +379 -0
  148. package/src/services/core/ai-docs/ARCHITECTURE.md +696 -0
  149. package/src/services/core/websocket/WebSocketManager.ts +2 -0
  150. package/src/services/core/websocket/types.ts +1 -1
  151. package/src/services/index.ts +1 -1
  152. package/src/services/task/Task.ts +837 -0
  153. package/src/services/task/TaskFactory.ts +55 -0
  154. package/src/services/task/TaskManager.ts +738 -613
  155. package/src/services/task/TaskUtils.ts +205 -25
  156. package/src/services/task/ai-docs/AGENTS.md +455 -0
  157. package/src/services/task/ai-docs/ARCHITECTURE.md +585 -0
  158. package/src/services/task/constants.ts +7 -0
  159. package/src/services/task/dialer.ts +80 -0
  160. package/src/services/task/digital/Digital.ts +95 -0
  161. package/src/services/task/state-machine/TaskStateMachine.ts +1077 -0
  162. package/src/services/task/state-machine/actions.ts +685 -0
  163. package/src/services/task/state-machine/ai-docs/AGENTS.md +495 -0
  164. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1135 -0
  165. package/src/services/task/state-machine/constants.ts +172 -0
  166. package/src/services/task/state-machine/guards.ts +406 -0
  167. package/src/services/task/state-machine/index.ts +28 -0
  168. package/src/services/task/state-machine/types.ts +241 -0
  169. package/src/services/task/state-machine/uiControlsComputer.ts +867 -0
  170. package/src/services/task/taskDataNormalizer.ts +137 -0
  171. package/src/services/task/types.ts +710 -71
  172. package/src/services/task/voice/Voice.ts +1267 -0
  173. package/src/services/task/voice/WebRTC.ts +187 -0
  174. package/src/types.ts +122 -2
  175. package/src/utils/AGENTS.md +276 -0
  176. package/src/webex.js +2 -0
  177. package/test/unit/spec/cc.ts +343 -23
  178. package/test/unit/spec/logger-proxy.ts +70 -0
  179. package/test/unit/spec/services/ApiAiAssistant.ts +122 -17
  180. package/test/unit/spec/services/UserPreference.ts +401 -0
  181. package/test/unit/spec/services/WebCallingService.ts +7 -1
  182. package/test/unit/spec/services/config/index.ts +30 -30
  183. package/test/unit/spec/services/core/Utils.ts +425 -8
  184. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +66 -40
  185. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  186. package/test/unit/spec/services/task/Task.ts +477 -0
  187. package/test/unit/spec/services/task/TaskFactory.ts +62 -0
  188. package/test/unit/spec/services/task/TaskManager.ts +832 -1702
  189. package/test/unit/spec/services/task/TaskUtils.ts +206 -0
  190. package/test/unit/spec/services/task/dialer.ts +190 -0
  191. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  192. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +1825 -0
  193. package/test/unit/spec/services/task/state-machine/guards.ts +479 -0
  194. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  195. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +2020 -0
  196. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  197. package/test/unit/spec/services/task/voice/Voice.ts +631 -0
  198. package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
  199. package/umd/contact-center.min.js +2 -2
  200. package/umd/contact-center.min.js.map +1 -1
  201. package/dist/services/task/index.js +0 -1525
  202. package/dist/services/task/index.js.map +0 -1
  203. package/dist/types/services/task/index.d.ts +0 -650
  204. package/src/services/task/index.ts +0 -1801
  205. package/test/unit/spec/services/task/index.ts +0 -2184
@@ -66,7 +66,6 @@ describe('AgentConfigService', () => {
66
66
  method: 'GET',
67
67
  });
68
68
  expect(result).toEqual(mockResponse.body);
69
-
70
69
  expect(LoggerProxy.info).toHaveBeenCalledWith('Fetching user data using CI', {
71
70
  module: CONFIG_FILE_NAME,
72
71
  method: 'getUserUsingCI',
@@ -124,7 +123,6 @@ describe('AgentConfigService', () => {
124
123
  method: 'GET',
125
124
  });
126
125
  expect(result).toEqual(mockResponse.body);
127
-
128
126
  expect(LoggerProxy.info).toHaveBeenCalledWith('Fetching desktop profile', {
129
127
  module: CONFIG_FILE_NAME,
130
128
  method: 'getDesktopProfileById',
@@ -183,7 +181,6 @@ describe('AgentConfigService', () => {
183
181
  method: 'GET',
184
182
  });
185
183
  expect(result).toEqual(mockResponse.body);
186
-
187
184
  expect(LoggerProxy.info).toHaveBeenCalledWith('Fetching list of teams', {
188
185
  module: CONFIG_FILE_NAME,
189
186
  method: 'getListOfTeams',
@@ -263,11 +260,10 @@ describe('AgentConfigService', () => {
263
260
 
264
261
  expect(mockWebexRequest.request).toHaveBeenCalledWith({
265
262
  service: mockWccAPIURL,
266
- resource: `organization/${mockOrgId}/v2/auxiliary-code?page=${page}&pageSize=${pageSize}&filter=id=in=(${filter})&attributes=${attributes}`,
263
+ resource: `organization/${mockOrgId}/v2/auxiliary-code?page=${page}&pageSize=${pageSize}&filter=id=in=(${filter})&attributes=${attributes}&desktopProfileFilter=true`,
267
264
  method: 'GET',
268
265
  });
269
266
  expect(result).toEqual(mockResponse.body);
270
-
271
267
  expect(LoggerProxy.info).toHaveBeenCalledWith('Fetching list of aux codes', {
272
268
  module: CONFIG_FILE_NAME,
273
269
  method: 'getListOfAuxCodes',
@@ -495,7 +491,7 @@ describe('AgentConfigService', () => {
495
491
  const mockResponse = {
496
492
  statusCode: 200,
497
493
  body: {
498
- realtimeTranscripts: {enable: true},
494
+ data: [{realtimeTranscripts: {enable: true}}],
499
495
  },
500
496
  };
501
497
  mockWebexRequest.request.mockResolvedValue(mockResponse);
@@ -710,6 +706,32 @@ describe('AgentConfigService', () => {
710
706
  });
711
707
 
712
708
  describe('getAgentConfig', () => {
709
+ const mockTeamData = [
710
+ {id: 'team1', name: 'Support Team'},
711
+ {id: 'team2', name: 'Sales Team'},
712
+ ];
713
+
714
+ const mockOrgInfo = {
715
+ tenantId: 'tenant123',
716
+ timezone: 'GMT',
717
+ environment: 'produs1',
718
+ };
719
+
720
+ const mockSiteInfo = {
721
+ id: 'c6a5451f-5ba7-49a1-aee8-fbef70c19ece',
722
+ name: 'Site-1',
723
+ multimediaProfileId: 'c5888e6f-5661-4871-9936-cbcec7658d41',
724
+ };
725
+
726
+ const mockURLMapping = [
727
+ {key: 'ACQUEON_API_URL', url: 'https://api.example.com'},
728
+ {key: 'ACQUEON_CONSOLE_URL', url: 'https://console.example.com'},
729
+ ];
730
+
731
+ const mockAIFeatureFlags = {
732
+ data: [{realtimeTranscripts: {enable: true}}],
733
+ };
734
+
713
735
  beforeEach(() => {
714
736
  jest.clearAllMocks();
715
737
  });
@@ -724,7 +746,7 @@ describe('AgentConfigService', () => {
724
746
  agentProfileId: 'profile123',
725
747
  siteId: 'site789',
726
748
  dbId: 'db123',
727
- defaultDialledNumber: '1234567890',
749
+ deafultDialledNumber: '1234567890',
728
750
  id: 'user001',
729
751
  teamIds: ['team1', 'team2'],
730
752
  };
@@ -770,12 +792,6 @@ describe('AgentConfigService', () => {
770
792
  maskSensitiveData: false,
771
793
  };
772
794
 
773
- const mockSiteInfo = {
774
- id: 'c6a5451f-5ba7-49a1-aee8-fbef70c19ece',
775
- name: 'Site-1',
776
- multimediaProfileId: 'c5888e6f-5661-4871-9936-cbcec7658d41',
777
- };
778
-
779
795
  const mockTenantData = {
780
796
  timeoutDesktopInactivityEnabled: false,
781
797
  timeoutDesktopInactivityMins: 15,
@@ -789,11 +805,6 @@ describe('AgentConfigService', () => {
789
805
  callVariablesSuppressed: false,
790
806
  };
791
807
 
792
- const mockURLMapping = [
793
- {key: 'ACQUEON_API_URL', url: 'https://api.example.com'},
794
- {key: 'ACQUEON_CONSOLE_URL', url: 'https://console.example.com'},
795
- ];
796
-
797
808
  const mockAuxCodes = [
798
809
  {id: 'aux1', type: 'WRAP_UP_CODE', name: 'Wrap Up Code 1', isDefault: true},
799
810
  {id: 'aux2', type: 'IDLE_CODE', name: 'Idle Code 1', isDefault: true},
@@ -864,7 +875,7 @@ describe('AgentConfigService', () => {
864
875
  skillProfileId: 'skillProfile456',
865
876
  siteId: 'site789',
866
877
  dbId: 'db123',
867
- defaultDialledNumber: '1234567890',
878
+ deafultDialledNumber: '1234567890',
868
879
  id: 'user001',
869
880
  teamIds: ['team1', 'team2'],
870
881
  };
@@ -915,12 +926,6 @@ describe('AgentConfigService', () => {
915
926
  maskSensitiveData: true,
916
927
  };
917
928
 
918
- const mockSiteInfo = {
919
- id: 'c6a5451f-5ba7-49a1-aee8-fbef70c19ece',
920
- name: 'Site-1',
921
- multimediaProfileId: 'c5888e6f-5661-4871-9936-cbcec7658d41',
922
- };
923
-
924
929
  const mockTenantData = {
925
930
  timeoutDesktopInactivityEnabled: true,
926
931
  timeoutDesktopInactivityMins: 15,
@@ -935,11 +940,6 @@ describe('AgentConfigService', () => {
935
940
  lostConnectionRecoveryTimeout: 30,
936
941
  };
937
942
 
938
- const mockURLMapping = [
939
- {key: 'ACQUEON_API_URL', url: 'https://api.example.com'},
940
- {key: 'ACQUEON_CONSOLE_URL', url: 'https://console.example.com'},
941
- ];
942
-
943
943
  const mockAuxCodes = [
944
944
  {id: 'aux1', type: 'WRAP_UP_CODE', name: 'Wrap Up Code 1'},
945
945
  {id: 'aux2', type: 'IDLE_CODE', name: 'Idle Code 1'},
@@ -1,5 +1,4 @@
1
1
  import * as Utils from '../../../../../src/services/core/Utils';
2
- import {FALLBACK_DIAL_NUMBER_REGEX} from '../../../../../src/services/core/Utils';
3
2
  import LoggerProxy from '../../../../../src/logger-proxy';
4
3
  import WebexRequest from '../../../../../src/services/core/WebexRequest';
5
4
  import {LoginOption, WebexRequestPayload} from '../../../../../src/types';
@@ -12,6 +11,7 @@ jest.mock('../../../../../src/logger-proxy', () => ({
12
11
  log: jest.fn(),
13
12
  error: jest.fn(),
14
13
  info: jest.fn(),
14
+ warn: jest.fn(),
15
15
  initialize: jest.fn(),
16
16
  },
17
17
  }));
@@ -531,7 +531,341 @@ describe('Utils', () => {
531
531
  };
532
532
 
533
533
  const result = Utils.calculateDestAgentId(interaction, currentAgentId);
534
- expect(result).toBeUndefined();
534
+ expect(result).toBe('');
535
+ });
536
+
537
+ it('should handle CBT scenario when phone number is not a direct participant key', () => {
538
+ const interaction: any = {
539
+ media: {
540
+ consult: {
541
+ mType: 'consult',
542
+ participants: [currentAgentId, '5551234567'], // Phone number in media
543
+ },
544
+ },
545
+ participants: {
546
+ // Note: '5551234567' is NOT a key - this is CBT
547
+ 'agent-uuid-cbt': {
548
+ type: 'Agent',
549
+ pType: 'dn',
550
+ dn: '5551234567', // Found by matching DN
551
+ id: 'agent-uuid-cbt',
552
+ },
553
+ },
554
+ };
555
+
556
+ const result = Utils.calculateDestAgentId(interaction, currentAgentId);
557
+ expect(result).toBe('agent-uuid-cbt'); // Returns the CBT agent
558
+ });
559
+ });
560
+
561
+ describe('calculateDestType', () => {
562
+ const currentAgentId = 'current-agent-123';
563
+
564
+ it('should return DIALNUMBER when pType is DN', () => {
565
+ const interaction: any = {
566
+ media: {
567
+ consult: {
568
+ mType: 'consult',
569
+ participants: [currentAgentId, 'dest-agent-456'],
570
+ },
571
+ },
572
+ participants: {
573
+ [currentAgentId]: {type: 'Agent', pType: 'Agent'},
574
+ 'dest-agent-456': {type: 'Agent', pType: 'DN', id: 'dest-agent-456'},
575
+ },
576
+ };
577
+
578
+ const result = Utils.calculateDestType(interaction, currentAgentId);
579
+ expect(result).toBe('dialNumber');
580
+ });
581
+
582
+ it('should return ENTRYPOINT when pType is EP-DN', () => {
583
+ const interaction: any = {
584
+ media: {
585
+ consult: {
586
+ mType: 'consult',
587
+ participants: [currentAgentId, 'dest-agent-456'],
588
+ },
589
+ },
590
+ participants: {
591
+ [currentAgentId]: {type: 'Agent', pType: 'Agent'},
592
+ 'dest-agent-456': {type: 'Agent', pType: 'EP-DN', id: 'dest-agent-456'},
593
+ },
594
+ };
595
+
596
+ const result = Utils.calculateDestType(interaction, currentAgentId);
597
+ expect(result).toBe('entryPoint');
598
+ });
599
+
600
+ it('should return lowercase pType for other types', () => {
601
+ const interaction: any = {
602
+ media: {
603
+ consult: {
604
+ mType: 'consult',
605
+ participants: [currentAgentId, 'dest-agent-456'],
606
+ },
607
+ },
608
+ participants: {
609
+ [currentAgentId]: {type: 'Agent', pType: 'Agent'},
610
+ 'dest-agent-456': {type: 'Agent', pType: 'Agent', id: 'dest-agent-456'},
611
+ },
612
+ };
613
+
614
+ const result = Utils.calculateDestType(interaction, currentAgentId);
615
+ expect(result).toBe('agent');
616
+ });
617
+
618
+ it('should return agent when no destination agent found', () => {
619
+ const interaction: any = {
620
+ media: {},
621
+ participants: {
622
+ [currentAgentId]: {type: 'Agent', pType: 'Agent'},
623
+ },
624
+ };
625
+
626
+ const result = Utils.calculateDestType(interaction, currentAgentId);
627
+ expect(result).toBe('agent');
628
+ });
629
+ });
630
+
631
+ describe('buildConsultConferenceParamData', () => {
632
+ it('maps entryPoint destinationType correctly', () => {
633
+ const result = Utils.buildConsultConferenceParamData(
634
+ {
635
+ agentId: 'agent1',
636
+ destinationType: 'entryPoint',
637
+ destAgentId: 'ep123',
638
+ },
639
+ 'interaction123'
640
+ );
641
+
642
+ expect(result).toEqual({
643
+ interactionId: 'interaction123',
644
+ data: {
645
+ agentId: 'agent1',
646
+ to: 'ep123',
647
+ destinationType: 'entryPoint',
648
+ },
649
+ });
650
+ });
651
+
652
+ it('maps EP-DN/EP_DN destinationType variants to entryPoint', () => {
653
+ const hyphenResult = Utils.buildConsultConferenceParamData(
654
+ {
655
+ agentId: 'agent1',
656
+ destinationType: 'EP-DN',
657
+ destAgentId: 'ep123',
658
+ },
659
+ 'interaction123'
660
+ );
661
+ const underscoreResult = Utils.buildConsultConferenceParamData(
662
+ {
663
+ agentId: 'agent1',
664
+ destinationType: 'EP_DN',
665
+ destAgentId: 'ep123',
666
+ },
667
+ 'interaction123'
668
+ );
669
+
670
+ expect(hyphenResult.data.destinationType).toBe('entryPoint');
671
+ expect(underscoreResult.data.destinationType).toBe('entryPoint');
672
+ });
673
+ });
674
+
675
+ describe('getDestAgentIdForCBT', () => {
676
+ it('should return destination agent ID for CBT scenario', () => {
677
+ const interaction: any = {
678
+ participants: {
679
+ 'agent-uuid-123': {
680
+ type: 'Agent',
681
+ pType: 'dn',
682
+ dn: '5551234567',
683
+ id: 'agent-uuid-123',
684
+ },
685
+ 'customer-1': {
686
+ type: 'Customer',
687
+ pType: 'Customer',
688
+ id: 'customer-1',
689
+ },
690
+ },
691
+ };
692
+ const consultingAgent = '5551234567'; // Phone number, not in participants as key
693
+
694
+ const result = Utils.getDestAgentIdForCBT(interaction, consultingAgent);
695
+ expect(result).toBe('agent-uuid-123');
696
+ });
697
+
698
+ it('should return empty string when consultingAgent is in participants (non-CBT)', () => {
699
+ const interaction: any = {
700
+ participants: {
701
+ 'agent-123': {
702
+ type: 'Agent',
703
+ pType: 'Agent',
704
+ id: 'agent-123',
705
+ },
706
+ },
707
+ };
708
+ const consultingAgent = 'agent-123'; // Exists as key in participants
709
+
710
+ const result = Utils.getDestAgentIdForCBT(interaction, consultingAgent);
711
+ expect(result).toBe('');
712
+ });
713
+
714
+ it('should return empty string when no matching dial number found', () => {
715
+ const interaction: any = {
716
+ participants: {
717
+ 'agent-uuid-123': {
718
+ type: 'Agent',
719
+ pType: 'dn',
720
+ dn: '5559999999',
721
+ id: 'agent-uuid-123',
722
+ },
723
+ },
724
+ };
725
+ const consultingAgent = '5551234567'; // Different number
726
+
727
+ const result = Utils.getDestAgentIdForCBT(interaction, consultingAgent);
728
+ expect(result).toBe('');
729
+ });
730
+
731
+ it('should return empty string when consultingAgent is empty', () => {
732
+ const interaction: any = {
733
+ participants: {
734
+ 'agent-uuid-123': {
735
+ type: 'Agent',
736
+ pType: 'dn',
737
+ dn: '5551234567',
738
+ },
739
+ },
740
+ };
741
+
742
+ const result = Utils.getDestAgentIdForCBT(interaction, '');
743
+ expect(result).toBe('');
744
+ });
745
+
746
+ it('should match only when participant type is dial number and type is Agent', () => {
747
+ const interaction: any = {
748
+ participants: {
749
+ 'participant-1': {
750
+ type: 'Customer',
751
+ pType: 'dn',
752
+ dn: '5551234567',
753
+ },
754
+ 'participant-2': {
755
+ type: 'Agent',
756
+ pType: 'Agent',
757
+ dn: '5551234567',
758
+ },
759
+ 'participant-3': {
760
+ type: 'Agent',
761
+ pType: 'dn',
762
+ dn: '5551234567',
763
+ id: 'correct-agent',
764
+ },
765
+ },
766
+ };
767
+
768
+ const result = Utils.getDestAgentIdForCBT(interaction, '5551234567');
769
+ expect(result).toBe('participant-3');
770
+ });
771
+
772
+ it('should handle case-insensitive participant type comparison', () => {
773
+ const interaction: any = {
774
+ participants: {
775
+ 'agent-uuid': {
776
+ type: 'Agent',
777
+ pType: 'DN', // Uppercase (dial number)
778
+ dn: '5551234567',
779
+ },
780
+ },
781
+ };
782
+
783
+ const result = Utils.getDestAgentIdForCBT(interaction, '5551234567');
784
+ expect(result).toBe('agent-uuid');
785
+ });
786
+ });
787
+
788
+ describe('calculateDestAgentId', () => {
789
+ const currentAgentId = 'agent-123';
790
+
791
+ it('should return destAgentIdCBT when found', () => {
792
+ const interaction: any = {
793
+ media: {
794
+ consult: {
795
+ mType: 'consult',
796
+ participants: [currentAgentId, '5551234567'],
797
+ },
798
+ },
799
+ participants: {
800
+ 'agent-uuid-456': {
801
+ type: 'Agent',
802
+ pType: 'dn',
803
+ dn: '5551234567',
804
+ id: 'agent-uuid-456',
805
+ },
806
+ },
807
+ };
808
+
809
+ const result = Utils.calculateDestAgentId(interaction, currentAgentId);
810
+ expect(result).toBe('agent-uuid-456');
811
+ });
812
+
813
+ it('should return participant id for regular agent when not CBT', () => {
814
+ const consultedAgentId = 'agent-456';
815
+ const interaction: any = {
816
+ media: {
817
+ consult: {
818
+ mType: 'consult',
819
+ participants: [currentAgentId, consultedAgentId],
820
+ },
821
+ },
822
+ participants: {
823
+ [consultedAgentId]: {
824
+ type: 'Agent',
825
+ id: consultedAgentId,
826
+ },
827
+ },
828
+ };
829
+
830
+ const result = Utils.calculateDestAgentId(interaction, currentAgentId);
831
+ expect(result).toBe(consultedAgentId);
832
+ });
833
+
834
+ it('should return epId for EpDn type participants', () => {
835
+ const consultedAgentId = 'epdn-456';
836
+ const interaction: any = {
837
+ media: {
838
+ consult: {
839
+ mType: 'consult',
840
+ participants: [currentAgentId, consultedAgentId],
841
+ },
842
+ },
843
+ participants: {
844
+ [consultedAgentId]: {
845
+ type: 'EpDn',
846
+ id: consultedAgentId,
847
+ epId: 'entry-point-id-789',
848
+ },
849
+ },
850
+ };
851
+
852
+ const result = Utils.calculateDestAgentId(interaction, currentAgentId);
853
+ expect(result).toBe('entry-point-id-789');
854
+ });
855
+
856
+ it('should return undefined when no consulting agent found', () => {
857
+ const interaction: any = {
858
+ media: {
859
+ mainCall: {
860
+ mType: 'mainCall',
861
+ participants: [currentAgentId],
862
+ },
863
+ },
864
+ participants: {},
865
+ };
866
+
867
+ const result = Utils.calculateDestAgentId(interaction, currentAgentId);
868
+ expect(result).toBe('');
535
869
  });
536
870
 
537
871
  it('should handle CBT scenario when phone number is not a direct participant key', () => {
@@ -569,7 +903,7 @@ describe('Utils', () => {
569
903
  const usOnlyEntry = {
570
904
  name: 'US',
571
905
  prefix: '1',
572
- regex: FALLBACK_DIAL_NUMBER_REGEX.source,
906
+ regex: '1[0-9]{3}[2-9][0-9]{6}([,]{1,10}[0-9]+){0,1}',
573
907
  strippedChars: '( )-',
574
908
  };
575
909
 
@@ -585,6 +919,11 @@ describe('Utils', () => {
585
919
  const result = Utils.isValidDialNumber('+442030484377', dialPlanEntries);
586
920
  expect(result).toBe(true);
587
921
  });
922
+
923
+ it('should return true for a European number', () => {
924
+ const result = Utils.isValidDialNumber('6955577166', dialPlanEntries);
925
+ expect(result).toBe(true);
926
+ });
588
927
  });
589
928
 
590
929
  describe('with US-only dial plan entry', () => {
@@ -606,16 +945,94 @@ describe('Utils', () => {
606
945
  });
607
946
  });
608
947
 
609
- describe('with empty dial plan entries (fallback to US regex)', () => {
610
- it('should return true for a valid US phone number', () => {
611
- const result = Utils.isValidDialNumber('12223334567', []);
948
+ describe('with empty dial plan entries (defers to server)', () => {
949
+ it('should return true for any dial number', () => {
950
+ expect(Utils.isValidDialNumber('12223334567', [])).toBe(true);
951
+ });
952
+
953
+ it('should return true for a UK phone number', () => {
954
+ expect(Utils.isValidDialNumber('+442030484377', [])).toBe(true);
955
+ });
956
+
957
+ it('should return true for a European number', () => {
958
+ expect(Utils.isValidDialNumber('6955577166', [])).toBe(true);
959
+ });
960
+ });
961
+
962
+ describe('strippedChars handling', () => {
963
+ it('should strip characters before regex matching', () => {
964
+ const strictEntry = {
965
+ name: 'Digits Only',
966
+ prefix: '',
967
+ regex: '^[0-9]{10,15}$',
968
+ strippedChars: '( )-+',
969
+ };
970
+ const result = Utils.isValidDialNumber('+44 (203) 048-4377', [strictEntry]);
612
971
  expect(result).toBe(true);
613
972
  });
614
973
 
615
- it('should return false for a UK phone number', () => {
616
- const result = Utils.isValidDialNumber('+442030484377', []);
974
+ it('should handle entries with no strippedChars', () => {
975
+ const noStripEntry = {
976
+ name: 'No Strip',
977
+ prefix: '',
978
+ regex: '^[0-9]+$',
979
+ strippedChars: '',
980
+ };
981
+ expect(Utils.isValidDialNumber('12345', [noStripEntry])).toBe(true);
982
+ expect(Utils.isValidDialNumber('+12345', [noStripEntry])).toBe(false);
983
+ });
984
+ });
985
+
986
+ describe('empty or undefined dial number', () => {
987
+ it('should return false and log warning for undefined dial number', () => {
988
+ const result = Utils.isValidDialNumber(undefined as any, [anyFormatEntry]);
617
989
  expect(result).toBe(false);
990
+ expect(LoggerProxy.warn).toHaveBeenCalledWith(
991
+ 'Dial number is empty or undefined.',
992
+ expect.objectContaining({module: 'Utils', method: 'isValidDialNumber'})
993
+ );
618
994
  });
995
+
996
+ it('should return false and log warning for empty string dial number', () => {
997
+ const result = Utils.isValidDialNumber('', [anyFormatEntry]);
998
+ expect(result).toBe(false);
999
+ expect(LoggerProxy.warn).toHaveBeenCalledWith(
1000
+ 'Dial number is empty or undefined.',
1001
+ expect.objectContaining({module: 'Utils', method: 'isValidDialNumber'})
1002
+ );
1003
+ });
1004
+ });
1005
+
1006
+ describe('invalid regex handling', () => {
1007
+ it('should return false and log warning for invalid regex pattern', () => {
1008
+ const badEntry = {
1009
+ name: 'Bad Regex',
1010
+ prefix: '',
1011
+ regex: '[invalid(',
1012
+ strippedChars: '',
1013
+ };
1014
+ const result = Utils.isValidDialNumber('12345', [badEntry]);
1015
+ expect(result).toBe(false);
1016
+ expect(LoggerProxy.warn).toHaveBeenCalledWith(
1017
+ expect.stringContaining('Failed to validate dial number against entry "Bad Regex"'),
1018
+ expect.objectContaining({module: 'Utils', method: 'isValidDialNumber'})
1019
+ );
1020
+ });
1021
+ });
1022
+ });
1023
+
1024
+ describe('stripDialPlanChars', () => {
1025
+ it('should remove specified characters from input', () => {
1026
+ expect(Utils.stripDialPlanChars('+44 (203) 048-4377', '( )-+')).toBe('442030484377');
1027
+ });
1028
+
1029
+ it('should return input unchanged when strippedChars is empty', () => {
1030
+ expect(Utils.stripDialPlanChars('+442030484377', '')).toBe('+442030484377');
1031
+ });
1032
+
1033
+ it('should return input unchanged when strippedChars is null/undefined', () => {
1034
+ expect(Utils.stripDialPlanChars('12345', null as any)).toBe('12345');
1035
+ expect(Utils.stripDialPlanChars('12345', undefined as any)).toBe('12345');
619
1036
  });
620
1037
  });
621
1038