agora-appbuilder-core 4.1.24-beta.3 → 4.1.25-beta.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agora-appbuilder-core",
3
- "version": "4.1.24-beta.3",
3
+ "version": "4.1.25-beta.1",
4
4
  "description": "React Native template for RTE app builder",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -21,7 +21,6 @@ export {customize, $config};
21
21
  export * from './action-library';
22
22
  export * from './app-state';
23
23
  export * from './customEvents';
24
- export * from './logger';
25
24
  export * from './sub-components';
26
25
  export * from './typeDefinition';
27
26
  export * from './utils';
@@ -77,8 +77,8 @@ const DefaultConfig = {
77
77
  CHAT_ORG_NAME: "",
78
78
  CHAT_APP_NAME: "",
79
79
  CHAT_URL: "",
80
- CLI_VERSION: "3.1.24-beta.3",
81
- CORE_VERSION: "4.1.24-beta.3",
80
+ CLI_VERSION: "3.1.25-beta.1",
81
+ CORE_VERSION: "4.1.25-beta.1",
82
82
  DISABLE_LANDSCAPE_MODE: false,
83
83
  STT_AUTO_START: false,
84
84
  CLOUD_RECORDING_AUTO_START: false,
@@ -137,15 +137,6 @@ const AuthProvider = (props: AuthProviderProps) => {
137
137
  }
138
138
  }, [store?.token]);
139
139
 
