@webex/internal-plugin-metrics 3.8.0 → 3.8.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 (35) hide show
  1. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +49 -0
  2. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
  3. package/dist/call-diagnostic/call-diagnostic-metrics.js +301 -81
  4. package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
  5. package/dist/call-diagnostic/call-diagnostic-metrics.util.js +6 -0
  6. package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
  7. package/dist/call-diagnostic/config.js +32 -3
  8. package/dist/call-diagnostic/config.js.map +1 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/metrics.js +1 -1
  11. package/dist/metrics.types.js.map +1 -1
  12. package/dist/new-metrics.js +58 -5
  13. package/dist/new-metrics.js.map +1 -1
  14. package/dist/types/call-diagnostic/call-diagnostic-metrics-latencies.d.ts +15 -0
  15. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +154 -24
  16. package/dist/types/call-diagnostic/config.d.ts +14 -0
  17. package/dist/types/index.d.ts +2 -2
  18. package/dist/types/metrics.types.d.ts +28 -7
  19. package/dist/types/new-metrics.d.ts +28 -4
  20. package/package.json +12 -12
  21. package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +58 -0
  22. package/src/call-diagnostic/call-diagnostic-metrics.ts +294 -66
  23. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +6 -0
  24. package/src/call-diagnostic/config.ts +31 -0
  25. package/src/index.ts +4 -0
  26. package/src/metrics.types.ts +36 -6
  27. package/src/new-metrics.ts +73 -5
  28. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +20 -1
  29. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +167 -0
  30. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +1054 -153
  31. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +6 -0
  32. package/test/unit/spec/new-metrics.ts +94 -5
  33. package/test/unit/spec/prelogin-metrics-batcher.ts +1 -0
  34. package/dist/call-diagnostic-events-batcher.js +0 -59
  35. package/dist/call-diagnostic-events-batcher.js.map +0 -1
@@ -41,6 +41,9 @@ import {
41
41
  ClientSubServiceType,
42
42
  BrowserLaunchMethodType,
43
43
  DelayedClientEvent,
44
+ DelayedClientFeatureEvent,
45
+ FeatureEvent,
46
+ ClientFeatureEventPayload,
44
47
  } from '../metrics.types';
45
48
  import CallDiagnosticEventsBatcher from './call-diagnostic-metrics-batcher';
46
49
  import PreLoginMetricsBatcher from '../prelogin-metrics-batcher';
@@ -58,6 +61,8 @@ import {
58
61
  AUTHENTICATION_FAILED_CODE,
59
62
  WEBEX_SUB_SERVICE_TYPES,
60
63
  SDP_OFFER_CREATION_ERROR_MAP,
64
+ CALL_FEATURE_LOG_IDENTIFIER,
65
+ CALL_FEATURE_EVENT_FAILED_TO_SEND,
61
66
  } from './config';
62
67
 
63
68
  const {getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
@@ -97,6 +102,9 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
97
102
  private hasLoggedBrowserSerial: boolean;
98
103
  private device: any;
99
104
  private delayedClientEvents: DelayedClientEvent[] = [];
105
+ private delayedClientFeatureEvents: DelayedClientFeatureEvent[] = [];
106
+ private eventErrorCache: WeakMap<any, any> = new WeakMap();
107
+ private isMercuryConnected = false;
100
108
 
101
109
  // the default validator before piping an event to the batcher
102
110
  // this function can be overridden by the user
@@ -149,6 +157,16 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
149
157
  return undefined;
150
158
  }
151
159
 
