@webex/internal-plugin-metrics 3.3.0 → 3.3.1-next.10

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 (34) hide show
  1. package/dist/behavioral/behavioral-metrics.js +199 -0
  2. package/dist/behavioral/behavioral-metrics.js.map +1 -0
  3. package/dist/behavioral/config.js +11 -0
  4. package/dist/behavioral/config.js.map +1 -0
  5. package/dist/call-diagnostic/call-diagnostic-metrics.util.js +14 -11
  6. package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
  7. package/dist/call-diagnostic/config.js +19 -13
  8. package/dist/call-diagnostic/config.js.map +1 -1
  9. package/dist/index.js +7 -0
  10. package/dist/index.js.map +1 -1
  11. package/dist/metrics.js +1 -1
  12. package/dist/metrics.types.js.map +1 -1
  13. package/dist/new-metrics.js +31 -6
  14. package/dist/new-metrics.js.map +1 -1
  15. package/dist/types/behavioral/behavioral-metrics.d.ts +63 -0
  16. package/dist/types/behavioral/config.d.ts +1 -0
  17. package/dist/types/call-diagnostic/call-diagnostic-metrics.util.d.ts +3 -2
  18. package/dist/types/call-diagnostic/config.d.ts +2 -0
  19. package/dist/types/index.d.ts +2 -1
  20. package/dist/types/metrics.types.d.ts +28 -7
  21. package/dist/types/new-metrics.d.ts +14 -6
  22. package/package.json +11 -11
  23. package/src/behavioral/behavioral-metrics.ts +179 -0
  24. package/src/behavioral/config.ts +3 -0
  25. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +16 -17
  26. package/src/call-diagnostic/config.ts +9 -2
  27. package/src/index.ts +2 -0
  28. package/src/metrics.types.ts +56 -8
  29. package/src/new-metrics.ts +34 -8
  30. package/test/unit/spec/behavioral/behavioral-metrics.ts +164 -0
  31. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +48 -52
  32. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +1 -1
  33. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +41 -22
  34. package/test/unit/spec/prelogin-metrics-batcher.ts +1 -1
@@ -7,6 +7,9 @@ export type EnvironmentType = NonNullable<RawEvent['origin']['environment']>;
7
7
  export type NewEnvironmentType = NonNullable<RawEvent['origin']['newEnvironment']>;
8
8
  export type ClientLaunchMethodType = NonNullable<RawEvent['origin']['clientInfo']>['clientLaunchMethod'];
9
9
  export type BrowserLaunchMethodType = NonNullable<RawEvent['origin']['clientInfo']>['browserLaunchMethod'];