140
- // A running native app is already authenticated when it receives a URL
141
- // event, so there may be no later token change to consume returnTo.
142
- useEffect(() => {
143
- if (authenticated && returnTo && (isAndroid() || isIOS())) {
144
- history.push(returnTo);
145
- setReturnTo('');
146
- }
147
- }, [authenticated, history, returnTo]);
148
-
149
140
  const deepLinkUrl = (link: string | null) => {
150
141
  if (link !== null) {
151
142
  if (lifecycle?.onDeepLink?.(link)) {
@@ -38,8 +38,6 @@ export declare const StatusTypes: {
38
38
 
39
39
  export type StatusType = (typeof StatusTypes)[keyof typeof StatusTypes];
40
40
 
41
- export type CustomizationLogType = string;
42
-
43
41
  export enum LogSource {
44
42
  AgoraSDK = 'Agora-SDK',
45
43
  /** Logs related to all features */
@@ -109,7 +107,10 @@ type LogType = {
109
107
  | 'recording_delete'
110
108
  | 'ban_user';
111
109
  [LogSource.Events]: 'CUSTOM_EVENTS' | 'RTM_EVENTS';
112
- [LogSource.CustomizationAPI]: CustomizationLogType;
110
+ [LogSource.CustomizationAPI]:
111
+ | 'Log'
112
+ | 'AI_AGENT_CUSTOMIZATION'
113
+ | 'EXTERNAL_CUSTOMIZATION';
113
114
  [LogSource.SDK]: 'Log' | 'Event';
114
115
  };
115
116
 
@@ -40,8 +40,6 @@ import {
40
40
  sttTranscriptPanelSearchText,
41
41
  sttTranscriptPanelViewLatestText,
42
42
  } from '../../../src/language/default-labels/videoCallScreenLabels';
43
- import {logger, LogSource} from '../../logger/AppBuilderLogger';
44
- import {TRANSCRIPT_JOURNEY} from './transcriptJourney';
45
43
 
46
44
  export interface TranscriptProps {
47
45
  showHeader?: boolean;
@@ -58,7 +56,6 @@ const Transcript = (props: TranscriptProps) => {
58
56
  isSTTActive,
59
57
  selectedTranslationLanguage,
60
58
  transcriptViewMode,
61
- isSTTListenerAdded,
62
59
  } = useCaption();
63
60
 
64
61
  const settingSpokenLanguageLabel = useString(sttSettingSpokenLanguageText)();
@@ -71,39 +68,6 @@ const Transcript = (props: TranscriptProps) => {
71
68
 
72
69
  const data = meetingTranscript; // Object.entries(transcript);
73
70
  console.log('[STT_GLOBAL] meetingTranscript data: ', data);
74
- const hasLoggedFirstEntryRef = React.useRef(false);
75
- const transcriptEntryCountRef = React.useRef(data.length);
76
- transcriptEntryCountRef.current = data.length;
77
-
78
- React.useEffect(() => {
79
- logger.log(
80
- LogSource.Internals,
81
- 'TRANSCRIPT',
82
- `${TRANSCRIPT_JOURNEY} transcript panel state`,
83
- {
84
- stage: 'transcript_panel',
85
- isSTTActive,
86
- listenerRegistered: isSTTListenerAdded,
87
- transcriptEntryCount: transcriptEntryCountRef.current,
88
- },
89
- );
90
- }, [isSTTActive, isSTTListenerAdded]);
91
-
92
- React.useEffect(() => {
93
- if (data.length > 0 && !hasLoggedFirstEntryRef.current) {
94
- hasLoggedFirstEntryRef.current = true;
95
- logger.log(
96
- LogSource.Internals,
97
- 'TRANSCRIPT',
98
- `${TRANSCRIPT_JOURNEY} first transcript entry available to panel`,
99
- {
100
- stage: 'transcript_panel_data',
101
- outcome: 'success',
102
- transcriptEntryCount: data.length,
103
- },
104
- );
105
- }
106
- }, [data.length]);
107
71
 
108
72
  const [showButton, setShowButton] = React.useState(false);
109
73
 
@@ -0,0 +1,47 @@
1
+ import {
2
+ registerTranscriptStreamListener,
3
+ removeTranscriptStreamListener,
4
+ TranscriptStreamEngine,
5
+ } from '../transcriptStreamListener';
6
+
7
+ describe('transcript stream listener lifecycle', () => {
8
+ it('tracks and removes a native listener when addListener returns void', () => {
9
+ const listener = jest.fn();
10
+ const engine: TranscriptStreamEngine = {
11
+ addListener: jest.fn(),
12
+ removeListener: jest.fn(),
13
+ };
14
+
15
+ const registration = registerTranscriptStreamListener(engine, listener);
16
+
17
+ expect(registration).toEqual({subscription: null});
18
+ expect(engine.addListener).toHaveBeenCalledTimes(1);
19
+ expect(engine.addListener).toHaveBeenCalledWith(
20
+ 'onStreamMessage',
21
+ listener,
22
+ );
23
+
24
+ removeTranscriptStreamListener(engine, listener, registration, false);
25
+
26
+ expect(engine.removeListener).toHaveBeenCalledTimes(1);
27
+ expect(engine.removeListener).toHaveBeenCalledWith(
28
+ 'onStreamMessage',
29
+ listener,
30
+ );
31
+ });
32
+
33
+ it('uses the subscription returned by the web bridge', () => {
34
+ const listener = jest.fn();
35
+ const remove = jest.fn();
36
+ const engine: TranscriptStreamEngine = {
37
+ addListener: jest.fn(() => ({remove})),
38
+ removeListener: jest.fn(),
39
+ };
40
+
41
+ const registration = registerTranscriptStreamListener(engine, listener);
42
+ removeTranscriptStreamListener(engine, listener, registration, true);
43
+
44
+ expect(remove).toHaveBeenCalledTimes(1);
45
+ expect(engine.removeListener).not.toHaveBeenCalled();
46
+ });
47
+ });
@@ -0,0 +1,50 @@
1
+ export type TranscriptStreamListener = (...args: any[]) => void;
2
+
3
+ type TranscriptStreamSubscription = {
4
+ remove: () => void;
5
+ };
6
+
7
+ export type TranscriptStreamEngine = {
8
+ addListener: (
9
+ event: 'onStreamMessage',
10
+ listener: TranscriptStreamListener,
11
+ ) => unknown;
12
+ removeListener: (
13
+ event: 'onStreamMessage',
14
+ listener: TranscriptStreamListener,
15
+ ) => void;
16
+ };
17
+
18
+ export type TranscriptStreamListenerRegistration = {
19
+ subscription: TranscriptStreamSubscription | null;
20
+ };
21
+
22
+ export const registerTranscriptStreamListener = (
23
+ engine: TranscriptStreamEngine,
24
+ listener: TranscriptStreamListener,
25
+ ): TranscriptStreamListenerRegistration => {
26
+ const result = engine.addListener('onStreamMessage', listener);
27
+ const subscription =
28
+ result &&
29
+ typeof (result as TranscriptStreamSubscription).remove === 'function'
30
+ ? (result as TranscriptStreamSubscription)
31
+ : null;
32
+
33
+ // Native Agora returns void from addListener. The registration object is our
34
+ // platform-independent proof that registration completed successfully.
35
+ return {subscription};
36
+ };
37
+
38
+ export const removeTranscriptStreamListener = (
39
+ engine: TranscriptStreamEngine,
40
+ listener: TranscriptStreamListener,
41
+ registration: TranscriptStreamListenerRegistration,
42
+ web: boolean,
43
+ ) => {
44
+ if (web) {
45
+ registration.subscription?.remove();
46
+ return;
47
+ }
48
+
49
+ engine.removeListener('onStreamMessage', listener);
50
+ };
@@ -22,6 +22,12 @@ import {useContent, useRtc} from 'customization-api';
22
22
  import useStreamMessageUtils from './useStreamMessageUtils';
23
23
  import {isWebInternal} from '../../utils/common';
24
24
  import {TRANSCRIPT_JOURNEY} from './transcriptJourney';
25
+ import {
26
+ registerTranscriptStreamListener,
27
+ removeTranscriptStreamListener,
28
+ TranscriptStreamEngine,
29
+ TranscriptStreamListenerRegistration,
30
+ } from './transcriptStreamListener';
25
31
 
26
32
  // Types
27
33
  type GlobalSttState = {
@@ -321,22 +327,20 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
321
327
  prevSpeakerRef,
322
328
  selectedTranslationLanguageRef,
323
329
  });
324
- const transcriptListenerSubscriptionRef = React.useRef<{
325
- remove: () => void;
326
- } | null>(null);
327
-
328
- const handleStreamMessageCallback = React.useCallback(
329
- (...args: any[]) => {
330
- if (isWebInternal()) {
331
- const [uid, data] = args;
332
- streamMessageCallback([uid, data]);
333
- } else {
334
- const [, uid, , data] = args;
335
- streamMessageCallback([uid, data]);
336
- }
337
- },
338
- [streamMessageCallback],
339
- );
330
+ const streamMessageCallbackRef = React.useRef(streamMessageCallback);
331
+ streamMessageCallbackRef.current = streamMessageCallback;
332
+ const transcriptListenerRegistrationRef =
333
+ React.useRef<TranscriptStreamListenerRegistration | null>(null);
334
+
335
+ const handleStreamMessageCallback = React.useCallback((...args: any[]) => {
336
+ if (isWebInternal()) {
337
+ const [uid, data] = args;
338
+ streamMessageCallbackRef.current([uid, data]);
339
+ } else {
340
+ const [, uid, , data] = args;
341
+ streamMessageCallbackRef.current([uid, data]);
342
+ }
343
+ }, []);
340
344
 
341
345
  // Register once for the lifetime of the active call. Keeping collection in
342
346
  // the provider makes it independent of whether caption/transcript UI is open.
@@ -344,7 +348,7 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
344
348
  if (
345
349
  !$config.ENABLE_STT ||
346
350
  !callActive ||
347
- transcriptListenerSubscriptionRef.current
351
+ transcriptListenerRegistrationRef.current
348
352
  ) {
349
353
  return;
350
354
  }
@@ -356,10 +360,11 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
356
360
  {stage: 'listener_registration', outcome: 'started'},
357
361
  );
358
362
  try {
359
- transcriptListenerSubscriptionRef.current = RtcEngineUnsafe.addListener(
360
- 'onStreamMessage',
361
- handleStreamMessageCallback,
362
- );
363
+ transcriptListenerRegistrationRef.current =
364
+ registerTranscriptStreamListener(
365
+ RtcEngineUnsafe as unknown as TranscriptStreamEngine,
366
+ handleStreamMessageCallback,
367
+ );
363
368
  setIsSTTListenerAdded(true);
364
369
  logger.log(
365
370
  LogSource.Internals,
@@ -378,10 +383,9 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
378
383
  error: error ?? null,
379
384
  },
380
385
  );
386
+ return;
381
387
  }
382
- }, [RtcEngineUnsafe, callActive, handleStreamMessageCallback]);
383
388
 
384
- React.useEffect(() => {
385
389
  return () => {
386
390
  logger.log(
387
391
  LogSource.Internals,
@@ -390,19 +394,27 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
390
394
  {
391
395
  stage: 'listener_cleanup',
392
396
  outcome: 'started',
393
- listenerReferencePresent: !!transcriptListenerSubscriptionRef.current,
397
+ listenerRegistered: !!transcriptListenerRegistrationRef.current,
394
398
  },
395
399
  );
396
- transcriptListenerSubscriptionRef.current?.remove();
397
- transcriptListenerSubscriptionRef.current = null;
400
+ if (transcriptListenerRegistrationRef.current) {
401
+ removeTranscriptStreamListener(
402
+ RtcEngineUnsafe as unknown as TranscriptStreamEngine,
403
+ handleStreamMessageCallback,
404
+ transcriptListenerRegistrationRef.current,
405
+ isWebInternal(),
406
+ );
407
+ }
408
+ transcriptListenerRegistrationRef.current = null;
409
+ setIsSTTListenerAdded(false);
398
410
  logger.log(
399
411
  LogSource.Internals,
400
412
  'TRANSCRIPT',
401
- `${TRANSCRIPT_JOURNEY} stream listener subscription remove called and local reference cleared`,
413
+ `${TRANSCRIPT_JOURNEY} stream listener removed and local references cleared`,
402
414
  {stage: 'listener_cleanup', outcome: 'completed'},
403
415
  );
404
416
  };
405
- }, []);
417
+ }, [RtcEngineUnsafe, callActive, handleStreamMessageCallback]);
406
418
 
