@webex/plugin-meetings 3.11.0-next.27 → 3.11.0-next.29

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.
@@ -76,6 +76,9 @@ declare const _default: {
76
76
  stopIceGatheringAfterFirstRelayCandidate: boolean;
77
77
  enableAudioTwccForMultistream: boolean;
78
78
  enablePerUdpUrlReachability: boolean;
79
+ locus: {
80
+ excludedDataSets: string[];
81
+ };
79
82
  };
80
83
  };
81
84
  export default _default;
@@ -59,6 +59,7 @@ declare class HashTreeParser {
59
59
  visibleDataSets: VisibleDataSetInfo[];
60
60
  debugId: string;
61
61
  heartbeatIntervalMs?: number;
62
+ private excludedDataSets;
62
63
  /**
63
64
  * Constructor for HashTreeParser
64
65
  * @param {Object} options
@@ -73,6 +74,7 @@ declare class HashTreeParser {
73
74
  webexRequest: WebexRequestMethod;
74
75
  locusInfoUpdateCallback: LocusInfoUpdateCallback;
75
76
  debugId: string;
77
+ excludedDataSets?: string[];
76
78
  });
77
79
  /**
78
80
  * Checks if the given data set name is in the list of visible data sets
@@ -80,6 +82,18 @@ declare class HashTreeParser {
80
82
  * @returns {Boolean} True if the data set is visible, false otherwise
81
83
  */
82
84
  private isVisibleDataSet;
85
+ /**
86
+ * Checks if the given data set name is in the excluded list
87
+ * @param {string} dataSetName data set name to check
88
+ * @returns {boolean} True if the data set is excluded, false otherwise
89
+ */
90
+ private isExcludedDataSet;
91
+ /**
92
+ * Adds a data set to the visible data sets list, unless it is in the excluded list.
93
+ * @param {VisibleDataSetInfo} dataSetInfo data set info to add
94
+ * @returns {boolean} True if the data set was added, false if it was excluded
95
+ */
96
+ private addToVisibleDataSetsList;
83
97
  /**
84
98
  * Initializes a new visible data set by creating a hash tree for it, adding it to all the internal structures,
85
99
  * and sending an initial sync request to Locus with empty leaf data - that will trigger Locus to gives us all the data
@@ -506,7 +506,7 @@ var Webinar = _webexCore.WebexPlugin.extend({
506
506
  }, _callee8);
507
507
  }))();
508
508
  },
509
- version: "3.11.0-next.27"
509
+ version: "3.11.0-next.29"
510
510
  });
511
511
  var _default = exports.default = Webinar;
512
512
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -93,5 +93,5 @@
93
93
  "//": [
94
94
  "TODO: upgrade jwt-decode when moving to node 18"
95
95
  ],
96
- "version": "3.11.0-next.27"
96
+ "version": "3.11.0-next.29"
97
97
  }
package/src/config.ts CHANGED
@@ -101,5 +101,8 @@ export default {
101
101
  stopIceGatheringAfterFirstRelayCandidate: false,
102
102
  enableAudioTwccForMultistream: false,
103
103
  enablePerUdpUrlReachability: false, // true: separate peer connection per each UDP URL; false: single peer connection for all URLs
104
+ locus: {
105
+ excludedDataSets: ['attendees'], // attendees data set only applies to webinar attendees and we never really need that
106
+ },
104
107
  },
105
108
  };
@@ -91,6 +91,7 @@ class HashTreeParser {
91
91
  visibleDataSets: VisibleDataSetInfo[];
92
92
  debugId: string;
93
93
  heartbeatIntervalMs?: number;
94
+ private excludedDataSets: string[];
94
95
 
95
96
  /**
96
97
  * Constructor for HashTreeParser
@@ -106,14 +107,18 @@ class HashTreeParser {
106
107
  webexRequest: WebexRequestMethod;
107
108
  locusInfoUpdateCallback: LocusInfoUpdateCallback;
108
109
  debugId: string;
110
+ excludedDataSets?: string[];
109
111
  }) {
110
112
  const {dataSets, locus} = options.initialLocus; // extract dataSets from initialLocus
111
113
 
112
114
  this.debugId = options.debugId;
113
115
  this.webexRequest = options.webexRequest;
114
116
  this.locusInfoUpdateCallback = options.locusInfoUpdateCallback;
117
+ this.excludedDataSets = options.excludedDataSets || [];
115
118
  this.visibleDataSetsUrl = locus?.links?.resources?.visibleDataSets?.url;
116
- this.visibleDataSets = cloneDeep(options.metadata?.visibleDataSets || []);
119
+ this.visibleDataSets = (
120
+ cloneDeep(options.metadata?.visibleDataSets || []) as VisibleDataSetInfo[]
121
+ ).filter((vds) => !this.isExcludedDataSet(vds.name));
117
122
 
118
123
  if (options.metadata?.visibleDataSets?.length === 0) {
119
124
  LoggerProxy.logger.warn(
@@ -155,6 +160,34 @@ class HashTreeParser {
155
160
  return this.visibleDataSets.some((vds) => vds.name === dataSetName);
156
161
  }
157
162
 
163
+ /**
164
+ * Checks if the given data set name is in the excluded list
165
+ * @param {string} dataSetName data set name to check
166
+ * @returns {boolean} True if the data set is excluded, false otherwise
167
+ */
168
+ private isExcludedDataSet(dataSetName: string): boolean {
169
+ return this.excludedDataSets.some((name) => name === dataSetName);
170
+ }
171
+
172
+ /**
173
+ * Adds a data set to the visible data sets list, unless it is in the excluded list.
174
+ * @param {VisibleDataSetInfo} dataSetInfo data set info to add
175
+ * @returns {boolean} True if the data set was added, false if it was excluded
176
+ */
177
+ private addToVisibleDataSetsList(dataSetInfo: VisibleDataSetInfo): boolean {
178
+ if (this.isExcludedDataSet(dataSetInfo.name)) {
179
+ LoggerProxy.logger.info(
180
+ `HashTreeParser#addToVisibleDataSetsList --> ${this.debugId} Data set "${dataSetInfo.name}" is in the excluded list, ignoring`
181
+ );
182
+
183
+ return false;
184
+ }
185
+
186
+ this.visibleDataSets.push(dataSetInfo);
187
+
188
+ return true;
189
+ }
190
+
158
191
  /**
159
192
  * Initializes a new visible data set by creating a hash tree for it, adding it to all the internal structures,
160
193
  * and sending an initial sync request to Locus with empty leaf data - that will trigger Locus to gives us all the data
@@ -180,7 +213,9 @@ class HashTreeParser {
180
213
  `HashTreeParser#initializeNewVisibleDataSet --> ${this.debugId} Adding visible data set "${dataSetInfo.name}"`
181
214
  );
182
215
 
183
- this.visibleDataSets.push(visibleDataSetInfo);
216
+ if (!this.addToVisibleDataSetsList(visibleDataSetInfo)) {
217
+ return Promise.resolve({updateType: LocusInfoUpdateType.OBJECTS_UPDATED, updatedObjects: []});
218
+ }
184
219
 
185
220
  const hashTree = new HashTree([], dataSetInfo.leafCount);
186
221
 
@@ -328,10 +363,16 @@ class HashTreeParser {
328
363
  }
329
364
 
330
365
  if (!this.isVisibleDataSet(name)) {
331
- this.visibleDataSets.push({
332
- name,
333
- url,
334
- });
366
+ if (
367
+ !this.addToVisibleDataSetsList({
368
+ name,
369
+ url,
370
+ })
371
+ ) {
372
+ // dataset is excluded, skip it
373
+ // eslint-disable-next-line no-continue
374
+ continue;
375
+ }
335
376
  }
336
377
 
337
378
  if (!this.dataSets[name].hashTree) {
@@ -693,7 +734,9 @@ class HashTreeParser {
693
734
  // visibleDataSets can only be changed by Metadata object updates
694
735
  updatedObjects.forEach((object) => {
695
736
  if (isMetadata(object) && object.data?.visibleDataSets) {
696
- const newVisibleDataSets = object.data.visibleDataSets;
737
+ const newVisibleDataSets = object.data.visibleDataSets.filter(
738
+ (vds) => !this.isExcludedDataSet(vds.name)
739
+ );
697
740
 
698
741
  removedDataSets = this.visibleDataSets.filter(
699
742
  (ds) => !newVisibleDataSets.some((nvs) => nvs.name === ds.name)
@@ -805,7 +848,10 @@ class HashTreeParser {
805
848
  `HashTreeParser#processVisibleDataSetChanges --> ${this.debugId} Adding visible data set "${ds.name}"`
806
849
  );
807
850
 
808
- this.visibleDataSets.push(ds);
851
+ if (!this.addToVisibleDataSetsList(ds)) {
852
+ // eslint-disable-next-line no-continue
853
+ continue;
854
+ }
809
855
 
810
856
  const hashTree = new HashTree([], dataSetInfo.leafCount);
811
857
 
@@ -379,6 +379,7 @@ export default class LocusInfo extends EventsScope {
379
379
  webexRequest: this.webex.request.bind(this.webex),
380
380
  locusInfoUpdateCallback: this.updateFromHashTree.bind(this),
381
381
  debugId: `HT-${this.meetingId.substring(0, 4)}`,
382
+ excludedDataSets: this.webex.config.meetings.locus?.excludedDataSets,
382
383
  });
383
384
  }
384
385
 
@@ -6214,14 +6214,10 @@ export default class Meeting extends StatelessWebexPlugin {
6214
6214
  return undefined;
6215
6215
  }
6216
6216
  // @ts-ignore - Fix type
6217
- await this.webex.internal.llm.disconnectLLM(
6218
- isJoined
6219
- ? {
6220
- code: 3050,
6221
- reason: 'done (permanent)',
6222
- }
6223
- : undefined
6224
- );
6217
+ await this.webex.internal.llm.disconnectLLM({
6218
+ code: 3050,
6219
+ reason: 'done (permanent)',
6220
+ });
6225
6221
  // @ts-ignore - Fix type
6226
6222
  this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
6227
6223
  // @ts-ignore - Fix type
@@ -165,7 +165,8 @@ describe('HashTreeParser', () => {
165
165
  // Helper to create a HashTreeParser instance with common defaults
166
166
  function createHashTreeParser(
167
167
  initialLocus: any = exampleInitialLocus,
168
- metadata: any = exampleMetadata
168
+ metadata: any = exampleMetadata,
169
+ excludedDataSets?: string[]
169
170
  ) {
170
171
  return new HashTreeParser({
171
172
  initialLocus,
@@ -173,6 +174,7 @@ describe('HashTreeParser', () => {
173
174
  webexRequest,
174
175
  locusInfoUpdateCallback: callback,
175
176
  debugId: 'test',
177
+ excludedDataSets,
176
178
  });
177
179
  }
178
180
 
@@ -353,6 +355,66 @@ describe('HashTreeParser', () => {
353
355
  expect(emptySet.hashTree).to.be.undefined;
354
356
  });
355
357
 
358
+ it('should exclude datasets listed in excludedDataSets during initialization', () => {
359
+ const parser = createHashTreeParser(exampleInitialLocus, exampleMetadata, ['atd-unmuted']);
360
+
361
+ // 'atd-unmuted' should be excluded from visibleDataSets
362
+ expect(parser.visibleDataSets.some((vds) => vds.name === 'atd-unmuted')).to.be.false;
363
+
364
+ // 'main' and 'self' should still be visible
365
+ expect(parser.visibleDataSets.some((vds) => vds.name === 'main')).to.be.true;
366
+ expect(parser.visibleDataSets.some((vds) => vds.name === 'self')).to.be.true;
367
+
368
+ // 'atd-unmuted' dataset entry should exist but without a hash tree (because it's not visible)
369
+ expect(parser.dataSets['atd-unmuted']).to.exist;
370
+ expect(parser.dataSets['atd-unmuted'].hashTree).to.be.undefined;
371
+
372
+ // 'main' and 'self' should have hash trees
373
+ expect(parser.dataSets.main.hashTree).to.be.instanceOf(HashTree);
374
+ expect(parser.dataSets.self.hashTree).to.be.instanceOf(HashTree);
375
+ });
376
+
377
+ it('should exclude datasets listed in excludedDataSets when adding new visible datasets', async () => {
378
+ // Create parser without 'atd-unmuted' in initial metadata visibleDataSets
379
+ const metadataWithoutAtdUnmuted = {
380
+ ...exampleMetadata,
381
+ visibleDataSets: exampleMetadata.visibleDataSets.filter((vds) => vds.name !== 'atd-unmuted'),
382
+ };
383
+ const parser = createHashTreeParser(exampleInitialLocus, metadataWithoutAtdUnmuted, [
384
+ 'atd-unmuted',
385
+ ]);
386
+
387
+ // 'atd-unmuted' should not be in visibleDataSets initially
388
+ expect(parser.visibleDataSets.some((vds) => vds.name === 'atd-unmuted')).to.be.false;
389
+
390
+ // Now simulate initializeDataSets which calls addToVisibleDataSetsList
391
+ const atdUnmutedDataSet = createDataSet('atd-unmuted', 16, 3000);
392
+
393
+ mockGetAllDataSetsMetadata(webexRequest, visibleDataSetsUrl, [
394
+ createDataSet('main', 16, 1000),
395
+ createDataSet('self', 1, 2000),
396
+ atdUnmutedDataSet,
397
+ ]);
398
+
399
+ mockSyncRequest(
400
+ webexRequest,
401
+ 'https://locus-a.wbx2.com/locus/api/v1/loci/97d64a5f/datasets/atd-unmuted'
402
+ );
403
+
404
+ const message = {
405
+ dataSets: [createDataSet('main', 16, 1000)],
406
+ visibleDataSetsUrl,
407
+ locusUrl,
408
+ };
409
+ await parser.initializeFromMessage(message);
410
+
411
+ // 'atd-unmuted' should still not be in visibleDataSets because it is excluded
412
+ expect(parser.visibleDataSets.some((vds) => vds.name === 'atd-unmuted')).to.be.false;
413
+ // but 'main' and 'self' should be there
414
+ expect(parser.visibleDataSets.some((vds) => vds.name === 'main')).to.be.true;
415
+ expect(parser.visibleDataSets.some((vds) => vds.name === 'self')).to.be.true;
416
+ });
417
+
356
418
  // helper method, needed because both initializeFromMessage and initializeFromGetLociResponse
357
419
  // do almost exactly the same thing
358
420
  const testInitializationOfDatasetsAndHashTrees = async (testCallback) => {
@@ -12744,7 +12744,10 @@ describe('plugin-meetings', () => {
12744
12744
 
12745
12745
  const result = await meeting.updateLLMConnection();
12746
12746
 
12747
- assert.calledWith(webex.internal.llm.disconnectLLM, undefined);
12747
+ assert.calledWith(webex.internal.llm.disconnectLLM, {
12748
+ code: 3050,
12749
+ reason: 'done (permanent)',
12750
+ });
12748
12751
  assert.notCalled(webex.internal.llm.registerAndConnect);
12749
12752
  assert.equal(result, undefined);
12750
12753
  assert.calledWithExactly(