@hexar/biometric-identity-sdk-react-native 1.1.16 → 1.1.18

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ProfilePictureCapture.d.ts","sourceRoot":"","sources":["../../src/components/ProfilePictureCapture.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AASxE,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAmC,cAAc,EAAsB,MAAM,oCAAoC,CAAC;AAGzJ,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,CAAC,MAAM,EAAE,8BAA8B,KAAK,IAAI,CAAC;IAC7D,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAED,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CAmNtE,CAAC;AAuBF,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"ProfilePictureCapture.d.ts","sourceRoot":"","sources":["../../src/components/ProfilePictureCapture.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AASxE,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAmC,cAAc,EAAsB,MAAM,oCAAoC,CAAC;AAGzJ,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,CAAC,MAAM,EAAE,8BAA8B,KAAK,IAAI,CAAC;IAC7D,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAED,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CAiPtE,CAAC;AAuBF,eAAe,qBAAqB,CAAC"}
@@ -58,16 +58,25 @@ const ProfilePictureCapture = ({ onComplete, onError, onCancel, theme, language,
58
58
  setIsLoadingChallenges(true);
59
59
  try {
60
60
  const challenges = await fetchChallenges('active');
61
+ biometric_identity_sdk_core_1.logger.info('ProfilePictureCapture: Challenges loaded', {
62
+ challengeCount: challenges.length,
63
+ challenges: challenges.map(c => c.action)
64
+ });
61
65
  setCurrentChallenges(challenges);
62
66
  }
63
67
  catch (error) {
64
- biometric_identity_sdk_core_1.logger.warn('Failed to fetch challenges, VideoRecorder will use defaults');
68
+ biometric_identity_sdk_core_1.logger.warn('Failed to fetch challenges, VideoRecorder will use defaults', error);
65
69
  setCurrentChallenges([]);
66
70
  }
67
71
  setIsLoadingChallenges(false);
68
72
  };
69
73
  loadChallenges();
70
74
  }
75
+ else if (isInitialized) {
76
+ // If not using backend, still initialize with empty array (VideoRecorder will use defaults)
77
+ setCurrentChallenges([]);
78
+ setIsLoadingChallenges(false);
79
+ }
71
80
  }, [isInitialized, isUsingBackend, fetchChallenges]);
72
81
  const strings = (0, biometric_identity_sdk_core_1.getStrings)();
73
82
  const validateWithBackend = (0, react_1.useCallback)(async (videoResult) => {
@@ -142,6 +151,13 @@ const ProfilePictureCapture = ({ onComplete, onError, onCancel, theme, language,
142
151
  }
143
152
  }, [isInitialized, isUsingBackend, sdk]);
144
153
  const handleVideoComplete = (0, react_1.useCallback)(async (videoResult) => {
154
+ biometric_identity_sdk_core_1.logger.info('ProfilePictureCapture: Video recording completed', {
155
+ framesCount: videoResult.frames?.length || 0,
156
+ duration: videoResult.duration,
157
+ challengesCompleted: videoResult.challengesCompleted || [],
158
+ challengesCompletedCount: videoResult.challengesCompleted?.length || 0,
159
+ expectedChallengesCount: currentChallenges.length,
160
+ });
145
161
  setIsValidating(true);
146
162
  try {
147
163
  const result = await validateWithBackend(videoResult);
@@ -185,7 +201,7 @@ const ProfilePictureCapture = ({ onComplete, onError, onCancel, theme, language,
185
201
  };
186
202
  onError(biometricError);
187
203
  }
188
- }, [validateWithBackend, onComplete, onError, strings, language]);
204
+ }, [validateWithBackend, onComplete, onError, strings, language, currentChallenges]);
189
205
  const handleVideoCancel = (0, react_1.useCallback)(() => {
190
206
  if (onCancel) {
191
207
  onCancel();
@@ -198,6 +214,13 @@ const ProfilePictureCapture = ({ onComplete, onError, onCancel, theme, language,
198
214
  react_1.default.createElement(react_native_1.Text, { style: [styles.loadingText, { color: theme?.textColor || '#1e1b4b' }] }, strings.liveness.processing || strings.validation.checkingLiveness || 'Processing...'),
199
215
  react_1.default.createElement(react_native_1.Text, { style: [styles.loadingSubtext, { color: theme?.secondaryTextColor || '#64748b' }] }, strings.validation.almostDone || strings.common.loading || 'This may take a few seconds'))));
200
216
  }
217
+ // Wait for initialization and challenge loading before showing VideoRecorder
218
+ if (!isInitialized || (isUsingBackend && isLoadingChallenges)) {
219
+ return (react_1.default.createElement(react_native_1.SafeAreaView, { style: [styles.container, { backgroundColor: theme?.backgroundColor || '#FFFFFF' }] },
220
+ react_1.default.createElement(react_native_1.View, { style: styles.loadingContainer },
221
+ react_1.default.createElement(react_native_1.ActivityIndicator, { size: "large", color: theme?.primaryColor || '#4f46e5' }),
222
+ react_1.default.createElement(react_native_1.Text, { style: [styles.loadingText, { color: theme?.textColor || '#1e1b4b' }] }, strings.liveness.preparing || 'Preparing...'))));
223
+ }
201
224
  return (react_1.default.createElement(VideoRecorder_1.VideoRecorder, { theme: theme, language: language, smartMode: true, challenges: currentChallenges, sessionId: sdk.getSessionId() || undefined, onComplete: handleVideoComplete, onCancel: handleVideoCancel, onFetchChallenges: handleFetchChallenges }));
202
225
  };