407
419
  const flushPendingTranscript = React.useCallback(async () => {
408
420
  await flushStreamMessageQueue();
@@ -435,12 +447,17 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
435
447
  const updateErrorLabel = useString(sttUpdateError)();
436
448
 
437
449
  // --- Derived readiness flag for STT ---
450
+ const localUidReady = !!localUid;
451
+ const localBotUidReady = !!localBotUid;
452
+ const rtmJoined = !!hasUserJoinedRTM;
453
+ const activeCallReady = !!callActive;
454
+ const roomInfoReady = !!(roomId?.host || roomId?.attendee);
438
455
  const sttDepsReady =
439
- !!localUid &&
440
- !!localBotUid &&
441
- !!hasUserJoinedRTM &&
442
- !!callActive &&
443
- !!(roomId?.host || roomId?.attendee);
456
+ localUidReady &&
457
+ localBotUidReady &&
458
+ rtmJoined &&
459
+ activeCallReady &&
460
+ roomInfoReady;
444
461
 
445
462
  const sttStartGuardRef = React.useRef(false);
446
463
  const sttAutoStartGuardRef = React.useRef(false);
@@ -452,27 +469,42 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
452
469
  }, [sttDepsReady]);
453
470
 
454
471
  React.useEffect(() => {
472
+ const missingDependencies = [
473
+ !localUidReady && 'localUid',
474
+ !localBotUidReady && 'localBotUid',
475
+ !rtmJoined && 'RTM',
476
+ !activeCallReady && 'activeCall',
477
+ !roomInfoReady && 'roomInfo',
478
+ !isSTTListenerAdded && 'streamListener',
479
+ ].filter(Boolean);
480
+ const transcriptReady = sttDepsReady && isSTTListenerAdded;
481
+
455
482
  logger.log(
456
483
  LogSource.Internals,
457
484
  'TRANSCRIPT',
458
- `${TRANSCRIPT_JOURNEY} STT readiness changed`,
485
+ `${TRANSCRIPT_JOURNEY} STT readiness: ${
486
+ transcriptReady
487
+ ? 'READY'
488
+ : `WAITING (missing: ${missingDependencies.join(', ')})`
489
+ }`,
459
490
  {
460
491
  stage: 'stt_readiness',
461
- outcome: sttDepsReady ? 'ready' : 'waiting',
462
- localUidReady: !!localUid,
463
- localBotUidReady: !!localBotUid,
464
- rtmJoined: !!hasUserJoinedRTM,
465
- callActive: !!callActive,
466
- roomInfoReady: !!(roomId?.host || roomId?.attendee),
467
- listenerRegistered: !!transcriptListenerSubscriptionRef.current,
492
+ outcome: transcriptReady ? 'ready' : 'waiting',
493
+ localUidReady,
494
+ localBotUidReady,
495
+ rtmJoined,
496
+ callActive: activeCallReady,
497
+ roomInfoReady,
498
+ listenerRegistered: isSTTListenerAdded,
468
499
  },
469
500
  );
470
501
  }, [
471
- callActive,
472
- hasUserJoinedRTM,
473
- localBotUid,
474
- localUid,
475
- roomId,
502
+ activeCallReady,
503
+ isSTTListenerAdded,
504
+ localBotUidReady,
505
+ localUidReady,
506
+ roomInfoReady,
507
+ rtmJoined,
476
508
  sttDepsReady,
477
509
  ]);
