@webex/plugin-meetings 3.10.0-next.8 → 3.10.0-webex-services-ready.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/annotation/annotation.types.js.map +1 -1
- package/dist/annotation/constants.js.map +1 -1
- package/dist/annotation/index.js +19 -22
- package/dist/annotation/index.js.map +1 -1
- package/dist/breakouts/breakout.js +6 -6
- package/dist/breakouts/breakout.js.map +1 -1
- package/dist/breakouts/collection.js.map +1 -1
- package/dist/breakouts/edit-lock-error.js +9 -11
- package/dist/breakouts/edit-lock-error.js.map +1 -1
- package/dist/breakouts/events.js.map +1 -1
- package/dist/breakouts/index.js +126 -127
- package/dist/breakouts/index.js.map +1 -1
- package/dist/breakouts/request.js +6 -8
- package/dist/breakouts/request.js.map +1 -1
- package/dist/breakouts/utils.js.map +1 -1
- package/dist/common/browser-detection.js.map +1 -1
- package/dist/common/collection.js +1 -2
- package/dist/common/collection.js.map +1 -1
- package/dist/common/config.js.map +1 -1
- package/dist/common/errors/captcha-error.js +9 -11
- package/dist/common/errors/captcha-error.js.map +1 -1
- package/dist/common/errors/intent-to-join.js +10 -12
- package/dist/common/errors/intent-to-join.js.map +1 -1
- package/dist/common/errors/join-forbidden-error.js +10 -12
- package/dist/common/errors/join-forbidden-error.js.map +1 -1
- package/dist/common/errors/join-meeting.js +10 -12
- package/dist/common/errors/join-meeting.js.map +1 -1
- package/dist/common/errors/join-webinar-error.js +9 -11
- package/dist/common/errors/join-webinar-error.js.map +1 -1
- package/dist/common/errors/media.js +9 -11
- package/dist/common/errors/media.js.map +1 -1
- package/dist/common/errors/multistream-not-supported-error.js +9 -11
- package/dist/common/errors/multistream-not-supported-error.js.map +1 -1
- package/dist/common/errors/no-meeting-info.js +9 -11
- package/dist/common/errors/no-meeting-info.js.map +1 -1
- package/dist/common/errors/parameter.js +11 -14
- package/dist/common/errors/parameter.js.map +1 -1
- package/dist/common/errors/password-error.js +9 -11
- package/dist/common/errors/password-error.js.map +1 -1
- package/dist/common/errors/permission.js +9 -11
- package/dist/common/errors/permission.js.map +1 -1
- package/dist/common/errors/reclaim-host-role-errors.js +32 -38
- package/dist/common/errors/reclaim-host-role-errors.js.map +1 -1
- package/dist/common/errors/reconnection-not-started.js +5 -6
- package/dist/common/errors/reconnection-not-started.js.map +1 -1
- package/dist/common/errors/reconnection.js +9 -11
- package/dist/common/errors/reconnection.js.map +1 -1
- package/dist/common/errors/stats.js +9 -11
- package/dist/common/errors/stats.js.map +1 -1
- package/dist/common/errors/webex-errors.js +20 -29
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/common/errors/webex-meetings-error.js +9 -12
- package/dist/common/errors/webex-meetings-error.js.map +1 -1
- package/dist/common/events/events-scope.js +9 -10
- package/dist/common/events/events-scope.js.map +1 -1
- package/dist/common/events/events.js +9 -10
- package/dist/common/events/events.js.map +1 -1
- package/dist/common/events/trigger-proxy.js.map +1 -1
- package/dist/common/events/util.js.map +1 -1
- package/dist/common/logs/logger-config.js.map +1 -1
- package/dist/common/logs/logger-proxy.js.map +1 -1
- package/dist/common/logs/request.js +17 -17
- package/dist/common/logs/request.js.map +1 -1
- package/dist/common/queue.js +1 -2
- package/dist/common/queue.js.map +1 -1
- package/dist/config.js +0 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js +11 -8
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/constants.js.map +1 -1
- package/dist/controls-options-manager/enums.js.map +1 -1
- package/dist/controls-options-manager/index.js +1 -2
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/controls-options-manager/types.js.map +1 -1
- package/dist/controls-options-manager/util.js +1 -2
- package/dist/controls-options-manager/util.js.map +1 -1
- package/dist/hashTree/constants.js +20 -0
- package/dist/hashTree/constants.js.map +1 -0
- package/dist/hashTree/hashTree.js +515 -0
- package/dist/hashTree/hashTree.js.map +1 -0
- package/dist/hashTree/hashTreeParser.js +1266 -0
- package/dist/hashTree/hashTreeParser.js.map +1 -0
- package/dist/hashTree/types.js +21 -0
- package/dist/hashTree/types.js.map +1 -0
- package/dist/hashTree/utils.js +48 -0
- package/dist/hashTree/utils.js.map +1 -0
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/interceptors/index.js.map +1 -1
- package/dist/interceptors/locusRetry.js +6 -8
- package/dist/interceptors/locusRetry.js.map +1 -1
- package/dist/interceptors/locusRouteToken.js +6 -8
- package/dist/interceptors/locusRouteToken.js.map +1 -1
- package/dist/interpretation/collection.js.map +1 -1
- package/dist/interpretation/index.js +1 -2
- package/dist/interpretation/index.js.map +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/interpretation/siLanguage.js.map +1 -1
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/embeddedAppsUtils.js.map +1 -1
- package/dist/locus-info/fullState.js.map +1 -1
- package/dist/locus-info/hostUtils.js.map +1 -1
- package/dist/locus-info/index.js +551 -94
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/infoUtils.js.map +1 -1
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/locus-info/parser.js +3 -4
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/locus-info/types.js +7 -0
- package/dist/locus-info/types.js.map +1 -0
- package/dist/media/MediaConnectionAwaiter.js +1 -2
- package/dist/media/MediaConnectionAwaiter.js.map +1 -1
- package/dist/media/index.js +0 -2
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +15 -17
- package/dist/media/properties.js.map +1 -1
- package/dist/media/util.js.map +1 -1
- package/dist/meeting/brbState.js +8 -9
- package/dist/meeting/brbState.js.map +1 -1
- package/dist/meeting/connectionStateHandler.js +10 -13
- package/dist/meeting/connectionStateHandler.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +1555 -1527
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +13 -17
- package/dist/meeting/locusMediaRequest.js.map +1 -1
- package/dist/meeting/muteState.js +11 -12
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +101 -104
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/request.type.js.map +1 -1
- package/dist/meeting/state.js.map +1 -1
- package/dist/meeting/type.js.map +1 -1
- package/dist/meeting/util.js +24 -23
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting/voicea-meeting.js +3 -3
- package/dist/meeting/voicea-meeting.js.map +1 -1
- package/dist/meeting-info/collection.js +7 -10
- package/dist/meeting-info/collection.js.map +1 -1
- package/dist/meeting-info/index.js +1 -2
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +135 -146
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/request.js +1 -2
- package/dist/meeting-info/request.js.map +1 -1
- package/dist/meeting-info/util.js +36 -37
- package/dist/meeting-info/util.js.map +1 -1
- package/dist/meeting-info/utilv2.js +30 -31
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/collection.js +6 -8
- package/dist/meetings/collection.js.map +1 -1
- package/dist/meetings/index.js +179 -141
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/meetings.types.js.map +1 -1
- package/dist/meetings/request.js +6 -8
- package/dist/meetings/request.js.map +1 -1
- package/dist/meetings/util.js +25 -23
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.js +1 -2
- package/dist/member/index.js.map +1 -1
- package/dist/member/types.js +6 -3
- package/dist/member/types.js.map +1 -1
- package/dist/member/util.js.map +1 -1
- package/dist/members/collection.js +1 -2
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js +18 -21
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js +8 -11
- package/dist/members/request.js.map +1 -1
- package/dist/members/types.js.map +1 -1
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/constants.js +3 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/metrics/index.js +3 -4
- package/dist/metrics/index.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +1 -2
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/receiveSlot.js +34 -45
- package/dist/multistream/receiveSlot.js.map +1 -1
- package/dist/multistream/receiveSlotManager.js +8 -9
- package/dist/multistream/receiveSlotManager.js.map +1 -1
- package/dist/multistream/remoteMedia.js +12 -15
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.js +1 -2
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js +122 -123
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +29 -30
- package/dist/multistream/sendSlotManager.js.map +1 -1
- package/dist/personal-meeting-room/index.js +16 -19
- package/dist/personal-meeting-room/index.js.map +1 -1
- package/dist/personal-meeting-room/request.js +7 -10
- package/dist/personal-meeting-room/request.js.map +1 -1
- package/dist/personal-meeting-room/util.js.map +1 -1
- package/dist/reachability/clusterReachability.js +56 -373
- package/dist/reachability/clusterReachability.js.map +1 -1
- package/dist/reachability/index.js +203 -205
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/reachability.types.js +14 -1
- package/dist/reachability/reachability.types.js.map +1 -1
- package/dist/reachability/reachabilityPeerConnection.js +445 -0
- package/dist/reachability/reachabilityPeerConnection.js.map +1 -0
- package/dist/reachability/request.js.map +1 -1
- package/dist/reachability/util.js.map +1 -1
- package/dist/reactions/constants.js.map +1 -1
- package/dist/reactions/reactions.js.map +1 -1
- package/dist/reactions/reactions.type.js.map +1 -1
- package/dist/reconnection-manager/index.js +178 -176
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/recording-controller/enums.js.map +1 -1
- package/dist/recording-controller/index.js +1 -2
- package/dist/recording-controller/index.js.map +1 -1
- package/dist/recording-controller/util.js.map +1 -1
- package/dist/roap/index.js +12 -15
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +24 -26
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js +75 -76
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/roap/types.js.map +1 -1
- package/dist/transcription/index.js +4 -5
- package/dist/transcription/index.js.map +1 -1
- package/dist/types/constants.d.ts +26 -21
- package/dist/types/hashTree/constants.d.ts +8 -0
- package/dist/types/hashTree/hashTree.d.ts +129 -0
- package/dist/types/hashTree/hashTreeParser.d.ts +260 -0
- package/dist/types/hashTree/types.d.ts +25 -0
- package/dist/types/hashTree/utils.d.ts +9 -0
- package/dist/types/locus-info/index.d.ts +91 -42
- package/dist/types/locus-info/types.d.ts +46 -0
- package/dist/types/meeting/index.d.ts +22 -9
- package/dist/types/meetings/index.d.ts +9 -2
- package/dist/types/metrics/constants.d.ts +2 -0
- package/dist/types/reachability/clusterReachability.d.ts +10 -88
- package/dist/types/reachability/reachability.types.d.ts +12 -1
- package/dist/types/reachability/reachabilityPeerConnection.d.ts +111 -0
- package/dist/webinar/collection.js +1 -2
- package/dist/webinar/collection.js.map +1 -1
- package/dist/webinar/index.js +148 -158
- package/dist/webinar/index.js.map +1 -1
- package/package.json +22 -21
- package/src/constants.ts +13 -1
- package/src/hashTree/constants.ts +9 -0
- package/src/hashTree/hashTree.ts +463 -0
- package/src/hashTree/hashTreeParser.ts +1161 -0
- package/src/hashTree/types.ts +30 -0
- package/src/hashTree/utils.ts +42 -0
- package/src/locus-info/index.ts +556 -85
- package/src/locus-info/types.ts +48 -0
- package/src/meeting/index.ts +58 -26
- package/src/meeting/util.ts +1 -0
- package/src/meetings/index.ts +104 -51
- package/src/metrics/constants.ts +2 -0
- package/src/reachability/clusterReachability.ts +50 -347
- package/src/reachability/reachability.types.ts +15 -1
- package/src/reachability/reachabilityPeerConnection.ts +416 -0
- package/test/unit/spec/hashTree/hashTree.ts +655 -0
- package/test/unit/spec/hashTree/hashTreeParser.ts +1532 -0
- package/test/unit/spec/hashTree/utils.ts +103 -0
- package/test/unit/spec/locus-info/index.js +667 -1
- package/test/unit/spec/meeting/index.js +91 -20
- package/test/unit/spec/meeting/utils.js +77 -0
- package/test/unit/spec/meetings/index.js +71 -26
- package/test/unit/spec/reachability/clusterReachability.ts +281 -138
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import HashTree from './hashTree';
|
|
2
|
+
import { Enum } from '../constants';
|
|
3
|
+
import { HtMeta } from './types';
|
|
4
|
+
import { LocusDTO } from '../locus-info/types';
|
|
5
|
+
export interface DataSet {
|
|
6
|
+
url: string;
|
|
7
|
+
root: string;
|
|
8
|
+
version: number;
|
|
9
|
+
leafCount: number;
|
|
10
|
+
name: string;
|
|
11
|
+
idleMs: number;
|
|
12
|
+
backoff: {
|
|
13
|
+
maxMs: number;
|
|
14
|
+
exponent: number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export interface HashTreeObject {
|
|
18
|
+
htMeta: HtMeta;
|
|
19
|
+
data: Record<string, any>;
|
|
20
|
+
}
|
|
21
|
+
export interface RootHashMessage {
|
|
22
|
+
dataSets: Array<DataSet>;
|
|
23
|
+
}
|
|
24
|
+
export interface HashTreeMessage {
|
|
25
|
+
dataSets: Array<DataSet>;
|
|
26
|
+
visibleDataSetsUrl: string;
|
|
27
|
+
locusStateElements?: Array<HashTreeObject>;
|
|
28
|
+
locusSessionId?: string;
|
|
29
|
+
locusUrl: string;
|
|
30
|
+
}
|
|
31
|
+
interface InternalDataSet extends DataSet {
|
|
32
|
+
hashTree?: HashTree;
|
|
33
|
+
timer?: ReturnType<typeof setTimeout>;
|
|
34
|
+
}
|
|
35
|
+
type WebexRequestMethod = (options: Record<string, any>) => Promise<any>;
|
|
36
|
+
export declare const LocusInfoUpdateType: {
|
|
37
|
+
readonly OBJECTS_UPDATED: "OBJECTS_UPDATED";
|
|
38
|
+
readonly MEETING_ENDED: "MEETING_ENDED";
|
|
39
|
+
};
|
|
40
|
+
export type LocusInfoUpdateType = Enum<typeof LocusInfoUpdateType>;
|
|
41
|
+
export type LocusInfoUpdateCallback = (updateType: LocusInfoUpdateType, data?: {
|
|
42
|
+
updatedObjects: HashTreeObject[];
|
|
43
|
+
}) => void;
|
|
44
|
+
/**
|
|
45
|
+
* Checks if the given hash tree object is of type "self"
|
|
46
|
+
* @param {HashTreeObject} object object to check
|
|
47
|
+
* @returns {boolean} True if the object is of type "self", false otherwise
|
|
48
|
+
*/
|
|
49
|
+
export declare function isSelf(object: HashTreeObject): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Parses hash tree eventing locus data
|
|
52
|
+
*/
|
|
53
|
+
declare class HashTreeParser {
|
|
54
|
+
dataSets: Record<string, InternalDataSet>;
|
|
55
|
+
visibleDataSetsUrl: string;
|
|
56
|
+
webexRequest: WebexRequestMethod;
|
|
57
|
+
locusInfoUpdateCallback: LocusInfoUpdateCallback;
|
|
58
|
+
visibleDataSets: string[];
|
|
59
|
+
debugId: string;
|
|
60
|
+
/**
|
|
61
|
+
* Constructor for HashTreeParser
|
|
62
|
+
* @param {Object} options
|
|
63
|
+
* @param {Object} options.initialLocus The initial locus data containing the hash tree information
|
|
64
|
+
*/
|
|
65
|
+
constructor(options: {
|
|
66
|
+
initialLocus: {
|
|
67
|
+
dataSets: Array<DataSet>;
|
|
68
|
+
locus: any;
|
|
69
|
+
};
|
|
70
|
+
webexRequest: WebexRequestMethod;
|
|
71
|
+
locusInfoUpdateCallback: LocusInfoUpdateCallback;
|
|
72
|
+
debugId: string;
|
|
73
|
+
});
|
|
74
|
+
/**
|
|
75
|
+
* Initializes a new visible data set by creating a hash tree for it, adding it to all the internal structures,
|
|
76
|
+
* and sending an initial sync request to Locus with empty leaf data - that will trigger Locus to gives us all the data
|
|
77
|
+
* from that dataset (in the response or via messages).
|
|
78
|
+
*
|
|
79
|
+
* @param {DataSet} dataSet The new data set to be added
|
|
80
|
+
* @returns {Promise}
|
|
81
|
+
*/
|
|
82
|
+
private initializeNewVisibleDataSet;
|
|
83
|
+
/**
|
|
84
|
+
* Sends a special sync request to Locus with all leaves empty - this is a way to get all the data for a given dataset.
|
|
85
|
+
*
|
|
86
|
+
* @param {string} datasetName - name of the dataset for which to send the request
|
|
87
|
+
* @param {string} debugText - text to include in logs
|
|
88
|
+
* @returns {Promise}
|
|
89
|
+
*/
|
|
90
|
+
private sendInitializationSyncRequestToLocus;
|
|
91
|
+
/**
|
|
92
|
+
* Queries Locus for information about all the data sets
|
|
93
|
+
*
|
|
94
|
+
* @param {string} url - url from which we can get info about all data sets
|
|
95
|
+
* @returns {Promise}
|
|
96
|
+
*/
|
|
97
|
+
private getAllDataSetsMetadata;
|
|
98
|
+
/**
|
|
99
|
+
* Initializes the hash tree parser from a message received from Locus.
|
|
100
|
+
*
|
|
101
|
+
* @param {HashTreeMessage} message - initial hash tree message received from Locus
|
|
102
|
+
* @returns {Promise}
|
|
103
|
+
*/
|
|
104
|
+
initializeFromMessage(message: HashTreeMessage): Promise<void>;
|
|
105
|
+
/**
|
|
106
|
+
* Initializes the hash tree parser from GET /loci API response by fetching all data sets metadata
|
|
107
|
+
* first and then doing an initialization sync on each data set
|
|
108
|
+
*
|
|
109
|
+
* This function requires that this.visibleDataSets have been already populated correctly by the constructor.
|
|
110
|
+
*
|
|
111
|
+
* @param {LocusDTO} locus - locus object received from GET /loci
|
|
112
|
+
* @returns {Promise}
|
|
113
|
+
*/
|
|
114
|
+
initializeFromGetLociResponse(locus: LocusDTO): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* Initializes data sets by doing an initialization sync on each visible data set that doesn't have a hash tree yet.
|
|
117
|
+
*
|
|
118
|
+
* @param {DataSet[]} dataSets Array of DataSet objects to initialize
|
|
119
|
+
* @param {string} debugText Text to include in logs for debugging purposes
|
|
120
|
+
* @returns {Promise}
|
|
121
|
+
*/
|
|
122
|
+
private initializeDataSets;
|
|
123
|
+
/**
|
|
124
|
+
* Each dataset exists at a different place in the dto
|
|
125
|
+
* iterate recursively over the locus and if it has a htMeta key,
|
|
126
|
+
* create an object with the type, id and version and add it to the appropriate leafData array
|
|
127
|
+
*
|
|
128
|
+
* @param {any} locus - The current part of the locus being processed
|
|
129
|
+
* @param {Object} [options]
|
|
130
|
+
* @param {boolean} [options.copyData=false] - Whether to copy the data for each leaf into returned result
|
|
131
|
+
* @returns {any} - An object mapping dataset names to arrays of leaf data
|
|
132
|
+
*/
|
|
133
|
+
private analyzeLocusHtMeta;
|
|
134
|
+
/**
|
|
135
|
+
* Checks if the provided hash tree message indicates the end of the meeting and that there won't be any more updates.
|
|
136
|
+
*
|
|
137
|
+
* @param {HashTreeMessage} message - The hash tree message to check
|
|
138
|
+
* @returns {boolean} - Returns true if the message indicates the end of the meeting, false otherwise
|
|
139
|
+
*/
|
|
140
|
+
private isEndMessage;
|
|
141
|
+
/**
|
|
142
|
+
* Handles the root hash heartbeat message
|
|
143
|
+
*
|
|
144
|
+
* @param {RootHashMessage} message - The root hash heartbeat message
|
|
145
|
+
* @returns {void}
|
|
146
|
+
*/
|
|
147
|
+
private handleRootHashHeartBeatMessage;
|
|
148
|
+
/**
|
|
149
|
+
* This method should be called when we receive a partial locus DTO that contains dataSets and htMeta information
|
|
150
|
+
* It updates the hash trees with the new leaf data based on the received Locus
|
|
151
|
+
*
|
|
152
|
+
* @param {Object} update - The locus update containing data sets and locus information
|
|
153
|
+
* @returns {void}
|
|
154
|
+
*/
|
|
155
|
+
handleLocusUpdate(update: {
|
|
156
|
+
dataSets?: Array<DataSet>;
|
|
157
|
+
locus: any;
|
|
158
|
+
}): void;
|
|
159
|
+
/**
|
|
160
|
+
* Updates the internal data set information based on the received data set from Locus.
|
|
161
|
+
*
|
|
162
|
+
* @param {DataSet} receivedDataSet - The latest data set information received from Locus to update the internal state.
|
|
163
|
+
* @returns {void}
|
|
164
|
+
*/
|
|
165
|
+
private updateDataSetInfo;
|
|
166
|
+
/**
|
|
167
|
+
* Checks for changes in the visible data sets based on the updated objects.
|
|
168
|
+
* @param {HashTreeObject[]} updatedObjects - The list of updated hash tree objects.
|
|
169
|
+
* @returns {Object} An object containing the removed and added visible data sets.
|
|
170
|
+
*/
|
|
171
|
+
private checkForVisibleDataSetChanges;
|
|
172
|
+
/**
|
|
173
|
+
* Deletes the hash tree for the specified data set.
|
|
174
|
+
*
|
|
175
|
+
* @param {string} dataSetName name of the data set to delete
|
|
176
|
+
* @returns {void}
|
|
177
|
+
*/
|
|
178
|
+
private deleteHashTree;
|
|
179
|
+
/**
|
|
180
|
+
* Adds entries to the passed in updateObjects array
|
|
181
|
+
* for the changes that result from removing visible data sets and creates hash
|
|
182
|
+
* trees for the new visible data sets, but without populating the hash trees.
|
|
183
|
+
*
|
|
184
|
+
* This function is synchronous. If we are missing information about some new
|
|
185
|
+
* visible data sets and they require async initialization, the names of these data sets
|
|
186
|
+
* are returned in an array.
|
|
187
|
+
*
|
|
188
|
+
* @param {string[]} removedDataSets - The list of removed data sets.
|
|
189
|
+
* @param {string[]} addedDataSets - The list of added data sets.
|
|
190
|
+
* @param {HashTreeObject[]} updatedObjects - The list of updated hash tree objects to which changes will be added.
|
|
191
|
+
* @returns {string[]} names of data sets that couldn't be initialized synchronously
|
|
192
|
+
*/
|
|
193
|
+
private processVisibleDataSetChanges;
|
|
194
|
+
/**
|
|
195
|
+
* Adds entries to the passed in updateObjects array
|
|
196
|
+
* for the changes that result from adding and removing visible data sets.
|
|
197
|
+
*
|
|
198
|
+
* @param {HashTreeMessage} message - The hash tree message that triggered the visible data set changes.
|
|
199
|
+
* @param {string[]} addedDataSets - The list of added data sets.
|
|
200
|
+
* @returns {Promise<void>}
|
|
201
|
+
*/
|
|
202
|
+
private initializeNewVisibleDataSets;
|
|
203
|
+
/**
|
|
204
|
+
* Parses incoming hash tree messages, updates the hash trees and returns information about the changes
|
|
205
|
+
*
|
|
206
|
+
* @param {HashTreeMessage} message - The hash tree message containing data sets and objects to be processed
|
|
207
|
+
* @param {string} [debugText] - Optional debug text to include in logs
|
|
208
|
+
* @returns {Promise}
|
|
209
|
+
*/
|
|
210
|
+
private parseMessage;
|
|
211
|
+
/**
|
|
212
|
+
* Handles incoming hash tree messages, updates the hash trees and calls locusInfoUpdateCallback
|
|
213
|
+
*
|
|
214
|
+
* @param {HashTreeMessage} message - The hash tree message containing data sets and objects to be processed
|
|
215
|
+
* @param {string} [debugText] - Optional debug text to include in logs
|
|
216
|
+
* @returns {void}
|
|
217
|
+
*/
|
|
218
|
+
handleMessage(message: HashTreeMessage, debugText?: string): Promise<void>;
|
|
219
|
+
/**
|
|
220
|
+
* Calls the updateInfo callback if there are any updates to report
|
|
221
|
+
*
|
|
222
|
+
* @param {Object} updates parsed from a Locus message
|
|
223
|
+
* @returns {void}
|
|
224
|
+
*/
|
|
225
|
+
private callLocusInfoUpdateCallback;
|
|
226
|
+
/**
|
|
227
|
+
* Calculates a weighted backoff time that should be used for syncs
|
|
228
|
+
*
|
|
229
|
+
* @param {Object} backoff - The backoff configuration containing maxMs and exponent
|
|
230
|
+
* @returns {number} - A weighted backoff time based on the provided configuration, using algorithm supplied by Locus team
|
|
231
|
+
*/
|
|
232
|
+
private getWeightedBackoffTime;
|
|
233
|
+
/**
|
|
234
|
+
* Runs the sync algorithm for the given data set.
|
|
235
|
+
*
|
|
236
|
+
* @param {DataSet} receivedDataSet - The data set to run the sync algorithm for.
|
|
237
|
+
* @returns {void}
|
|
238
|
+
*/
|
|
239
|
+
private runSyncAlgorithm;
|
|
240
|
+
/**
|
|
241
|
+
* Stops all timers for the data sets to prevent any further sync attempts.
|
|
242
|
+
* @returns {void}
|
|
243
|
+
*/
|
|
244
|
+
private stopAllTimers;
|
|
245
|
+
/**
|
|
246
|
+
* Gets the current hashes from the locus for a specific data set.
|
|
247
|
+
* @param {string} dataSetName
|
|
248
|
+
* @returns {string[]}
|
|
249
|
+
*/
|
|
250
|
+
private getHashesFromLocus;
|
|
251
|
+
/**
|
|
252
|
+
* Sends a sync request to Locus for the specified data set.
|
|
253
|
+
*
|
|
254
|
+
* @param {InternalDataSet} dataSet The data set to sync.
|
|
255
|
+
* @param {Record<number, LeafDataItem[]>} mismatchedLeavesData The mismatched leaves data to include in the sync request.
|
|
256
|
+
* @returns {Promise<HashTreeMessage|null>}
|
|
257
|
+
*/
|
|
258
|
+
private sendSyncRequestToLocus;
|
|
259
|
+
}
|
|
260
|
+
export default HashTreeParser;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Enum } from '../constants';
|
|
2
|
+
export declare const ObjectType: {
|
|
3
|
+
readonly participant: "participant";
|
|
4
|
+
readonly self: "self";
|
|
5
|
+
readonly locus: "locus";
|
|
6
|
+
readonly mediaShare: "mediashare";
|
|
7
|
+
readonly info: "info";
|
|
8
|
+
readonly fullState: "fullstate";
|
|
9
|
+
};
|
|
10
|
+
export type ObjectType = Enum<typeof ObjectType>;
|
|
11
|
+
export declare const ObjectTypeToLocusKeyMap: {
|
|
12
|
+
info: string;
|
|
13
|
+
fullstate: string;
|
|
14
|
+
self: string;
|
|
15
|
+
participant: string;
|
|
16
|
+
mediashare: string;
|
|
17
|
+
};
|
|
18
|
+
export interface HtMeta {
|
|
19
|
+
elementId: {
|
|
20
|
+
type: ObjectType;
|
|
21
|
+
id: number;
|
|
22
|
+
version: number;
|
|
23
|
+
};
|
|
24
|
+
dataSetNames: string[];
|
|
25
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analyzes given part of Locus DTO recursively and delete any nested objects that have their own htMeta
|
|
3
|
+
*
|
|
4
|
+
* @param {Object} currentLocusPart part of locus DTO to analyze
|
|
5
|
+
* @param {Object} parent parent object
|
|
6
|
+
* @param {string|number} currentKey key of the parent object that currentLocusPart is
|
|
7
|
+
* @returns {void}
|
|
8
|
+
*/
|
|
9
|
+
export declare const deleteNestedObjectsWithHtMeta: (currentLocusPart: any, parent?: any, currentKey?: string | number) => void;
|
|
@@ -1,45 +1,15 @@
|
|
|
1
1
|
import EventsScope from '../common/events/events-scope';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
sessionId: string;
|
|
10
|
-
seessionIds: string[];
|
|
11
|
-
startTime: number;
|
|
12
|
-
state: string;
|
|
13
|
-
type: string;
|
|
2
|
+
import { LOCUSEVENT } from '../constants';
|
|
3
|
+
import HashTreeParser, { DataSet, HashTreeMessage, HashTreeObject } from '../hashTree/hashTreeParser';
|
|
4
|
+
import { LocusDTO } from './types';
|
|
5
|
+
export type LocusLLMEvent = {
|
|
6
|
+
data: {
|
|
7
|
+
eventType: typeof LOCUSEVENT.HASH_TREE_DATA_UPDATED;
|
|
8
|
+
stateElementsMessage: HashTreeMessage;
|
|
14
9
|
};
|
|
15
|
-
host?: {
|
|
16
|
-
id: string;
|
|
17
|
-
incomingCallProtocols: any[];
|
|
18
|
-
isExternal: boolean;
|
|
19
|
-
name: string;
|
|
20
|
-
orgId: string;
|
|
21
|
-
};
|
|
22
|
-
info?: any;
|
|
23
|
-
links?: any;
|
|
24
|
-
mediaShares?: any[];
|
|
25
|
-
meetings?: any[];
|
|
26
|
-
participants: any[];
|
|
27
|
-
replaces?: any[];
|
|
28
|
-
self?: any;
|
|
29
|
-
sequence?: {
|
|
30
|
-
dirtyParticipants: number;
|
|
31
|
-
entries: number[];
|
|
32
|
-
rangeEnd: number;
|
|
33
|
-
rangeStart: number;
|
|
34
|
-
sequenceHash: number;
|
|
35
|
-
sessionToken: string;
|
|
36
|
-
since: string;
|
|
37
|
-
totalParticipants: number;
|
|
38
|
-
};
|
|
39
|
-
syncUrl?: string;
|
|
40
|
-
url?: string;
|
|
41
10
|
};
|
|
42
11
|
export type LocusApiResponseBody = {
|
|
12
|
+
dataSets?: DataSet[];
|
|
43
13
|
locus: LocusDTO;
|
|
44
14
|
};
|
|
45
15
|
/**
|
|
@@ -80,6 +50,9 @@ export default class LocusInfo extends EventsScope {
|
|
|
80
50
|
resources: any;
|
|
81
51
|
mainSessionLocusCache: any;
|
|
82
52
|
self: any;
|
|
53
|
+
hashTreeParser?: HashTreeParser;
|
|
54
|
+
hashTreeObjectId2ParticipantId: Map<number, string>;
|
|
55
|
+
classicVsHashTreeMismatchMetricCounter: number;
|
|
83
56
|
/**
|
|
84
57
|
* Constructor
|
|
85
58
|
* @param {function} updateMeeting callback to update the meeting object from an object
|
|
@@ -90,6 +63,7 @@ export default class LocusInfo extends EventsScope {
|
|
|
90
63
|
constructor(updateMeeting: any, webex: any, meetingId: any);
|
|
91
64
|
/**
|
|
92
65
|
* Does a Locus sync. It tries to get the latest delta DTO or if it can't, it falls back to getting the full Locus DTO.
|
|
66
|
+
* WARNING: This function must not be used for hash tree based Locus meetings.
|
|
93
67
|
*
|
|
94
68
|
* @param {Meeting} meeting
|
|
95
69
|
* @param {boolean} isLocusUrlChanged
|
|
@@ -121,11 +95,28 @@ export default class LocusInfo extends EventsScope {
|
|
|
121
95
|
*/
|
|
122
96
|
init(locus?: any): void;
|
|
123
97
|
/**
|
|
124
|
-
*
|
|
98
|
+
* Creates the HashTreeParser instance.
|
|
99
|
+
* @param {Object} initial locus data
|
|
100
|
+
* @returns {void}
|
|
101
|
+
*/
|
|
102
|
+
private createHashTreeParser;
|
|
103
|
+
/**
|
|
104
|
+
* @param {Object} data - data to initialize locus info with. It may be from a join or GET /loci response or from a Mercury event that triggers a creation of meeting object
|
|
125
105
|
* @returns {undefined}
|
|
126
106
|
* @memberof LocusInfo
|
|
127
107
|
*/
|
|
128
|
-
initialSetup(
|
|
108
|
+
initialSetup(data: {
|
|
109
|
+
trigger: 'join-response';
|
|
110
|
+
locus: LocusDTO;
|
|
111
|
+
dataSets?: DataSet[];
|
|
112
|
+
} | {
|
|
113
|
+
trigger: 'locus-message';
|
|
114
|
+
locus?: LocusDTO;
|
|
115
|
+
hashTreeMessage?: HashTreeMessage;
|
|
116
|
+
} | {
|
|
117
|
+
trigger: 'get-loci-response';
|
|
118
|
+
locus?: LocusDTO;
|
|
119
|
+
}): Promise<void>;
|
|
129
120
|
/**
|
|
130
121
|
* Handles HTTP response from Locus API call.
|
|
131
122
|
* @param {Meeting} meeting meeting object
|
|
@@ -133,6 +124,39 @@ export default class LocusInfo extends EventsScope {
|
|
|
133
124
|
* @returns {void}
|
|
134
125
|
*/
|
|
135
126
|
handleLocusAPIResponse(meeting: any, responseBody: LocusApiResponseBody): void;
|
|
127
|
+
/**
|
|
128
|
+
*
|
|
129
|
+
* @param {HashTreeObject} object data set object
|
|
130
|
+
* @param {any} locus
|
|
131
|
+
* @returns {void}
|
|
132
|
+
*/
|
|
133
|
+
updateLocusFromHashTreeObject(object: HashTreeObject, locus: LocusDTO): LocusDTO;
|
|
134
|
+
/**
|
|
135
|
+
* Sends a metric when we receive something from Locus that uses hash trees while we
|
|
136
|
+
* expect classic deltas or the other way around.
|
|
137
|
+
* @param {Meeting} meeting
|
|
138
|
+
* @param {string} message
|
|
139
|
+
* @returns {void}
|
|
140
|
+
*/
|
|
141
|
+
sendClassicVsHashTreeMismatchMetric(meeting: any, message: string): void;
|
|
142
|
+
/**
|
|
143
|
+
* Handles a hash tree message received from Locus.
|
|
144
|
+
*
|
|
145
|
+
* @param {Meeting} meeting - The meeting object
|
|
146
|
+
* @param {eventType} eventType - The event type
|
|
147
|
+
* @param {HashTreeMessage} message incoming hash tree message
|
|
148
|
+
* @returns {void}
|
|
149
|
+
*/
|
|
150
|
+
private handleHashTreeMessage;
|
|
151
|
+
/**
|
|
152
|
+
* Callback registered with HashTreeParser to receive locus info updates.
|
|
153
|
+
* Updates our locus info based on the data parsed by the hash tree parser.
|
|
154
|
+
*
|
|
155
|
+
* @param {LocusInfoUpdateType} updateType - The type of update received.
|
|
156
|
+
* @param {Object} [data] - Additional data for the update, if applicable.
|
|
157
|
+
* @returns {void}
|
|
158
|
+
*/
|
|
159
|
+
private updateFromHashTree;
|
|
136
160
|
/**
|
|
137
161
|
* @param {Meeting} meeting
|
|
138
162
|
* @param {Object} data
|
|
@@ -148,14 +172,39 @@ export default class LocusInfo extends EventsScope {
|
|
|
148
172
|
* @memberof LocusInfo
|
|
149
173
|
*/
|
|
150
174
|
emitScoped(scope?: any, eventName?: string, args?: any): boolean;
|
|
175
|
+
/**
|
|
176
|
+
* Function for handling full locus when it's using hash trees (so not the "classic" one).
|
|
177
|
+
*
|
|
178
|
+
* @param {object} locus locus object
|
|
179
|
+
* @param {string} eventType locus event
|
|
180
|
+
* @param {DataSet[]} dataSets
|
|
181
|
+
* @returns {void}
|
|
182
|
+
*/
|
|
183
|
+
private onFullLocusWithHashTrees;
|
|
184
|
+
/**
|
|
185
|
+
* Function for handling full locus when it's the "classic" one (not hash trees)
|
|
186
|
+
*
|
|
187
|
+
* @param {object} locus locus object
|
|
188
|
+
* @param {string} eventType locus event
|
|
189
|
+
* @returns {void}
|
|
190
|
+
*/
|
|
191
|
+
private onFullLocusClassic;
|
|
151
192
|
/**
|
|
152
193
|
* updates the locus with full locus object
|
|
153
194
|
* @param {object} locus locus object
|
|
154
|
-
* @param {string} eventType
|
|
195
|
+
* @param {string} eventType locus event
|
|
196
|
+
* @param {DataSet[]} dataSets
|
|
155
197
|
* @returns {object} null
|
|
156
198
|
* @memberof LocusInfo
|
|
157
199
|
*/
|
|
158
|
-
onFullLocus(locus: any, eventType?: string): void;
|
|
200
|
+
onFullLocus(locus: any, eventType?: string, dataSets?: Array<DataSet>): void;
|
|
201
|
+
/**
|
|
202
|
+
* Common part of handling full locus, used by both classic and hash tree based locus handling
|
|
203
|
+
* @param {object} locus locus object
|
|
204
|
+
* @param {string} eventType locus event
|
|
205
|
+
* @returns {void}
|
|
206
|
+
*/
|
|
207
|
+
private onFullLocusCommon;
|
|
159
208
|
/**
|
|
160
209
|
* @param {String} eventType
|
|
161
210
|
* @returns {undefined}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { HtMeta } from '../hashTree/types';
|
|
2
|
+
export type LocusFullState = {
|
|
3
|
+
active: boolean;
|
|
4
|
+
count: number;
|
|
5
|
+
lastActive: string;
|
|
6
|
+
locked: boolean;
|
|
7
|
+
sessionId: string;
|
|
8
|
+
seessionIds: string[];
|
|
9
|
+
startTime: number;
|
|
10
|
+
state: string;
|
|
11
|
+
type: string;
|
|
12
|
+
};
|
|
13
|
+
export type LocusDTO = {
|
|
14
|
+
controls?: any;
|
|
15
|
+
fullState?: LocusFullState;
|
|
16
|
+
host?: {
|
|
17
|
+
id: string;
|
|
18
|
+
incomingCallProtocols: any[];
|
|
19
|
+
isExternal: boolean;
|
|
20
|
+
name: string;
|
|
21
|
+
orgId: string;
|
|
22
|
+
};
|
|
23
|
+
htMeta?: HtMeta;
|
|
24
|
+
info?: any;
|
|
25
|
+
jsSdkMeta?: {
|
|
26
|
+
removedParticipantIds: string[];
|
|
27
|
+
};
|
|
28
|
+
links?: any;
|
|
29
|
+
mediaShares?: any[];
|
|
30
|
+
meetings?: any[];
|
|
31
|
+
participants: any[];
|
|
32
|
+
replaces?: any[];
|
|
33
|
+
self?: any;
|
|
34
|
+
sequence?: {
|
|
35
|
+
dirtyParticipants: number;
|
|
36
|
+
entries: number[];
|
|
37
|
+
rangeEnd: number;
|
|
38
|
+
rangeStart: number;
|
|
39
|
+
sequenceHash: number;
|
|
40
|
+
sessionToken: string;
|
|
41
|
+
since: string;
|
|
42
|
+
totalParticipants: number;
|
|
43
|
+
};
|
|
44
|
+
syncUrl?: string;
|
|
45
|
+
url?: string;
|
|
46
|
+
};
|
|
@@ -23,6 +23,8 @@ import { LocusMediaRequest } from './locusMediaRequest';
|
|
|
23
23
|
import { BrbState } from './brbState';
|
|
24
24
|
import { SetStageOptions } from './request.type';
|
|
25
25
|
import { Invitee } from './type';
|
|
26
|
+
import { DataSet } from '../hashTree/hashTreeParser';
|
|
27
|
+
import { LocusDTO } from '../locus-info/types';
|
|
26
28
|
export type CaptionData = {
|
|
27
29
|
id: string;
|
|
28
30
|
isFinal: boolean;
|
|
@@ -1034,25 +1036,30 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1034
1036
|
*/
|
|
1035
1037
|
setSipUri(sipUri: string): void;
|
|
1036
1038
|
/**
|
|
1037
|
-
* Set the locus info the class instance
|
|
1038
|
-
*
|
|
1039
|
-
*
|
|
1040
|
-
* @param {
|
|
1041
|
-
* @param {
|
|
1042
|
-
* @param {String}
|
|
1043
|
-
* @param {
|
|
1039
|
+
* Set the locus info the class instance. Should be called with the parsed locus
|
|
1040
|
+
* we got in the join response.
|
|
1041
|
+
*
|
|
1042
|
+
* @param {Object} data
|
|
1043
|
+
* @param {Array} data.mediaConnections
|
|
1044
|
+
* @param {String} data.locusUrl
|
|
1045
|
+
* @param {String} data.locusId
|
|
1046
|
+
* @param {String} data.mediaId
|
|
1047
|
+
* @param {Object} data.host
|
|
1044
1048
|
* @todo change name to genertic parser
|
|
1045
1049
|
* @returns {undefined}
|
|
1046
1050
|
* @private
|
|
1047
1051
|
* @memberof Meeting
|
|
1048
1052
|
*/
|
|
1049
|
-
setLocus(
|
|
1053
|
+
setLocus(data: {
|
|
1054
|
+
locus: LocusDTO;
|
|
1050
1055
|
mediaConnections: Array<any>;
|
|
1051
1056
|
locusUrl: string;
|
|
1052
1057
|
locusId: string;
|
|
1053
1058
|
mediaId: string;
|
|
1054
1059
|
host: object;
|
|
1055
|
-
|
|
1060
|
+
selfId: string;
|
|
1061
|
+
dataSets: DataSet[];
|
|
1062
|
+
}): void;
|
|
1056
1063
|
/**
|
|
1057
1064
|
* Upload logs for the current meeting
|
|
1058
1065
|
* @param {object} options file name and function name
|
|
@@ -1269,6 +1276,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1269
1276
|
startTranscription(options?: {
|
|
1270
1277
|
spokenLanguage?: string;
|
|
1271
1278
|
}): Promise<void>;
|
|
1279
|
+
/** Handles Locus LLM events
|
|
1280
|
+
*
|
|
1281
|
+
* @param {LocusLLMEvent} event - The Locus LLM event to process
|
|
1282
|
+
* @returns {void}
|
|
1283
|
+
*/
|
|
1284
|
+
private processLocusLLMEvent;
|
|
1272
1285
|
/**
|
|
1273
1286
|
* Callback called when a relay event is received from meeting LLM Connection
|
|
1274
1287
|
* @param {RelayEvent} e Event object coming from LLM Connection
|
|
@@ -5,10 +5,17 @@ import { WebexPlugin } from '@webex/webex-core';
|
|
|
5
5
|
import { DeviceRegistrationOptions } from '@webex/internal-plugin-device';
|
|
6
6
|
import * as mediaHelpersModule from '@webex/media-helpers';
|
|
7
7
|
import 'webrtc-adapter';
|
|
8
|
-
import { DESTINATION_TYPE } from '../constants';
|
|
8
|
+
import { LOCUSEVENT, DESTINATION_TYPE } from '../constants';
|
|
9
9
|
import { CallStateForMetrics } from '../meeting';
|
|
10
10
|
import Reachability from '../reachability';
|
|
11
11
|
import { INoiseReductionEffect, IVirtualBackgroundEffect, MeetingRegistrationStatus } from './meetings.types';
|
|
12
|
+
import { HashTreeMessage } from '../hashTree/hashTreeParser';
|
|
13
|
+
export type LocusEvent = {
|
|
14
|
+
eventType: LOCUSEVENT;
|
|
15
|
+
locusUrl?: string;
|
|
16
|
+
locus?: any;
|
|
17
|
+
stateElementsMessage?: HashTreeMessage;
|
|
18
|
+
};
|
|
12
19
|
/**
|
|
13
20
|
* Meetings Ready Event
|
|
14
21
|
* Emitted when the meetings instance on webex is ready
|
|
@@ -129,7 +136,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
129
136
|
* @private
|
|
130
137
|
* @memberof Meetings
|
|
131
138
|
*/
|
|
132
|
-
getCorrespondingMeetingByLocus(data:
|
|
139
|
+
getCorrespondingMeetingByLocus(data: LocusEvent): any;
|
|
133
140
|
/**
|
|
134
141
|
* handle locus events and takes meeting actions with them as they come in
|
|
135
142
|
* @param {Object} data a locus event
|
|
@@ -84,5 +84,7 @@ declare const BEHAVIORAL_METRICS: {
|
|
|
84
84
|
VERIFY_REGISTRATION_ID_ERROR: string;
|
|
85
85
|
JOIN_FORBIDDEN_ERROR: string;
|
|
86
86
|
MEDIA_ISSUE_DETECTED: string;
|
|
87
|
+
LOCUS_CLASSIC_VS_HASH_TREE_MISMATCH: string;
|
|
88
|
+
LOCUS_HASH_TREE_UNSUPPORTED_OPERATION: string;
|
|
87
89
|
};
|
|
88
90
|
export { BEHAVIORAL_METRICS as default };
|