@webex/internal-plugin-metrics 3.11.0 → 3.12.0-llmrefactor.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/automated-user.js +19 -0
  2. package/dist/automated-user.js.map +1 -0
  3. package/dist/batcher.js +3 -0
  4. package/dist/batcher.js.map +1 -1
  5. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +639 -65
  6. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
  7. package/dist/call-diagnostic/call-diagnostic-metrics.js +168 -76
  8. package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
  9. package/dist/call-diagnostic/call-diagnostic-metrics.util.js +18 -4
  10. package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
  11. package/dist/call-diagnostic/config.js +17 -3
  12. package/dist/call-diagnostic/config.js.map +1 -1
  13. package/dist/config.js +1 -0
  14. package/dist/config.js.map +1 -1
  15. package/dist/generic-metrics.js +8 -6
  16. package/dist/generic-metrics.js.map +1 -1
  17. package/dist/index.js +22 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/metrics.js +1 -1
  20. package/dist/metrics.types.js +4 -0
  21. package/dist/metrics.types.js.map +1 -1
  22. package/dist/new-metrics.js +105 -26
  23. package/dist/new-metrics.js.map +1 -1
  24. package/dist/prelogin-metrics.js +106 -0
  25. package/dist/prelogin-metrics.js.map +1 -0
  26. package/dist/privacy-and-security-permission-enricher/constants.js +18 -0
  27. package/dist/privacy-and-security-permission-enricher/constants.js.map +1 -0
  28. package/dist/privacy-and-security-permission-enricher/index.js +143 -0
  29. package/dist/privacy-and-security-permission-enricher/index.js.map +1 -0
  30. package/dist/privacy-and-security-permission-enricher/types.js +7 -0
  31. package/dist/privacy-and-security-permission-enricher/types.js.map +1 -0
  32. package/dist/privacy-and-security-permission-enricher/utils.js +71 -0
  33. package/dist/privacy-and-security-permission-enricher/utils.js.map +1 -0
  34. package/dist/types/automated-user.d.ts +2 -0
  35. package/dist/types/call-diagnostic/call-diagnostic-metrics-latencies.d.ts +208 -5
  36. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +79 -15
  37. package/dist/types/call-diagnostic/call-diagnostic-metrics.util.d.ts +5 -0
  38. package/dist/types/call-diagnostic/config.d.ts +5 -0
  39. package/dist/types/config.d.ts +1 -0
  40. package/dist/types/index.d.ts +6 -3
  41. package/dist/types/metrics.types.d.ts +9 -4
  42. package/dist/types/new-metrics.d.ts +29 -1
  43. package/dist/types/prelogin-metrics.d.ts +47 -0
  44. package/dist/types/privacy-and-security-permission-enricher/constants.d.ts +6 -0
  45. package/dist/types/privacy-and-security-permission-enricher/index.d.ts +40 -0
  46. package/dist/types/privacy-and-security-permission-enricher/types.d.ts +14 -0
  47. package/dist/types/privacy-and-security-permission-enricher/utils.d.ts +5 -0
  48. package/package.json +12 -11
  49. package/src/automated-user.ts +16 -0
  50. package/src/batcher.js +4 -0
  51. package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +800 -75
  52. package/src/call-diagnostic/call-diagnostic-metrics.ts +102 -15
  53. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +22 -2
  54. package/src/call-diagnostic/config.ts +15 -0
  55. package/src/config.js +1 -0
  56. package/src/generic-metrics.ts +6 -6
  57. package/src/index.ts +9 -0
  58. package/src/metrics.types.ts +27 -5
  59. package/src/new-metrics.ts +95 -6
  60. package/src/prelogin-metrics.ts +94 -0
  61. package/src/privacy-and-security-permission-enricher/constants.ts +33 -0
  62. package/src/privacy-and-security-permission-enricher/index.ts +142 -0
  63. package/src/privacy-and-security-permission-enricher/types.ts +21 -0
  64. package/src/privacy-and-security-permission-enricher/utils.ts +82 -0
  65. package/test/unit/spec/automated-user.ts +43 -0
  66. package/test/unit/spec/batcher.js +43 -0
  67. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +47 -11
  68. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +1550 -416
  69. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +887 -159
  70. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +61 -3
  71. package/test/unit/spec/new-metrics.ts +183 -50
  72. package/test/unit/spec/prelogin-metrics-batcher.ts +71 -36
  73. package/test/unit/spec/prelogin-metrics.ts +132 -0
  74. package/test/unit/spec/privacy-and-security-permission-enricher.ts +318 -0