10
+ export type MetricEventProduct = 'webex' | 'wxcc_desktop';
11
+ export type MetricEventAgent = 'user' | 'browser' | 'system' | 'sdk' | 'redux' | 'service';
12
+ export type MetricEventVerb = 'create' | 'get' | 'fetch' | 'update' | 'list' | 'delete' | 'select' | 'view' | 'set' | 'toggle' | 'load' | 'reload' | 'click' | 'hover' | 'register' | 'unregister' | 'enable' | 'disable' | 'use' | 'complete' | 'submit' | 'apply' | 'cancel' | 'abort' | 'sync' | 'login' | 'logout';
10
13
  export type SubmitClientEventOptions = {
11
14
  meetingId?: string;
12
15
  mediaConnections?: any[];
@@ -37,11 +40,27 @@ export interface ClientEvent {
37
40
  payload?: RawClientEvent;
38
41
  options?: SubmitClientEventOptions;
39
42
  }
43
+ export interface BehavioralEventContext {
44
+ app: {
45
+ version: string;
46
+ };
47
+ device: {
48
+ id: string;
49
+ };
50
+ locale: string;
51
+ os: {
52
+ name: string;
53
+ version: string;
54
+ };
55
+ }
40
56
  export interface BehavioralEvent {
41
- name: 'host.meeting.participant.admitted' | 'sdk.media-flow.started';
42
- payload?: never;
43
- options?: never;
57
+ context: BehavioralEventContext;
58
+ metricName: string;
59
+ tags: Record<string, string | number | boolean>;
60
+ timestamp: number;
61
+ type: string[];
44
62
  }
63
+ export type BehavioralEventPayload = BehavioralEvent['tags'];
45
64
  export interface OperationalEvent {
46
65
  name: never;
47
66
  payload?: never;
@@ -60,7 +79,7 @@ export interface MediaQualityEvent {
60
79
  export type RecursivePartial<T> = {
61
80
  [P in keyof T]?: T[P] extends (infer U)[] ? RecursivePartial<U>[] : T[P] extends object ? RecursivePartial<T[P]> : T[P];
62
81
  };
63
- export type MetricEventNames = InternalEvent['name'] | ClientEvent['name'] | BehavioralEvent['name'] | OperationalEvent['name'] | FeatureEvent['name'] | MediaQualityEvent['name'];
82
+ export type MetricEventNames = InternalEvent['name'] | ClientEvent['name'] | BehavioralEvent['metricName'] | OperationalEvent['name'] | FeatureEvent['name'] | MediaQualityEvent['name'];
64
83
  export type ClientInfo = NonNullable<RawEvent['origin']['clientInfo']>;
65
84
  export type ClientType = NonNullable<RawEvent['origin']['clientInfo']>['clientType'];
66
85
  export type SubClientType = NonNullable<RawEvent['origin']['clientInfo']>['subClientType'];
@@ -80,9 +99,11 @@ export type SubmitInternalEvent = (args: {
80
99
  options?: any;
81
100
  }) => void;
82
101
  export type SubmitBehavioralEvent = (args: {
83
- name: BehavioralEvent['name'];
84
- payload?: RecursivePartial<BehavioralEvent['payload']>;
85
- options?: any;
102
+ product: MetricEventProduct;
103
+ agent: MetricEventAgent;
104
+ target: string;
105
+ verb: MetricEventVerb;
106
+ payload?: BehavioralEventPayload;
86
107
  }) => void;
87
108
  export type SubmitClientEvent = (args: {
88
109
  name: ClientEvent['name'];
@@ -1,6 +1,7 @@
1
1
  import { WebexPlugin } from '@webex/webex-core';
2
2
  import CallDiagnosticMetrics from './call-diagnostic/call-diagnostic-metrics';
3
- import { RecursivePartial, ClientEvent, FeatureEvent, BehavioralEvent, OperationalEvent, MediaQualityEvent, InternalEvent, SubmitClientEventOptions } from './metrics.types';
3
+ import BehavioralMetrics from './behavioral/behavioral-metrics';
4
+ import { RecursivePartial, MetricEventProduct, MetricEventAgent, MetricEventVerb, ClientEvent, FeatureEvent, BehavioralEventPayload, OperationalEvent, MediaQualityEvent, InternalEvent, SubmitClientEventOptions } from './metrics.types';
4
5
  import CallDiagnosticLatencies from './call-diagnostic/call-diagnostic-metrics-latencies';
5
6
  /**
6
7
  * Metrics plugin to centralize all types of metrics.
@@ -10,6 +11,7 @@ declare class Metrics extends WebexPlugin {
10
11
  static instance: Metrics;
11
12
  callDiagnosticLatencies: CallDiagnosticLatencies;
12
13
  callDiagnosticMetrics: CallDiagnosticMetrics;
14
+ behavioralMetrics: BehavioralMetrics;
13
15
  /**
14
16
  * Constructor
15
17
  * @param args
@@ -31,15 +33,21 @@ declare class Metrics extends WebexPlugin {
31
33
  payload?: RecursivePartial<InternalEvent['payload']>;
32
34
  options?: any;
33
35
  }): void;
36
+ /**
37
+ * @returns true once we have the deviceId we need to submit behavioral events to Amplitude
38
+ */
39
+ isReadyToSubmitBehavioralEvents(): boolean;
34
40
  /**
35
41
  * Behavioral event
36
42
  * @param args
37
43
  */
38
- submitBehavioralEvent({ name, payload, options, }: {
39
- name: BehavioralEvent['name'];
40
- payload?: RecursivePartial<BehavioralEvent['payload']>;
41
- options?: any;
42
- }): void;
44
+ submitBehavioralEvent({ product, agent, target, verb, payload, }: {
45
+ product: MetricEventProduct;
46
+ agent: MetricEventAgent;
47
+ target: string;
48
+ verb: MetricEventVerb;
49
+ payload?: BehavioralEventPayload;
50
+ }): any;
43
51
  /**
44
52
  * Operational event
45
53
  * @param args
package/package.json CHANGED
@@ -26,22 +26,22 @@
26
26
  "@webex/eslint-config-legacy": "0.0.0",
27
27
  "@webex/jest-config-legacy": "0.0.0",
28
28
  "@webex/legacy-tools": "0.0.0",
29
- "@webex/test-helper-chai": "3.3.0",
30
- "@webex/test-helper-mocha": "3.3.0",
31
- "@webex/test-helper-mock-webex": "3.3.0",
32
- "@webex/test-helper-test-users": "3.3.0",
29
+ "@webex/test-helper-chai": "3.3.1-next.10",
30
+ "@webex/test-helper-mocha": "3.3.1-next.10",
31
+ "@webex/test-helper-mock-webex": "3.3.1-next.10",
32
+ "@webex/test-helper-test-users": "3.3.1-next.10",
33
33
  "eslint": "^8.24.0",
34
34
  "prettier": "^2.7.1",
35
35
  "sinon": "^9.2.4"
36
36
  },
37
37
  "dependencies": {
38
- "@webex/common": "3.3.0",
39
- "@webex/common-timers": "3.3.0",
38
+ "@webex/common": "3.3.1-next.10",
39
+ "@webex/common-timers": "3.3.1-next.10",
40
40
  "@webex/event-dictionary-ts": "^1.0.1406",
41
- "@webex/internal-plugin-metrics": "3.3.0",
42
- "@webex/test-helper-chai": "3.3.0",
43
- "@webex/test-helper-mock-webex": "3.3.0",
44
- "@webex/webex-core": "3.3.0",
41
+ "@webex/internal-plugin-metrics": "3.3.1-next.10",
42
+ "@webex/test-helper-chai": "3.3.1-next.10",
43
+ "@webex/test-helper-mock-webex": "3.3.1-next.10",
44
+ "@webex/webex-core": "3.3.1-next.10",
45
45
  "ip-anonymize": "^0.1.0",
46
46
  "lodash": "^4.17.21",
47
47
  "uuid": "^3.3.2"
@@ -54,5 +54,5 @@
54
54
  "test:style": "eslint ./src/**/*.*",
55
55
  "test:unit": "webex-legacy-tools test --unit --runner mocha"
56
56
  },
57
- "version": "3.3.0"
57
+ "version": "3.3.1-next.10"
58
58
  }
@@ -0,0 +1,179 @@
1
+ import {merge} from 'lodash';
2
+ import {BrowserDetection} from '@webex/common';
3
+ import {StatelessWebexPlugin} from '@webex/webex-core';
4
+ import {getOSNameInternal} from '../metrics';
5
+ import {BEHAVIORAL_LOG_IDENTIFIER} from './config';
6
+ import {
7
+ MetricEventProduct,
8
+ MetricEventAgent,
9
+ MetricEventVerb,
10
+ BehavioralEventContext,
11
+ BehavioralEvent,
12
+ BehavioralEventPayload,
13
+ } from '../metrics.types';
14
+ import ClientMetricsBatcher from '../client-metrics-batcher';
15
+
16
+ const {getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
17
+
18
+ /**
19
+ * @description Util class to handle Behavioral Metrics
20
+ * @export
21
+ * @class BehavioralMetrics
22
+ */
23
+ export default class BehavioralMetrics extends StatelessWebexPlugin {
24
+ // @ts-ignore
25
+ private clientMetricsBatcher: ClientMetricsBatcher;
26
+ private logger: any; // to avoid adding @ts-ignore everywhere
27
+ private device: any;
28
+ private version: string;
29
+
30
+ /**
31
+ * Constructor
32
+ * @param {any[]} args
33
+ */
34
+ constructor(...args) {
35
+ super(...args);
36
+ // @ts-ignore
37
+ this.logger = this.webex.logger;
38
+ // @ts-ignore
39
+ this.device = this.webex.internal.device;
40
+ // @ts-ignore
41
+ this.version = this.webex.version;
42
+ // @ts-ignore
43
+ this.clientMetricsBatcher = new ClientMetricsBatcher({}, {parent: this.webex});
44
+ }
45
+
46
+ /**
47
+ * Returns the deviceId from our registration with WDM.
48
+ * @returns {string} deviceId or empty string
49
+ */
50
+ private getDeviceId(): string {
51
+ const {url} = this.device;
52
+ if (url && url.length !== 0) {
53
+ const n = url.lastIndexOf('/');
54
+ if (n !== -1) {
55
+ return url.substring(n + 1);
56
+ }
57
+ }
58
+
59
+ return '';
60
+ }
61
+
62
+ /**
63
+ * Returns the context object to be submitted with all behavioral metrics.
64
+ * @returns {BehavioralEventContext}
65
+ */
66
+ private getContext(): BehavioralEventContext {
67
+ const context: BehavioralEventContext = {
68
+ app: {
69
+ version: this.version,
70
+ },
71
+ device: {
72
+ id: this.getDeviceId(),
73
+ },
74
+ locale: window.navigator.language,
75
+ os: {
76
+ name: getOSNameInternal(),
77
+ version: getOSVersion(),
78
+ },
79
+ };
80
+
81
+ return context;
82
+ }
83
+
84
+ /**
85
+ * Returns the default tags to be included with all behavioral metrics.
86
+ * @returns {BehavioralEventPayload}
87
+ */
88
+ private getDefaultTags(): BehavioralEventPayload {
89
+ const tags = {
90
+ browser: getBrowserName(),
91
+ browserHeight: window.innerHeight,
92
+ browserVersion: getBrowserVersion(),
93
+ browserWidth: window.innerWidth,
94
+ domain: window.location.hostname,
95
+ inIframe: window.self !== window.top,
96
+ locale: window.navigator.language,
97
+ os: getOSNameInternal(),
98
+ };
99
+
100
+ return tags;
101
+ }
102
+
103
+ /**
104
+ * Creates the object to send to our metrics endpoint for a behavioral event
105
+ * @param {MetricEventProduct} product
106
+ * @param {MetricEventAgent} agent
107
+ * @param {string} target
108
+ * @param {MetricEventVerb} verb
109
+ * @returns {BehavioralEventPayload}
110
+ */
111
+ private createEventObject({
112
+ product,
113
+ agent,
114
+ target,
115
+ verb,
116
+ payload,
117
+ }: {
118
+ product: MetricEventProduct;
119
+ agent: MetricEventAgent;
120
+ target: string;
121
+ verb: MetricEventVerb;
122
+ payload?: BehavioralEventPayload;
123
+ }): BehavioralEvent {
124
+ const metricName = `${product}.${agent}.${target}.${verb}`;
125
+ let allTags: BehavioralEventPayload = payload;
126
+ allTags = merge(allTags, this.getDefaultTags());
127
+
128
+ const event: BehavioralEvent = {
129
+ context: this.getContext(),
130
+ metricName,
131
+ tags: allTags,
132
+ timestamp: Date.now(),
133
+ type: ['behavioral'],
134
+ };
135
+
136
+ return event;
137
+ }
138
+
139
+ /**
140
+ * Returns true once we're ready to submit behavioral metrics, after startup.
141
+ * @returns {boolean} true when deviceId is defined and non-empty
142
+ */
143
+ public isReadyToSubmitBehavioralEvents(): boolean {
144
+ const deviceId = this.getDeviceId();
145
+
146
+ return deviceId && deviceId.length !== 0;
147
+ }
148
+
149
+ /**
150
+ * Submit a behavioral metric to our metrics endpoint.
151
+ * @param {MetricEventProduct} product the product from which the metric is being submitted, e.g. 'webex' web client, 'wxcc_desktop'
152
+ * @param {MetricEventAgent} agent the source of the action for this metric
153
+ * @param {string} target the 'thing' that this metric includes information about
154
+ * @param {MetricEventVerb} verb the action that this metric includes information about
155
+ * @param {BehavioralEventPayload} payload information specific to this event. This should be flat, i.e. it should not include nested objects.
156
+ * @returns {Promise<any>}
157
+ */
158
+ public submitBehavioralEvent({
159
+ product,
160
+ agent,
161
+ target,
162
+ verb,
163
+ payload,
164
+ }: {
165
+ product: MetricEventProduct;
166
+ agent: MetricEventAgent;
167
+ target: string;
168
+ verb: MetricEventVerb;
169
+ payload?: BehavioralEventPayload;
170
+ }) {
171
+ this.logger.log(
172
+ BEHAVIORAL_LOG_IDENTIFIER,
173
+ `BehavioralMetrics: @submitBehavioralEvent. Submit Behavioral event: ${product}.${agent}.${target}.${verb}`
174
+ );
175
+ const behavioralEvent = this.createEventObject({product, agent, target, verb, payload});
176
+
177
+ return this.clientMetricsBatcher.request(behavioralEvent);
178
+ }
179
+ }
@@ -0,0 +1,3 @@
1
+ /* eslint-disable import/prefer-default-export */
2
+
3
+ export const BEHAVIORAL_LOG_IDENTIFIER = 'behavioral-events -> ';
@@ -21,6 +21,7 @@ import {
21
21
  MISSING_ROAP_ANSWER_CLIENT_CODE,
22
22
  WBX_APP_API_URL,
23
23
  ERROR_DESCRIPTIONS,
24
+ ICE_AND_REACHABILITY_FAILED_CLIENT_CODE,
24
25
  } from './config';
25
26
 
26
27
  const {getOSName, getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
@@ -225,7 +226,7 @@ export const getBuildType = (
225
226
  */
226
227
  export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
227
228
  const origin: Partial<Event['origin']> = {
228
- buildType: exports.getBuildType(
229
+ buildType: getBuildType(
229
230
  item.eventPayload?.event?.eventData?.webClientDomain,
230
231
  item.eventPayload?.event?.eventData?.markAsTestEvent
231
232
  ),
@@ -284,6 +285,8 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
284
285
 
285
286
  case 'client.media.rx.start':
286
287
  joinTimes.localSDPGenRemoteSDPRecv = cdl.getLocalSDPGenRemoteSDPRecv();
288
+ audioSetupDelay.joinRespRxStart = cdl.getAudioJoinRespRxStart();
289
+ videoSetupDelay.joinRespRxStart = cdl.getVideoJoinRespRxStart();
287
290
  break;
288
291
 
289
292
  case 'client.media-engine.ready':
@@ -293,10 +296,8 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
293
296
  joinTimes.stayLobbyTime = cdl.getStayLobbyTime();
294
297
  break;
295
298
 
296
- case 'client.mediaquality.event':
297
- audioSetupDelay.joinRespRxStart = cdl.getAudioJoinRespRxStart();
299
+ case 'client.media.tx.start':
298
300
  audioSetupDelay.joinRespTxStart = cdl.getAudioJoinRespTxStart();
299
- videoSetupDelay.joinRespRxStart = cdl.getVideoJoinRespRxStart();
300
301
  videoSetupDelay.joinRespTxStart = cdl.getVideoJoinRespTxStart();
301
302
  }
302
303
 
@@ -314,7 +315,6 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
314
315
 
315
316
  item.eventPayload.origin = Object.assign(origin, item.eventPayload.origin);
316
317
 
317
- // @ts-ignore
318
318
  webex.logger.log(
319
319
  `CallDiagnosticLatencies,prepareDiagnosticMetricItem: ${JSON.stringify({
320
320
  latencies: Object.fromEntries(cdl.latencyTimestamps),
@@ -370,12 +370,14 @@ export const extractVersionMetadata = (version: string) => {
370
370
  */
371
371
  export const generateClientErrorCodeForIceFailure = ({
372
372
  signalingState,
373
- iceConnectionState,
373
+ iceConnected,
374
374
  turnServerUsed,
375
+ unreachable,
375
376
  }: {
376
377
  signalingState: RTCPeerConnection['signalingState'];
377
- iceConnectionState: RTCPeerConnection['iceConnectionState'];
378
+ iceConnected: boolean;
378
379
  turnServerUsed: boolean;
380
+ unreachable: boolean;
379
381
  }) => {
380
382
  let errorCode = ICE_FAILURE_CLIENT_CODE; // default;
381
383
 
@@ -383,20 +385,17 @@ export const generateClientErrorCodeForIceFailure = ({
383
385
  errorCode = MISSING_ROAP_ANSWER_CLIENT_CODE;
384
386
  }
385
387
 
386
- if (
387
- signalingState === 'stable' &&
388
- (iceConnectionState === 'connected' || iceConnectionState === 'disconnected')
389
- ) {
388
+ if (signalingState === 'stable' && iceConnected) {
390
389
  errorCode = DTLS_HANDSHAKE_FAILED_CLIENT_CODE;
391
390
  }
392
391
 
393
- if (
394
- signalingState !== 'have-local-offer' &&
395
- iceConnectionState !== 'connected' &&
396
- iceConnectionState !== 'disconnected'
397
- ) {
392
+ if (signalingState !== 'have-local-offer' && !iceConnected) {
398
393
  if (turnServerUsed) {
399
- errorCode = ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE;
394
+ if (unreachable) {
395
+ errorCode = ICE_AND_REACHABILITY_FAILED_CLIENT_CODE;
396
+ } else {
397
+ errorCode = ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE;
398
+ }
400
399
  } else {
401
400
  errorCode = ICE_FAILED_WITHOUT_TURN_TLS_CLIENT_CODE;
402
401
  }
@@ -16,6 +16,7 @@ export const MISSING_ROAP_ANSWER_CLIENT_CODE = 2007;
16
16
  export const DTLS_HANDSHAKE_FAILED_CLIENT_CODE = 2008;
17
17
  export const ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE = 2010;
18
18
  export const ICE_FAILED_WITHOUT_TURN_TLS_CLIENT_CODE = 2009;
19
+ export const ICE_AND_REACHABILITY_FAILED_CLIENT_CODE = 2011;
19
20
  export const WBX_APP_API_URL = 'wbxappapi'; // MeetingInfo WebexAppApi response object normally contains a body.url that includes the string 'wbxappapi'
20
21
 
21
22
  export const WEBEX_SUB_SERVICE_TYPES: Record<string, ClientSubServiceType> = {
@@ -125,6 +126,7 @@ export const ERROR_DESCRIPTIONS = {
125
126
  DTLS_HANDSHAKE_FAILED: 'DTLSHandshakeFailed',
126
127
  ICE_FAILED_WITHOUT_TURN_TLS: 'ICEFailedWithoutTURN_TLS',
127
128
  ICE_FAILED_WITH_TURN_TLS: 'ICEFailedWithTURN_TLS',
129
+ ICE_AND_REACHABILITY_FAILED: 'ICEAndReachabilityFailed',
128
130
  SDP_OFFER_CREATION_ERROR: 'SdpOfferCreationError',
129
131
  SDP_OFFER_CREATION_ERROR_MISSING_CODEC: 'SdpOfferCreationErrorMissingCodec',
130
132
  };
@@ -377,7 +379,7 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEv
377
379
  },
378
380
  [MISSING_ROAP_ANSWER_CLIENT_CODE]: {
379
381
  errorDescription: ERROR_DESCRIPTIONS.MISSING_ROAP_ANSWER,
380
- category: 'signaling',
382
+ category: 'media',
381
383
  fatal: true,
382
384
  },
383
385
  [DTLS_HANDSHAKE_FAILED_CLIENT_CODE]: {
@@ -392,7 +394,12 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEv
392
394
  },
393
395
  [ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE]: {
394
396
  errorDescription: ERROR_DESCRIPTIONS.ICE_FAILED_WITH_TURN_TLS,
395
- category: 'network',
397
+ category: 'media',
398
+ fatal: true,
399
+ },
400
+ [ICE_AND_REACHABILITY_FAILED_CLIENT_CODE]: {
401
+ errorDescription: ERROR_DESCRIPTIONS.ICE_AND_REACHABILITY_FAILED,
402
+ category: 'expected',
396
403
  fatal: true,
397
404
  },
398
405
  2050: {
package/src/index.ts CHANGED
@@ -22,6 +22,7 @@ import * as CALL_DIAGNOSTIC_CONFIG from './call-diagnostic/config';
22
22
  import * as CallDiagnosticUtils from './call-diagnostic/call-diagnostic-metrics.util';
23
23
  import CallDiagnosticMetrics from './call-diagnostic/call-diagnostic-metrics';
24
24
  import CallDiagnosticLatencies from './call-diagnostic/call-diagnostic-metrics-latencies';
25
+ import BehavioralMetrics from './behavioral/behavioral-metrics';
25
26
 
26
27
  registerInternalPlugin('metrics', Metrics, {
27
28
  config,
@@ -41,6 +42,7 @@ export {
41
42
  CallDiagnosticUtils,
42
43
  CallDiagnosticLatencies,
43
44
  CallDiagnosticMetrics,
45
+ BehavioralMetrics,
44
46
  };
45
47
  export type {
46
48
  ClientEvent,
@@ -20,6 +20,39 @@ export type BrowserLaunchMethodType = NonNullable<
20
20
  RawEvent['origin']['clientInfo']
21
21
  >['browserLaunchMethod'];
22
22
 
23
+ export type MetricEventProduct = 'webex' | 'wxcc_desktop';
24
+
25
+ export type MetricEventAgent = 'user' | 'browser' | 'system' | 'sdk' | 'redux' | 'service';
26
+
27
+ export type MetricEventVerb =
28
+ | 'create'
29
+ | 'get'
30
+ | 'fetch'
31
+ | 'update'
32
+ | 'list'
33
+ | 'delete'
34
+ | 'select'
35
+ | 'view'
36
+ | 'set'
37
+ | 'toggle'
38
+ | 'load'
39
+ | 'reload'
40
+ | 'click'
41
+ | 'hover'
42
+ | 'register'
43
+ | 'unregister'
44
+ | 'enable'
45
+ | 'disable'
46
+ | 'use'
47
+ | 'complete'
48
+ | 'submit'
49
+ | 'apply'
50
+ | 'cancel'
51
+ | 'abort'
52
+ | 'sync'
53
+ | 'login'
54
+ | 'logout';
55
+
23
56
  export type SubmitClientEventOptions = {
24
57
  meetingId?: string;
25
58
  mediaConnections?: any[];
@@ -66,13 +99,26 @@ export interface ClientEvent {
66
99
  options?: SubmitClientEventOptions;
67
100
  }
68
101
 
102
+ export interface BehavioralEventContext {
103
+ app: {version: string};
104
+ device: {id: string};
105
+ locale: string;
106
+ os: {
107
+ name: string;
108
+ version: string;
109
+ };
110
+ }
111
+
69
112
  export interface BehavioralEvent {
70
- // TODO: not implemented
71
- name: 'host.meeting.participant.admitted' | 'sdk.media-flow.started';
72
- payload?: never;
73
- options?: never;
113
+ context: BehavioralEventContext;
114
+ metricName: string;
115
+ tags: Record<string, string | number | boolean>;
116
+ timestamp: number;
117
+ type: string[];
74
118
  }
75
119
 
120
+ export type BehavioralEventPayload = BehavioralEvent['tags'];
121
+
76
122
  export interface OperationalEvent {
77
123
  // TODO: not implemented
78
124
  name: never;
@@ -104,7 +150,7 @@ export type RecursivePartial<T> = {
104
150
  export type MetricEventNames =
105
151
  | InternalEvent['name']
106
152
  | ClientEvent['name']
107
- | BehavioralEvent['name']
153
+ | BehavioralEvent['metricName']
108
154
  | OperationalEvent['name']
109
155
  | FeatureEvent['name']
110
156
  | MediaQualityEvent['name'];
@@ -137,9 +183,11 @@ export type SubmitInternalEvent = (args: {
137
183
  }) => void;
138
184
 
139
185
  export type SubmitBehavioralEvent = (args: {
140
- name: BehavioralEvent['name'];
141
- payload?: RecursivePartial<BehavioralEvent['payload']>;
142
- options?: any;
186
+ product: MetricEventProduct;
187
+ agent: MetricEventAgent;
188
+ target: string;
189
+ verb: MetricEventVerb;
190
+ payload?: BehavioralEventPayload;
143
191
  }) => void;
144
192
 
145
193
  export type SubmitClientEvent = (args: {
@@ -6,11 +6,15 @@
6
6
  import {WebexPlugin} from '@webex/webex-core';
7
7
 
8
8
  import CallDiagnosticMetrics from './call-diagnostic/call-diagnostic-metrics';
9
+ import BehavioralMetrics from './behavioral/behavioral-metrics';
9
10
  import {
10
11
  RecursivePartial,
12
+ MetricEventProduct,
13
+ MetricEventAgent,
14
+ MetricEventVerb,
11
15
  ClientEvent,
12
16
  FeatureEvent,
13
- BehavioralEvent,
17
+ BehavioralEventPayload,
14
18
  OperationalEvent,
15
19
  MediaQualityEvent,
16
20
  InternalEvent,
@@ -32,6 +36,7 @@ class Metrics extends WebexPlugin {
32
36
  callDiagnosticLatencies: CallDiagnosticLatencies;
33
37
  // Helper classes to handle the different types of metrics
34
38
  callDiagnosticMetrics: CallDiagnosticMetrics;
39
+ behavioralMetrics: BehavioralMetrics;
35
40
 
36
41
  /**
37
42
  * Constructor
@@ -56,6 +61,8 @@ class Metrics extends WebexPlugin {
56
61
  this.webex.once('ready', () => {
57
62
  // @ts-ignore
58
63
  this.callDiagnosticMetrics = new CallDiagnosticMetrics({}, {parent: this.webex});
64
+ // @ts-ignore
65
+ this.behavioralMetrics = new BehavioralMetrics({}, {parent: this.webex});
59
66
  });
60
67
  }
61
68
 
@@ -79,21 +86,40 @@ class Metrics extends WebexPlugin {
79
86
  }
80
87
  }
81
88
 
89
+ /**
90
+ * @returns true once we have the deviceId we need to submit behavioral events to Amplitude
91
+ */
92
+ isReadyToSubmitBehavioralEvents() {
93
+ return this.behavioralMetrics.isReadyToSubmitBehavioralEvents();
94
+ }
95
+
82
96
  /**
83
97
  * Behavioral event
84
98
  * @param args
85
99
  */
86
100
  submitBehavioralEvent({
87
- name,
101
+ product,
102
+ agent,
103
+ target,
104
+ verb,
88
105
  payload,
89
- options,
90
106
  }: {
91
- name: BehavioralEvent['name'];
92
- payload?: RecursivePartial<BehavioralEvent['payload']>;
93
- options?: any;
107
+ product: MetricEventProduct;
108
+ agent: MetricEventAgent;
109
+ target: string;
110
+ verb: MetricEventVerb;
111
+ payload?: BehavioralEventPayload;
94
112
  }) {
95
- this.callDiagnosticLatencies.saveTimestamp({key: name});
96
- throw new Error('Not implemented.');
113
+ if (!this.behavioralMetrics) {
114
+ // @ts-ignore
115
+ this.webex.logger.log(
116
+ `NewMetrics: @submitBehavioralEvent. Attempted to submit before webex.ready: ${product}.${agent}.${target}.${verb}`
117
+ );
118
+
119
+ return Promise.resolve();
120
+ }
121
+
122
+ return this.behavioralMetrics.submitBehavioralEvent({product, agent, target, verb, payload});
97
123
  }
98
124
 
99
125
  /**