@webex/internal-plugin-metrics 3.11.0-webex-services-ready.1 → 3.12.0-auth-prejoin-fetch.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.
Files changed (84) hide show
  1. package/README.md +36 -0
  2. package/dist/automated-user.js +19 -0
  3. package/dist/automated-user.js.map +1 -0
  4. package/dist/batcher.js +3 -0
  5. package/dist/batcher.js.map +1 -1
  6. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +639 -65
  7. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
  8. package/dist/call-diagnostic/call-diagnostic-metrics.js +168 -76
  9. package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
  10. package/dist/call-diagnostic/call-diagnostic-metrics.util.js +11 -3
  11. package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
  12. package/dist/call-diagnostic/config.js +16 -3
  13. package/dist/call-diagnostic/config.js.map +1 -1
  14. package/dist/config.js +4 -0
  15. package/dist/config.js.map +1 -1
  16. package/dist/generic-metrics.js +8 -6
  17. package/dist/generic-metrics.js.map +1 -1
  18. package/dist/index.js +22 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/metrics.js +1 -1
  21. package/dist/metrics.types.js +4 -0
  22. package/dist/metrics.types.js.map +1 -1
  23. package/dist/new-metrics.js +108 -26
  24. package/dist/new-metrics.js.map +1 -1
  25. package/dist/prelogin-metrics.js +106 -0
  26. package/dist/prelogin-metrics.js.map +1 -0
  27. package/dist/privacy-and-security-permission-enricher/constants.js +18 -0
  28. package/dist/privacy-and-security-permission-enricher/constants.js.map +1 -0
  29. package/dist/privacy-and-security-permission-enricher/index.js +143 -0
  30. package/dist/privacy-and-security-permission-enricher/index.js.map +1 -0
  31. package/dist/privacy-and-security-permission-enricher/types.js +7 -0
  32. package/dist/privacy-and-security-permission-enricher/types.js.map +1 -0
  33. package/dist/privacy-and-security-permission-enricher/utils.js +71 -0
  34. package/dist/privacy-and-security-permission-enricher/utils.js.map +1 -0
  35. package/dist/types/automated-user.d.ts +2 -0
  36. package/dist/types/call-diagnostic/call-diagnostic-metrics-latencies.d.ts +208 -5
  37. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +79 -15
  38. package/dist/types/call-diagnostic/config.d.ts +4 -0
  39. package/dist/types/config.d.ts +4 -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/dist/types/unhandled-exception-telemetry/index.d.ts +60 -0
  49. package/dist/types/unhandled-exception-telemetry/utils.d.ts +6 -0
  50. package/dist/unhandled-exception-telemetry/index.js +330 -0
  51. package/dist/unhandled-exception-telemetry/index.js.map +1 -0
  52. package/dist/unhandled-exception-telemetry/utils.js +105 -0
  53. package/dist/unhandled-exception-telemetry/utils.js.map +1 -0
  54. package/package.json +12 -11
  55. package/src/automated-user.ts +16 -0
  56. package/src/batcher.js +4 -0
  57. package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +800 -75
  58. package/src/call-diagnostic/call-diagnostic-metrics.ts +102 -15
  59. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +12 -2
  60. package/src/call-diagnostic/config.ts +14 -0
  61. package/src/config.js +4 -0
  62. package/src/generic-metrics.ts +6 -6
  63. package/src/index.ts +9 -0
  64. package/src/metrics.types.ts +27 -5
  65. package/src/new-metrics.ts +98 -6
  66. package/src/prelogin-metrics.ts +94 -0
  67. package/src/privacy-and-security-permission-enricher/constants.ts +33 -0
  68. package/src/privacy-and-security-permission-enricher/index.ts +142 -0
  69. package/src/privacy-and-security-permission-enricher/types.ts +21 -0
  70. package/src/privacy-and-security-permission-enricher/utils.ts +82 -0
  71. package/src/unhandled-exception-telemetry/index.ts +403 -0
  72. package/src/unhandled-exception-telemetry/utils.ts +101 -0
  73. package/test/unit/spec/automated-user.ts +43 -0
  74. package/test/unit/spec/batcher.js +43 -0
  75. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +47 -11
  76. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +1550 -416
  77. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +887 -159
  78. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +37 -3
  79. package/test/unit/spec/new-metrics.ts +203 -50
  80. package/test/unit/spec/prelogin-metrics-batcher.ts +71 -36
  81. package/test/unit/spec/prelogin-metrics.ts +132 -0
  82. package/test/unit/spec/privacy-and-security-permission-enricher.ts +318 -0
  83. package/test/unit/spec/unhandled-exception-telemetry/utils.ts +109 -0
  84. package/test/unit/spec/unhandled-exception-telemetry.ts +688 -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) {
@@ -284,7 +284,8 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
284
284
  devicePairingType: webex.devicemanager.getPairedMethod(),
285
285
  deviceURL: pairedDevice.url,
286
286
  isPersonalDevice: pairedDevice.mode === 'personal',
287
- productName: pairedDevice.devices[0]?.productName,
287
+ productName:
288
+ pairedDevice.devices?.length > 0 ? pairedDevice.devices[0]?.productName : undefined,
288
289
  };
