@webex/plugin-meetings 3.12.0-next.6 → 3.12.0-next.61
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/AGENTS.md +9 -0
- package/dist/aiEnableRequest/index.js +15 -2
- package/dist/aiEnableRequest/index.js.map +1 -1
- package/dist/breakouts/breakout.js +8 -3
- package/dist/breakouts/breakout.js.map +1 -1
- package/dist/breakouts/index.js +26 -2
- package/dist/breakouts/index.js.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +6 -3
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/constants.js +11 -1
- package/dist/controls-options-manager/constants.js.map +1 -1
- package/dist/controls-options-manager/index.js +38 -24
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/controls-options-manager/util.js +91 -0
- package/dist/controls-options-manager/util.js.map +1 -1
- package/dist/hashTree/constants.js +10 -1
- package/dist/hashTree/constants.js.map +1 -1
- package/dist/hashTree/hashTreeParser.js +716 -370
- package/dist/hashTree/hashTreeParser.js.map +1 -1
- package/dist/hashTree/utils.js +22 -0
- package/dist/hashTree/utils.js.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/interceptors/locusRetry.js +23 -8
- package/dist/interceptors/locusRetry.js.map +1 -1
- package/dist/interpretation/index.js +10 -1
- package/dist/interpretation/index.js.map +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/controlsUtils.js +4 -1
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +289 -87
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/types.js +19 -0
- package/dist/locus-info/types.js.map +1 -1
- package/dist/media/index.js +3 -1
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +1 -0
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +3 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +907 -535
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/util.js +19 -2
- package/dist/meeting/util.js.map +1 -1
- package/dist/meetings/index.js +231 -78
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/meetings.types.js +6 -1
- package/dist/meetings/meetings.types.js.map +1 -1
- package/dist/meetings/request.js +39 -0
- package/dist/meetings/request.js.map +1 -1
- package/dist/meetings/util.js +79 -5
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.js +10 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/types.js.map +1 -1
- package/dist/member/util.js +3 -0
- package/dist/member/util.js.map +1 -1
- package/dist/metrics/constants.js +4 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/multistream/codec/constants.js +63 -0
- package/dist/multistream/codec/constants.js.map +1 -0
- package/dist/multistream/mediaRequestManager.js +62 -15
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/receiveSlot.js +9 -0
- package/dist/multistream/receiveSlot.js.map +1 -1
- package/dist/reactions/reactions.type.js.map +1 -1
- package/dist/recording-controller/index.js +1 -3
- package/dist/recording-controller/index.js.map +1 -1
- package/dist/types/config.d.ts +2 -0
- package/dist/types/constants.d.ts +2 -0
- package/dist/types/controls-options-manager/constants.d.ts +6 -1
- package/dist/types/controls-options-manager/index.d.ts +10 -0
- package/dist/types/hashTree/constants.d.ts +1 -0
- package/dist/types/hashTree/hashTreeParser.d.ts +92 -16
- package/dist/types/hashTree/utils.d.ts +11 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/interceptors/locusRetry.d.ts +4 -4
- package/dist/types/locus-info/index.d.ts +46 -6
- package/dist/types/locus-info/types.d.ts +21 -1
- package/dist/types/media/properties.d.ts +1 -0
- package/dist/types/meeting/in-meeting-actions.d.ts +2 -0
- package/dist/types/meeting/index.d.ts +87 -3
- package/dist/types/meeting/util.d.ts +8 -0
- package/dist/types/meetings/index.d.ts +30 -2
- package/dist/types/meetings/meetings.types.d.ts +15 -0
- package/dist/types/meetings/request.d.ts +14 -0
- package/dist/types/member/index.d.ts +1 -0
- package/dist/types/member/types.d.ts +1 -0
- package/dist/types/member/util.d.ts +1 -0
- package/dist/types/metrics/constants.d.ts +3 -0
- package/dist/types/multistream/codec/constants.d.ts +7 -0
- package/dist/types/multistream/mediaRequestManager.d.ts +22 -5
- package/dist/types/reactions/reactions.type.d.ts +3 -0
- package/dist/webinar/index.js +361 -235
- package/dist/webinar/index.js.map +1 -1
- package/package.json +22 -22
- package/src/aiEnableRequest/index.ts +16 -0
- package/src/breakouts/breakout.ts +3 -1
- package/src/breakouts/index.ts +31 -0
- package/src/config.ts +2 -0
- package/src/constants.ts +5 -1
- package/src/controls-options-manager/constants.ts +14 -1
- package/src/controls-options-manager/index.ts +47 -24
- package/src/controls-options-manager/util.ts +81 -1
- package/src/hashTree/constants.ts +9 -0
- package/src/hashTree/hashTreeParser.ts +429 -183
- package/src/hashTree/utils.ts +17 -0
- package/src/index.ts +5 -0
- package/src/interceptors/locusRetry.ts +25 -4
- package/src/interpretation/index.ts +25 -8
- package/src/locus-info/controlsUtils.ts +3 -1
- package/src/locus-info/index.ts +291 -97
- package/src/locus-info/types.ts +25 -1
- package/src/media/index.ts +3 -0
- package/src/media/properties.ts +1 -0
- package/src/meeting/in-meeting-actions.ts +4 -0
- package/src/meeting/index.ts +388 -33
- package/src/meeting/util.ts +20 -2
- package/src/meetings/index.ts +134 -44
- package/src/meetings/meetings.types.ts +19 -0
- package/src/meetings/request.ts +43 -0
- package/src/meetings/util.ts +97 -1
- package/src/member/index.ts +10 -0
- package/src/member/types.ts +1 -0
- package/src/member/util.ts +3 -0
- package/src/metrics/constants.ts +3 -0
- package/src/multistream/codec/constants.ts +58 -0
- package/src/multistream/mediaRequestManager.ts +119 -28
- package/src/multistream/receiveSlot.ts +18 -0
- package/src/reactions/reactions.type.ts +3 -0
- package/src/recording-controller/index.ts +1 -2
- package/src/webinar/index.ts +162 -21
- package/test/unit/spec/aiEnableRequest/index.ts +86 -0
- package/test/unit/spec/breakouts/breakout.ts +9 -3
- package/test/unit/spec/breakouts/index.ts +49 -0
- package/test/unit/spec/controls-options-manager/index.js +140 -29
- package/test/unit/spec/controls-options-manager/util.js +165 -0
- package/test/unit/spec/hashTree/hashTreeParser.ts +1508 -149
- package/test/unit/spec/hashTree/utils.ts +88 -1
- package/test/unit/spec/interceptors/locusRetry.ts +205 -4
- package/test/unit/spec/interpretation/index.ts +26 -4
- package/test/unit/spec/locus-info/controlsUtils.js +172 -57
- package/test/unit/spec/locus-info/index.js +475 -81
- package/test/unit/spec/media/index.ts +31 -0
- package/test/unit/spec/meeting/in-meeting-actions.ts +2 -0
- package/test/unit/spec/meeting/index.js +1131 -49
- package/test/unit/spec/meeting/muteState.js +3 -0
- package/test/unit/spec/meeting/utils.js +33 -0
- package/test/unit/spec/meetings/index.js +360 -10
- package/test/unit/spec/meetings/request.js +141 -0
- package/test/unit/spec/meetings/utils.js +189 -0
- package/test/unit/spec/member/index.js +7 -0
- package/test/unit/spec/member/util.js +24 -0
- package/test/unit/spec/multistream/mediaRequestManager.ts +501 -37
- package/test/unit/spec/recording-controller/index.js +9 -8
- package/test/unit/spec/webinar/index.ts +141 -16
package/src/meeting/util.ts
CHANGED
|
@@ -371,6 +371,7 @@ const MeetingUtil = {
|
|
|
371
371
|
meeting.breakouts.cleanUp();
|
|
372
372
|
meeting.webinar.cleanUp();
|
|
373
373
|
meeting.simultaneousInterpretation.cleanUp();
|
|
374
|
+
meeting.locusInfo.cleanUp();
|
|
374
375
|
meeting.locusMediaRequest = undefined;
|
|
375
376
|
|
|
376
377
|
meeting.webex?.internal?.newMetrics?.callDiagnosticMetrics?.clearEventLimitsForCorrelationId(
|
|
@@ -845,6 +846,19 @@ const MeetingUtil = {
|
|
|
845
846
|
requestBody.sequence = sequence;
|
|
846
847
|
},
|
|
847
848
|
|
|
849
|
+
/**
|
|
850
|
+
* Checks if Locus API response contains a Locus DTO
|
|
851
|
+
*
|
|
852
|
+
* @param {any} response http response from Locus API call
|
|
853
|
+
* @returns {boolean} true if response contains a Locus DTO
|
|
854
|
+
*/
|
|
855
|
+
isLocusDtoInAPIResponse(response: any) {
|
|
856
|
+
return (
|
|
857
|
+
response?.body?.locus || // for APIs called on our participant - locus is one of props in the response body
|
|
858
|
+
response?.body?.url // for APIs that act on locus itself (like mute all), the body is the locus
|
|
859
|
+
);
|
|
860
|
+
},
|
|
861
|
+
|
|
848
862
|
/**
|
|
849
863
|
* Updates the locus info for the meeting with the locus
|
|
850
864
|
* information returned from API requests made to Locus
|
|
@@ -853,12 +867,13 @@ const MeetingUtil = {
|
|
|
853
867
|
* @param {Object} response The response of the http request
|
|
854
868
|
* @returns {Object}
|
|
855
869
|
*/
|
|
856
|
-
updateLocusFromApiResponse: (meeting, response) => {
|
|
870
|
+
updateLocusFromApiResponse: (meeting: any, response: any) => {
|
|
857
871
|
if (!meeting) {
|
|
858
872
|
return response;
|
|
859
873
|
}
|
|
860
874
|
|
|
861
|
-
|
|
875
|
+
// locus API responses can come in different shapes:
|
|
876
|
+
if (MeetingUtil.isLocusDtoInAPIResponse(response)) {
|
|
862
877
|
meeting.locusInfo.handleLocusAPIResponse(meeting, response.body);
|
|
863
878
|
}
|
|
864
879
|
|
|
@@ -930,6 +945,9 @@ const MeetingUtil = {
|
|
|
930
945
|
attendeeRequestAiAssistantDeclinedAll: (displayHints = []) =>
|
|
931
946
|
displayHints.includes(DISPLAY_HINTS.ATTENDEE_REQUEST_AI_ASSISTANT_DECLINED_ALL),
|
|
932
947
|
|
|
948
|
+
isAnonymizeDisplayNamesEnabled: (displayHints) =>
|
|
949
|
+
displayHints.includes(DISPLAY_HINTS.ANONYMOUS_DISPLAY_NAMES_ENABLED),
|
|
950
|
+
|
|
933
951
|
selfSupportsFeature: (feature: SELF_POLICY, userPolicies: Record<SELF_POLICY, boolean>) => {
|
|
934
952
|
if (!userPolicies) {
|
|
935
953
|
return true;
|
package/src/meetings/index.ts
CHANGED
|
@@ -55,10 +55,12 @@ import PasswordError from '../common/errors/password-error';
|
|
|
55
55
|
import CaptchaError from '../common/errors/captcha-error';
|
|
56
56
|
import MeetingCollection from './collection';
|
|
57
57
|
import {
|
|
58
|
+
FetchSitePreferencesMeViaSiteOptions,
|
|
58
59
|
MEETING_KEY,
|
|
59
60
|
INoiseReductionEffect,
|
|
60
61
|
IVirtualBackgroundEffect,
|
|
61
62
|
MeetingRegistrationStatus,
|
|
63
|
+
SitePreferencesResponse,
|
|
62
64
|
} from './meetings.types';
|
|
63
65
|
import MeetingsUtil from './util';
|
|
64
66
|
import PermissionError from '../common/errors/permission';
|
|
@@ -69,7 +71,9 @@ import JoinForbiddenError from '../common/errors/join-forbidden-error';
|
|
|
69
71
|
import {HashTreeMessage} from '../hashTree/hashTreeParser';
|
|
70
72
|
import {HashTreeObject} from '../hashTree/types';
|
|
71
73
|
import {isSelf} from '../hashTree/utils';
|
|
74
|
+
|
|
72
75
|
import {createLocusFromHashTreeMessage, findMeetingForHashTreeMessage} from '../locus-info';
|
|
76
|
+
import {LocusDTO} from '../locus-info/types';
|
|
73
77
|
|
|
74
78
|
let mediaLogger;
|
|
75
79
|
|
|
@@ -313,7 +317,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
313
317
|
const breakoutLocus = this.meetingCollection.getActiveBreakoutLocus(breakoutUrl);
|
|
314
318
|
|
|
315
319
|
const isSelfJoined = newLocus?.self?.state === _JOINED_;
|
|
316
|
-
const isSelfMoved = newLocus
|
|
320
|
+
const isSelfMoved = MeetingsUtil.isSelfMovedOrBreakoutEnded(newLocus);
|
|
317
321
|
// @ts-ignore
|
|
318
322
|
const deviceFromNewLocus = MeetingsUtil.getThisDevice(newLocus, this.webex.internal.device.url);
|
|
319
323
|
const isResourceMovedOnThisDevice =
|
|
@@ -390,7 +394,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
390
394
|
private isNeedHandleLocusDTO(meeting: any, newLocus: any) {
|
|
391
395
|
if (newLocus) {
|
|
392
396
|
const isNewLocusAsBreakout = MeetingsUtil.isBreakoutLocusDTO(newLocus);
|
|
393
|
-
const isSelfMoved = newLocus
|
|
397
|
+
const isSelfMoved = MeetingsUtil.isSelfMovedOrBreakoutEnded(newLocus);
|
|
394
398
|
const isSelfMovedToLobby =
|
|
395
399
|
newLocus?.self?.devices[0]?.intent?.reason === _ON_HOLD_LOBBY_ &&
|
|
396
400
|
newLocus?.self?.devices[0]?.intent?.type === _WAIT_;
|
|
@@ -435,14 +439,11 @@ export default class Meetings extends WebexPlugin {
|
|
|
435
439
|
if (existingMeeting) {
|
|
436
440
|
return existingMeeting;
|
|
437
441
|
}
|
|
438
|
-
|
|
439
442
|
if (data.eventType === LOCUSEVENT.HASH_TREE_DATA_UPDATED) {
|
|
440
443
|
// need to check if maybe this event indicates a move to/from breakout
|
|
441
444
|
const meetingForHashTreeMessage = findMeetingForHashTreeMessage(
|
|
442
|
-
data
|
|
443
|
-
this.meetingCollection
|
|
444
|
-
// @ts-ignore
|
|
445
|
-
this.webex.internal.device.url
|
|
445
|
+
data?.stateElementsMessage,
|
|
446
|
+
this.meetingCollection
|
|
446
447
|
);
|
|
447
448
|
|
|
448
449
|
if (meetingForHashTreeMessage) {
|
|
@@ -492,7 +493,6 @@ export default class Meetings extends WebexPlugin {
|
|
|
492
493
|
*/
|
|
493
494
|
private handleLocusEvent(data: LocusEvent, useRandomDelayForInfo = false) {
|
|
494
495
|
let meeting = this.getCorrespondingMeetingByLocus(data);
|
|
495
|
-
|
|
496
496
|
// @ts-ignore
|
|
497
497
|
if (this.config.experimental.storeLocusHashTreeEventsForDebugging) {
|
|
498
498
|
storeEventForDebugging('mercury', data);
|
|
@@ -586,17 +586,21 @@ export default class Meetings extends WebexPlugin {
|
|
|
586
586
|
this.create(data.locus, DESTINATION_TYPE.LOCUS_ID, useRandomDelayForInfo)
|
|
587
587
|
.then(async (newMeeting) => {
|
|
588
588
|
meeting = newMeeting;
|
|
589
|
-
|
|
590
589
|
try {
|
|
591
590
|
// It's a new meeting so initialize the locus data
|
|
592
|
-
await meeting.locusInfo.initialSetup(
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
591
|
+
await meeting.locusInfo.initialSetup(
|
|
592
|
+
{
|
|
593
|
+
trigger:
|
|
594
|
+
data.eventType === LOCUSEVENT.SDK_LOCUS_FROM_SYNC_MEETINGS
|
|
595
|
+
? 'get-loci-response'
|
|
596
|
+
: 'locus-message',
|
|
597
|
+
locus: data.locus,
|
|
598
|
+
hashTreeMessage: data.stateElementsMessage,
|
|
599
|
+
},
|
|
600
|
+
(locus: LocusDTO) => {
|
|
601
|
+
meeting.finalizeMeetingAfterInitialLocusSetup(locus);
|
|
602
|
+
}
|
|
603
|
+
);
|
|
600
604
|
} catch (error) {
|
|
601
605
|
LoggerProxy.logger.warn(
|
|
602
606
|
`Meetings:index#handleLocusEvent --> Error initializing locus data: ${error.message}`
|
|
@@ -931,6 +935,27 @@ export default class Meetings extends WebexPlugin {
|
|
|
931
935
|
}
|
|
932
936
|
}
|
|
933
937
|
|
|
938
|
+
/**
|
|
939
|
+
* API to toggle AV1 codec support for video slides in multistream,
|
|
940
|
+
* needs to be called before webex.meetings.joinWithMedia()
|
|
941
|
+
*
|
|
942
|
+
* @param {Boolean} newValue
|
|
943
|
+
* @private
|
|
944
|
+
* @memberof Meetings
|
|
945
|
+
* @returns {undefined}
|
|
946
|
+
*/
|
|
947
|
+
private _toggleEnableAv1SlidesSupport(newValue: boolean) {
|
|
948
|
+
if (typeof newValue !== 'boolean') {
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
// @ts-ignore
|
|
953
|
+
if (this.config.enableAv1SlidesSupport !== newValue) {
|
|
954
|
+
// @ts-ignore
|
|
955
|
+
this.config.enableAv1SlidesSupport = newValue;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
|
|
934
959
|
/**
|
|
935
960
|
* API to toggle stopping ICE Candidates Gathering after first relay candidate,
|
|
936
961
|
* needs to be called before webex.meetings.joinWithMedia()
|
|
@@ -1403,6 +1428,31 @@ export default class Meetings extends WebexPlugin {
|
|
|
1403
1428
|
return this.personalMeetingRoom;
|
|
1404
1429
|
}
|
|
1405
1430
|
|
|
1431
|
+
/**
|
|
1432
|
+
* Fetches site preferences for the provided Webex site, or the preferred Webex site.
|
|
1433
|
+
* This is used to determine capabilities of the site, such as whether scheduling a webinar is supported.
|
|
1434
|
+
*
|
|
1435
|
+
* @param {object} [options]
|
|
1436
|
+
* @param {string} [options.siteUrl] - Webex site URL. Defaults to preferredWebexSite, for example "cisco.webex.com".
|
|
1437
|
+
* @param {string} [options.siteName] - Site name query override. Defaults to the site name derived from siteUrl, for example "cisco" for "cisco.webex.com".
|
|
1438
|
+
* @param {SitePreferenceSelectOption[]} [options.selectOptions] - Preference sections to fetch. Defaults to 'scheduling'.
|
|
1439
|
+
* @returns {Promise<SitePreferencesResponse>} site preferences response body
|
|
1440
|
+
* @throws {ParameterError}
|
|
1441
|
+
* @public
|
|
1442
|
+
* @memberof Meetings
|
|
1443
|
+
* @example
|
|
1444
|
+
* const preferences = await webex.meetings.fetchSitePreferencesMeViaSite();
|
|
1445
|
+
* const supportScheduleWebinar = preferences?.scheduling?.supportScheduleWebinar;
|
|
1446
|
+
*/
|
|
1447
|
+
public fetchSitePreferencesMeViaSite(
|
|
1448
|
+
options: FetchSitePreferencesMeViaSiteOptions = {}
|
|
1449
|
+
): Promise<SitePreferencesResponse> {
|
|
1450
|
+
return this.request.fetchSitePreferencesMeViaSite({
|
|
1451
|
+
...options,
|
|
1452
|
+
siteUrl: options.siteUrl || this.preferredWebexSite,
|
|
1453
|
+
});
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1406
1456
|
/**
|
|
1407
1457
|
* Returns basic information about a meeting that exists or
|
|
1408
1458
|
* used to exist in the MeetingCollection
|
|
@@ -1765,10 +1815,14 @@ export default class Meetings extends WebexPlugin {
|
|
|
1765
1815
|
extraParams: infoExtraParams,
|
|
1766
1816
|
sendCAevents: !!callStateForMetrics?.correlationId, // if client sends correlation id as argument of public create(), then it means that this meeting creation is part of a pre-join intent from user
|
|
1767
1817
|
};
|
|
1818
|
+
const shouldDeferMeetingInfoFetch = type === DESTINATION_TYPE.LOCUS_ID && !destination?.info;
|
|
1819
|
+
|
|
1820
|
+
const isOneOnOneCallLocus =
|
|
1821
|
+
type === DESTINATION_TYPE.LOCUS_ID && MeetingsUtil.isOneOnOneCall(destination);
|
|
1768
1822
|
|
|
1769
1823
|
if (meetingInfo) {
|
|
1770
1824
|
meeting.injectMeetingInfo(meetingInfo, meetingInfoOptions, meetingLookupUrl);
|
|
1771
|
-
} else if (type !== DESTINATION_TYPE.ONE_ON_ONE_CALL) {
|
|
1825
|
+
} else if (type !== DESTINATION_TYPE.ONE_ON_ONE_CALL && !isOneOnOneCallLocus) {
|
|
1772
1826
|
// ignore fetchMeetingInfo for 1:1 meetings
|
|
1773
1827
|
if (enableUnifiedMeetings && !isMeetingActive && useRandomDelayForInfo && waitingTime > 0) {
|
|
1774
1828
|
meeting.fetchMeetingInfoTimeoutId = setTimeout(
|
|
@@ -1776,8 +1830,12 @@ export default class Meetings extends WebexPlugin {
|
|
|
1776
1830
|
waitingTime
|
|
1777
1831
|
);
|
|
1778
1832
|
meeting.parseMeetingInfo(undefined, destination);
|
|
1779
|
-
} else {
|
|
1833
|
+
} else if (!shouldDeferMeetingInfoFetch) {
|
|
1780
1834
|
await meeting.fetchMeetingInfo(meetingInfoOptions);
|
|
1835
|
+
} else {
|
|
1836
|
+
LoggerProxy.logger.info(
|
|
1837
|
+
'Meetings:index#createMeeting --> defer fetchMeetingInfo for incomplete locus, will do it after locus initialSetup'
|
|
1838
|
+
);
|
|
1781
1839
|
}
|
|
1782
1840
|
}
|
|
1783
1841
|
} catch (err) {
|
|
@@ -1811,7 +1869,11 @@ export default class Meetings extends WebexPlugin {
|
|
|
1811
1869
|
// For type LOCUS_ID we need to parse the locus object to get the information
|
|
1812
1870
|
// about the caller and callee
|
|
1813
1871
|
// Meeting Added event will be created in `handleLocusEvent`
|
|
1814
|
-
if
|
|
1872
|
+
// Only emit MEETING_ADDED if the meeting still exists in the collection.
|
|
1873
|
+
// If fetchMeetingInfo failed and the meeting was destroyed in the catch block,
|
|
1874
|
+
// skip emitting to prevent orphaned meeting references on the consumer side.
|
|
1875
|
+
// @ts-ignore - getMeetingByType types value as object but accepts strings (same as handleLocusEvent)
|
|
1876
|
+
if (type !== DESTINATION_TYPE.LOCUS_ID && this.getMeetingByType(_ID_, meeting.id)) {
|
|
1815
1877
|
if (!meeting.sipUri) {
|
|
1816
1878
|
meeting.setSipUri(destination);
|
|
1817
1879
|
}
|
|
@@ -1886,23 +1948,23 @@ export default class Meetings extends WebexPlugin {
|
|
|
1886
1948
|
* @public
|
|
1887
1949
|
* @memberof Meetings
|
|
1888
1950
|
*/
|
|
1889
|
-
public syncMeetings({
|
|
1951
|
+
public async syncMeetings({
|
|
1952
|
+
keepOnlyLocusMeetings = true,
|
|
1953
|
+
skipHashTreeSync = false,
|
|
1954
|
+
} = {}): Promise<void> {
|
|
1890
1955
|
// @ts-ignore
|
|
1891
1956
|
if (this.webex.credentials.isUnverifiedGuest) {
|
|
1892
1957
|
LoggerProxy.logger.info(
|
|
1893
|
-
'Meetings:index#syncMeetings --> skipping
|
|
1958
|
+
'Meetings:index#syncMeetings --> user is unverified guest, skipping calling Locus for meeting sync'
|
|
1894
1959
|
);
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
return this.request
|
|
1900
|
-
.getActiveMeetings()
|
|
1901
|
-
.then((locusArray) => {
|
|
1902
|
-
const activeLocusUrl = [];
|
|
1960
|
+
} else {
|
|
1961
|
+
try {
|
|
1962
|
+
const locusArray = await this.request.getActiveMeetings();
|
|
1963
|
+
const activeLocusUrl: string[] = [];
|
|
1903
1964
|
|
|
1904
1965
|
if (locusArray?.loci && locusArray.loci.length > 0) {
|
|
1905
1966
|
const lociToUpdate = this.sortLocusArrayToUpdate(locusArray.loci);
|
|
1967
|
+
|
|
1906
1968
|
lociToUpdate.forEach((locus) => {
|
|
1907
1969
|
activeLocusUrl.push(locus.url);
|
|
1908
1970
|
this.handleLocusEvent({
|
|
@@ -1920,21 +1982,50 @@ export default class Meetings extends WebexPlugin {
|
|
|
1920
1982
|
// (they had a locusUrl previously but are no longer active) in the sync
|
|
1921
1983
|
for (const meeting of Object.values(meetingsCollection)) {
|
|
1922
1984
|
// @ts-ignore
|
|
1923
|
-
const {locusUrl} = meeting;
|
|
1985
|
+
const {locusUrl, locusInfo} = meeting;
|
|
1924
1986
|
if ((keepOnlyLocusMeetings || locusUrl) && !activeLocusUrl.includes(locusUrl)) {
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1987
|
+
const globalMeetingId = locusInfo?.info?.globalMeetingId;
|
|
1988
|
+
|
|
1989
|
+
if (
|
|
1990
|
+
globalMeetingId &&
|
|
1991
|
+
locusArray?.loci?.some(
|
|
1992
|
+
(locus: LocusDTO) => locus.info?.globalMeetingId === globalMeetingId
|
|
1993
|
+
)
|
|
1994
|
+
) {
|
|
1995
|
+
// don't destroy the meeting as Locus API still returned some Locus that shares
|
|
1996
|
+
// the same globalMeetingId - that happens for example if a webinar user (who hasn't scheduled it)
|
|
1997
|
+
// is in a breakout and gets moved to a different breakout while we were offline
|
|
1998
|
+
} else {
|
|
1999
|
+
// destroy function also uploads logs
|
|
2000
|
+
// @ts-ignore
|
|
2001
|
+
this.destroy(meeting, MEETING_REMOVED_REASON.NO_MEETINGS_TO_SYNC);
|
|
2002
|
+
}
|
|
1928
2003
|
}
|
|
1929
2004
|
}
|
|
1930
2005
|
}
|
|
1931
|
-
})
|
|
1932
|
-
.catch((error) => {
|
|
2006
|
+
} catch (error) {
|
|
1933
2007
|
LoggerProxy.logger.error(
|
|
1934
2008
|
`Meetings:index#syncMeetings --> failed to sync meetings, ${error}`
|
|
1935
2009
|
);
|
|
1936
|
-
throw
|
|
1937
|
-
}
|
|
2010
|
+
throw error;
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
if (!skipHashTreeSync) {
|
|
2015
|
+
// Trigger hash tree syncs for all remaining meetings
|
|
2016
|
+
const remainingMeetings = this.meetingCollection.getAll();
|
|
2017
|
+
const syncPromises = [];
|
|
2018
|
+
|
|
2019
|
+
for (const meeting of Object.values(remainingMeetings) as any[]) {
|
|
2020
|
+
if (meeting.locusInfo) {
|
|
2021
|
+
syncPromises.push(meeting.locusInfo.syncAllHashTreeDatasets());
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
if (syncPromises.length > 0) {
|
|
2026
|
+
await Promise.all(syncPromises);
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
1938
2029
|
}
|
|
1939
2030
|
|
|
1940
2031
|
/**
|
|
@@ -1950,8 +2041,8 @@ export default class Meetings extends WebexPlugin {
|
|
|
1950
2041
|
this.breakoutLocusForHandleLater = [];
|
|
1951
2042
|
const lociToUpdate = [...mainLoci];
|
|
1952
2043
|
breakoutLoci.forEach((breakoutLocus) => {
|
|
1953
|
-
const associateMainLocus = mainLoci.find(
|
|
1954
|
-
(mainLocus
|
|
2044
|
+
const associateMainLocus = mainLoci.find((mainLocus) =>
|
|
2045
|
+
MeetingsUtil.isMainAssociatedWithBreakout(mainLocus, breakoutLocus)
|
|
1955
2046
|
);
|
|
1956
2047
|
const existCorrespondingMeeting = this.getCorrespondingMeetingByLocus({
|
|
1957
2048
|
eventType: LOCUSEVENT.SDK_NO_EVENT,
|
|
@@ -1979,7 +2070,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
1979
2070
|
* @public
|
|
1980
2071
|
* @memberof Meetings
|
|
1981
2072
|
*/
|
|
1982
|
-
checkHandleBreakoutLocus(newCreatedLocus) {
|
|
2073
|
+
checkHandleBreakoutLocus(newCreatedLocus: any) {
|
|
1983
2074
|
if (
|
|
1984
2075
|
!newCreatedLocus ||
|
|
1985
2076
|
!this.breakoutLocusForHandleLater ||
|
|
@@ -1990,9 +2081,8 @@ export default class Meetings extends WebexPlugin {
|
|
|
1990
2081
|
if (MeetingsUtil.isBreakoutLocusDTO(newCreatedLocus)) {
|
|
1991
2082
|
return;
|
|
1992
2083
|
}
|
|
1993
|
-
const existIndex = this.breakoutLocusForHandleLater.findIndex(
|
|
1994
|
-
(breakoutLocus)
|
|
1995
|
-
breakoutLocus.controls?.breakout?.url === newCreatedLocus.controls?.breakout?.url
|
|
2084
|
+
const existIndex = this.breakoutLocusForHandleLater.findIndex((breakoutLocus: any) =>
|
|
2085
|
+
MeetingsUtil.isMainAssociatedWithBreakout(newCreatedLocus, breakoutLocus)
|
|
1996
2086
|
);
|
|
1997
2087
|
|
|
1998
2088
|
if (existIndex < 0) {
|
|
@@ -31,3 +31,22 @@ export type MeetingRegistrationStatus = {
|
|
|
31
31
|
mercuryConnect: boolean;
|
|
32
32
|
checkH264Support: boolean;
|
|
33
33
|
};
|
|
34
|
+
|
|
35
|
+
export enum SitePreferenceSelectOption {
|
|
36
|
+
SCHEDULING = 'scheduling',
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type FetchSitePreferencesMeViaSiteOptions = {
|
|
40
|
+
siteUrl?: string;
|
|
41
|
+
siteName?: string;
|
|
42
|
+
selectOptions?: SitePreferenceSelectOption[];
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const DEFAULT_SITE_PREFERENCE_SELECT_OPTIONS = [SitePreferenceSelectOption.SCHEDULING];
|
|
46
|
+
|
|
47
|
+
export type SitePreferencesResponse = {
|
|
48
|
+
scheduling?: {
|
|
49
|
+
supportScheduleWebinar?: boolean;
|
|
50
|
+
webinarWebLink?: string;
|
|
51
|
+
};
|
|
52
|
+
};
|
package/src/meetings/request.ts
CHANGED
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
import {StatelessWebexPlugin} from '@webex/webex-core';
|
|
3
3
|
|
|
4
4
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
5
|
+
import ParameterError from '../common/errors/parameter';
|
|
5
6
|
import {HTTP_VERBS, API, RESOURCE} from '../constants';
|
|
7
|
+
import {
|
|
8
|
+
DEFAULT_SITE_PREFERENCE_SELECT_OPTIONS,
|
|
9
|
+
type FetchSitePreferencesMeViaSiteOptions,
|
|
10
|
+
type SitePreferencesResponse,
|
|
11
|
+
} from './meetings.types';
|
|
12
|
+
import MeetingsUtil from './util';
|
|
6
13
|
|
|
7
14
|
/**
|
|
8
15
|
* @class MeetingRequest
|
|
@@ -45,6 +52,42 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
45
52
|
return this.webex.internal.services.getMeetingPreferences();
|
|
46
53
|
}
|
|
47
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Fetches site preferences from a given site given a select option and a siteUrl with an optional siteName. If siteName is not provided, it will be derived from the siteUrl. If siteUrl is not provided, it will throw an error. If selectOptions is not provided, it will default to scheduling.
|
|
57
|
+
*
|
|
58
|
+
* @param {object} [options]
|
|
59
|
+
* @param {string} [options.siteUrl] - Webex site URL, for example "cisco.webex.com".
|
|
60
|
+
* @param {string} [options.siteName] - Site name query override. Defaults to the site name derived from options.siteUrl, e.g., "cisco".
|
|
61
|
+
* @param {SitePreferenceSelectOption[]} [options.selectOptions] - Preference sections to fetch. Defaults to 'scheduling'.
|
|
62
|
+
* @returns {Promise<SitePreferencesResponse>} site preferences response body
|
|
63
|
+
* @throws {ParameterError}
|
|
64
|
+
* @public
|
|
65
|
+
* @memberof MeetingRequest
|
|
66
|
+
*/
|
|
67
|
+
fetchSitePreferencesMeViaSite(
|
|
68
|
+
options: FetchSitePreferencesMeViaSiteOptions = {}
|
|
69
|
+
): Promise<SitePreferencesResponse> {
|
|
70
|
+
const {siteUrl, selectOptions = DEFAULT_SITE_PREFERENCE_SELECT_OPTIONS} = options;
|
|
71
|
+
|
|
72
|
+
if (!siteUrl) {
|
|
73
|
+
throw new ParameterError(
|
|
74
|
+
'No siteUrl available. Call register() before fetching site preferences or provide options.siteUrl.'
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// @ts-ignore - config comes from registerPlugin
|
|
79
|
+
const multipartSitePrefixList = this.config.meetings.multipartSitePrefixList || [];
|
|
80
|
+
const siteName = options.siteName || MeetingsUtil.getSiteName(siteUrl, multipartSitePrefixList);
|
|
81
|
+
|
|
82
|
+
// @ts-ignore
|
|
83
|
+
return this.request({
|
|
84
|
+
method: HTTP_VERBS.GET,
|
|
85
|
+
uri: `https://${siteUrl}/wbxappapi/v1/users/me/preference?select=${encodeURIComponent(
|
|
86
|
+
selectOptions.join(',')
|
|
87
|
+
)}&siteurl=${encodeURIComponent(siteName)}`,
|
|
88
|
+
}).then((res: any) => res.body);
|
|
89
|
+
}
|
|
90
|
+
|
|
48
91
|
// locus federation, determines and populate locus if the responseBody has remote URLs to fetch locus details
|
|
49
92
|
|
|
50
93
|
/**
|
package/src/meetings/util.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
/* globals window */
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
+
_CALL_,
|
|
4
5
|
_CREATED_,
|
|
5
6
|
_INCOMING_,
|
|
6
7
|
_JOINED_,
|
|
7
8
|
_LEFT_,
|
|
8
9
|
DESTINATION_TYPE,
|
|
9
10
|
_MOVED_,
|
|
11
|
+
_SIP_BRIDGE_,
|
|
12
|
+
_SPACE_SHARE_,
|
|
10
13
|
BREAKOUTS,
|
|
11
14
|
EVENT_TRIGGERS,
|
|
12
15
|
LOCUS,
|
|
@@ -18,6 +21,7 @@ import Trigger from '../common/events/trigger-proxy';
|
|
|
18
21
|
import BEHAVIORAL_METRICS from '../metrics/constants';
|
|
19
22
|
import Metrics from '../metrics';
|
|
20
23
|
import {MEETING_KEY} from './meetings.types';
|
|
24
|
+
import {EndMeetingReason, LocusFullState} from '../locus-info/types';
|
|
21
25
|
|
|
22
26
|
/**
|
|
23
27
|
* Meetings Media Codec Missing Event
|
|
@@ -152,6 +156,30 @@ MeetingsUtil.parseDefaultSiteFromMeetingPreferences = (userPreferences) => {
|
|
|
152
156
|
return result;
|
|
153
157
|
};
|
|
154
158
|
|
|
159
|
+
MeetingsUtil.getSiteName = (site: string, multipartSitePrefixList: string[] = []) => {
|
|
160
|
+
if (!site) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
let siteName: string | undefined;
|
|
165
|
+
|
|
166
|
+
multipartSitePrefixList.forEach((multipartSitePrefix) => {
|
|
167
|
+
if (!siteName && site.includes(multipartSitePrefix)) {
|
|
168
|
+
const secondDot = site.indexOf('.', site.indexOf('.') + 1);
|
|
169
|
+
|
|
170
|
+
siteName = site.substring(0, secondDot);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
if (siteName) {
|
|
175
|
+
return siteName;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
siteName = site.substring(0, site.indexOf('.'));
|
|
179
|
+
|
|
180
|
+
return siteName;
|
|
181
|
+
};
|
|
182
|
+
|
|
155
183
|
/**
|
|
156
184
|
* Will check to see if the H.264 media codec is supported.
|
|
157
185
|
* @async
|
|
@@ -266,6 +294,49 @@ MeetingsUtil.getThisDevice = (newLocus: any, deviceUrl: string) => {
|
|
|
266
294
|
return null;
|
|
267
295
|
};
|
|
268
296
|
|
|
297
|
+
/**
|
|
298
|
+
* Checks if the fullState indicates the meeting has fully ended (not just a breakout move).
|
|
299
|
+
* @param {Object} fullState locus fullState data
|
|
300
|
+
* @returns {boolean}
|
|
301
|
+
*/
|
|
302
|
+
MeetingsUtil.isWholeMeetingEnded = (fullState: LocusFullState): boolean => {
|
|
303
|
+
return (
|
|
304
|
+
fullState.state === LOCUS.STATE.INACTIVE &&
|
|
305
|
+
fullState.endMeetingReason !== EndMeetingReason.breakoutEnded
|
|
306
|
+
);
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Checks if the self state in a locus indicates a breakout move or breakout end.
|
|
311
|
+
* Returns true when:
|
|
312
|
+
* - self state is LEFT with reason MOVED (regular breakout move), OR
|
|
313
|
+
* - fullState is INACTIVE with endMeetingReason BREAKOUT_ENDED (breakout session ended)
|
|
314
|
+
* @param {Object} locus locus data
|
|
315
|
+
* @returns {boolean}
|
|
316
|
+
*/
|
|
317
|
+
MeetingsUtil.isSelfMovedOrBreakoutEnded = (locus: any): boolean => {
|
|
318
|
+
const isSelfLeftMoved = locus?.self?.state === _LEFT_ && locus?.self?.reason === _MOVED_;
|
|
319
|
+
const isBreakoutEnded =
|
|
320
|
+
locus?.fullState?.state === LOCUS.STATE.INACTIVE &&
|
|
321
|
+
locus?.fullState?.endMeetingReason === EndMeetingReason.breakoutEnded;
|
|
322
|
+
|
|
323
|
+
return isSelfLeftMoved || isBreakoutEnded;
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Checks if a locus is a 1:1 call using locus.fullState.type.
|
|
328
|
+
* Returns true when fullState.type is CALL, SIP_BRIDGE, or SPACE_SHARE.
|
|
329
|
+
* @param {Object} locus locus data
|
|
330
|
+
* @returns {boolean}
|
|
331
|
+
*/
|
|
332
|
+
MeetingsUtil.isOneOnOneCall = (locus: any): boolean => {
|
|
333
|
+
const fullStateType = locus?.fullState?.type;
|
|
334
|
+
|
|
335
|
+
return (
|
|
336
|
+
fullStateType === _CALL_ || fullStateType === _SIP_BRIDGE_ || fullStateType === _SPACE_SHARE_
|
|
337
|
+
);
|
|
338
|
+
};
|
|
339
|
+
|
|
269
340
|
/**
|
|
270
341
|
* get self device joined status from locus data
|
|
271
342
|
* @param {Object} meeting current meeting data
|
|
@@ -294,7 +365,10 @@ MeetingsUtil.joinedOnThisDevice = (meeting: any, newLocus: any, deviceUrl: strin
|
|
|
294
365
|
* @private
|
|
295
366
|
*/
|
|
296
367
|
MeetingsUtil.isBreakoutLocusDTO = (newLocus: any) => {
|
|
297
|
-
return
|
|
368
|
+
return (
|
|
369
|
+
newLocus?.controls?.breakout?.sessionType === BREAKOUTS.SESSION_TYPES.BREAKOUT ||
|
|
370
|
+
!!newLocus?.info?.isBreakout
|
|
371
|
+
);
|
|
298
372
|
};
|
|
299
373
|
|
|
300
374
|
/**
|
|
@@ -310,4 +384,26 @@ MeetingsUtil.isValidBreakoutLocus = (locus: any) => {
|
|
|
310
384
|
|
|
311
385
|
return isLocusAsBreakout && !inActiveStatus && selfJoined;
|
|
312
386
|
};
|
|
387
|
+
/**
|
|
388
|
+
* check if the breakout locus is associated with the main locus by comparing the breakout control url or the replaces info in self device
|
|
389
|
+
* @param {Object} mainLocus main locus data
|
|
390
|
+
* @param {Object} breakoutLocus breakout locus data
|
|
391
|
+
* @returns {boolean}
|
|
392
|
+
* @private
|
|
393
|
+
*/
|
|
394
|
+
MeetingsUtil.isMainAssociatedWithBreakout = (mainLocus: any, breakoutLocus: any) => {
|
|
395
|
+
if (
|
|
396
|
+
mainLocus.controls?.breakout?.url &&
|
|
397
|
+
mainLocus.controls?.breakout?.url === breakoutLocus.controls?.breakout?.url
|
|
398
|
+
) {
|
|
399
|
+
return true;
|
|
400
|
+
}
|
|
401
|
+
const deviceUrl = breakoutLocus?.self?.deviceUrl;
|
|
402
|
+
const replaceInfo = MeetingsUtil.getThisDevice(breakoutLocus, deviceUrl)?.replaces?.[0];
|
|
403
|
+
if (replaceInfo?.locusUrl && replaceInfo.locusUrl === mainLocus.url) {
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return false;
|
|
408
|
+
};
|
|
313
409
|
export default MeetingsUtil;
|
package/src/member/index.ts
CHANGED
|
@@ -27,6 +27,7 @@ export default class Member {
|
|
|
27
27
|
isModerator: any;
|
|
28
28
|
isModeratorAssignmentProhibited: any;
|
|
29
29
|
isPresenterAssignmentProhibited: any;
|
|
30
|
+
isAttendeeAssignmentProhibited: any;
|
|
30
31
|
isMutable: any;
|
|
31
32
|
isNotAdmitted: any;
|
|
32
33
|
isRecording: any;
|
|
@@ -292,6 +293,14 @@ export default class Member {
|
|
|
292
293
|
*/
|
|
293
294
|
this.isPresenterAssignmentProhibited = null;
|
|
294
295
|
|
|
296
|
+
/**
|
|
297
|
+
* @instance
|
|
298
|
+
* @type {Boolean}
|
|
299
|
+
* @public
|
|
300
|
+
* @memberof Member
|
|
301
|
+
*/
|
|
302
|
+
this.isAttendeeAssignmentProhibited = null;
|
|
303
|
+
|
|
295
304
|
/**
|
|
296
305
|
* @instance
|
|
297
306
|
* @type {Boolean}
|
|
@@ -369,6 +378,7 @@ export default class Member {
|
|
|
369
378
|
MemberUtil.isModeratorAssignmentProhibited(participant);
|
|
370
379
|
this.isPresenterAssignmentProhibited =
|
|
371
380
|
MemberUtil.isPresenterAssignmentProhibited(participant);
|
|
381
|
+
this.isAttendeeAssignmentProhibited = MemberUtil.isAttendeeAssignmentProhibited(participant);
|
|
372
382
|
this.canApproveAIEnablement = MemberUtil.canApproveAIEnablement(participant);
|
|
373
383
|
this.processStatus(participant);
|
|
374
384
|
this.processRoles(participant);
|
package/src/member/types.ts
CHANGED
|
@@ -103,6 +103,7 @@ export interface Participant {
|
|
|
103
103
|
moderator: boolean; // Locus docs say this is deprecated and role control should be used instead
|
|
104
104
|
moderatorAssignmentNotAllowed: boolean;
|
|
105
105
|
presenterAssignmentNotAllowed: boolean;
|
|
106
|
+
attendeeAssignmentNotAllowed?: boolean;
|
|
106
107
|
person: ParticipantPerson;
|
|
107
108
|
resourceGuest: boolean;
|
|
108
109
|
state: string; // probably one of MEETING_STATE.STATES
|
package/src/member/util.ts
CHANGED
|
@@ -140,6 +140,9 @@ const MemberUtil = {
|
|
|
140
140
|
isPresenterAssignmentProhibited: (participant: Participant) =>
|
|
141
141
|
participant && participant.presenterAssignmentNotAllowed,
|
|
142
142
|
|
|
143
|
+
isAttendeeAssignmentProhibited: (participant: Participant) =>
|
|
144
|
+
!!(participant && participant.attendeeAssignmentNotAllowed),
|
|
145
|
+
|
|
143
146
|
/**
|
|
144
147
|
* checks to see if the participant id is the same as the passed id
|
|
145
148
|
* there are multiple ids that can be used
|
package/src/metrics/constants.ts
CHANGED
|
@@ -96,6 +96,9 @@ const BEHAVIORAL_METRICS = {
|
|
|
96
96
|
SET_CUSTOM_CODEC_PARAMETERS_USED: 'js_sdk_set_custom_codec_parameters_used',
|
|
97
97
|
MARK_CUSTOM_CODEC_PARAMETERS_FOR_DELETION_USED:
|
|
98
98
|
'js_sdk_mark_custom_codec_parameters_for_deletion_used',
|
|
99
|
+
HASH_TREE_SYNC_FAILURE: 'js_sdk_hash_tree_sync_failure',
|
|
100
|
+
HASH_TREE_HEARTBEAT_WATCHDOG_EXPIRED: 'js_sdk_hash_tree_heartbeat_watchdog_expired',
|
|
101
|
+
HASH_TREE_EMPTY_LOCUS_STATE_ELEMENTS: 'js_sdk_hash_tree_empty_locus_state_elements',
|
|
99
102
|
};
|
|
100
103
|
|
|
101
104
|
export {BEHAVIORAL_METRICS as default};
|