@@ -6,6 +6,7 @@ import uuid from 'uuid';
6
6
  import {merge} from 'lodash';
7
7
  import {StatelessWebexPlugin} from '@webex/webex-core';
8
8
  import {getOSNameInternal} from '../metrics';
9
+ import * as AutomatedUserUtils from '../automated-user';
9
10
 
10
11
  import {
11
12
  anonymizeIPAddress,
@@ -99,7 +100,12 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
99
100
  // @ts-ignore
100
101
  private preLoginMetricsBatcher: PreLoginMetricsBatcher;
101
102
 
102
- private logger: any; // to avoid adding @ts-ignore everywhere
103
+ // lazy getter to avoid @ts-ignore on every call site
104
+ private get logger(): any {
105
+ // @ts-ignore
106
+ return this.webex.logger;
107
+ }
108
+
103
109
  private hasLoggedBrowserSerial: boolean;
104
110
  private device: any;
105
111
  private delayedClientEvents: DelayedClientEvent[] = [];
@@ -108,6 +114,8 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
108
114
  private isMercuryConnected = false;
109
115
  private eventLimitTracker: Map<string, number> = new Map();
110
116
  private eventLimitWarningsLogged: Set<string> = new Set();
117
+ private isTelemetryOptOutManual = false;
118
+ private isTelemetryOptOutAutomatic = false;
111
119
 
112
120
  // the default validator before piping an event to the batcher
113
121
  // this function can be overridden by the user
@@ -124,8 +132,6 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
124
132
  constructor(...args) {
125
133
  super(...args);
126
134
  // @ts-ignore
127
- this.logger = this.webex.logger;
128
- // @ts-ignore
129
135
  this.callDiagnosticEventsBatcher = new CallDiagnosticEventsBatcher({}, {parent: this.webex});
130
136
  // @ts-ignore
131
137
  this.preLoginMetricsBatcher = new PreLoginMetricsBatcher({}, {parent: this.webex});
@@ -145,6 +151,58 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
145
151
  return null;
146
152
  }
147
153
 
154
+ /**
155
+ * Returns the user activation state reported from the browser's navigator.userActivation API
156
+ * @returns object with hasBeenActive and isActive booleans, or undefined if unavailable
157
+ */
158
+ getUserActivation(): {hasBeenActive: boolean; isActive: boolean} | undefined {
159
+ const userActivation =
160
+ typeof navigator !== 'undefined'
161
+ ? (navigator as {userActivation?: {hasBeenActive: boolean; isActive: boolean}})
162
+ .userActivation
163
+ : undefined;
164
+
165
+ if (userActivation) {
166
+ return {
167
+ hasBeenActive: userActivation.hasBeenActive,
168
+ isActive: userActivation.isActive,
169
+ };
170
+ }
171
+
172
+ return undefined;
173
+ }
174
+
175
+ /**
176
+ * Returns the telemetryOptOut value of the current user
177
+ * @returns one of 'manual', 'automatic', undefined
178
+ */
179
+ public getTelemetryOptOut() {
180
+ if (this.isTelemetryOptOutManual) {
181
+ return 'manual';
182
+ }
183
+ if (this.isTelemetryOptOutAutomatic) {
184
+ return 'automatic';
185
+ }
186
+
187
+ return undefined;
188
+ }
189
+
190
+ /**
191
+ * Sets the manual telemetry opt-out status for the current user
192
+ * @param value - boolean value indicating manual telemetry opt-out status
193
+ */
194
+ public setIsTelemetryOptOutManual(value: boolean) {
195
+ this.isTelemetryOptOutManual = value;
196
+ }
197
+
198
+ /**
199
+ * Sets the automatic telemetry opt-out status for the current user
200
+ * @param value - boolean value indicating automatic telemetry opt-out status
201
+ */
202
+ public setIsTelemetryOptOutAutomatic(value: boolean) {
203
+ this.isTelemetryOptOutAutomatic = value;
204
+ }
205
+
148
206
  /**
149
207
  * Returns if the meeting has converged architecture enabled
150
208
  * @param options.meetingId
@@ -190,6 +248,11 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
190
248
 
191
249
  // if ConvergedArchitecture enable and isConvergedWebinarWebcast -- then webcast
192
250
  if (meetingInfo?.enableConvergedArchitecture && meetingInfo?.enableEvent) {
251
+ // if enableConvergedWebinarLargeScale - then large scale webinar
252
+ if (meetingInfo?.enableConvergedWebinarLargeScale) {
253
+ return WEBEX_SUB_SERVICE_TYPES.LARGE_SCALE_WEBINAR;
254
+ }
255
+
193
256
  return meetingInfo?.isConvergedWebinarWebcast
194
257
  ? WEBEX_SUB_SERVICE_TYPES.WEBCAST
195
258
  : WEBEX_SUB_SERVICE_TYPES.WEBINAR;
@@ -213,12 +276,12 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
213
276
  getOrigin(options: GetOriginOptions, meetingId?: string) {
214
277
  const defaultClientType: ClientType =
215
278
  // @ts-ignore
216
- this.webex.meetings.config?.metrics?.clientType;
279
+ this.webex.meetings?.config?.metrics?.clientType;
217
280
  const defaultSubClientType: SubClientType =
218
281
  // @ts-ignore
219
- this.webex.meetings.config?.metrics?.subClientType;
282
+ this.webex.meetings?.config?.metrics?.subClientType;
220
283
  // @ts-ignore
221
- const providedClientVersion: string = this.webex.meetings.config?.metrics?.clientVersion;
284
+ const providedClientVersion: string = this.webex.meetings?.config?.metrics?.clientVersion;
222
285
  // @ts-ignore
223
286
  const defaultSDKClientVersion = `${CLIENT_NAME}/${this.webex.version}`;
224
287
 
@@ -229,6 +292,18 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
229
292
  versionMetadata = extractVersionMetadata(providedClientVersion);
230
293
  }
231
294
 
295
+ // Browser details and the support verdict can all be supplied by the host client, which is able
296
+ // to resolve wrapper browsers (Electron, WebOS) to the engine that actually determines
297
+ // capability. The browser fields fall back to the SDK's own detection when not supplied, the
298
+ // same way clientVersion falls back to the SDK version.
299
+ const {
300
+ browser: providedBrowser,
301
+ browserVersion: providedBrowserVersion,
302
+ isSupportedBrowserFamily,
303
+ isOutdatedBrowserVersion,
304
+ // @ts-ignore
305
+ } = this.webex.meetings?.config?.metrics ?? {};
306
+
232
307
  if (!this.hasLoggedBrowserSerial) {
233
308
  this.logger.log(
234
309
  CALL_DIAGNOSTIC_LOG_IDENTIFIER,
@@ -258,25 +333,27 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
258
333
  ...versionMetadata,
259
334
  publicNetworkPrefix:
260
335
  // @ts-ignore
261
- anonymizeIPAddress(this.webex.meetings.geoHintInfo?.clientAddress) || undefined,
336
+ anonymizeIPAddress(this.webex.meetings?.geoHintInfo?.clientAddress) || undefined,
262
337
  localNetworkPrefix:
263
338
  anonymizeIPAddress(
264
339
  // @ts-ignore
265
- this.webex.meetings.meetingCollection
266
- .get(meetingId)
340
+ this.webex.meetings?.meetingCollection
341
+ ?.get(meetingId)
267
342
  ?.statsAnalyzer?.getLocalIpAddress()
268
343
  ) || undefined,
269
344
  osVersion: getOSVersion() || 'unknown',
270
345
  subClientType: options?.subClientType || defaultSubClientType,
271
346
  os: getOSNameInternal(),
272
- browser: getBrowserName(),
273
- browserVersion: getBrowserVersion(),
347
+ browser: providedBrowser || getBrowserName(),
348
+ browserVersion: providedBrowserVersion || getBrowserVersion(),
349
+ ...(isSupportedBrowserFamily === undefined ? {} : {isSupportedBrowserFamily}),
350
+ ...(isOutdatedBrowserVersion === undefined ? {} : {isOutdatedBrowserVersion}),
274
351
  },
275
352
  };
276
353
 
277
354
  if (meetingId) {
278
355
  // @ts-ignore
279
- const meeting = this.webex.meetings.getBasicMeetingInformation(meetingId);
356
+ const meeting = this.webex.meetings?.getBasicMeetingInformation(meetingId);
280
357
  if (meeting?.environment) {
281
358
  origin.environment = meeting.environment;
282
359
  }
@@ -366,6 +443,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
366
443
  if (meeting?.locusInfo?.fullState) {
367
444
  identifiers.locusUrl = meeting.locusUrl;
368
445
  identifiers.locusId = meeting.locusUrl && meeting.locusUrl.split('/').pop();
446
+ identifiers.locusSessionId = meeting.locusInfo.fullState.sessionId;
369
447
  identifiers.locusStartTime =
370
448
  meeting.locusInfo.fullState && meeting.locusInfo.fullState.lastActive;
371
449
  }
@@ -425,7 +503,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
425
503
  sent: 'not_defined_yet',
426
504
  },
427
505
  // @ts-ignore
428
- senderCountryCode: this.webex.meetings.geoHintInfo?.countryCode,
506
+ senderCountryCode: this.webex.meetings?.geoHintInfo?.countryCode,
429
507
  event: eventData,
430
508
  };
431
509
 
@@ -601,6 +679,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
601
679
  mediaEngineSoftwareVersion: getOSVersion() || 'unknown',
602
680
  startTime: new Date().toISOString(),
603
681
  },
682
+ webexSubServiceType: this.getSubServiceType(meeting),
604
683
  };
605
684
 
606
685
  // merge any new properties, or override existing ones
@@ -983,7 +1062,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
983
1062
  sessionCorrelationId,
984
1063
  });
985
1064
 
986
- // create common event object structur
1065
+ // create common event object structure
987
1066
  const commonEventObject = {
988
1067
  name,
989
1068
  canProceed: true,
@@ -996,6 +1075,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
996
1075
  'loginType' in meeting.callStateForMetrics
997
1076
  ? meeting.callStateForMetrics.loginType
998
1077
  : this.getCurLoginType(),
1078
+ telemetryOptOut: this.getTelemetryOptOut(),
999
1079
  isConvergedArchitectureEnabled: this.getIsConvergedArchitectureEnabled({
1000
1080
  meetingId,
1001
1081
  }),
@@ -1004,6 +1084,9 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
1004
1084
  webexSubServiceType: this.getSubServiceType(meeting),
1005
1085
  // @ts-ignore
1006
1086
  webClientPreload: this.webex.meetings?.config?.metrics?.webClientPreload,
1087
+ isVipMeeting: meeting?.meetingInfo?.vipmeeting || false,
1088
+ isAutomatedUser: AutomatedUserUtils.isAutomatedUser(),
1089
+ userActivation: this.getUserActivation(),
1007
1090
  };
1008
1091
 
1009
1092
  const joinFlowVersion = options.joinFlowVersion ?? meeting.callStateForMetrics?.joinFlowVersion;
@@ -1123,8 +1206,11 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
1123
1206
  isMercuryConnected: this.isMercuryConnected,
1124
1207
  },
1125
1208
  loginType: this.getCurLoginType(),
1209
+ telemetryOptOut: this.getTelemetryOptOut(),
1126
1210
  // @ts-ignore
1127
1211
  webClientPreload: this.webex.meetings?.config?.metrics?.webClientPreload,
1212
+ isAutomatedUser: AutomatedUserUtils.isAutomatedUser(),
1213
+ userActivation: this.getUserActivation(),
1128
1214
  };
1129
1215
 
1130
1216
  if (options.joinFlowVersion) {
@@ -1334,6 +1420,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
1334
1420
  eventPayload: event,
1335
1421
  type: ['diagnostic-event'],
1336
1422
  };
1423
+
1337
1424
  this.preLoginMetricsBatcher.savePreLoginId(preLoginId);
1338
1425
 
1339
1426
  return this.preLoginMetricsBatcher.request(finalEvent);
@@ -1381,7 +1468,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
1381
1468
  },
1382
1469
  headers: {},
1383
1470
  // @ts-ignore
1384
- waitForServiceTimeout: this.webex.internal.metrics.config.waitForServiceTimeout,
1471
+ waitForServiceTimeout: this.webex.internal.metrics?.config?.waitForServiceTimeout,
1385
1472
  };
1386
1473
 
1387
1474
  if (options.preLoginId) {
@@ -179,6 +179,16 @@ export const isSdpOfferCreationError = (rawError: any) => {
179
179
  return false;
180
180
  };
181
181
 
182
+ export const isWebrtcApiNotAvailableError = (
183
+ rawError: {code: number; message: string; name: string} | unknown
184
+ ) => {
185
+ if ((rawError as {name: string}).name === ERROR_DESCRIPTIONS.WEBRTC_API_NOT_AVAILABLE) {
186
+ return true;
187
+ }
188
+
189
+ return false;
190
+ };
191
+
182
192
  /**
183
193
  * Checks if the given error is a browser media error by its name.
184
194
  * Returns true if the error name matches any known browser media error name in the mapping.
@@ -274,7 +284,8 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
274
284
  devicePairingType: webex.devicemanager.getPairedMethod(),
275
285
  deviceURL: pairedDevice.url,
276
286
  isPersonalDevice: pairedDevice.mode === 'personal',
277
- productName: pairedDevice.devices[0]?.productName,
287
+ productName:
288
+ pairedDevice.devices?.length > 0 ? pairedDevice.devices[0]?.productName : undefined,
278
289
  };
279
290
  item.eventPayload.event.pairingState = 'paired';
280
291
  item.eventPayload.event.pairedDevice = devicePayload;
@@ -351,7 +362,6 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
351
362
  joinTimes.totalMediaJMT = cdl.getTotalMediaJMT();
352
363
  joinTimes.interstitialToMediaOKJMT = cdl.getInterstitialToMediaOKJMT();
353
364
  joinTimes.callInitMediaEngineReady = cdl.getCallInitMediaEngineReady();
354
- joinTimes.stayLobbyTime = cdl.getStayLobbyTime();
355
365
  joinTimes.totalMediaJMTWithUserDelay = cdl.getTotalMediaJMTWithUserDelay();
356
366
  joinTimes.totalJMTWithUserDelay = cdl.getTotalJMTWithUserDelay();
357
367
  break;
@@ -359,6 +369,11 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
359
369
  case 'client.media.tx.start':
360
370
  audioSetupDelay.joinRespTxStart = cdl.getAudioJoinRespTxStart();
361
371
  videoSetupDelay.joinRespTxStart = cdl.getVideoJoinRespTxStart();
372
+ break;
373
+
374
+ case 'client.lobby.exited':
375
+ joinTimes.stayLobbyTime = cdl.getStayLobbyTime();
376
+ break;
362
377
  }
363
378
 
364
379
  if (!isEmpty(joinTimes)) {
@@ -375,6 +390,11 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
375
390
 
376
391
  item.eventPayload.origin = Object.assign(origin, item.eventPayload.origin);
377
392
 
393
+ // Mark call milestones in logs for easier filtering and analysis
394
+ if (eventName) {
395
+ webex.logger.log('Milestone,CallDiagnostic', eventName);
396
+ }
397
+
378
398
  webex.logger.log(
379
399
  `CallDiagnosticLatencies,prepareDiagnosticMetricItem: ${JSON.stringify({
380
400
  latencies: Object.fromEntries(cdl.latencyTimestamps),
@@ -26,6 +26,7 @@ export const WEBEX_SUB_SERVICE_TYPES: Record<string, ClientSubServiceType> = {
26
26
  SCHEDULED_MEETING: 'ScheduledMeeting',
27
27
  WEBINAR: 'Webinar',
28
28
  WEBCAST: 'Webcast',
29
+ LARGE_SCALE_WEBINAR: 'LargeScaleWebinar',
29
30
  };
30
31
 
31
32
  // Found in https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
@@ -133,8 +134,10 @@ export const ERROR_DESCRIPTIONS = {
133
134
  MULTISTREAM_NOT_AVAILABLE: 'MultistreamNotAvailable',
134
135
  SDP_OFFER_CREATION_ERROR: 'SdpOfferCreationError',
135
136
  SDP_OFFER_CREATION_ERROR_MISSING_CODEC: 'SdpOfferCreationErrorMissingCodec',
137
+ WEBRTC_API_NOT_AVAILABLE: 'WebrtcApiNotAvailableError',
136
138
  WDM_RESTRICTED_REGION: 'WdmRestrictedRegion',
137
139
  USER_NOT_ALLOWED_JOIN_WEBINAR: 'UserNotAllowedJoinWebinar',
140
+ INVALID_MEETING_INFO: 'InvalidMeetingInfo',
138
141
  };
139
142
 
140
143
  export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
@@ -145,6 +148,8 @@ export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
145
148
  99002: 4100,
146
149
  // Cannot find the data. Unkown meeting.
147
150
  99009: 4100,
151
+ // The input parameters contain invalid item
152
+ 99019: 4105,
148
153
  // Meeting is not allow to cross env
149
154
  58500: 4100,
150
155
  // Input parameters contain invalit item
@@ -200,6 +205,8 @@ export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
200
205
  423005: 4005,
201
206
  // Wrong password or host key with too many requests
202
207
  423006: 4005,
208
+ // PanelistPasswordError too many time,please input captcha code
209
+ 423008: 4005,
203
210
  // PasswordError with right captcha, please input captcha code
204
211
  423010: 4005,
205
212
  // PasswordOrHostKeyError with right captcha, please input captcha code
@@ -226,6 +233,8 @@ export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
226
233
  403003: 4101,
227
234
  // Attendee email is required
228
235
  403030: 4101,
236
+ // webinar need login when un-invited attendee join
237
+ 403106: 4104,
229
238
 
230
239
  // ---- Locus ------
231
240
  // FREE_USER_MAX_PARTICIPANTS_EXCEEDED
@@ -695,6 +704,12 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEv
695
704
  category: 'expected',
696
705
  fatal: true,
697
706
  },
707
+ 4105: {
708
+ errorDescription: ERROR_DESCRIPTIONS.INVALID_MEETING_INFO,
709
+ category: 'expected',
710
+ fatal: false,
711
+ shownToUser: true,
712
+ },
698
713
  2729: {
699
714
  errorDescription: ERROR_DESCRIPTIONS.NO_MEDIA_FOUND,
700
715
  category: 'expected',
package/src/config.js CHANGED
@@ -19,6 +19,7 @@ export default {
19
19
  batcherMaxCalls: 50,
20
20
  batcherMaxWait: 1500,
21
21
  batcherRetryPlateau: 32000,
22
+ batcherRetryOnNetworkError: true,
22
23
  waitForServiceTimeout: 30,
23
24
  },
24
25
  };
@@ -79,7 +79,7 @@ export default abstract class GenericMetrics extends StatelessWebexPlugin {
79
79
  device: {
80
80
  id: this.getDeviceId(),
81
81
  },
82
- locale: window.navigator.language,
82
+ locale: window?.navigator.language,
83
83
  os: {
84
84
  name: getOSNameInternal(),
85
85
  version: getOSVersion(),
@@ -94,12 +94,12 @@ export default abstract class GenericMetrics extends StatelessWebexPlugin {
94
94
  protected getBrowserDetails(): object {
95
95
  return {
96
96
  browser: getBrowserName(),
97
- browserHeight: window.innerHeight,
97
+ browserHeight: window?.innerHeight,
98
98
  browserVersion: getBrowserVersion(),
99
- browserWidth: window.innerWidth,
100
- domain: window.location.hostname,
101
- inIframe: window.self !== window.top,
102
- locale: window.navigator.language,
99
+ browserWidth: window?.innerWidth,
100
+ domain: window?.location.hostname,
101
+ inIframe: window?.self !== window?.top,
102
+ locale: window?.navigator.language,
103
103
  os: getOSNameInternal(),
104
104
  };
105
105
  }
package/src/index.ts CHANGED
@@ -8,6 +8,7 @@ import Metrics from './metrics';
8
8
  import config from './config';
9
9
  import NewMetrics from './new-metrics';
10
10
  import * as Utils from './utils';
11
+ import * as AutomatedUserUtils from './automated-user';
11
12
  import {
12
13
  ClientEvent,
13
14
  ClientEventLeaveReason,
@@ -19,6 +20,8 @@ import {
19
20
  SubmitMQE,
20
21
  PreComputedLatencies,
21
22
  SubmitFeatureEvent,
23
+ LocusSyncLatencyEventName,
24
+ PrivacyAndSecurityPermission,
22
25
  } from './metrics.types';
23
26
  import * as CALL_DIAGNOSTIC_CONFIG from './call-diagnostic/config';
24
27
  import * as CallDiagnosticUtils from './call-diagnostic/call-diagnostic-metrics.util';
@@ -28,6 +31,7 @@ import BehavioralMetrics from './behavioral-metrics';
28
31
  import OperationalMetrics from './operational-metrics';
29
32
  import BusinessMetrics from './business-metrics';
30
33
  import RtcMetrics from './rtcMetrics';
34
+ import PreLoginMetrics from './prelogin-metrics';
31
35
 
32
36
  registerInternalPlugin('metrics', Metrics, {
33
37
  config,
@@ -42,6 +46,7 @@ export {default, getOSNameInternal} from './metrics';
42
46
  export {
43
47
  config,
44
48
  CALL_DIAGNOSTIC_CONFIG,
49
+ AutomatedUserUtils,
45
50
  NewMetrics,
46
51
  Utils,
47
52
  CallDiagnosticUtils,
@@ -51,7 +56,9 @@ export {
51
56
  OperationalMetrics,
52
57
  BusinessMetrics,
53
58
  RtcMetrics,
59
+ PreLoginMetrics,
54
60
  };
61
+ export {isAutomatedUser, isAutomatedUserAgent} from './automated-user';
55
62
  export type {
56
63
  ClientEvent,
57
64
  ClientEventLeaveReason,
@@ -63,4 +70,6 @@ export type {
63
70
  SubmitBusinessEvent,
64
71
  PreComputedLatencies,
65
72
  SubmitFeatureEvent,
73
+ LocusSyncLatencyEventName,
74
+ PrivacyAndSecurityPermission,
66
75
  };
@@ -1,4 +1,4 @@
1
- import {
1
+ import type {
2
2
  ClientEvent as RawClientEvent,
3
3
  Event as RawEvent,
4
4
  MediaQualityEvent as RawMediaQualityEvent,
@@ -23,6 +23,15 @@ export type ClientUserNameInput = NonNullable<RawClientEvent['userNameInput']>;
23
23
 
24
24
  export type ClientEmailInput = NonNullable<RawClientEvent['emailInput']>;
25
25
 
26
+ export type PrivacyAndSecurityPermission = NonNullable<
27
+ RawClientEvent['privacyAndSecurityPermission']
28
+ >;
29
+
30
+ export type PrivacyAndSecurityPermissionResource = keyof PrivacyAndSecurityPermission;
31
+
32
+ export type PrivacyAndSecurityPermissionState =
33
+ PrivacyAndSecurityPermission[PrivacyAndSecurityPermissionResource];
34
+
26
35
  export type BrowserLaunchMethodType = NonNullable<
27
36
  RawEvent['origin']['clientInfo']
28
37
  >['browserLaunchMethod'];
@@ -149,6 +158,17 @@ export type SubmitMQEOptions = {
149
158
  globalMeetingId?: string;
150
159
  };
151
160
 
161
+ export const LOCUS_SYNC_LATENCY_EVENT_NAMES = [
162
+ 'internal.client.locus.sync.start',
163
+ 'internal.client.locus.hashtree.request',
164
+ 'internal.client.locus.hashtree.response',
165
+ 'internal.client.locus.sync.request',
166
+ 'internal.client.locus.sync.response',
167
+ 'internal.client.locus.sync.message.received',
168
+ ] as const;
169
+
170
+ export type LocusSyncLatencyEventName = (typeof LOCUS_SYNC_LATENCY_EVENT_NAMES)[number];
171
+
152
172
  export type InternalEvent = {
153
173
  name:
154
174
  | 'internal.client.meetinginfo.request'
@@ -156,14 +176,14 @@ export type InternalEvent = {
156
176
  | 'internal.register.device.request'
157
177
  | 'internal.register.device.response'
158
178
  | 'internal.reset.join.latencies'
159
- | 'internal.client.meeting.click.joinbutton'
160
179
  | 'internal.host.meeting.participant.admitted'
161
180
  | 'internal.client.meeting.interstitial-window.showed'
162
181
  | 'internal.client.interstitial-window.click.joinbutton'
163
182
  | 'internal.client.add-media.turn-discovery.start'
164
183
  | 'internal.client.add-media.turn-discovery.end'
165
184
  | 'internal.client.share.initiated'
166
- | 'internal.client.share.stopped';
185
+ | 'internal.client.share.stopped'
186
+ | LocusSyncLatencyEventName;
167
187
 
168
188
  payload?: never;
169
189
  options?: never;
@@ -197,7 +217,7 @@ export interface BusinessEventPayload {
197
217
  metricName: string;
198
218
  timestamp: number;
199
219
  context: DeviceContext;
200
- browserDetails: EventPayload;
220
+ browserDetails: object;
201
221
  value: EventPayload;
202
222
  }
203
223
 
@@ -319,12 +339,14 @@ export type PreComputedLatencies =
319
339
  | 'internal.get.cluster.time'
320
340
  | 'internal.click.to.interstitial'
321
341
  | 'internal.click.to.interstitial.with.user.delay'
342
+ | 'internal.click.to.interstitial.for.client.jmt'
322
343
  | 'internal.refresh.captcha.time'
323
344
  | 'internal.exchange.ci.token.time'
324
345
  | 'internal.get.u2c.time'
325
346
  | 'internal.call.init.join.req'
326
347
  | 'internal.other.app.api.time'
327
- | 'internal.api.fetch.intelligence.models';
348
+ | 'internal.api.fetch.intelligence.models'
349
+ | 'internal.client.locus.sync.random.backoff';
328
350
 
329
351
  export interface IdType {
330
352
  meetingId?: string;