289
290
  item.eventPayload.event.pairingState = 'paired';
290
291
  item.eventPayload.event.pairedDevice = devicePayload;
@@ -361,7 +362,6 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
361
362
  joinTimes.totalMediaJMT = cdl.getTotalMediaJMT();
362
363
  joinTimes.interstitialToMediaOKJMT = cdl.getInterstitialToMediaOKJMT();
363
364
  joinTimes.callInitMediaEngineReady = cdl.getCallInitMediaEngineReady();
364
- joinTimes.stayLobbyTime = cdl.getStayLobbyTime();
365
365
  joinTimes.totalMediaJMTWithUserDelay = cdl.getTotalMediaJMTWithUserDelay();
366
366
  joinTimes.totalJMTWithUserDelay = cdl.getTotalJMTWithUserDelay();
367
367
  break;
@@ -369,6 +369,11 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
369
369
  case 'client.media.tx.start':
370
370
  audioSetupDelay.joinRespTxStart = cdl.getAudioJoinRespTxStart();
371
371
  videoSetupDelay.joinRespTxStart = cdl.getVideoJoinRespTxStart();
372
+ break;
373
+
374
+ case 'client.lobby.exited':
375
+ joinTimes.stayLobbyTime = cdl.getStayLobbyTime();
376
+ break;
372
377
  }
373
378
 
374
379
  if (!isEmpty(joinTimes)) {
@@ -385,6 +390,11 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
385
390
 
386
391
  item.eventPayload.origin = Object.assign(origin, item.eventPayload.origin);
387
392
 
393
+ // Mark call milestones in logs for easier filtering and analysis
394
+ if (eventName) {
395
+ webex.logger.log('Milestone,CallDiagnostic', eventName);
396
+ }
397
+
388
398
  webex.logger.log(
389
399
  `CallDiagnosticLatencies,prepareDiagnosticMetricItem: ${JSON.stringify({
390
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
@@ -136,6 +137,7 @@ export const ERROR_DESCRIPTIONS = {
136
137
  WEBRTC_API_NOT_AVAILABLE: 'WebrtcApiNotAvailableError',
137
138
  WDM_RESTRICTED_REGION: 'WdmRestrictedRegion',
138
139
  USER_NOT_ALLOWED_JOIN_WEBINAR: 'UserNotAllowedJoinWebinar',
140
+ INVALID_MEETING_INFO: 'InvalidMeetingInfo',
139
141
  };
140
142
 
141
143
  export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
@@ -146,6 +148,8 @@ export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
146
148
  99002: 4100,
147
149
  // Cannot find the data. Unkown meeting.
148
150
  99009: 4100,
151
+ // The input parameters contain invalid item
152
+ 99019: 4105,
149
153
  // Meeting is not allow to cross env
150
154
  58500: 4100,
151
155
  // Input parameters contain invalit item
@@ -201,6 +205,8 @@ export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
201
205
  423005: 4005,
202
206
  // Wrong password or host key with too many requests
203
207
  423006: 4005,
208
+ // PanelistPasswordError too many time,please input captcha code
209
+ 423008: 4005,
204
210
  // PasswordError with right captcha, please input captcha code
205
211
  423010: 4005,
206
212
  // PasswordOrHostKeyError with right captcha, please input captcha code
@@ -227,6 +233,8 @@ export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
227
233
  403003: 4101,
228
234
  // Attendee email is required
229
235
  403030: 4101,
236
+ // webinar need login when un-invited attendee join
237
+ 403106: 4104,
230
238
 
231
239
  // ---- Locus ------
232
240
  // FREE_USER_MAX_PARTICIPANTS_EXCEEDED
@@ -696,6 +704,12 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEv
696
704
  category: 'expected',
697
705
  fatal: true,
698
706
  },
707
+ 4105: {
708
+ errorDescription: ERROR_DESCRIPTIONS.INVALID_MEETING_INFO,
709
+ category: 'expected',
710
+ fatal: false,
711
+ shownToUser: true,
712
+ },
699
713
  2729: {
700
714
  errorDescription: ERROR_DESCRIPTIONS.NO_MEDIA_FOUND,
701
715
  category: 'expected',
package/src/config.js CHANGED
@@ -15,10 +15,14 @@ export default {
15
15
  },
16
16
  metrics: {
17
17
  appType: inBrowser ? 'browser' : 'nodejs',
18
+ unhandledExceptionTelemetry: {
19
+ enabled: false,
20
+ },
18
21
  batcherWait: 500,
19
22
  batcherMaxCalls: 50,
20
23
  batcherMaxWait: 1500,
21
24
  batcherRetryPlateau: 32000,
25
+ batcherRetryOnNetworkError: true,
22
26
  waitForServiceTimeout: 30,
23
27
  },
24
28
  };
@@ -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;