203
226
  exports.ProfilePictureCapture = ProfilePictureCapture;
@@ -1 +1 @@
1
- {"version":3,"file":"VideoRecorder.d.ts","sourceRoot":"","sources":["../../src/components/VideoRecorder.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAaxE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,iBAAiB,EAAmC,MAAM,oCAAoC,CAAC;AAE1I,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,YAAY,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACrC,0CAA0C;IAC1C,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wCAAwC;IACxC,UAAU,EAAE,CAAC,SAAS,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACtD,iCAAiC;IACjC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,gDAAgD;IAChD,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAiDD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAi2BtD,CAAC;AA4OF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"VideoRecorder.d.ts","sourceRoot":"","sources":["../../src/components/VideoRecorder.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAaxE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,iBAAiB,EAAmC,MAAM,oCAAoC,CAAC;AAE1I,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,YAAY,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACrC,0CAA0C;IAC1C,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wCAAwC;IACxC,UAAU,EAAE,CAAC,SAAS,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACtD,iCAAiC;IACjC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,gDAAgD;IAChD,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAiDD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAg5BtD,CAAC;AA4OF,eAAe,aAAa,CAAC"}
@@ -200,6 +200,13 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
200
200
  },
201
201
  ];
202
202
  }
203
+ biometric_identity_sdk_core_1.logger.info('VideoRecorder: Challenges initialized', {
204
+ challengeCount: challengeList.length,
205
+ challengeActions: challengeList.map(c => c.action),
206
+ source: propChallenges && propChallenges.length > 0 ? 'propChallenges' :
207
+ onFetchChallenges ? 'onFetchChallenges' :
208
+ instructions && instructions.length > 0 ? 'instructions' : 'default'
209
+ });
203
210
  setChallenges(challengeList);
204
211
  setPhase('countdown');
205
212
  }
@@ -494,6 +501,12 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
494
501
  }
495
502
  }, [frames, completedChallenges, challenges, sessionId, onComplete, minDurationMs, resetAndRetry, strings]);