160
+ /**
161
+ * Sets mercury connected status for event data object in CA events
162
+ * @public
163
+ * @param status - boolean value indicating mercury connection status
164
+ * @return {void}
165
+ */
166
+ public setMercuryConnectedStatus(status: boolean): void {
167
+ this.isMercuryConnected = status;
168
+ }
169
+
152
170
  /**
153
171
  * Returns meeting's subServiceType
154
172
  * @param meeting
@@ -166,23 +184,17 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
166
184
  if (meetingInfo?.webexScheduled && !meetingInfo?.enableEvent && !meetingInfo?.pmr) {
167
185
  return WEBEX_SUB_SERVICE_TYPES.SCHEDULED_MEETING;
168
186
  }
169
- // if Scheduled, Webinar, not pmr - then Webinar
170
- if (
171
- meetingInfo?.webexScheduled &&
172
- meetingInfo?.enableEvent &&
173
- !meetingInfo?.pmr &&
174
- meetingInfo?.isConvergedWebinar
175
- ) {
176
- return WEBEX_SUB_SERVICE_TYPES.WEBINAR;
187
+
188
+ // if ConvergedArchitecture enable and isConvergedWebinarWebcast -- then webcast
189
+ if (meetingInfo?.enableConvergedArchitecture && meetingInfo?.enableEvent) {
190
+ return meetingInfo?.isConvergedWebinarWebcast
191
+ ? WEBEX_SUB_SERVICE_TYPES.WEBCAST
192
+ : WEBEX_SUB_SERVICE_TYPES.WEBINAR;
177
193
  }
178
- // if Scheduled, Webinar enable webcast - then webcast
179
- if (
180
- meetingInfo?.webexScheduled &&
181
- meetingInfo?.enableEvent &&
182
- !meetingInfo?.pmr &&
183
- meetingInfo?.isConvergedWebinarWebcast
184
- ) {
185
- return WEBEX_SUB_SERVICE_TYPES.WEBCAST;
194
+
195
+ // if Scheduled, enable event, not pmr - then Webinar
196
+ if (meetingInfo?.webexScheduled && meetingInfo?.enableEvent && !meetingInfo?.pmr) {
197
+ return WEBEX_SUB_SERVICE_TYPES.WEBINAR;
186
198
  }
187
199
  }
188
200
 
@@ -421,12 +433,97 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
421
433
  }
422
434
 
423
435
  /**
424
- * TODO: NOT IMPLEMENTED
436
+ * Create feature event
437
+ * @param name
438
+ * @param payload
439
+ * @param options
440
+ * @returns
441
+ */
442
+ private prepareClientFeatureEvent({
443
+ name,
444
+ payload,
445
+ options,
446
+ }: {
447
+ name: FeatureEvent['name'];
448
+ payload?: ClientFeatureEventPayload;
449
+ options?: SubmitClientEventOptions;
450
+ }) {
451
+ const {meetingId, correlationId} = options;
452
+ let featureEventObject: FeatureEvent['payload'];
453
+
454
+ // events that will most likely happen in join phase
455
+ if (meetingId) {
456
+ featureEventObject = this.createFeatureEventObjectInMeeting({name, options});
457
+ } else {
458
+ throw new Error('Not implemented');
459
+ }
460
+
461
+ // merge any new properties, or override existing ones
462
+ featureEventObject = merge(featureEventObject, payload);
463
+
464
+ // append client event data to the call diagnostic event
465
+ const featureEvent = this.prepareDiagnosticEvent(featureEventObject, options);
466
+
467
+ return featureEvent;
468
+ }
469
+
470
+ /**
425
471
  * Submit Feature Event
472
+ * submit to business_ucf
426
473
  * @returns
427
474
  */