478
510
 
@@ -593,21 +625,22 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
593
625
  try {
594
626
  setIsLangChangeInProgress(true);
595
627
  const result = await start(localBotUidRef.current, newConfig);
628
+ console.log('[STT] start result: ', result);
596
629
  if (result.success) {
597
630
  setIsSTTError(false);
598
631
  logger.log(
599
632
  LogSource.NetworkRest,
600
633
  'stt',
601
- `${TRANSCRIPT_JOURNEY} STT started successfully`,
602
- result.data ?? null,
634
+ 'STT started successfully',
635
+ result.data,
603
636
  );
604
637
  } else {
605
638
  setIsSTTError(true);
606
639
  logger.error(
607
640
  LogSource.NetworkRest,
608
641
  'stt',
609
- `${TRANSCRIPT_JOURNEY} failed to start STT`,
610
- result.error ?? null,
642
+ 'Failed to start STT',
643
+ result.error,
611
644
  );
612
645
  Toast.show({
613
646
  leadingIconName: 'alert',
@@ -624,12 +657,7 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
624
657
  } catch (error: any) {
625
658
  setIsLangChangeInProgress(false);
626
659
  setIsSTTError(true);
627
- logger.error(
628
- LogSource.NetworkRest,
629
- 'stt',
630
- `${TRANSCRIPT_JOURNEY} STT start error`,
631
- error ?? null,
632
- );
660
+ logger.error(LogSource.NetworkRest, 'stt', 'STT start error', error);
633
661
  // Show error toast: text1 = translated label, text2 = exception error
634
662
  Toast.show({
635
663
  leadingIconName: 'alert',
@@ -674,16 +702,16 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
674
702
  logger.log(
675
703
  LogSource.NetworkRest,
676
704
  'stt',
677
- `${TRANSCRIPT_JOURNEY} STT updated successfully`,
678
- result.data ?? null,
705
+ 'STT updated successfully',
706
+ result.data,
679
707
  );
680
708
  } else {
681
709
  setIsSTTError(true);
682
710
  logger.error(
683
711
  LogSource.NetworkRest,
684
712
  'stt',
685
- `${TRANSCRIPT_JOURNEY} failed to update STT`,
686
- result.error ?? null,
713
+ 'Failed to update STT',
714
+ result.error,
687
715
  );
688
716
  // Show error toast: text1 = translated label, text2 = API error
689
717
  Toast.show({
@@ -701,12 +729,7 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
701
729
  } catch (error: any) {
702
730
  setIsLangChangeInProgress(false);
703
731
  setIsSTTError(true);
704
- logger.error(
705
- LogSource.NetworkRest,
706
- 'stt',
707
- `${TRANSCRIPT_JOURNEY} STT update error`,
708
- error ?? null,
709
- );
732
+ logger.error(LogSource.NetworkRest, 'stt', 'STT update error', error);
710
733
  // Show error toast: text1 = translated label, text2 = exception error
711
734
  Toast.show({
712
735
  leadingIconName: 'alert',
@@ -725,20 +748,10 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
725
748
  };
726
749
 
727
750
  const stopSTTBotSession = React.useCallback(async () => {
728
- logger.log(
729
- LogSource.Internals,
730
- 'TRANSCRIPT',
731
- `${TRANSCRIPT_JOURNEY} STT stop requested`,
732
- {stage: 'stt_stop', localBotUid: localBotUidRef.current ?? null},
733
- );
751
+ console.log('[STT] stopSTTBotSession called');
734
752
 
735
753
  if (!localBotUidRef.current) {
736
- logger.warn(
737
- LogSource.Internals,
738
- 'TRANSCRIPT',
739
- `${TRANSCRIPT_JOURNEY} STT stop skipped because bot UID is missing`,
740
- {stage: 'stt_stop', outcome: 'skipped'},
741
- );
754
+ console.warn('[STT] Missing botUid for stop');
742
755
  return;
743
756
  }
744
757
 
@@ -754,16 +767,16 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
754
767
  logger.log(
755
768
  LogSource.NetworkRest,
756
769
  'stt',
757
- `${TRANSCRIPT_JOURNEY} STT stopped successfully`,
758
- result.data ?? null,
770
+ 'STT stopped successfully',
771
+ result.data,
759
772
  );
760
773
  } else {
761
774
  setIsSTTError(true);
762
775
  logger.error(
763
776
  LogSource.NetworkRest,
764
777
  'stt',
765
- `${TRANSCRIPT_JOURNEY} failed to stop STT`,
766
- result.error ?? null,
778
+ 'Failed to stop STT',
779
+ result.error,
767
780
  );
768
781
  }
769
782
  } catch (error) {
@@ -771,8 +784,8 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
771
784
  logger.error(
772
785
  LogSource.NetworkRest,
773
786
  'stt',
774
- `${TRANSCRIPT_JOURNEY} error in stopSTTBotSession`,
775
- error ?? null,
787
+ 'Error in stopSTTBotSession',
788
+ error,
776
789
  );
777
790
  }
778
791
  }, [stop]);
@@ -843,29 +856,12 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
843
856
  // Queue
844
857
  enqueueSttEvent(updatedState, true, targetChange);
845
858
 
846
- logger.log(
847
- LogSource.Internals,
848
- 'TRANSCRIPT',
849
- `${TRANSCRIPT_JOURNEY} local spoken-language state queued`,
850
- {
851
- stage: 'global_state_queue',
852
- outcome: 'queued',
853
- spokenLanguage: updatedState.globalSpokenLanguage ?? null,
854
- translationTargetCount:
855
- updatedState.globalTranslationTargets.length,
856
- },
859
+ console.log(
860
+ '[STT_GLOBAL] confirmSpokenLanguageChange sent STT_GLOBAL_STATE: ',
861
+ updatedState,
857
862
  );
858
863
  } catch (error) {
859
- logger.error(
860
- LogSource.Internals,
861
- 'TRANSCRIPT',
862
- `${TRANSCRIPT_JOURNEY} local spoken-language state failed`,
863
- {
864
- stage: 'global_state_queue',
865
- outcome: 'failure',
866
- error: error ?? null,
867
- },
868
- );
864
+ console.log('[STT_GLOBAL] confirmSpokenLanguageChange error: ', error);
869
865
  }
870
866
  },
871
867
  [localUid], // only real dependency
@@ -920,24 +916,15 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
920
916
  // Queues all local + remote stt events
921
917
  const enqueueSttEvent = React.useCallback(
922
918
  (state: GlobalSttState, isLocal: boolean, targetChange?: TargetChange) => {
919
+ console.log(
920
+ '[STT_GLOBAL] inside enqueueSttEvent - sttDepsReadyRef flag',
921
+ sttDepsReadyRef.current,
922
+ );
923
923
  sttEventQueueRef.current.push({
924
924
  state,
925
925
  isLocal,
926
926
  targetChange,
927
927
  });
928
- logger.log(
929
- LogSource.Internals,
930
- 'TRANSCRIPT',
931
- `${TRANSCRIPT_JOURNEY} STT global state queued`,
932
- {
933
- stage: 'global_state_queue',
934
- outcome: 'queued',
935
- stateOrigin: isLocal ? 'local' : 'remote',
936
- sttEnabled: state.globalSttEnabled,
937
- sttDepsReady: sttDepsReadyRef.current,
938
- queueSize: sttEventQueueRef.current.length,
939
- },
940
- );
941
928
  if (sttDepsReadyRef.current) {
942
929
  processSttEventQueue();
943
930
  }
@@ -964,12 +951,7 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
964
951
  !globalSttStateRef.current.globalSttEnabled &&
965
952
  sttEventQueueRef.current.length === 0
966
953
  ) {
967
- logger.log(
968
- LogSource.Internals,
969
- 'TRANSCRIPT',
970
- `${TRANSCRIPT_JOURNEY} STT auto-start state injected`,
971
- {stage: 'global_state_queue', outcome: 'queued'},
972
- );
954
+ console.log('[STT] AUTO_START injecting auto start state');
973
955
 
974
956
  sttAutoStartGuardRef.current = true;
975
957
 
@@ -996,12 +978,7 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
996
978
  const {state: newState, isLocal, targetChange} = item;
997
979
  const prevState = globalSttStateRef.current;
998
980
  if (isSameState(prevState, newState)) {
999
- logger.log(
1000
- LogSource.Internals,
1001
- 'TRANSCRIPT',
1002
- `${TRANSCRIPT_JOURNEY} duplicate STT global state skipped`,
1003
- {stage: 'global_state_queue', outcome: 'skipped'},
1004
- );
981
+ console.log('[STT] Skipped duplicate STT_GLOBAL_STATE');
1005
982
  continue; // no call to processGlobalSttSingleEvent
1006
983
  }
1007
984
  const ok = await processGlobalSttSingleEvent(
@@ -1011,22 +988,16 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
1011
988
  );
1012
989
  if (!ok) {
1013
990
  if (isLocal) {
1014
- logger.warn(
1015
- LogSource.Internals,
1016
- 'TRANSCRIPT',
1017
- `${TRANSCRIPT_JOURNEY} local global state update skipped because API failed`,
1018
- {stage: 'global_state_apply', outcome: 'skipped'},
991
+ console.warn(
992
+ '[STT] Skipping local global state update because API failed.',
1019
993
  );
1020
994
  continue;
1021
995
  }
1022
996
  // A received RTM event is authoritative for the meeting-level state.
1023
997
  // Failure to provision this participant's bot must not make the UI
1024
998
  // report that meeting STT is disabled while captions are arriving.
1025
- logger.warn(
1026
- LogSource.Internals,
1027
- 'TRANSCRIPT',
1028
- `${TRANSCRIPT_JOURNEY} remote global state applied after local STT API failure`,
1029
- {stage: 'global_state_apply', outcome: 'applied_with_api_failure'},
999
+ console.warn(
1000
+ '[STT] Applying remote global state after local STT API failure.',
1030
1001
  );
1031
1002
  }
1032
1003
  // update global state AFTER processing
@@ -1051,24 +1022,10 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
1051
1022
  const isStopOperation = wasEnabledBefore && !isEnabledNow;
1052
1023
  try {
1053
1024
  if (isStartOperation) {
1054
- logger.log(
1055
- LogSource.Internals,
1056
- 'TRANSCRIPT',
1057
- `${TRANSCRIPT_JOURNEY} STT global state selected start operation`,
1058
- {
1059
- stage: 'global_state_operation',
1060
- outcome: 'started',
1061
- stateOrigin: isLocal ? 'local' : 'remote',
1062
- },
1063
- );
1025
+ console.log('[STT] Remote global STT -> starting session', newState);
1064
1026
  // Start guard starts
1065
1027
  if (sttStartGuardRef.current) {
1066
- logger.log(
1067
- LogSource.Internals,
1068
- 'TRANSCRIPT',
1069
- `${TRANSCRIPT_JOURNEY} STT start skipped by start guard`,
1070
- {stage: 'global_state_operation', outcome: 'skipped'},
1071
- );
1028
+ console.log('[STT] Start skipped (already started)');
1072
1029
  return;
1073
1030
  }
1074
1031
  sttStartGuardRef.current = true;
@@ -1139,16 +1096,7 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
1139
1096
  }
1140
1097
  return true;
1141
1098
  } else if (isUpdateOperation) {
1142
- logger.log(
1143
- LogSource.Internals,
1144
- 'TRANSCRIPT',
1145
- `${TRANSCRIPT_JOURNEY} STT global state selected update operation`,
1146
- {
1147
- stage: 'global_state_operation',
1148
- outcome: 'started',
1149
- stateOrigin: isLocal ? 'local' : 'remote',
1150
- },
1151
- );
1099
+ console.log('[STT] Global STT -> updating session', newState);
1152
1100
  const result = await updateSTTBotSession(
1153
1101
  {
1154
1102
  source: [newState.globalSpokenLanguage],
@@ -1212,16 +1160,7 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
1212
1160
  }
1213
1161
  return true;
1214
1162
  } else if (isStopOperation) {
1215
- logger.log(
1216
- LogSource.Internals,
1217
- 'TRANSCRIPT',
1218
- `${TRANSCRIPT_JOURNEY} STT global state selected stop operation`,
1219
- {
1220
- stage: 'global_state_operation',
1221
- outcome: 'started',
1222
- stateOrigin: isLocal ? 'local' : 'remote',
1223
- },
1224
- );
1163
+ console.log('[STT] Global STT -> stopping session', newState);
1225
1164
  await stopSTTBotSession();
1226
1165
  sttStartGuardRef.current = false;
1227
1166
  return true;
@@ -1234,8 +1173,8 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
1234
1173
  logger.error(
1235
1174
  LogSource.Internals,
1236
1175
  'STT',
1237
- `${TRANSCRIPT_JOURNEY} error handling STT_GLOBAL_STATE event`,
1238
- error ?? null,
1176
+ 'Error handling STT_GLOBAL_STATE event',
1177
+ error,
1239
1178
  );
1240
1179
  return false;
1241
1180
  }
@@ -1247,16 +1186,7 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
1247
1186
  React.useEffect(() => {
1248
1187
  const handleGlobalSTTChange = async (evt: any) => {
1249
1188
  const {payload} = evt || {};
1250
- logger.log(
1251
- LogSource.Internals,
1252
- 'TRANSCRIPT',
1253
- `${TRANSCRIPT_JOURNEY} STT_GLOBAL_STATE event received`,
1254
- {
1255
- stage: 'global_state_event',
1256
- outcome: 'received',
1257
- payloadPresent: typeof payload === 'string' && payload.length > 0,
1258
- },
1259
- );
1189
+ console.log('[STT] STT_GLOBAL_STATE event received: ', evt);
1260
1190
  let newState: GlobalSttState;
1261
1191
  try {
1262
1192
  newState = JSON.parse(payload);
@@ -1264,8 +1194,8 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
1264
1194
  logger.error(
1265
1195
  LogSource.Internals,
1266
1196
  'STT',
1267
- `${TRANSCRIPT_JOURNEY} failed to parse STT_GLOBAL_STATE event payload`,
1268
- error ?? null,
1197
+ 'Failed to parse STT_GLOBAL_STATE event payload',
1198
+ error,
1269
1199
  );
1270
1200
  return;
1271
1201
  }
@@ -7,7 +7,6 @@ import {logger, LogSource} from '../../logger/AppBuilderLogger';
7
7
  import getUniqueID from '../../utils/getUniqueID';
8
8
  import {buildSTTRequestBody, type STTMethod} from './sttRequestBody';
9
9
  import {ensureSTTSessionId} from './sttSessionId';
10
- import {TRANSCRIPT_JOURNEY} from './transcriptJourney';
11
10
 
12
11
  export interface STTAPIResponse {
13
12
  success: boolean;
@@ -100,12 +99,12 @@ const useSTTAPI = (): IuseSTTAPI => {
100
99
  });
101
100
 
102
101
  console.log(
103
- `${TRANSCRIPT_JOURNEY} [STT_BOT_SUBSCRIPTION] ${method.toUpperCase()} - Bot UID: ${botUid} will subscribe to User UID: ${ownerUid}`,
102
+ `[STT_BOT_SUBSCRIPTION] ${method.toUpperCase()} - Bot UID: ${botUid} will subscribe to User UID: ${ownerUid}`,
104
103
  {
105
104
  method,
106
105
  botUid,
107
106
  ownerUid,
108
- translationConfig: translationConfig ?? null,
107
+ translationConfig,
109
108
  },
110
109
  );
111
110
  const response = await fetch(`${STT_API_URL}/${method}`, {
@@ -147,10 +146,10 @@ const useSTTAPI = (): IuseSTTAPI => {
147
146
  logger.error(
148
147
  LogSource.NetworkRest,
149
148
  'stt',
150
- `${TRANSCRIPT_JOURNEY} STT API Failure - Called ${method}`,
151
- errorPayload ?? {message},
149
+ `STT API Failure - Called ${method}`,
150
+ errorPayload,
152
151
  {
153
- responseData: res ?? null,
152
+ responseData: res,
154
153
  httpStatus,
155
154
  requestId,
156
155
  startReqTs,
@@ -173,9 +172,9 @@ const useSTTAPI = (): IuseSTTAPI => {
173
172
  logger.log(
174
173
  LogSource.NetworkRest,
175
174
  'stt',
176
- `${TRANSCRIPT_JOURNEY} STT API Success - Called ${method}`,
175
+ `STT API Success - Called ${method}`,
177
176
  {
178
- responseData: res ?? null,
177
+ responseData: res,
179
178
  httpStatus,
180
179
  requestId,
181
180
  startReqTs,
@@ -195,8 +194,8 @@ const useSTTAPI = (): IuseSTTAPI => {
195
194
  logger.error(
196
195
  LogSource.NetworkRest,
197
196
  'stt',
198
- `${TRANSCRIPT_JOURNEY} STT API Failure - Called ${method}`,
199
- error ?? null,
197
+ `STT API Failure - Called ${method}`,
198
+ error,
200
199
  {
201
200
  requestId,
202
201
  startReqTs,
@@ -236,14 +235,14 @@ const useSTTAPI = (): IuseSTTAPI => {
236
235
  logger.log(
237
236
  LogSource.NetworkRest,
238
237
  'stt',
239
- `${TRANSCRIPT_JOURNEY} Retrying STT start after transient failure`,
238
+ 'Retrying STT start after transient failure',
240
239
  {
241
240
  attempt,
242
241
  maxAttempts: STT_START_MAX_ATTEMPTS,
243
242
  retryDelayMs,
244
243
  botUid,
245
- httpStatus: result.httpStatus ?? null,
246
- errorCode: result.error?.code ?? null,
244
+ httpStatus: result.httpStatus,
245
+ errorCode: result.error?.code,
247
246
  },
248
247
  );
249
248
  await wait(retryDelayMs);
@@ -3,8 +3,6 @@ import protoRoot from './proto/ptoto';
3
3
  import PQueue from 'p-queue';
4
4
  import type {CaptionObj, TranscriptItem} from './useCaption';
5
5
  import type {LanguageType} from './utils';
6
- import {logger, LogSource} from '../../logger/AppBuilderLogger';
7
- import {TRANSCRIPT_JOURNEY} from './transcriptJourney';
8
6
 
9
7
  type StreamMessageCallback = (args: [number, Uint8Array]) => void;
10
8
  type FinalListType = {
@@ -44,29 +42,8 @@ const useStreamMessageUtils = ({
44
42
  const finalTranscriptListRef = React.useRef<FinalListType>({});
45
43
  const finalTranslationListRef = React.useRef<FinalTranslationListType>({});
46
44
  const queue = React.useMemo(() => new PQueue({concurrency: 1}), []);
47
- const messagesReceivedRef = React.useRef(0);
48
- const messagesProcessedRef = React.useRef(0);
49
- const finalizedSegmentsRef = React.useRef(0);
50
- const speakersWithFinalizedSegmentsRef = React.useRef(new Set<string>());
51
45
 
52
46
  const streamMessageCallback: StreamMessageCallback = args => {
53
- const [receivedBotUid, receivedPayload] = args;
54
- const messageNumber = ++messagesReceivedRef.current;
55
- if (messageNumber === 1 || messageNumber % 50 === 0) {
56
- logger.log(
57
- LogSource.Internals,
58
- 'TRANSCRIPT',
59
- `${TRANSCRIPT_JOURNEY} stream message received`,
60
- {
61
- stage: 'stream_message_received',
62
- outcome: 'success',
63
- botUid: receivedBotUid ?? null,
64
- payloadByteLength: receivedPayload?.byteLength || 0,
65
- messagesReceived: messageNumber,
66
- messagesProcessed: messagesProcessedRef.current,
67
- },
68
- );
69
- }
70
47
  const queueCallback = (args1: [number, Uint8Array]) => {
71
48
  const finalList = finalListRef.current;
72
49
  const finalTranscriptList = finalTranscriptListRef.current;
@@ -244,29 +221,11 @@ const useStreamMessageUtils = ({
244
221
  finalList[textstream.uid].push(finalText);
245
222
  finalTranscriptList[textstream.uid].push(finalText);
246
223
  currentFinalText = finalText;
247
- const speakerUid = textstream.uid ?? null;
248
- const speakerKey = String(speakerUid ?? 'unknown');
249
- const isFirstFinalizedSegmentForSpeaker =
250
- !speakersWithFinalizedSegmentsRef.current.has(speakerKey);
251
- finalizedSegmentsRef.current += 1;
224
+ // log info to show measure the duration of passes in which a sentence gets finalized
252
225
  const duration = performance.now() - captionStartTimeRef.current;
253
- if (isFirstFinalizedSegmentForSpeaker) {
254
- speakersWithFinalizedSegmentsRef.current.add(speakerKey);
255
- logger.log(
256
- LogSource.Internals,
257
- 'TRANSCRIPT',
258
- `${TRANSCRIPT_JOURNEY} first transcript segment finalized for speaker`,
259
- {
260
- stage: 'segment_finalized',
261
- outcome: 'success',
262
- botUid: botUid ?? null,
263
- speakerUid,
264
- finalCharacterCount: currentFinalText.length,
265
- finalizeDurationMs: duration,
266
- finalizedSegments: finalizedSegmentsRef.current,
267
- },
268
- );
269
- }
226
+ console.log(
227
+ `stt-Time taken to finalize caption ${currentFinalText}: ${duration}ms`,
228
+ );
270
229
  captionStartTimeRef.current = 0; // Reset start time
271
230
  }
272
231
 
@@ -405,74 +364,14 @@ const useStreamMessageUtils = ({
405
364
  };
406
365
  void queue
407
366
  .add(() => queueCallback(args))
408
- .then(() => {
409
- const processedCount = ++messagesProcessedRef.current;
410
- if (processedCount === 1 || processedCount % 50 === 0) {
411
- logger.log(
412
- LogSource.Internals,
413
- 'TRANSCRIPT',
414
- `${TRANSCRIPT_JOURNEY} stream message processed`,
415
- {
416
- stage: 'stream_message_processed',
417
- outcome: 'success',
418
- botUid: receivedBotUid ?? null,
419
- messagesReceived: messagesReceivedRef.current,
420
- messagesProcessed: processedCount,
421
- queueSize: queue.size,
422
- },
423
- );
424
- }
425
- })
426
- .catch(error => {
427
- logger.error(
428
- LogSource.Internals,
429
- 'TRANSCRIPT',
430
- `${TRANSCRIPT_JOURNEY} failed to process stream message`,
431
- {
432
- stage: 'stream_message_processing',
433
- outcome: 'failure',
434
- botUid: receivedBotUid ?? null,
435
- messageNumber,
436
- messagesReceived: messagesReceivedRef.current,
437
- messagesProcessed: messagesProcessedRef.current,
438
- error: error ?? null,
439
- },
440
- );
441
- });
367
+ .then(() => console.log('stt- using pq queue'))
368
+ .catch(error =>
369
+ console.error('Failed to process STT stream message', error),
370
+ );
442
371
  };
443
372
 
444
373
  const flushStreamMessageQueue = React.useCallback(async () => {
445
- logger.log(
446
- LogSource.Internals,
447
- 'TRANSCRIPT',
448
- `${TRANSCRIPT_JOURNEY} stream queue flush requested`,
449
- {
450
- stage: 'stream_queue_flush',
451
- outcome: 'started',
452
- messagesReceived: messagesReceivedRef.current,
453
- messagesProcessed: messagesProcessedRef.current,
454
- finalizedSegments: finalizedSegmentsRef.current,
455
- speakersWithFinalizedSegments:
456
- speakersWithFinalizedSegmentsRef.current.size,
457
- queueSize: queue.size,
458
- },
459
- );
460
374
  await queue.onIdle();
461
- logger.log(
462
- LogSource.Internals,
463
- 'TRANSCRIPT',
464
- `${TRANSCRIPT_JOURNEY} stream queue flush completed`,
465
- {
466
- stage: 'stream_queue_flush',
467
- outcome: 'success',
468
- messagesReceived: messagesReceivedRef.current,
469
- messagesProcessed: messagesProcessedRef.current,
470
- finalizedSegments: finalizedSegmentsRef.current,
471
- speakersWithFinalizedSegments:
472
- speakersWithFinalizedSegmentsRef.current.size,
473
- queueSize: queue.size,
474
- },
475
- );
476
375
  }, [queue]);
477
376
 
478
377
  return {
@@ -1,33 +0,0 @@
1
- import {
2
- CustomizationLogType,
3
- LogSource,
4
- logger,
5
- } from '../src/logger/AppBuilderLogger';
6
-
7
- export type CustomizationLogLevel = 'debug' | 'info' | 'warn' | 'error';
8
- export type CustomizationLogData = Record<string, unknown>;
9
- export type CustomizationLogEvent = {
10
- type: CustomizationLogType;
11
- event: string;
12
- data?: CustomizationLogData;
13
- level?: CustomizationLogLevel;
14
- };
15
-
16
- /**
17
- * Sends a customization event through the active App Builder log transport.
18
- * The logger adds the current session, room, user, platform, and SDK context.
19
- * Callers must redact credentials and other sensitive values before logging.
20
- */
21
- export const logCustomizationEvent = ({
22
- type,
23
- event,
24
- data,
25
- level = 'info',
26
- }: CustomizationLogEvent) => {
27
- if (data) {
28
- logger[level](LogSource.CustomizationAPI, type, event, data);
29
- return;
30
- }
31
-
32
- logger[level](LogSource.CustomizationAPI, type, event);
33
- };
@@ -1,7 +0,0 @@
1
- import {TRANSCRIPT_JOURNEY} from '../transcriptJourney';
2
-
3
- describe('transcript journey logging', () => {
4
- it('uses one searchable prefix', () => {
5
- expect(TRANSCRIPT_JOURNEY).toBe('[TRANSCRIPT_JOURNEY]');
6
- });
7
- });