496
503
  const runChallenge = (0, react_1.useCallback)((index) => {
504
+ biometric_identity_sdk_core_1.logger.info('VideoRecorder: runChallenge called', {
505
+ index,
506
+ challengesLength: challenges.length,
507
+ challengeActions: challenges.map(c => c.action),
508
+ completedChallengesCount: completedChallenges.length
509
+ });
497
510
  if (index >= challenges.length) {
498
511
  setOverallProgress(100);
499
512
  if (recordingTimeoutRef.current) {
@@ -556,7 +569,16 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
556
569
  }, 100);
557
570
  setTimeout(() => {
558
571
  clearInterval(progressInterval);
559
- setCompletedChallenges(prev => [...prev, challenge.action]);
572
+ setCompletedChallenges(prev => {
573
+ const updated = [...prev, challenge.action];
574
+ biometric_identity_sdk_core_1.logger.info('VideoRecorder: Challenge completed', {
575
+ action: challenge.action,
576
+ index,
577
+ completedCount: updated.length,
578
+ completedActions: updated
579
+ });
580
+ return updated;
581
+ });
560
582
  react_native_1.Animated.timing(fadeAnim, {
561
583
  toValue: 0,
562
584
  duration: 200,
@@ -593,7 +615,32 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
593
615
  else {
594
616
  startFrameCapture();
595
617
  }
596
- runChallenge(0);
618
+ /**
619
+ * If challenges are not available, set default challenges and run challenge
620
+ * This should not happen if ProfilePictureCapture properly waits for challenges
621
+ * But as a fallback, set defaults and retry after state update
622
+ * Schedule runChallenge to execute after state update completes
623
+ * This ensures the updated challenges are available when runChallenge executes
624
+ * Check again after state update - runChallenge callback should have latest challenges
625
+ */
626
+ if (challenges.length === 0) {
627
+ biometric_identity_sdk_core_1.logger.warn('VideoRecorder: No challenges available when starting recording - challenges should have been loaded by initChallenges');
628
+ const defaultChallenges = smartMode ? getDefaultChallenges((0, biometric_identity_sdk_core_1.getStrings)()) : [
629
+ {
630
+ action: 'stay_still',
631
+ instruction: (0, biometric_identity_sdk_core_1.getStrings)().liveness.instructions.stayStill || 'Look at the camera and stay still',
632
+ duration_ms: duration || 5000,
633
+ order: 1,
634
+ },
635
+ ];
636
+ setChallenges(defaultChallenges);
637
+ Promise.resolve().then(() => {
638
+ runChallenge(0);
639
+ });
640
+ }
641
+ else {
642
+ runChallenge(0);
643
+ }
597
644
  const maxDuration = Math.max(totalDuration, minDurationMs + 2000);
598
645
  recordingTimeoutRef.current = setTimeout(() => {
599
646
  if (isRecordingRef.current) {
@@ -608,7 +655,7 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
608
655
  recordingTimeoutRef.current = null;
609
656
  }
610
657
  };
611
- }, [device, totalDuration, minDurationMs, handleVideoComplete, handleRecordingError, runChallenge, stopRecording, startFrameCapture]);
658
+ }, [device, totalDuration, minDurationMs, handleVideoComplete, handleRecordingError, runChallenge, stopRecording, startFrameCapture, challenges, smartMode, duration]);
612
659
  const currentChallenge = challenges[currentChallengeIndex];
613
660
  const getDirectionIndicator = () => {
614
661
  if (!currentChallenge)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hexar/biometric-identity-sdk-react-native",
3
- "version": "1.1.16",
3
+ "version": "1.1.18",
4
4
  "description": "React Native wrapper for Biometric Identity SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -61,14 +61,22 @@ export const ProfilePictureCapture: React.FC<ProfilePictureCaptureProps> = ({
61
61
  setIsLoadingChallenges(true);
62
62
  try {
63
63
  const challenges = await fetchChallenges('active');
64
+ logger.info('ProfilePictureCapture: Challenges loaded', {
65
+ challengeCount: challenges.length,
66
+ challenges: challenges.map(c => c.action)
67
+ });
64
68
  setCurrentChallenges(challenges);
65
69
  } catch (error) {
66
- logger.warn('Failed to fetch challenges, VideoRecorder will use defaults');
70
+ logger.warn('Failed to fetch challenges, VideoRecorder will use defaults', error);
67
71
  setCurrentChallenges([]);
68
72
  }
69
73
  setIsLoadingChallenges(false);
70
74
  };
71
75
  loadChallenges();
76
+ } else if (isInitialized) {
77
+ // If not using backend, still initialize with empty array (VideoRecorder will use defaults)
78
+ setCurrentChallenges([]);
79
+ setIsLoadingChallenges(false);
72
80
  }
73
81
  }, [isInitialized, isUsingBackend, fetchChallenges]);
74
82
 
@@ -154,6 +162,14 @@ export const ProfilePictureCapture: React.FC<ProfilePictureCaptureProps> = ({
154
162
  }, [isInitialized, isUsingBackend, sdk]);
155
163
 
156
164
  const handleVideoComplete = useCallback(async (videoResult: VideoRecordingResult) => {
165
+ logger.info('ProfilePictureCapture: Video recording completed', {
166
+ framesCount: videoResult.frames?.length || 0,
167
+ duration: videoResult.duration,
168
+ challengesCompleted: videoResult.challengesCompleted || [],
169
+ challengesCompletedCount: videoResult.challengesCompleted?.length || 0,
170
+ expectedChallengesCount: currentChallenges.length,
171
+ });
172
+
157
173
  setIsValidating(true);
158
174
 
159
175
  try {
@@ -201,7 +217,7 @@ export const ProfilePictureCapture: React.FC<ProfilePictureCaptureProps> = ({
201
217
  } as BiometricError;
202
218
  onError(biometricError);
203
219
  }
204
- }, [validateWithBackend, onComplete, onError, strings, language]);
220
+ }, [validateWithBackend, onComplete, onError, strings, language, currentChallenges]);
205
221
 
