@webex/contact-center 3.8.1 → 3.9.0-multipleLLM.1
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.
- package/dist/cc.js +106 -63
- package/dist/cc.js.map +1 -1
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/logger-proxy.js +24 -1
- package/dist/logger-proxy.js.map +1 -1
- package/dist/metrics/MetricsManager.js +1 -1
- package/dist/metrics/MetricsManager.js.map +1 -1
- package/dist/metrics/behavioral-events.js +88 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +26 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/AddressBook.js +271 -0
- package/dist/services/AddressBook.js.map +1 -0
- package/dist/services/EntryPoint.js +227 -0
- package/dist/services/EntryPoint.js.map +1 -0
- package/dist/services/Queue.js +261 -0
- package/dist/services/Queue.js.map +1 -0
- package/dist/services/config/constants.js +24 -2
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/index.js +1 -43
- package/dist/services/config/index.js.map +1 -1
- package/dist/services/config/types.js +22 -5
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/GlobalTypes.js.map +1 -1
- package/dist/services/core/Utils.js +162 -2
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +0 -4
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/websocket/WebSocketManager.js +0 -4
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/task/TaskManager.js +74 -2
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/constants.js +7 -1
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/contact.js +86 -0
- package/dist/services/task/contact.js.map +1 -1
- package/dist/services/task/index.js +384 -72
- package/dist/services/task/index.js.map +1 -1
- package/dist/services/task/types.js +14 -0
- package/dist/services/task/types.js.map +1 -1
- package/dist/types/cc.d.ts +77 -43
- package/dist/types/index.d.ts +8 -3
- package/dist/types/metrics/constants.d.ts +20 -0
- package/dist/types/services/AddressBook.d.ts +74 -0
- package/dist/types/services/EntryPoint.d.ts +67 -0
- package/dist/types/services/Queue.d.ts +76 -0
- package/dist/types/services/config/constants.d.ts +23 -1
- package/dist/types/services/config/index.d.ts +1 -14
- package/dist/types/services/config/types.d.ts +44 -64
- package/dist/types/services/core/GlobalTypes.d.ts +25 -0
- package/dist/types/services/core/Utils.d.ts +40 -1
- package/dist/types/services/task/constants.d.ts +6 -0
- package/dist/types/services/task/contact.d.ts +10 -0
- package/dist/types/services/task/index.d.ts +44 -2
- package/dist/types/services/task/types.d.ts +123 -1
- package/dist/types/types.d.ts +162 -0
- package/dist/types/utils/PageCache.d.ts +173 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/PageCache.js +192 -0
- package/dist/utils/PageCache.js.map +1 -0
- package/dist/webex.js +1 -1
- package/package.json +10 -10
- package/src/cc.ts +122 -81
- package/src/index.ts +19 -3
- package/src/logger-proxy.ts +24 -1
- package/src/metrics/MetricsManager.ts +1 -1
- package/src/metrics/behavioral-events.ts +92 -0
- package/src/metrics/constants.ts +30 -0
- package/src/services/AddressBook.ts +291 -0
- package/src/services/EntryPoint.ts +241 -0
- package/src/services/Queue.ts +277 -0
- package/src/services/config/constants.ts +26 -2
- package/src/services/config/index.ts +1 -55
- package/src/services/config/types.ts +22 -65
- package/src/services/core/GlobalTypes.ts +27 -0
- package/src/services/core/Utils.ts +199 -1
- package/src/services/core/aqm-reqs.ts +0 -5
- package/src/services/core/websocket/WebSocketManager.ts +0 -4
- package/src/services/task/TaskManager.ts +79 -3
- package/src/services/task/constants.ts +6 -0
- package/src/services/task/contact.ts +80 -0
- package/src/services/task/index.ts +457 -57
- package/src/services/task/types.ts +133 -0
- package/src/types.ts +180 -0
- package/src/utils/PageCache.ts +252 -0
- package/test/unit/spec/cc.ts +31 -82
- package/test/unit/spec/metrics/MetricsManager.ts +0 -1
- package/test/unit/spec/metrics/behavioral-events.ts +56 -0
- package/test/unit/spec/services/AddressBook.ts +332 -0
- package/test/unit/spec/services/EntryPoint.ts +259 -0
- package/test/unit/spec/services/Queue.ts +323 -0
- package/test/unit/spec/services/config/index.ts +0 -71
- package/test/unit/spec/services/core/Utils.ts +50 -0
- package/test/unit/spec/services/core/aqm-reqs.ts +1 -3
- package/test/unit/spec/services/core/websocket/WebSocketManager.ts +0 -4
- package/test/unit/spec/services/task/TaskManager.ts +145 -1
- package/test/unit/spec/services/task/contact.ts +31 -1
- package/test/unit/spec/services/task/index.ts +410 -123
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -370,6 +370,126 @@ export enum TASK_EVENTS {
|
|
|
370
370
|
* ```
|
|
371
371
|
*/
|
|
372
372
|
TASK_OFFER_CONTACT = 'task:offerContact',
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Triggered when a conference is being established
|
|
376
|
+
* @example
|
|
377
|
+
* ```typescript
|
|
378
|
+
* task.on(TASK_EVENTS.TASK_CONFERENCE_ESTABLISHING, (task: ITask) => {
|
|
379
|
+
* console.log('Conference establishing:', task.data.interactionId);
|
|
380
|
+
* // Handle conference setup in progress
|
|
381
|
+
* });
|
|
382
|
+
* ```
|
|
383
|
+
*/
|
|
384
|
+
TASK_CONFERENCE_ESTABLISHING = 'task:conferenceEstablishing',
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Triggered when a conference is started successfully
|
|
388
|
+
* @example
|
|
389
|
+
* ```typescript
|
|
390
|
+
* task.on(TASK_EVENTS.TASK_CONFERENCE_STARTED, (task: ITask) => {
|
|
391
|
+
* console.log('Conference started:', task.data.interactionId);
|
|
392
|
+
* // Handle conference start
|
|
393
|
+
* });
|
|
394
|
+
* ```
|
|
395
|
+
*/
|
|
396
|
+
TASK_CONFERENCE_STARTED = 'task:conferenceStarted',
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Triggered when a conference fails to start
|
|
400
|
+
* @example
|
|
401
|
+
* ```typescript
|
|
402
|
+
* task.on(TASK_EVENTS.TASK_CONFERENCE_FAILED, (task: ITask) => {
|
|
403
|
+
* console.log('Conference failed:', task.data.interactionId);
|
|
404
|
+
* // Handle conference failure
|
|
405
|
+
* });
|
|
406
|
+
* ```
|
|
407
|
+
*/
|
|
408
|
+
TASK_CONFERENCE_FAILED = 'task:conferenceFailed',
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Triggered when a conference is ended successfully
|
|
412
|
+
* @example
|
|
413
|
+
* ```typescript
|
|
414
|
+
* task.on(TASK_EVENTS.TASK_CONFERENCE_ENDED, (task: ITask) => {
|
|
415
|
+
* console.log('Conference ended:', task.data.interactionId);
|
|
416
|
+
* // Handle conference end
|
|
417
|
+
* });
|
|
418
|
+
* ```
|
|
419
|
+
*/
|
|
420
|
+
TASK_CONFERENCE_ENDED = 'task:conferenceEnded',
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Triggered when a participant joins the conference
|
|
424
|
+
* @example
|
|
425
|
+
* ```typescript
|
|
426
|
+
* task.on(TASK_EVENTS.TASK_PARTICIPANT_JOINED, (task: ITask) => {
|
|
427
|
+
* console.log('Participant joined conference:', task.data.interactionId);
|
|
428
|
+
* // Handle participant joining
|
|
429
|
+
* });
|
|
430
|
+
* ```
|
|
431
|
+
*/
|
|
432
|
+
TASK_PARTICIPANT_JOINED = 'task:participantJoined',
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Triggered when a participant leaves the conference
|
|
436
|
+
* @example
|
|
437
|
+
* ```typescript
|
|
438
|
+
* task.on(TASK_EVENTS.TASK_PARTICIPANT_LEFT, (task: ITask) => {
|
|
439
|
+
* console.log('Participant left conference:', task.data.interactionId);
|
|
440
|
+
* // Handle participant leaving
|
|
441
|
+
* });
|
|
442
|
+
* ```
|
|
443
|
+
*/
|
|
444
|
+
TASK_PARTICIPANT_LEFT = 'task:participantLeft',
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Triggered when conference transfer is successful
|
|
448
|
+
* @example
|
|
449
|
+
* ```typescript
|
|
450
|
+
* task.on(TASK_EVENTS.TASK_CONFERENCE_TRANSFERRED, (task: ITask) => {
|
|
451
|
+
* console.log('Conference transferred:', task.data.interactionId);
|
|
452
|
+
* // Handle successful conference transfer
|
|
453
|
+
* });
|
|
454
|
+
* ```
|
|
455
|
+
*/
|
|
456
|
+
TASK_CONFERENCE_TRANSFERRED = 'task:conferenceTransferred',
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Triggered when conference transfer fails
|
|
460
|
+
* @example
|
|
461
|
+
* ```typescript
|
|
462
|
+
* task.on(TASK_EVENTS.TASK_CONFERENCE_TRANSFER_FAILED, (task: ITask) => {
|
|
463
|
+
* console.log('Conference transfer failed:', task.data.interactionId);
|
|
464
|
+
* // Handle failed conference transfer
|
|
465
|
+
* });
|
|
466
|
+
* ```
|
|
467
|
+
*/
|
|
468
|
+
TASK_CONFERENCE_TRANSFER_FAILED = 'task:conferenceTransferFailed',
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Triggered when ending a conference fails
|
|
472
|
+
* @example
|
|
473
|
+
* ```typescript
|
|
474
|
+
* task.on(TASK_EVENTS.TASK_CONFERENCE_END_FAILED, (task: ITask) => {
|
|
475
|
+
* console.log('Conference end failed:', task.data.interactionId);
|
|
476
|
+
* // Handle failed conference end
|
|
477
|
+
* });
|
|
478
|
+
* ```
|
|
479
|
+
*/
|
|
480
|
+
TASK_CONFERENCE_END_FAILED = 'task:conferenceEndFailed',
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Triggered when participant exit from conference fails
|
|
484
|
+
* @example
|
|
485
|
+
* ```typescript
|
|
486
|
+
* task.on(TASK_EVENTS.TASK_PARTICIPANT_LEFT_FAILED, (task: ITask) => {
|
|
487
|
+
* console.log('Participant failed to leave conference:', task.data.interactionId);
|
|
488
|
+
* // Handle failed participant exit
|
|
489
|
+
* });
|
|
490
|
+
* ```
|
|
491
|
+
*/
|
|
492
|
+
TASK_PARTICIPANT_LEFT_FAILED = 'task:participantLeftFailed',
|
|
373
493
|
}
|
|
374
494
|
|
|
375
495
|
/**
|
|
@@ -883,6 +1003,19 @@ export type ConsultConferenceData = {
|
|
|
883
1003
|
destinationType: string;
|
|
884
1004
|
};
|
|
885
1005
|
|
|
1006
|
+
/**
|
|
1007
|
+
* Legacy consultation conference data type matching Agent Desktop
|
|
1008
|
+
* @public
|
|
1009
|
+
*/
|
|
1010
|
+
export type consultConferencePayloadData = {
|
|
1011
|
+
/** Identifier of the agent initiating consult/conference */
|
|
1012
|
+
agentId: string;
|
|
1013
|
+
/** Type of destination (e.g., 'agent', 'queue') */
|
|
1014
|
+
destinationType: string;
|
|
1015
|
+
/** Identifier of the destination agent */
|
|
1016
|
+
destAgentId: string;
|
|
1017
|
+
};
|
|
1018
|
+
|
|
886
1019
|
/**
|
|
887
1020
|
* Parameters required for cancelling a consult to queue operation
|
|
888
1021
|
* @public
|
package/src/types.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import * as Agent from './services/agent/types';
|
|
8
8
|
import * as Contact from './services/task/types';
|
|
9
9
|
import {Profile} from './services/config/types';
|
|
10
|
+
import {PaginatedResponse, BaseSearchParams} from './utils/PageCache';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Generic type for converting a const enum object into a union type of its values.
|
|
@@ -192,6 +193,10 @@ export interface LogContext {
|
|
|
192
193
|
method?: string;
|
|
193
194
|
interactionId?: string;
|
|
194
195
|
trackingId?: string;
|
|
196
|
+
/** Additional structured data to include in logs */
|
|
197
|
+
data?: Record<string, any>;
|
|
198
|
+
/** Error object to include in logs */
|
|
199
|
+
error?: Error | unknown;
|
|
195
200
|
}
|
|
196
201
|
|
|
197
202
|
/**
|
|
@@ -620,6 +625,181 @@ export type StationReLoginResponse = Agent.ReloginSuccess | Error;
|
|
|
620
625
|
*/
|
|
621
626
|
export type SetStateResponse = Agent.StateChangeSuccess | Error;
|
|
622
627
|
|
|
628
|
+
/**
|
|
629
|
+
* AddressBook types
|
|
630
|
+
*/
|
|
631
|
+
export interface AddressBookEntry {
|
|
632
|
+
id: string;
|
|
633
|
+
organizationId?: string;
|
|
634
|
+
version?: number;
|
|
635
|
+
name: string;
|
|
636
|
+
number: string;
|
|
637
|
+
createdTime?: number;
|
|
638
|
+
lastUpdatedTime?: number;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
export type AddressBookEntriesResponse = PaginatedResponse<AddressBookEntry>;
|
|
642
|
+
|
|
643
|
+
export interface AddressBookEntrySearchParams extends BaseSearchParams {
|
|
644
|
+
addressBookId?: string;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* EntryPointRecord types
|
|
649
|
+
*/
|
|
650
|
+
export interface EntryPointRecord {
|
|
651
|
+
id: string;
|
|
652
|
+
name: string;
|
|
653
|
+
description?: string;
|
|
654
|
+
type: string;
|
|
655
|
+
isActive: boolean;
|
|
656
|
+
orgId: string;
|
|
657
|
+
createdAt?: string;
|
|
658
|
+
updatedAt?: string;
|
|
659
|
+
settings?: Record<string, any>;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
export type EntryPointListResponse = PaginatedResponse<EntryPointRecord>;
|
|
663
|
+
export type EntryPointSearchParams = BaseSearchParams;
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Queue types
|
|
667
|
+
*/
|
|
668
|
+
export interface QueueSkillRequirement {
|
|
669
|
+
organizationId?: string;
|
|
670
|
+
id?: string;
|
|
671
|
+
version?: number;
|
|
672
|
+
skillId: string;
|
|
673
|
+
skillName?: string;
|
|
674
|
+
skillType?: string;
|
|
675
|
+
condition: string;
|
|
676
|
+
skillValue: string;
|
|
677
|
+
createdTime?: number;
|
|
678
|
+
lastUpdatedTime?: number;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
export interface QueueAgent {
|
|
682
|
+
id: string;
|
|
683
|
+
ciUserId?: string;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
export interface AgentGroup {
|
|
687
|
+
teamId: string;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
export interface CallDistributionGroup {
|
|
691
|
+
agentGroups: AgentGroup[];
|
|
692
|
+
order: number;
|
|
693
|
+
duration?: number;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
export interface AssistantSkillMapping {
|
|
697
|
+
assistantSkillId?: string;
|
|
698
|
+
assistantSkillUpdatedTime?: number;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* Configuration for a contact service queue
|
|
703
|
+
* @public
|
|
704
|
+
*/
|
|
705
|
+
export interface ContactServiceQueue {
|
|
706
|
+
/** Organization ID */
|
|
707
|
+
organizationId?: string;
|
|
708
|
+
/** Unique identifier for the queue */
|
|
709
|
+
id?: string;
|
|
710
|
+
/** Version of the queue */
|
|
711
|
+
version?: number;
|
|
712
|
+
/** Name of the Contact Service Queue */
|
|
713
|
+
name: string;
|
|
714
|
+
/** Description of the queue */
|
|
715
|
+
description?: string;
|
|
716
|
+
/** Queue type (INBOUND, OUTBOUND) */
|
|
717
|
+
queueType: 'INBOUND' | 'OUTBOUND';
|
|
718
|
+
/** Whether to check agent availability */
|
|
719
|
+
checkAgentAvailability: boolean;
|
|
720
|
+
/** Channel type (TELEPHONY, EMAIL, SOCIAL_CHANNEL, CHAT, etc.) */
|
|
721
|
+
channelType: 'TELEPHONY' | 'EMAIL' | 'FAX' | 'CHAT' | 'VIDEO' | 'OTHERS' | 'SOCIAL_CHANNEL';
|
|
722
|
+
/** Social channel type for SOCIAL_CHANNEL channelType */
|
|
723
|
+
socialChannelType?:
|
|
724
|
+
| 'MESSAGEBIRD'
|
|
725
|
+
| 'MESSENGER'
|
|
726
|
+
| 'WHATSAPP'
|
|
727
|
+
| 'APPLE_BUSINESS_CHAT'
|
|
728
|
+
| 'GOOGLE_BUSINESS_MESSAGES';
|
|
729
|
+
/** Service level threshold in seconds */
|
|
730
|
+
serviceLevelThreshold: number;
|
|
731
|
+
/** Maximum number of simultaneous contacts */
|
|
732
|
+
maxActiveContacts: number;
|
|
733
|
+
/** Maximum time in queue in seconds */
|
|
734
|
+
maxTimeInQueue: number;
|
|
735
|
+
/** Default music in queue media file ID */
|
|
736
|
+
defaultMusicInQueueMediaFileId: string;
|
|
737
|
+
/** Timezone for routing strategies */
|
|
738
|
+
timezone?: string;
|
|
739
|
+
/** Whether the queue is active */
|
|
740
|
+
active: boolean;
|
|
741
|
+
/** Whether outdial campaign is enabled */
|
|
742
|
+
outdialCampaignEnabled?: boolean;
|
|
743
|
+
/** Whether monitoring is permitted */
|
|
744
|
+
monitoringPermitted: boolean;
|
|
745
|
+
/** Whether parking is permitted */
|
|
746
|
+
parkingPermitted: boolean;
|
|
747
|
+
/** Whether recording is permitted */
|
|
748
|
+
recordingPermitted: boolean;
|
|
749
|
+
/** Whether recording all calls is permitted */
|
|
750
|
+
recordingAllCallsPermitted: boolean;
|
|
751
|
+
/** Whether pausing recording is permitted */
|
|
752
|
+
pauseRecordingPermitted: boolean;
|
|
753
|
+
/** Recording pause duration in seconds */
|
|
754
|
+
recordingPauseDuration?: number;
|
|
755
|
+
/** Control flow script URL */
|
|
756
|
+
controlFlowScriptUrl: string;
|
|
757
|
+
/** IVR requeue URL */
|
|
758
|
+
ivrRequeueUrl: string;
|
|
759
|
+
/** Overflow number for telephony */
|
|
760
|
+
overflowNumber?: string;
|
|
761
|
+
/** Vendor ID */
|
|
762
|
+
vendorId?: string;
|
|
763
|
+
/** Routing type */
|
|
764
|
+
routingType: 'LONGEST_AVAILABLE_AGENT' | 'SKILLS_BASED' | 'CIRCULAR' | 'LINEAR';
|
|
765
|
+
/** Skills-based routing type */
|
|
766
|
+
skillBasedRoutingType?: 'LONGEST_AVAILABLE_AGENT' | 'BEST_AVAILABLE_AGENT';
|
|
767
|
+
/** Queue routing type */
|
|
768
|
+
queueRoutingType: 'TEAM_BASED' | 'SKILL_BASED' | 'AGENT_BASED';
|
|
769
|
+
/** Queue skill requirements */
|
|
770
|
+
queueSkillRequirements?: QueueSkillRequirement[];
|
|
771
|
+
/** List of agents for agent-based queue */
|
|
772
|
+
agents?: QueueAgent[];
|
|
773
|
+
/** Call distribution groups */
|
|
774
|
+
callDistributionGroups: CallDistributionGroup[];
|
|
775
|
+
/** XSP version */
|
|
776
|
+
xspVersion?: string;
|
|
777
|
+
/** Subscription ID */
|
|
778
|
+
subscriptionId?: string;
|
|
779
|
+
/** Assistant skill mapping */
|
|
780
|
+
assistantSkill?: AssistantSkillMapping;
|
|
781
|
+
/** Whether this is a system default queue */
|
|
782
|
+
systemDefault?: boolean;
|
|
783
|
+
/** User who last updated agents list */
|
|
784
|
+
agentsLastUpdatedByUserName?: string;
|
|
785
|
+
/** Email of user who last updated agents list */
|
|
786
|
+
agentsLastUpdatedByUserEmailPrefix?: string;
|
|
787
|
+
/** When agents list was last updated */
|
|
788
|
+
agentsLastUpdatedTime?: number;
|
|
789
|
+
/** Creation timestamp in epoch millis */
|
|
790
|
+
createdTime?: number;
|
|
791
|
+
/** Last updated timestamp in epoch millis */
|
|
792
|
+
lastUpdatedTime?: number;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
export type ContactServiceQueuesResponse = PaginatedResponse<ContactServiceQueue>;
|
|
796
|
+
|
|
797
|
+
export interface ContactServiceQueueSearchParams extends BaseSearchParams {
|
|
798
|
+
desktopProfileFilter?: boolean;
|
|
799
|
+
provisioningView?: boolean;
|
|
800
|
+
singleObjectResponse?: boolean;
|
|
801
|
+
}
|
|
802
|
+
|
|
623
803
|
/**
|
|
624
804
|
* Response type for buddy agents query operations.
|
|
625
805
|
* Either a success response with list of buddy agents or an error.
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import LoggerProxy from '../logger-proxy';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Common pagination metadata interface used across all APIs.
|
|
5
|
+
* @public
|
|
6
|
+
* @template T - Additional metadata properties specific to the API
|
|
7
|
+
*/
|
|
8
|
+
export interface PaginationMeta {
|
|
9
|
+
/** Organization ID */
|
|
10
|
+
orgid?: string;
|
|
11
|
+
/** Current page number */
|
|
12
|
+
page?: number;
|
|
13
|
+
/** Page size for current data set */
|
|
14
|
+
pageSize?: number;
|
|
15
|
+
/** Number of pages */
|
|
16
|
+
totalPages?: number;
|
|
17
|
+
/** Total number of items */
|
|
18
|
+
totalRecords?: number;
|
|
19
|
+
/** Total number of items (alias for compatibility) */
|
|
20
|
+
totalItems?: number;
|
|
21
|
+
/** Current page number (alias for compatibility) */
|
|
22
|
+
currentPage?: number;
|
|
23
|
+
/** Map of pagination links */
|
|
24
|
+
links?: Record<string, string>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Common paginated response interface used across all APIs.
|
|
29
|
+
* @public
|
|
30
|
+
* @template T - The type of data items in the response
|
|
31
|
+
*/
|
|
32
|
+
export interface PaginatedResponse<T> {
|
|
33
|
+
/** Array of data items */
|
|
34
|
+
data: T[];
|
|
35
|
+
/** Pagination metadata */
|
|
36
|
+
meta: PaginationMeta;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Common search and pagination parameters interface.
|
|
41
|
+
* @public
|
|
42
|
+
*/
|
|
43
|
+
export interface BaseSearchParams {
|
|
44
|
+
/** Search keyword */
|
|
45
|
+
search?: string;
|
|
46
|
+
/** Filter criteria using RSQL syntax */
|
|
47
|
+
filter?: string;
|
|
48
|
+
/** Attributes to be returned */
|
|
49
|
+
attributes?: string;
|
|
50
|
+
/** Page number (starts from 0) */
|
|
51
|
+
page?: number;
|
|
52
|
+
/** Number of items per page */
|
|
53
|
+
pageSize?: number;
|
|
54
|
+
/** Sort field */
|
|
55
|
+
sortBy?: string;
|
|
56
|
+
/** Sort direction */
|
|
57
|
+
sortOrder?: 'asc' | 'desc';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Default pagination constants used across all APIs.
|
|
62
|
+
* @public
|
|
63
|
+
*/
|
|
64
|
+
export const PAGINATION_DEFAULTS = {
|
|
65
|
+
/** Default page number */
|
|
66
|
+
PAGE: 0,
|
|
67
|
+
/** Default page size */
|
|
68
|
+
PAGE_SIZE: 100,
|
|
69
|
+
} as const;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Interface for cached page entry with metadata
|
|
73
|
+
* @public
|
|
74
|
+
*/
|
|
75
|
+
export interface PageCacheEntry<T> {
|
|
76
|
+
/** Cached data items for this page */
|
|
77
|
+
data: T[];
|
|
78
|
+
/** Timestamp when this page was cached */
|
|
79
|
+
timestamp: number;
|
|
80
|
+
/** Total metadata if available */
|
|
81
|
+
totalMeta?: {
|
|
82
|
+
totalPages?: number;
|
|
83
|
+
totalRecords?: number;
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Interface for cache validation parameters
|
|
89
|
+
* @public
|
|
90
|
+
*/
|
|
91
|
+
export interface CacheValidationParams {
|
|
92
|
+
/** Search query parameter */
|
|
93
|
+
search?: string;
|
|
94
|
+
/** Filter parameter */
|
|
95
|
+
filter?: string;
|
|
96
|
+
/** Attributes parameter */
|
|
97
|
+
attributes?: string;
|
|
98
|
+
/** Sort by parameter */
|
|
99
|
+
sortBy?: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Default cache TTL in minutes
|
|
104
|
+
*/
|
|
105
|
+
const DEFAULT_CACHE_TTL_MINUTES = 5;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Page cache utility class for managing paginated API response caching.
|
|
109
|
+
* Provides consistent caching behavior across all Contact Center APIs.
|
|
110
|
+
*
|
|
111
|
+
* @class PageCache
|
|
112
|
+
* @public
|
|
113
|
+
* @template T - The type of data items being cached
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* // Create a cache instance for a specific data type
|
|
117
|
+
* const cache = new PageCache<AddressBookEntry>('AddressBook');
|
|
118
|
+
*
|
|
119
|
+
* // Check if we can use cache (no search/filter parameters)
|
|
120
|
+
* if (cache.canUseCache({ search, filter })) {
|
|
121
|
+
* const cacheKey = cache.buildCacheKey(orgId, page, pageSize);
|
|
122
|
+
* const cachedPage = cache.getCachedPage(cacheKey);
|
|
123
|
+
*
|
|
124
|
+
* if (cachedPage) {
|
|
125
|
+
* return cachedPage.data;
|
|
126
|
+
* }
|
|
127
|
+
* }
|
|
128
|
+
*
|
|
129
|
+
* // Cache API response
|
|
130
|
+
* cache.cachePage(cacheKey, responseData, responseMeta);
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
export class PageCache<T> {
|
|
134
|
+
private cache: Map<string, PageCacheEntry<T>> = new Map();
|
|
135
|
+
private apiName: string;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Creates an instance of PageCache
|
|
139
|
+
* @param {string} apiName - Name of the API using this cache (for logging)
|
|
140
|
+
* @public
|
|
141
|
+
*/
|
|
142
|
+
constructor(apiName: string) {
|
|
143
|
+
this.apiName = apiName;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Checks if cache can be used for the given parameters.
|
|
148
|
+
* Cache is only used for simple pagination without search/filter/attributes/sort.
|
|
149
|
+
* @param {CacheValidationParams} params - Parameters to validate
|
|
150
|
+
* @returns {boolean} True if cache can be used
|
|
151
|
+
* @public
|
|
152
|
+
*/
|
|
153
|
+
public canUseCache(params: CacheValidationParams): boolean {
|
|
154
|
+
const {search, filter, attributes, sortBy} = params;
|
|
155
|
+
|
|
156
|
+
return !search && !filter && !attributes && !sortBy;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Builds a cache key for the given parameters
|
|
161
|
+
* @param {string} orgId - Organization ID
|
|
162
|
+
* @param {number} page - Page number
|
|
163
|
+
* @param {number} pageSize - Page size
|
|
164
|
+
* @returns {string} Cache key
|
|
165
|
+
* @public
|
|
166
|
+
*/
|
|
167
|
+
public buildCacheKey(orgId: string, page: number, pageSize: number): string {
|
|
168
|
+
return `${orgId}:${page}:${pageSize}`;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Gets a cached page if it exists and is valid
|
|
173
|
+
* @param {string} cacheKey - Cache key to look up
|
|
174
|
+
* @returns {PageCacheEntry<T> | null} Cached page entry or null if not found/expired
|
|
175
|
+
* @public
|
|
176
|
+
*/
|
|
177
|
+
public getCachedPage(cacheKey: string): PageCacheEntry<T> | null {
|
|
178
|
+
const cachedEntry = this.cache.get(cacheKey);
|
|
179
|
+
|
|
180
|
+
if (!cachedEntry) {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Check if cache entry is expired
|
|
185
|
+
const now = Date.now();
|
|
186
|
+
const cacheAge = (now - cachedEntry.timestamp) / (1000 * 60); // in minutes
|
|
187
|
+
|
|
188
|
+
if (cacheAge >= DEFAULT_CACHE_TTL_MINUTES) {
|
|
189
|
+
LoggerProxy.log(`Cache entry expired for key: ${cacheKey}`, {
|
|
190
|
+
module: this.apiName,
|
|
191
|
+
method: 'getCachedPage',
|
|
192
|
+
});
|
|
193
|
+
this.cache.delete(cacheKey);
|
|
194
|
+
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return cachedEntry;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Caches a page of data with metadata
|
|
203
|
+
* @param {string} cacheKey - Cache key
|
|
204
|
+
* @param {T[]} data - Data items to cache
|
|
205
|
+
* @param {any} meta - Metadata from API response
|
|
206
|
+
* @public
|
|
207
|
+
*/
|
|
208
|
+
public cachePage(cacheKey: string, data: T[], meta?: any): void {
|
|
209
|
+
const cacheEntry: PageCacheEntry<T> = {
|
|
210
|
+
data,
|
|
211
|
+
timestamp: Date.now(),
|
|
212
|
+
totalMeta: meta
|
|
213
|
+
? {
|
|
214
|
+
totalPages: meta.totalPages,
|
|
215
|
+
totalRecords: meta.totalRecords || meta.totalItems,
|
|
216
|
+
}
|
|
217
|
+
: undefined,
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
this.cache.set(cacheKey, cacheEntry);
|
|
221
|
+
|
|
222
|
+
LoggerProxy.log(`Cached page with ${data.length} items for key: ${cacheKey}`, {
|
|
223
|
+
module: this.apiName,
|
|
224
|
+
method: 'cachePage',
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Clears all cached entries
|
|
230
|
+
* @public
|
|
231
|
+
*/
|
|
232
|
+
public clearCache(): void {
|
|
233
|
+
const cacheSize = this.cache.size;
|
|
234
|
+
this.cache.clear();
|
|
235
|
+
|
|
236
|
+
LoggerProxy.log(`Cleared ${cacheSize} cache entries`, {
|
|
237
|
+
module: this.apiName,
|
|
238
|
+
method: 'clearCache',
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Gets the current number of cached entries
|
|
244
|
+
* @returns {number} Number of cached entries
|
|
245
|
+
* @public
|
|
246
|
+
*/
|
|
247
|
+
public getCacheSize(): number {
|
|
248
|
+
return this.cache.size;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export default PageCache;
|