428
- public submitFeatureEvent() {
429
- throw Error('Not implemented');
475
+ public submitFeatureEvent({
476
+ name,
477
+ payload,
478
+ options,
479
+ delaySubmitEvent,
480
+ }: {
481
+ name: FeatureEvent['name'];
482
+ payload?: ClientFeatureEventPayload;
483
+ options?: SubmitClientEventOptions;
484
+ delaySubmitEvent?: boolean;
485
+ }) {
486
+ if (delaySubmitEvent) {
487
+ // Preserve the time when the event was triggered if delaying the submission to Call Features
488
+ const delayedOptions = {
489
+ ...options,
490
+ triggeredTime: new Date().toISOString(),
491
+ };
492
+
493
+ this.delayedClientFeatureEvents.push({
494
+ name,
495
+ payload,
496
+ options: delayedOptions,
497
+ });
498
+
499
+ return Promise.resolve();
500
+ }
501
+
502
+ this.logger.log(
503
+ CALL_FEATURE_LOG_IDENTIFIER,
504
+ 'CallFeatureMetrics: @submitFeatureEvent. Submit Client Feature Event CA event.',
505
+ `name: ${name}`
506
+ );
507
+ const featureEvent = this.prepareClientFeatureEvent({name, payload, options});
508
+
509
+ this.validator({type: 'ce', event: featureEvent});
510
+
511
+ return this.submitToCallFeatures(featureEvent);
512
+ }
513
+
514
+ /**
515
+ * Submit Feature Event
516
+ * type is business
517
+ * @param event
518
+ */
519
+ submitToCallFeatures(event: Event): Promise<any> {
520
+ // build metrics-a event type
521
+ const finalEvent = {
522
+ eventPayload: event,
523
+ type: ['business'],
524
+ };
525
+
526
+ return this.callDiagnosticEventsBatcher.request(finalEvent);
430
527
  }
431
528
 
432
529
  /**
@@ -561,16 +658,31 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
561
658
  return undefined;
562
659
  }
563
660
 
661
+ /**
662
+ * Clear the error cache
663
+ */
664
+ clearErrorCache() {
665
+ this.eventErrorCache = new WeakMap();
666
+ }
667
+
564
668
  /**
565
669
  * Generate error payload for Client Event
566
670
  * @param rawError
567
671
  */
568
672
  generateClientEventErrorPayload(rawError: any) {
673
+ const cachedError = this.eventErrorCache.get(rawError);
674
+
675
+ if (cachedError) {
676
+ return [cachedError, true];
677
+ }
678
+
569
679
  const rawErrorMessage = rawError.message;
570
680
  const httpStatusCode = rawError.statusCode;
681
+ let payload;
682
+
571
683
  if (rawError.name) {
572
684
  if (isBrowserMediaErrorName(rawError.name)) {
573
- return this.getErrorPayloadForClientErrorCode({
685
+ payload = this.getErrorPayloadForClientErrorCode({
574
686
  serviceErrorCode: undefined,
575
687
  clientErrorCode: BROWSER_MEDIA_ERROR_NAME_TO_CLIENT_ERROR_CODES_MAP[rawError.name],
576
688
  serviceErrorName: rawError.name,
@@ -580,11 +692,11 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
580
692
  }
581
693
  }
582
694
 
583
- if (isSdpOfferCreationError(rawError)) {
695
+ if (isSdpOfferCreationError(rawError) && !payload) {
584
696
  // error code is 30005, but that's not specific enough. we also need to check error.cause.type
585
697
  const causeType = rawError.cause?.type;
586
698
 
587
- return this.getErrorPayloadForClientErrorCode({
699
+ payload = this.getErrorPayloadForClientErrorCode({
588
700
  serviceErrorCode: undefined,
589
701
  clientErrorCode:
590
702
  SDP_OFFER_CREATION_ERROR_MAP[causeType] || SDP_OFFER_CREATION_ERROR_MAP.GENERAL,
@@ -602,8 +714,8 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
602
714
 
603
715
  if (serviceErrorCode) {
604
716
  const clientErrorCode = SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP[serviceErrorCode];
605
- if (clientErrorCode) {
606
- return this.getErrorPayloadForClientErrorCode({
717
+ if (clientErrorCode && !payload) {
718
+ payload = this.getErrorPayloadForClientErrorCode({
607
719
  clientErrorCode,
608
720
  serviceErrorCode,
609
721
  rawErrorMessage,
@@ -612,8 +724,8 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
612
724
  }
613
725
 
614
726
  // by default, if it is locus error, return new locus err
615
- if (isLocusServiceErrorCode(serviceErrorCode)) {
616
- return this.getErrorPayloadForClientErrorCode({
727
+ if (isLocusServiceErrorCode(serviceErrorCode) && !payload) {
728
+ payload = this.getErrorPayloadForClientErrorCode({
617
729
  clientErrorCode: NEW_LOCUS_ERROR_CLIENT_CODE,
618
730
  serviceErrorCode,
619
731
  rawErrorMessage,
@@ -622,8 +734,8 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
622
734
  }
623
735
  }
624
736
 
625
- if (isMeetingInfoServiceError(rawError)) {
626
- return this.getErrorPayloadForClientErrorCode({
737
+ if (isMeetingInfoServiceError(rawError) && !payload) {
738
+ payload = this.getErrorPayloadForClientErrorCode({
627
739
  clientErrorCode: MEETING_INFO_LOOKUP_ERROR_CLIENT_CODE,
628
740
  serviceErrorCode,
629
741
  rawErrorMessage,
@@ -631,8 +743,8 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
631
743
  });
632
744
  }
633
745
 
634
- if (isNetworkError(rawError)) {
635
- return this.getErrorPayloadForClientErrorCode({
746
+ if (isNetworkError(rawError) && !payload) {
747
+ payload = this.getErrorPayloadForClientErrorCode({
636
748
  clientErrorCode: NETWORK_ERROR,
637
749
  serviceErrorCode,
638
750
  payloadOverrides: rawError.payloadOverrides,
@@ -641,8 +753,8 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
641
753
  });
642
754
  }
643
755
 
644
- if (isUnauthorizedError(rawError)) {
645
- return this.getErrorPayloadForClientErrorCode({
756
+ if (isUnauthorizedError(rawError) && !payload) {
757
+ payload = this.getErrorPayloadForClientErrorCode({
646
758
  clientErrorCode: AUTHENTICATION_FAILED_CODE,
647
759
  serviceErrorCode,
648
760
  payloadOverrides: rawError.payloadOverrides,
@@ -651,32 +763,39 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
651
763
  });
652
764
  }
653
765
 
654
- // otherwise return unkown error but passing serviceErrorCode and serviceErrorName so that we know the issue
655
- return this.getErrorPayloadForClientErrorCode({
656
- clientErrorCode: UNKNOWN_ERROR,
657
- serviceErrorCode: serviceErrorCode || UNKNOWN_ERROR,
658
- serviceErrorName: rawError?.name,
659
- payloadOverrides: rawError.payloadOverrides,
660
- rawErrorMessage,
661
- httpStatusCode,
662
- });
766
+ if (!payload) {
767
+ // otherwise return unkown error but passing serviceErrorCode and serviceErrorName so that we know the issue
768
+ payload = this.getErrorPayloadForClientErrorCode({
769
+ clientErrorCode: UNKNOWN_ERROR,
770
+ serviceErrorCode: serviceErrorCode || UNKNOWN_ERROR,
771
+ serviceErrorName: rawError?.name,
772
+ payloadOverrides: rawError.payloadOverrides,
773
+ rawErrorMessage,
774
+ httpStatusCode,
775
+ });
776
+ }
777
+
778
+ // cache the payload for future use
779
+ this.eventErrorCache.set(rawError, payload);
780
+
781
+ return [payload, false];
663
782
  }
664
783
 
665
784
  /**
666
- * Create client event object for in meeting events
667
- * @param arg - create args
668
- * @param arg.event - event key
669
- * @param arg.options - options
785
+ * Create common object for in meeting events
786
+ * @param name
787
+ * @param options
788
+ * @param eventType - 'client' | 'feature'
670
789
  * @returns object
671
790
  */
672
- private createClientEventObjectInMeeting({
791
+ private createCommonEventObjectInMeeting({
673
792
  name,
674
793
  options,
675
- errors,
794
+ eventType = 'client',
676
795
  }: {
677
- name: ClientEvent['name'];
796
+ name: string;
678
797
  options?: SubmitClientEventOptions;
679
- errors?: ClientEventPayloadError;
798
+ eventType?: 'client' | 'feature';
680
799
  }) {
681
800
  const {
682
801
  meetingId,
@@ -691,16 +810,21 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
691
810
 
692
811
  if (!meeting) {
693
812
  console.warn(
694
- 'Attempt to send client event but no meeting was found...',
813
+ 'Attempt to send common event but no meeting was found...',
695
814
  `name: ${name}, meetingId: ${meetingId}`
696
815
  );
697
816
  // @ts-ignore
698
- this.webex.internal.metrics.submitClientMetrics(CALL_DIAGNOSTIC_EVENT_FAILED_TO_SEND, {
699
- fields: {
700
- meetingId,
701
- name,
702
- },
703
- });
817
+ this.webex.internal.metrics.submitClientMetrics(
818
+ eventType === 'feature'
819
+ ? CALL_FEATURE_EVENT_FAILED_TO_SEND
820
+ : CALL_DIAGNOSTIC_EVENT_FAILED_TO_SEND,
821
+ {
822
+ fields: {
823
+ meetingId,
824
+ name,
825
+ },
826
+ }
827
+ );
704
828
 
705
829
  return undefined;
706
830
  }
@@ -714,12 +838,11 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
714
838
  sessionCorrelationId,
715
839
  });
716
840
 
717
- // create client event object
718
- const clientEventObject: ClientEvent['payload'] = {
841
+ // create common event object structur
842
+ const commonEventObject = {
719
843
  name,
720
844
  canProceed: true,
721
845
  identifiers,
722
- errors,
723
846
  eventData: {
724
847
  webClientDomain: window.location.hostname,
725
848
  },
@@ -731,6 +854,8 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
731
854
  isConvergedArchitectureEnabled: this.getIsConvergedArchitectureEnabled({
732
855
  meetingId,
733
856
  }),
857
+ ...(meeting.userNameInput && {userNameInput: meeting.userNameInput}),
858
+ ...(meeting.emailInput && {emailInput: meeting.emailInput}),
734
859
  webexSubServiceType: this.getSubServiceType(meeting),
735
860
  // @ts-ignore
736
861
  webClientPreload: this.webex.meetings?.config?.metrics?.webClientPreload,
@@ -738,14 +863,80 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
738
863
 
739
864
  const joinFlowVersion = options.joinFlowVersion ?? meeting.callStateForMetrics?.joinFlowVersion;
740
865
  if (joinFlowVersion) {
741
- clientEventObject.joinFlowVersion = joinFlowVersion;
866
+ // @ts-ignore
867
+ commonEventObject.joinFlowVersion = joinFlowVersion;
868
+ }
869
+ const meetingJoinedTime = meeting.isoLocalClientMeetingJoinTime;
870
+ if (meetingJoinedTime) {
871
+ // @ts-ignore
872
+ commonEventObject.meetingJoinedTime = meetingJoinedTime;
742
873
  }
743
874
 
744
875
  if (options.meetingJoinPhase) {
745
- clientEventObject.meetingJoinPhase = options.meetingJoinPhase;
876
+ // @ts-ignore
877
+ commonEventObject.meetingJoinPhase = options.meetingJoinPhase;
746
878
  }
747
879
 
748
- return clientEventObject;
880
+ return commonEventObject;
881
+ }
882
+
883
+ /**
884
+ * Create client event object for in meeting events
885
+ * @param arg - create args
886
+ * @param arg.event - event key
887
+ * @param arg.options - options
888
+ * @returns object
889
+ */
890
+ private createClientEventObjectInMeeting({
891
+ name,
892
+ options,
893
+ errors,
894
+ }: {
895
+ name: ClientEvent['name'];
896
+ options?: SubmitClientEventOptions;
897
+ errors?: ClientEventPayloadError;
898
+ }) {
899
+ const commonObject = this.createCommonEventObjectInMeeting({
900
+ name,
901
+ options,
902
+ eventType: 'client',
903
+ });
904
+ if (!commonObject) return undefined;
905
+
906
+ return {
907
+ ...commonObject,
908
+ errors,
909
+ eventData: {
910
+ ...commonObject.eventData,
911
+ isMercuryConnected: this.isMercuryConnected,
912
+ },
913
+ } as ClientEvent['payload'];
914
+ }
915
+
916
+ /**
917
+ * Create feature event object for in meeting function event
918
+ * @param name
919
+ * @param options
920
+ * @returns object
921
+ */
922
+ private createFeatureEventObjectInMeeting({
923
+ name,
924
+ options,
925
+ }: {
926
+ name: FeatureEvent['name'];
927
+ options?: SubmitClientEventOptions;
928
+ }) {
929
+ const commonObject = this.createCommonEventObjectInMeeting({
930
+ name,
931
+ options,
932
+ eventType: 'feature',
933
+ });
934
+ if (!commonObject) return undefined;
935
+
936
+ return {
937
+ ...commonObject,
938
+ key: 'UcfFeatureUsage',
939
+ } as FeatureEvent['payload'];
749
940
  }
750
941
 
751
942
  /**
@@ -784,6 +975,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
784
975
  identifiers,
785
976
  eventData: {
786
977
  webClientDomain: window.location.hostname,
978
+ isMercuryConnected: this.isMercuryConnected,
787
979
  },
788
980
  loginType: this.getCurLoginType(),
789
981
  // @ts-ignore
@@ -798,6 +990,14 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
798
990
  clientEventObject.meetingJoinPhase = options.meetingJoinPhase;
799
991
  }
800
992
 
993
+ if (options.userNameInput) {
994
+ clientEventObject.userNameInput = options.userNameInput;
995
+ }
996
+
997
+ if (options.emailInput) {
998
+ clientEventObject.emailInput = options.emailInput;
999
+ }
1000
+
801
1001
  return clientEventObject;
802
1002
  }
803
1003
 
@@ -826,14 +1026,14 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
826
1026
  const errors: ClientEventPayloadError = [];
827
1027
 
828
1028
  if (rawError) {
829
- const generatedError = this.generateClientEventErrorPayload(rawError);
1029
+ const [generatedError, cached] = this.generateClientEventErrorPayload(rawError);
830
1030
  if (generatedError) {
831
1031
  errors.push(generatedError);
832
1032
  }
833
1033
  this.logger.log(
834
1034
  CALL_DIAGNOSTIC_LOG_IDENTIFIER,
835
1035
  'CallDiagnosticMetrics: @prepareClientEvent. Generated errors:',
836
- `generatedError: ${JSON.stringify(generatedError)}`
1036
+ `generatedError (cached: ${cached}): ${JSON.stringify(generatedError)}`
837
1037
  );
838
1038
  }
839
1039
 
@@ -911,7 +1111,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
911
1111
  /**
912
1112
  * Submit Delayed Client Event CA events. Clears delayedClientEvents array after submission.
913
1113
  */
914
- public submitDelayedClientEvents() {
1114
+ public submitDelayedClientEvents(overrides?: Partial<DelayedClientEvent['options']>) {
915
1115
  this.logger.log(
916
1116
  CALL_DIAGNOSTIC_LOG_IDENTIFIER,
917
1117
  'CallDiagnosticMetrics: @submitDelayedClientEvents. Submitting delayed client events.'
@@ -922,7 +1122,10 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
922
1122
  }
923
1123
 
924
1124
  const promises = this.delayedClientEvents.map((delayedSubmitClientEventParams) => {
925
- return this.submitClientEvent(delayedSubmitClientEventParams);
1125
+ const {name, payload, options} = delayedSubmitClientEventParams;
1126
+ const optionsWithOverrides: DelayedClientEvent['options'] = {...options, ...overrides};
1127
+
1128
+ return this.submitClientEvent({name, payload, options: optionsWithOverrides});
926
1129
  });
927
1130
 
928
1131
  this.delayedClientEvents = [];
@@ -930,6 +1133,31 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
930
1133
  return Promise.all(promises);
931
1134
  }
932
1135
 
1136
+ /**
1137
+ * Submit Delayed feature Event CA events. Clears submitDelayedClientFeatureEvents array after submission.
1138
+ */
1139
+ public submitDelayedClientFeatureEvents(overrides?: Partial<DelayedClientEvent['options']>) {
1140
+ this.logger.log(
1141
+ CALL_FEATURE_LOG_IDENTIFIER,
1142
+ 'CallDiagnosticMetrics: @submitDelayedClientFeatureEvents. Submitting delayed feature events.'
1143
+ );
1144
+
1145
+ if (this.delayedClientFeatureEvents.length === 0) {
1146
+ return Promise.resolve();
1147
+ }
1148
+
1149
+ const promises = this.delayedClientFeatureEvents.map((delayedSubmitClientEventParams) => {
1150
+ const {name, payload, options} = delayedSubmitClientEventParams;
1151
+ const optionsWithOverrides: DelayedClientEvent['options'] = {...options, ...overrides};
1152
+
1153
+ return this.submitFeatureEvent({name, payload, options: optionsWithOverrides});
1154
+ });
1155
+
1156
+ this.delayedClientFeatureEvents = [];
1157
+
1158
+ return Promise.all(promises);
1159
+ }
1160
+
933
1161
  /**
934
1162
  * Prepare the event and send the request to metrics-a service.
935
1163
  * @param event
@@ -257,6 +257,7 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
257
257
  switch (eventName) {
258
258
  case 'client.webexapp.launched':
259
259
  joinTimes.downloadTime = cdl.getDownloadTimeJMT();
260
+ joinTimes.pageJmt = cdl.getPageJMT();
260
261
  break;
261
262
  case 'client.login.end':
262
263
  joinTimes.otherAppApiReqResp = cdl.getOtherAppApiReqResp();
@@ -267,6 +268,7 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
267
268
  joinTimes.clickToInterstitial = cdl.getClickToInterstitial();
268
269
  joinTimes.refreshCaptchaServiceReqResp = cdl.getRefreshCaptchaReqResp();
269
270
  joinTimes.downloadIntelligenceModelsReqResp = cdl.getDownloadIntelligenceModelsReqResp();
271
+ joinTimes.clickToInterstitialWithUserDelay = cdl.getClickToInterstitialWithUserDelay();
270
272
  break;
271
273
 
272
274
  case 'client.call.initiated':
@@ -287,6 +289,8 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
287
289
  joinTimes.totalJmt = cdl.getTotalJMT();
288
290
  joinTimes.clientJmt = cdl.getClientJMT();
289
291
  joinTimes.downloadTime = cdl.getDownloadTimeJMT();
292
+ joinTimes.clickToInterstitialWithUserDelay = cdl.getClickToInterstitialWithUserDelay();
293
+ joinTimes.totalJMTWithUserDelay = cdl.getTotalJMTWithUserDelay();
290
294
  break;
291
295
 
292
296
  case 'client.ice.end':
@@ -307,6 +311,8 @@ export const prepareDiagnosticMetricItem = (webex: any, item: any) => {
307
311
  joinTimes.interstitialToMediaOKJMT = cdl.getInterstitialToMediaOKJMT();
308
312
  joinTimes.callInitMediaEngineReady = cdl.getCallInitMediaEngineReady();
309
313
  joinTimes.stayLobbyTime = cdl.getStayLobbyTime();
314
+ joinTimes.totalMediaJMTWithUserDelay = cdl.getTotalMediaJMTWithUserDelay();
315
+ joinTimes.totalJMTWithUserDelay = cdl.getTotalJMTWithUserDelay();
310
316
  break;
311
317
 
312
318
  case 'client.media.tx.start':
@@ -5,6 +5,7 @@
5
5
  import {ClientEventError, ClientSubServiceType} from '../metrics.types';
6
6
 
7
7
  export const CALL_DIAGNOSTIC_LOG_IDENTIFIER = 'call-diagnostic-events -> ';
8
+ export const CALL_FEATURE_LOG_IDENTIFIER = 'call-diagnostic-events-feature -> ';
8
9
 
9
10
  export const AUTHENTICATION_FAILED_CODE = 1010;
10
11
  export const NETWORK_ERROR = 1026;
@@ -133,6 +134,7 @@ export const ERROR_DESCRIPTIONS = {
133
134
  SDP_OFFER_CREATION_ERROR: 'SdpOfferCreationError',
134
135
  SDP_OFFER_CREATION_ERROR_MISSING_CODEC: 'SdpOfferCreationErrorMissingCodec',
135
136
  WDM_RESTRICTED_REGION: 'WdmRestrictedRegion',
137
+ USER_NOT_ALLOWED_JOIN_WEBINAR: 'UserNotAllowedJoinWebinar',
136
138
  };
137
139
 
138
140
  export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
@@ -151,6 +153,10 @@ export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
151
153
  403004: 4005,
152
154
  // Wrong password. Meeting is not allow to access since password error
153
155
  403028: 4005,
156
+ // meeting is not allow to access since require panelist password
157
+ 403025: 4005,
158
+ // wrong password. Meeting is not allow to access since panelist password error
159
+ 403125: 4005,
154
160
  // Wrong or expired permission. Meeting is not allow to access since permissionToken error or expire
155
161
  403032: 4005,
156
162
  // Meeting is required login for current user
@@ -202,6 +208,24 @@ export const SERVICE_ERROR_CODES_TO_CLIENT_ERROR_CODES_MAP = {
202
208
  423013: 4005,
203
209
  // Too many requests access
204
210
  429005: 4100,
211
+ // Webinar: Meeting registration is required
212
+ 403021: 4104,
213
+ // Webinar: Meeting registration is still pending
214
+ 403022: 4104,
215
+ // Webinar: Meeting registration have been rejected
216
+ 403024: 4104,
217
+ // Webinar: Registration ID verified failure
218
+ 403137: 4104,
219
+ // Webinar: Registration ID input too many time,please input captcha code
220
+ 423007: 4104,
221
+ // Webinar: Need to join meeting via webcast
222
+ 403026: 4104,
223
+ // Webinar: Meeting join required registration ID
224
+ 403037: 4104,
225
+ // Not reach JBH, can't join meeting
226
+ 403003: 4101,
227
+ // Attendee email is required
228
+ 403030: 4101,
205
229
 
206
230
  // ---- Locus ------
207
231
  // FREE_USER_MAX_PARTICIPANTS_EXCEEDED
@@ -666,6 +690,11 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEv
666
690
  category: 'expected',
667
691
  fatal: true,
668
692
  },
693
+ 4104: {
694
+ errorDescription: ERROR_DESCRIPTIONS.USER_NOT_ALLOWED_JOIN_WEBINAR,
695
+ category: 'expected',
696
+ fatal: true,
697
+ },
669
698
  2729: {
670
699
  errorDescription: ERROR_DESCRIPTIONS.NO_MEDIA_FOUND,
671
700
  category: 'expected',
@@ -710,3 +739,5 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEv
710
739
  };
711
740
 
712
741
  export const CALL_DIAGNOSTIC_EVENT_FAILED_TO_SEND = 'js_sdk_call_diagnostic_event_failed_to_send';
742
+
743
+ export const CALL_FEATURE_EVENT_FAILED_TO_SEND = 'js_sdk_call_feature_event_failed_to_send';
package/src/index.ts CHANGED
@@ -15,8 +15,10 @@ import {
15
15
  SubmitClientEvent,
16
16
  SubmitInternalEvent,
17
17
  SubmitOperationalEvent,
18
+ SubmitBusinessEvent,
18
19
  SubmitMQE,
19
20
  PreComputedLatencies,
21
+ SubmitFeatureEvent,
20
22
  } from './metrics.types';
21
23
  import * as CALL_DIAGNOSTIC_CONFIG from './call-diagnostic/config';
22
24
  import * as CallDiagnosticUtils from './call-diagnostic/call-diagnostic-metrics.util';
@@ -58,5 +60,7 @@ export type {
58
60
  SubmitInternalEvent,
59
61
  SubmitMQE,
60
62
  SubmitOperationalEvent,
63
+ SubmitBusinessEvent,
61
64
  PreComputedLatencies,
65
+ SubmitFeatureEvent,
62
66
  };