206
222
  const handleVideoCancel = useCallback(() => {
207
223
  if (onCancel) {
@@ -225,6 +241,20 @@ export const ProfilePictureCapture: React.FC<ProfilePictureCaptureProps> = ({
225
241
  );
226
242
  }
227
243
 
244
+ // Wait for initialization and challenge loading before showing VideoRecorder
245
+ if (!isInitialized || (isUsingBackend && isLoadingChallenges)) {
246
+ return (
247
+ <SafeAreaView style={[styles.container, { backgroundColor: theme?.backgroundColor || '#FFFFFF' }]}>
248
+ <View style={styles.loadingContainer}>
249
+ <ActivityIndicator size="large" color={theme?.primaryColor || '#4f46e5'} />
250
+ <Text style={[styles.loadingText, { color: theme?.textColor || '#1e1b4b' }]}>
251
+ {strings.liveness.preparing || 'Preparing...'}
252
+ </Text>
253
+ </View>
254
+ </SafeAreaView>
255
+ );
256
+ }
257
+
228
258
  return (
229
259
  <VideoRecorder
230
260
  theme={theme}
@@ -238,6 +238,13 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
238
238
  ];
239
239
  }
240
240
 
241
+ logger.info('VideoRecorder: Challenges initialized', {
242
+ challengeCount: challengeList.length,
243
+ challengeActions: challengeList.map(c => c.action),
244
+ source: propChallenges && propChallenges.length > 0 ? 'propChallenges' :
245
+ onFetchChallenges ? 'onFetchChallenges' :
246
+ instructions && instructions.length > 0 ? 'instructions' : 'default'
247
+ });
241
248
  setChallenges(challengeList);
242
249
  setPhase('countdown');
243
250
  } catch (error) {
@@ -574,6 +581,13 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
574
581
  }, [frames, completedChallenges, challenges, sessionId, onComplete, minDurationMs, resetAndRetry, strings]);
575
582
 
576
583
  const runChallenge = useCallback((index: number) => {
584
+ logger.info('VideoRecorder: runChallenge called', {
585
+ index,
586
+ challengesLength: challenges.length,
587
+ challengeActions: challenges.map(c => c.action),
588
+ completedChallengesCount: completedChallenges.length
589
+ });
590
+
577
591
  if (index >= challenges.length) {
578
592
  setOverallProgress(100);
579
593
 
@@ -647,7 +661,16 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
647
661
  setTimeout(() => {
648
662
  clearInterval(progressInterval);
649
663
 
650
- setCompletedChallenges(prev => [...prev, challenge.action]);
664
+ setCompletedChallenges(prev => {
665
+ const updated = [...prev, challenge.action];
666
+ logger.info('VideoRecorder: Challenge completed', {
667
+ action: challenge.action,
668
+ index,
669
+ completedCount: updated.length,
670
+ completedActions: updated
671
+ });
672
+ return updated;
673
+ });
651
674
 
652
675
  Animated.timing(fadeAnim, {
653
676
  toValue: 0,
@@ -687,7 +710,31 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
687
710
  startFrameCapture();
688
711
  }
689
712
 
690
- runChallenge(0);
713
+ /**
714
+ * If challenges are not available, set default challenges and run challenge
715
+ * This should not happen if ProfilePictureCapture properly waits for challenges
716
+ * But as a fallback, set defaults and retry after state update
717
+ * Schedule runChallenge to execute after state update completes
718
+ * This ensures the updated challenges are available when runChallenge executes
719
+ * Check again after state update - runChallenge callback should have latest challenges
720
+ */
721
+ if (challenges.length === 0) {
722
+ logger.warn('VideoRecorder: No challenges available when starting recording - challenges should have been loaded by initChallenges');
723
+ const defaultChallenges = smartMode ? getDefaultChallenges(getStrings()) : [
724
+ {
725
+ action: 'stay_still',
726
+ instruction: getStrings().liveness.instructions.stayStill || 'Look at the camera and stay still',
727
+ duration_ms: duration || 5000,
728
+ order: 1,
729
+ },
730
+ ];
731
+ setChallenges(defaultChallenges);
732
+ Promise.resolve().then(() => {
733
+ runChallenge(0);
734
+ });
735
+ } else {
736
+ runChallenge(0);
737
+ }
691
738
 
692
739
  const maxDuration = Math.max(totalDuration, minDurationMs + 2000);
693
740
  recordingTimeoutRef.current = setTimeout(() => {
@@ -704,7 +751,7 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
704
751
  recordingTimeoutRef.current = null;
705
752
  }
706
753
  };
707
- }, [device, totalDuration, minDurationMs, handleVideoComplete, handleRecordingError, runChallenge, stopRecording, startFrameCapture]);
754
+ }, [device, totalDuration, minDurationMs, handleVideoComplete, handleRecordingError, runChallenge, stopRecording, startFrameCapture, challenges, smartMode, duration]);
708
755
 
709
756
  const currentChallenge = challenges[currentChallengeIndex];
710
757