@hexar/biometric-identity-sdk-react-native 1.0.19 → 1.0.21

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":"BiometricIdentityFlow.d.ts","sourceRoot":"","sources":["../../src/components/BiometricIdentityFlow.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AACxE,OAAO,EAOL,SAAS,EACV,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,cAAc,EAKd,iBAAiB,EAElB,MAAM,oCAAoC,CAAC;AAU5C,MAAM,WAAW,0BAA0B;IACzC,oBAAoB,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACzD,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IACzC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,SAAS,CAAC;QACtB,OAAO,CAAC,EAAE,SAAS,CAAC;KACrB,CAAC;CACH;AAED,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CAiWtE,CAAC;AA8NF,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"BiometricIdentityFlow.d.ts","sourceRoot":"","sources":["../../src/components/BiometricIdentityFlow.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AACxE,OAAO,EAOL,SAAS,EACV,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,cAAc,EAKd,iBAAiB,EAElB,MAAM,oCAAoC,CAAC;AAU5C,MAAM,WAAW,0BAA0B;IACzC,oBAAoB,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACzD,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IACzC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,SAAS,CAAC;QACtB,OAAO,CAAC,EAAE,SAAS,CAAC;KACrB,CAAC;CACH;AAED,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CA2WtE,CAAC;AA8NF,eAAe,qBAAqB,CAAC"}
@@ -70,9 +70,7 @@ const BiometricIdentityFlow = ({ onValidationComplete, onError, theme, language,
70
70
  const strings = (0, biometric_identity_sdk_core_1.getStrings)();
71
71
  const styles = createStyles(theme);
72
72
  (0, react_1.useEffect)(() => {
73
- console.log('🔵 [BiometricIdentityFlow] useEffect triggered - currentStep:', state.currentStep, 'hasResult:', !!state.validationResult, 'hasCalled:', hasCalledValidationComplete.current);
74
73
  if (state.currentStep === biometric_identity_sdk_core_1.SDKStep.RESULT && state.validationResult && !hasCalledValidationComplete.current) {
75
- console.log('🟢 [BiometricIdentityFlow] Calling onValidationComplete callback');
76
74
  biometric_identity_sdk_core_1.logger.info('Validation completed, calling onValidationComplete callback');
77
75
  hasCalledValidationComplete.current = true;
78
76
  onValidationCompleteRef.current(state.validationResult);
@@ -125,6 +123,14 @@ const BiometricIdentityFlow = ({ onValidationComplete, onError, theme, language,
125
123
  }
126
124
  else if (cameraMode === 'video') {
127
125
  const videoResult = data;
126
+ biometric_identity_sdk_core_1.logger.info('Video recording received', {
127
+ framesCount: videoResult.frames?.length || 0,
128
+ duration: videoResult.duration
129
+ });
130
+ if (!videoResult.frames || videoResult.frames.length === 0) {
131
+ biometric_identity_sdk_core_1.logger.error('Video recording has no frames');
132
+ throw new Error('Video recording contains no frames');
133
+ }
128
134
  await storeVideoRecording({
129
135
  frames: videoResult.frames,
130
136
  duration: videoResult.duration,
@@ -133,43 +139,43 @@ const BiometricIdentityFlow = ({ onValidationComplete, onError, theme, language,
133
139
  challengesCompleted: videoResult.challengesCompleted,
134
140
  sessionId: videoResult.sessionId,
135
141
  });
136
- console.log('🔵 [BiometricIdentityFlow] Video stored, starting validation...');
137
- biometric_identity_sdk_core_1.logger.info('Starting validation...');
142
+ const stateAfterStore = sdk.getState();
143
+ biometric_identity_sdk_core_1.logger.info('Video stored, verifying state before validation', {
144
+ storedFramesCount: stateAfterStore.videoData?.frames?.length || 0,
145
+ hasVideoData: !!stateAfterStore.videoData
146
+ });
147
+ if (!stateAfterStore.videoData || !stateAfterStore.videoData.frames || stateAfterStore.videoData.frames.length === 0) {
148
+ biometric_identity_sdk_core_1.logger.error('Video data not properly stored in SDK state');
149
+ throw new Error('Video data was not properly stored');
150
+ }
151
+ biometric_identity_sdk_core_1.logger.info('Starting validation');
138
152
  let result = null;
139
153
  try {
140
154
  result = await validateIdentity();
141
- console.log('🟢 [BiometricIdentityFlow] Validation completed:', result);
142
- biometric_identity_sdk_core_1.logger.info('Validation completed successfully:', result);
155
+ biometric_identity_sdk_core_1.logger.info('Validation completed successfully');
143
156
  }
144
157
  catch (validationError) {
145
- console.error('❌ [BiometricIdentityFlow] Validation error:', validationError);
146
158
  biometric_identity_sdk_core_1.logger.error('Validation error:', validationError);
147
- throw validationError; // Re-throw to be caught by outer catch
159
+ throw validationError;
148
160
  }
149
161
  const finalState = sdk.getState();
150
- console.log('🔵 [BiometricIdentityFlow] Final state after validation:', JSON.stringify({
162
+ biometric_identity_sdk_core_1.logger.info('Final state after validation', {
151
163
  currentStep: finalState.currentStep,
152
- hasResult: !!finalState.validationResult,
153
- progress: finalState.progress,
154
- isLoading: finalState.isLoading
155
- }));
156
- biometric_identity_sdk_core_1.logger.info('Final state after validation:', finalState);
164
+ hasResult: !!finalState.validationResult
165
+ });
157
166
  if (result && !hasCalledValidationComplete.current) {
158
- console.log('🟢 [BiometricIdentityFlow] Calling onValidationComplete directly with result');
159
167
  biometric_identity_sdk_core_1.logger.info('Calling onValidationComplete directly with validation result');
160
168
  hasCalledValidationComplete.current = true;
161
169
  onValidationCompleteRef.current(result);
162
170
  }
163
171
  if (finalState.currentStep === biometric_identity_sdk_core_1.SDKStep.RESULT && finalState.validationResult && !hasCalledValidationComplete.current) {
164
- console.log('🟢 [BiometricIdentityFlow] Backup: Calling onValidationComplete from state');
165
- biometric_identity_sdk_core_1.logger.info('Backup: Calling onValidationComplete from state');
172
+ biometric_identity_sdk_core_1.logger.info('Calling onValidationComplete from state');
166
173
  hasCalledValidationComplete.current = true;
167
174
  onValidationCompleteRef.current(finalState.validationResult);
168
175
  }
169
176
  }
170
177
  }
171
178
  catch (error) {
172
- console.error('❌ [BiometricIdentityFlow] Capture/validation error:', error);
173
179
  biometric_identity_sdk_core_1.logger.error('Capture/validation error:', error);
174
180
  if (error && typeof error === 'object' && 'code' in error) {
175
181
  onErrorRef.current(error);
@@ -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;AA8CD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA2xBtD,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;AA8CD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAqzBtD,CAAC;AA4OF,eAAe,aAAa,CAAC"}
@@ -100,6 +100,7 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
100
100
  const [overallProgress, setOverallProgress] = (0, react_1.useState)(0);
101
101
  const [completedChallenges, setCompletedChallenges] = (0, react_1.useState)([]);
102
102
  const [frames, setFrames] = (0, react_1.useState)([]);
103
+ const framesRef = (0, react_1.useRef)([]);
103
104
  const [hasPermission, setHasPermission] = (0, react_1.useState)(false);
104
105
  const cameraRef = (0, react_1.useRef)(null);
105
106
  const { hasPermission: cameraPermission, requestPermission } = (0, react_native_vision_camera_1.useCameraPermission)();
@@ -257,6 +258,7 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
257
258
  }, [arrowAnim]);
258
259
  const resetAndRetry = (0, react_1.useCallback)(() => {
259
260
  setFrames([]);
261
+ framesRef.current = [];
260
262
  setCompletedChallenges([]);
261
263
  setCurrentChallengeIndex(0);
262
264
  setChallengeProgress(0);
@@ -293,16 +295,18 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
293
295
  biometric_identity_sdk_core_1.logger.warn('Could not read video file, using captured frames');
294
296
  }
295
297
  }
296
- let finalFrames = frames.length > 0 ? frames : [];
298
+ const currentFrames = framesRef.current.length > 0 ? framesRef.current : frames;
299
+ let finalFrames = currentFrames.length > 0 ? currentFrames : [];
297
300
  if (finalFrames.length === 0 && videoBase64) {
298
301
  finalFrames = [videoBase64];
299
302
  }
300
303
  if (finalFrames.length === 0) {
301
- biometric_identity_sdk_core_1.logger.error('No frames or video available, cannot complete');
304
+ biometric_identity_sdk_core_1.logger.error('No frames or video available, cannot complete. Frames ref:', framesRef.current.length, 'Frames state:', frames.length);
302
305
  setPhase('recording');
303
306
  handleRecordingError(new Error('No video frames captured'));
304
307
  return;
305
308
  }
309
+ biometric_identity_sdk_core_1.logger.info('Using frames for completion:', finalFrames.length, 'frames');
306
310
  const result = {
307
311
  frames: finalFrames,
308
312
  duration: actualDuration,
@@ -324,7 +328,16 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
324
328
  }, [frames, completedChallenges, challenges, sessionId, onComplete, resetAndRetry, handleRecordingError, strings, minDurationMs, phase]);
325
329
  const startFrameCapture = (0, react_1.useCallback)(() => {
326
330
  if (cameraRef.current && device) {
331
+ biometric_identity_sdk_core_1.logger.info('Starting frame capture');
332
+ framesRef.current = [];
327
333
  frameCaptureInterval.current = setInterval(async () => {
334
+ if (!isRecordingRef.current) {
335
+ if (frameCaptureInterval.current) {
336
+ clearInterval(frameCaptureInterval.current);
337
+ frameCaptureInterval.current = null;
338
+ }
339
+ return;
340
+ }
328
341
  try {
329
342
  const photo = await cameraRef.current?.takePhoto({
330
343
  flash: 'off',
@@ -334,26 +347,32 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
334
347
  const RNFS = require('react-native-fs');
335
348
  const base64 = await RNFS.readFile(photo.path, 'base64');
336
349
  setFrames(prev => {
337
- if (prev.length < 100) {
338
- return [...prev, base64];
350
+ const newFrames = prev.length < 100 ? [...prev, base64] : prev;
351
+ framesRef.current = newFrames;
352
+ if (newFrames.length % 10 === 0) {
353
+ biometric_identity_sdk_core_1.logger.info('Captured frames:', newFrames.length);
339
354
  }
340
- return prev;
355
+ return newFrames;
341
356
  });
342
357
  }
343
358
  catch (fsError) {
359
+ biometric_identity_sdk_core_1.logger.warn('Could not read photo file, using path:', fsError);
344
360
  setFrames(prev => {
345
- if (prev.length < 100) {
346
- return [...prev, photo.path];
347
- }
348
- return prev;
361
+ const newFrames = prev.length < 100 ? [...prev, photo.path] : prev;
362
+ framesRef.current = newFrames;
363
+ return newFrames;
349
364
  });
350
365
  }
351
366
  }
352
367
  }
353
368
  catch (error) {
369
+ biometric_identity_sdk_core_1.logger.warn('Frame capture error:', error);
354
370
  }
355
371
  }, 100);
356
372
  }
373
+ else {
374
+ biometric_identity_sdk_core_1.logger.warn('Cannot start frame capture: camera or device not available');
375
+ }
357
376
  }, [device]);
358
377
  const stopRecording = (0, react_1.useCallback)(async () => {
359
378
  if (recordingTimeoutRef.current) {
@@ -377,23 +396,26 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
377
396
  catch (error) {
378
397
  biometric_identity_sdk_core_1.logger.error('Error stopping video recording:', error);
379
398
  const actualDuration = Date.now() - recordingStartTime.current;
380
- if (actualDuration >= minDurationMs && frames.length > 0) {
399
+ const currentFrames = framesRef.current.length > 0 ? framesRef.current : frames;
400
+ if (actualDuration >= minDurationMs && currentFrames.length > 0) {
401
+ biometric_identity_sdk_core_1.logger.info('Stopping recording with frames:', currentFrames.length);
381
402
  const result = {
382
- frames,
403
+ frames: currentFrames,
383
404
  duration: actualDuration,
384
405
  instructionsFollowed: completedChallenges.length === challenges.length,
385
- qualityScore: Math.min(100, (frames.length / 30) * 100),
406
+ qualityScore: Math.min(100, (currentFrames.length / 30) * 100),
386
407
  challengesCompleted: completedChallenges,
387
408
  sessionId,
388
409
  };
389
410
  onComplete(result);
390
411
  }
391
412
  else {
413
+ biometric_identity_sdk_core_1.logger.info('Stopping recording with frames (fallback):', currentFrames.length);
392
414
  const result = {
393
- frames: frames.length > 0 ? frames : [],
415
+ frames: currentFrames.length > 0 ? currentFrames : [],
394
416
  duration: actualDuration,
395
417
  instructionsFollowed: completedChallenges.length === challenges.length,
396
- qualityScore: frames.length > 0 ? Math.min(100, (frames.length / 30) * 100) : 0,
418
+ qualityScore: currentFrames.length > 0 ? Math.min(100, (currentFrames.length / 30) * 100) : 0,
397
419
  challengesCompleted: completedChallenges,
398
420
  sessionId,
399
421
  };
@@ -403,19 +425,21 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
403
425
  }
404
426
  else {
405
427
  const actualDuration = Date.now() - recordingStartTime.current;
406
- if (frames.length === 0 && actualDuration < minDurationMs) {
407
- biometric_identity_sdk_core_1.logger.error('No frames and duration too short, cannot complete');
428
+ const currentFrames = framesRef.current.length > 0 ? framesRef.current : frames;
429
+ if (currentFrames.length === 0 && actualDuration < minDurationMs) {
430
+ biometric_identity_sdk_core_1.logger.error('No frames and duration too short, cannot complete. Frames ref:', framesRef.current.length, 'Frames state:', frames.length);
408
431
  setPhase('recording');
409
432
  react_native_1.Alert.alert(strings.errors.videoTooShort?.title || 'Recording Too Short', strings.errors.videoTooShort?.message || `Video must be at least ${minDurationMs / 1000} seconds. Please try again.`, [{ text: strings.common.retry || 'OK', onPress: resetAndRetry }]);
410
433
  return;
411
434
  }
412
435
  setPhase('processing');
413
436
  setOverallProgress(100);
437
+ biometric_identity_sdk_core_1.logger.info('Completing recording with frames:', currentFrames.length);
414
438
  const result = {
415
- frames: frames.length > 0 ? frames : [],
439
+ frames: currentFrames.length > 0 ? currentFrames : [],
416
440
  duration: actualDuration,
417
441
  instructionsFollowed: completedChallenges.length === challenges.length,
418
- qualityScore: frames.length > 0 ? Math.min(100, (frames.length / 30) * 100) : 0,
442
+ qualityScore: currentFrames.length > 0 ? Math.min(100, (currentFrames.length / 30) * 100) : 0,
419
443
  challengesCompleted: completedChallenges,
420
444
  sessionId,
421
445
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useBiometricSDK.d.ts","sourceRoot":"","sources":["../../src/hooks/useBiometricSDK.ts"],"names":[],"mappings":"AACA,OAAO,EACL,oBAAoB,EACpB,QAAQ,EACR,WAAW,EAGZ,MAAM,oCAAoC,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,oBAAoB,CAAC;IAC1B,KAAK,EAAE,QAAQ,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,YAAY,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,mBAAmB,EAAE,CAAC,SAAS,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,eAAe,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,KAAK,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IAC7E,gBAAgB,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IACrC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,WAAW,EAAE,CAAC,SAAS,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAED,eAAO,MAAM,eAAe,QAAO,qBA4QlC,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"useBiometricSDK.d.ts","sourceRoot":"","sources":["../../src/hooks/useBiometricSDK.ts"],"names":[],"mappings":"AACA,OAAO,EACL,oBAAoB,EACpB,QAAQ,EACR,WAAW,EAGZ,MAAM,oCAAoC,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,oBAAoB,CAAC;IAC1B,KAAK,EAAE,QAAQ,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,YAAY,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,mBAAmB,EAAE,CAAC,SAAS,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,eAAe,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,KAAK,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IAC7E,gBAAgB,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IACrC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,WAAW,EAAE,CAAC,SAAS,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAED,eAAO,MAAM,eAAe,QAAO,qBA2QlC,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -137,9 +137,13 @@ const useBiometricSDK = () => {
137
137
  * Validate identity with all collected data
138
138
  */
139
139
  const validateIdentity = (0, react_1.useCallback)(async () => {
140
- console.log('🔵 [useBiometricSDK] validateIdentity called');
141
- biometric_identity_sdk_core_1.logger.info('validateIdentity called, current state:', sdk.getState());
142
- setState(sdk.getState());
140
+ const currentState = sdk.getState();
141
+ biometric_identity_sdk_core_1.logger.info('validateIdentity called', {
142
+ hasFrontID: !!currentState.frontID,
143
+ hasVideoData: !!currentState.videoData,
144
+ videoFramesCount: currentState.videoData?.frames?.length || 0
145
+ });
146
+ setState(currentState);
143
147
  const pollInterval = setInterval(() => {
144
148
  if (isMounted.current) {
145
149
  const currentState = sdk.getState();
@@ -148,44 +152,41 @@ const useBiometricSDK = () => {
148
152
  }, 200);
149
153
  let finalPollInterval = null;
150
154
  try {
151
- console.log('🔵 [useBiometricSDK] Calling sdk.validateIdentity()...');
155
+ biometric_identity_sdk_core_1.logger.info('Calling sdk.validateIdentity');
152
156
  const result = await sdk.validateIdentity();
153
- console.log('🟢 [useBiometricSDK] sdk.validateIdentity() completed, result:', result);
154
- // Keep polling for a bit to ensure we capture the RESULT state transition
155
- // The SDK updates state synchronously, but we want to make sure React sees it
157
+ biometric_identity_sdk_core_1.logger.info('sdk.validateIdentity completed');
156
158
  let pollCount = 0;
157
- const maxPolls = 10; // Poll for up to 2 seconds (10 * 200ms)
159
+ const maxPolls = 10;
158
160
  finalPollInterval = setInterval(() => {
159
161
  pollCount++;
160
162
  if (isMounted.current) {
161
163
  const currentState = sdk.getState();
162
- biometric_identity_sdk_core_1.logger.info(`Polling state (${pollCount}/${maxPolls}):`, currentState);
163
164
  setState(currentState);
164
- // Stop polling once we reach RESULT or ERROR state
165
165
  if (currentState.currentStep === biometric_identity_sdk_core_1.SDKStep.RESULT || currentState.currentStep === biometric_identity_sdk_core_1.SDKStep.ERROR) {
166
- console.log('🟢 [useBiometricSDK] Reached final state:', currentState.currentStep);
167
166
  if (finalPollInterval)
168
167
  clearInterval(finalPollInterval);
169
168
  clearInterval(pollInterval);
170
- biometric_identity_sdk_core_1.logger.info('Reached final state, stopped polling:', currentState);
169
+ biometric_identity_sdk_core_1.logger.info('Reached final state, stopped polling', {
170
+ step: currentState.currentStep
171
+ });
171
172
  }
172
173
  else if (pollCount >= maxPolls) {
173
- // Force stop after max polls
174
174
  if (finalPollInterval)
175
175
  clearInterval(finalPollInterval);
176
176
  clearInterval(pollInterval);
177
177
  const finalState = sdk.getState();
178
- biometric_identity_sdk_core_1.logger.warn('Max polls reached, forcing final state:', finalState);
178
+ biometric_identity_sdk_core_1.logger.warn('Max polls reached, forcing final state');
179
179
  setState(finalState);
180
180
  }
181
181
  }
182
182
  }, 200);
183
- // Also get immediate state after promise resolves
184
183
  if (isMounted.current) {
185
184
  const immediateState = sdk.getState();
186
- biometric_identity_sdk_core_1.logger.info('Validation result received, immediate state:', immediateState);
185
+ biometric_identity_sdk_core_1.logger.info('Validation result received, immediate state', {
186
+ step: immediateState.currentStep,
187
+ hasResult: !!immediateState.validationResult
188
+ });
187
189
  setState(immediateState);
188
- // If we're already at RESULT, clear intervals immediately
189
190
  if (immediateState.currentStep === biometric_identity_sdk_core_1.SDKStep.RESULT || immediateState.currentStep === biometric_identity_sdk_core_1.SDKStep.ERROR) {
190
191
  if (finalPollInterval)
191
192
  clearInterval(finalPollInterval);
@@ -195,13 +196,11 @@ const useBiometricSDK = () => {
195
196
  return result;
196
197
  }
197
198
  catch (error) {
198
- // Clear all intervals on error
199
199
  clearInterval(pollInterval);
200
200
  if (finalPollInterval) {
201
201
  clearInterval(finalPollInterval);
202
202
  }
203
- console.error('❌ [useBiometricSDK] Validation error:', error);
204
- biometric_identity_sdk_core_1.logger.error('Validation error, state:', sdk.getState(), error);
203
+ biometric_identity_sdk_core_1.logger.error('Validation error', error);
205
204
  if (isMounted.current) {
206
205
  const errorState = sdk.getState();
207
206
  setState(errorState);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hexar/biometric-identity-sdk-react-native",
3
- "version": "1.0.19",
3
+ "version": "1.0.21",
4
4
  "description": "React Native wrapper for Biometric Identity SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -11,7 +11,7 @@
11
11
  "clean": "rm -rf dist"
12
12
  },
13
13
  "peerDependencies": {
14
- "@hexar/biometric-identity-sdk-core": ">=1.0.11",
14
+ "@hexar/biometric-identity-sdk-core": ">=1.0.12",
15
15
  "react": ">=18.0.0",
16
16
  "react-native": ">=0.70.0",
17
17
  "react-native-permissions": ">=4.0.0",
@@ -96,9 +96,7 @@ export const BiometricIdentityFlow: React.FC<BiometricIdentityFlowProps> = ({
96
96
  const styles = createStyles(theme);
97
97
 
98
98
  useEffect(() => {
99
- console.log('🔵 [BiometricIdentityFlow] useEffect triggered - currentStep:', state.currentStep, 'hasResult:', !!state.validationResult, 'hasCalled:', hasCalledValidationComplete.current);
100
99
  if (state.currentStep === SDKStep.RESULT && state.validationResult && !hasCalledValidationComplete.current) {
101
- console.log('🟢 [BiometricIdentityFlow] Calling onValidationComplete callback');
102
100
  logger.info('Validation completed, calling onValidationComplete callback');
103
101
  hasCalledValidationComplete.current = true;
104
102
  onValidationCompleteRef.current(state.validationResult);
@@ -155,6 +153,16 @@ export const BiometricIdentityFlow: React.FC<BiometricIdentityFlowProps> = ({
155
153
  } else if (cameraMode === 'video') {
156
154
  const videoResult: VideoRecordingResult = data;
157
155
 
156
+ logger.info('Video recording received', {
157
+ framesCount: videoResult.frames?.length || 0,
158
+ duration: videoResult.duration
159
+ });
160
+
161
+ if (!videoResult.frames || videoResult.frames.length === 0) {
162
+ logger.error('Video recording has no frames');
163
+ throw new Error('Video recording contains no frames');
164
+ }
165
+
158
166
  await storeVideoRecording({
159
167
  frames: videoResult.frames,
160
168
  duration: videoResult.duration,
@@ -164,45 +172,47 @@ export const BiometricIdentityFlow: React.FC<BiometricIdentityFlowProps> = ({
164
172
  sessionId: videoResult.sessionId,
165
173
  });
166
174
 
167
- console.log('🔵 [BiometricIdentityFlow] Video stored, starting validation...');
168
- logger.info('Starting validation...');
175
+ const stateAfterStore = sdk.getState();
176
+ logger.info('Video stored, verifying state before validation', {
177
+ storedFramesCount: stateAfterStore.videoData?.frames?.length || 0,
178
+ hasVideoData: !!stateAfterStore.videoData
179
+ });
180
+
181
+ if (!stateAfterStore.videoData || !stateAfterStore.videoData.frames || stateAfterStore.videoData.frames.length === 0) {
182
+ logger.error('Video data not properly stored in SDK state');
183
+ throw new Error('Video data was not properly stored');
184
+ }
185
+
186
+ logger.info('Starting validation');
169
187
 
170
188
  let result: ValidationResult | null = null;
171
189
  try {
172
190
  result = await validateIdentity();
173
- console.log('🟢 [BiometricIdentityFlow] Validation completed:', result);
174
- logger.info('Validation completed successfully:', result);
191
+ logger.info('Validation completed successfully');
175
192
  } catch (validationError) {
176
- console.error('❌ [BiometricIdentityFlow] Validation error:', validationError);
177
193
  logger.error('Validation error:', validationError);
178
- throw validationError; // Re-throw to be caught by outer catch
194
+ throw validationError;
179
195
  }
180
196
 
181
197
  const finalState = sdk.getState();
182
- console.log('🔵 [BiometricIdentityFlow] Final state after validation:', JSON.stringify({
198
+ logger.info('Final state after validation', {
183
199
  currentStep: finalState.currentStep,
184
- hasResult: !!finalState.validationResult,
185
- progress: finalState.progress,
186
- isLoading: finalState.isLoading
187
- }));
188
- logger.info('Final state after validation:', finalState);
200
+ hasResult: !!finalState.validationResult
201
+ });
189
202
 
190
203
  if (result && !hasCalledValidationComplete.current) {
191
- console.log('🟢 [BiometricIdentityFlow] Calling onValidationComplete directly with result');
192
204
  logger.info('Calling onValidationComplete directly with validation result');
193
205
  hasCalledValidationComplete.current = true;
194
206
  onValidationCompleteRef.current(result);
195
207
  }
196
208
 
197
209
  if (finalState.currentStep === SDKStep.RESULT && finalState.validationResult && !hasCalledValidationComplete.current) {
198
- console.log('🟢 [BiometricIdentityFlow] Backup: Calling onValidationComplete from state');
199
- logger.info('Backup: Calling onValidationComplete from state');
210
+ logger.info('Calling onValidationComplete from state');
200
211
  hasCalledValidationComplete.current = true;
201
212
  onValidationCompleteRef.current(finalState.validationResult);
202
213
  }
203
214
  }
204
215
  } catch (error) {
205
- console.error('❌ [BiometricIdentityFlow] Capture/validation error:', error);
206
216
  logger.error('Capture/validation error:', error);
207
217
 
208
218
  if (error && typeof error === 'object' && 'code' in error) {
@@ -127,6 +127,7 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
127
127
  const [overallProgress, setOverallProgress] = useState(0);
128
128
  const [completedChallenges, setCompletedChallenges] = useState<string[]>([]);
129
129
  const [frames, setFrames] = useState<string[]>([]);
130
+ const framesRef = useRef<string[]>([]);
130
131
  const [hasPermission, setHasPermission] = useState(false);
131
132
 
132
133
  const cameraRef = useRef<Camera>(null);
@@ -304,6 +305,7 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
304
305
 
305
306
  const resetAndRetry = useCallback(() => {
306
307
  setFrames([]);
308
+ framesRef.current = [];
307
309
  setCompletedChallenges([]);
308
310
  setCurrentChallengeIndex(0);
309
311
  setChallengeProgress(0);
@@ -354,19 +356,22 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
354
356
  }
355
357
  }
356
358
 
357
- let finalFrames = frames.length > 0 ? frames : [];
359
+ const currentFrames = framesRef.current.length > 0 ? framesRef.current : frames;
360
+ let finalFrames = currentFrames.length > 0 ? currentFrames : [];
358
361
 
359
362
  if (finalFrames.length === 0 && videoBase64) {
360
363
  finalFrames = [videoBase64];
361
364
  }
362
365
 
363
366
  if (finalFrames.length === 0) {
364
- logger.error('No frames or video available, cannot complete');
367
+ logger.error('No frames or video available, cannot complete. Frames ref:', framesRef.current.length, 'Frames state:', frames.length);
365
368
  setPhase('recording');
366
369
  handleRecordingError(new Error('No video frames captured'));
367
370
  return;
368
371
  }
369
372
 
373
+ logger.info('Using frames for completion:', finalFrames.length, 'frames');
374
+
370
375
  const result: VideoRecordingResult = {
371
376
  frames: finalFrames,
372
377
  duration: actualDuration,
@@ -390,7 +395,17 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
390
395
 
391
396
  const startFrameCapture = useCallback(() => {
392
397
  if (cameraRef.current && device) {
398
+ logger.info('Starting frame capture');
399
+ framesRef.current = [];
393
400
  frameCaptureInterval.current = setInterval(async () => {
401
+ if (!isRecordingRef.current) {
402
+ if (frameCaptureInterval.current) {
403
+ clearInterval(frameCaptureInterval.current);
404
+ frameCaptureInterval.current = null;
405
+ }
406
+ return;
407
+ }
408
+
394
409
  try {
395
410
  const photo = await cameraRef.current?.takePhoto({
396
411
  flash: 'off',
@@ -401,23 +416,28 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
401
416
  const RNFS = require('react-native-fs');
402
417
  const base64 = await RNFS.readFile(photo.path, 'base64');
403
418
  setFrames(prev => {
404
- if (prev.length < 100) {
405
- return [...prev, base64];
419
+ const newFrames = prev.length < 100 ? [...prev, base64] : prev;
420
+ framesRef.current = newFrames;
421
+ if (newFrames.length % 10 === 0) {
422
+ logger.info('Captured frames:', newFrames.length);
406
423
  }
407
- return prev;
424
+ return newFrames;
408
425
  });
409
426
  } catch (fsError) {
427
+ logger.warn('Could not read photo file, using path:', fsError);
410
428
  setFrames(prev => {
411
- if (prev.length < 100) {
412
- return [...prev, photo.path];
413
- }
414
- return prev;
429
+ const newFrames = prev.length < 100 ? [...prev, photo.path] : prev;
430
+ framesRef.current = newFrames;
431
+ return newFrames;
415
432
  });
416
433
  }
417
434
  }
418
435
  } catch (error) {
436
+ logger.warn('Frame capture error:', error);
419
437
  }
420
438
  }, 100);
439
+ } else {
440
+ logger.warn('Cannot start frame capture: camera or device not available');
421
441
  }
422
442
  }, [device]);
423
443
 
@@ -447,22 +467,26 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
447
467
  logger.error('Error stopping video recording:', error);
448
468
 
449
469
  const actualDuration = Date.now() - recordingStartTime.current;
450
- if (actualDuration >= minDurationMs && frames.length > 0) {
470
+ const currentFrames = framesRef.current.length > 0 ? framesRef.current : frames;
471
+
472
+ if (actualDuration >= minDurationMs && currentFrames.length > 0) {
473
+ logger.info('Stopping recording with frames:', currentFrames.length);
451
474
  const result: VideoRecordingResult = {
452
- frames,
475
+ frames: currentFrames,
453
476
  duration: actualDuration,
454
477
  instructionsFollowed: completedChallenges.length === challenges.length,
455
- qualityScore: Math.min(100, (frames.length / 30) * 100),
478
+ qualityScore: Math.min(100, (currentFrames.length / 30) * 100),
456
479
  challengesCompleted: completedChallenges,
457
480
  sessionId,
458
481
  };
459
482
  onComplete(result);
460
483
  } else {
484
+ logger.info('Stopping recording with frames (fallback):', currentFrames.length);
461
485
  const result: VideoRecordingResult = {
462
- frames: frames.length > 0 ? frames : [],
486
+ frames: currentFrames.length > 0 ? currentFrames : [],
463
487
  duration: actualDuration,
464
488
  instructionsFollowed: completedChallenges.length === challenges.length,
465
- qualityScore: frames.length > 0 ? Math.min(100, (frames.length / 30) * 100) : 0,
489
+ qualityScore: currentFrames.length > 0 ? Math.min(100, (currentFrames.length / 30) * 100) : 0,
466
490
  challengesCompleted: completedChallenges,
467
491
  sessionId,
468
492
  };
@@ -471,9 +495,10 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
471
495
  }
472
496
  } else {
473
497
  const actualDuration = Date.now() - recordingStartTime.current;
498
+ const currentFrames = framesRef.current.length > 0 ? framesRef.current : frames;
474
499
 
475
- if (frames.length === 0 && actualDuration < minDurationMs) {
476
- logger.error('No frames and duration too short, cannot complete');
500
+ if (currentFrames.length === 0 && actualDuration < minDurationMs) {
501
+ logger.error('No frames and duration too short, cannot complete. Frames ref:', framesRef.current.length, 'Frames state:', frames.length);
477
502
  setPhase('recording');
478
503
  Alert.alert(
479
504
  strings.errors.videoTooShort?.title || 'Recording Too Short',
@@ -486,11 +511,12 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
486
511
  setPhase('processing');
487
512
  setOverallProgress(100);
488
513
 
514
+ logger.info('Completing recording with frames:', currentFrames.length);
489
515
  const result: VideoRecordingResult = {
490
- frames: frames.length > 0 ? frames : [],
516
+ frames: currentFrames.length > 0 ? currentFrames : [],
491
517
  duration: actualDuration,
492
518
  instructionsFollowed: completedChallenges.length === challenges.length,
493
- qualityScore: frames.length > 0 ? Math.min(100, (frames.length / 30) * 100) : 0,
519
+ qualityScore: currentFrames.length > 0 ? Math.min(100, (currentFrames.length / 30) * 100) : 0,
494
520
  challengesCompleted: completedChallenges,
495
521
  sessionId,
496
522
  };
@@ -194,9 +194,13 @@ export const useBiometricSDK = (): UseBiometricSDKResult => {
194
194
  * Validate identity with all collected data
195
195
  */
196
196
  const validateIdentity = useCallback(async () => {
197
- console.log('🔵 [useBiometricSDK] validateIdentity called');
198
- logger.info('validateIdentity called, current state:', sdk.getState());
199
- setState(sdk.getState());
197
+ const currentState = sdk.getState();
198
+ logger.info('validateIdentity called', {
199
+ hasFrontID: !!currentState.frontID,
200
+ hasVideoData: !!currentState.videoData,
201
+ videoFramesCount: currentState.videoData?.frames?.length || 0
202
+ });
203
+ setState(currentState);
200
204
 
201
205
  const pollInterval = setInterval(() => {
202
206
  if (isMounted.current) {
@@ -208,46 +212,43 @@ export const useBiometricSDK = (): UseBiometricSDKResult => {
208
212
  let finalPollInterval: NodeJS.Timeout | null = null;
209
213
 
210
214
  try {
211
- console.log('🔵 [useBiometricSDK] Calling sdk.validateIdentity()...');
215
+ logger.info('Calling sdk.validateIdentity');
212
216
  const result = await sdk.validateIdentity();
213
- console.log('🟢 [useBiometricSDK] sdk.validateIdentity() completed, result:', result);
217
+ logger.info('sdk.validateIdentity completed');
214
218
 
215
- // Keep polling for a bit to ensure we capture the RESULT state transition
216
- // The SDK updates state synchronously, but we want to make sure React sees it
217
219
  let pollCount = 0;
218
- const maxPolls = 10; // Poll for up to 2 seconds (10 * 200ms)
220
+ const maxPolls = 10;
219
221
 
220
222
  finalPollInterval = setInterval(() => {
221
223
  pollCount++;
222
224
  if (isMounted.current) {
223
225
  const currentState = sdk.getState();
224
- logger.info(`Polling state (${pollCount}/${maxPolls}):`, currentState);
225
226
  setState(currentState);
226
227
 
227
- // Stop polling once we reach RESULT or ERROR state
228
228
  if (currentState.currentStep === SDKStep.RESULT || currentState.currentStep === SDKStep.ERROR) {
229
- console.log('🟢 [useBiometricSDK] Reached final state:', currentState.currentStep);
230
229
  if (finalPollInterval) clearInterval(finalPollInterval);
231
230
  clearInterval(pollInterval);
232
- logger.info('Reached final state, stopped polling:', currentState);
231
+ logger.info('Reached final state, stopped polling', {
232
+ step: currentState.currentStep
233
+ });
233
234
  } else if (pollCount >= maxPolls) {
234
- // Force stop after max polls
235
235
  if (finalPollInterval) clearInterval(finalPollInterval);
236
236
  clearInterval(pollInterval);
237
237
  const finalState = sdk.getState();
238
- logger.warn('Max polls reached, forcing final state:', finalState);
238
+ logger.warn('Max polls reached, forcing final state');
239
239
  setState(finalState);
240
240
  }
241
241
  }
242
242
  }, 200);
243
243
 
244
- // Also get immediate state after promise resolves
245
244
  if (isMounted.current) {
246
245
  const immediateState = sdk.getState();
247
- logger.info('Validation result received, immediate state:', immediateState);
246
+ logger.info('Validation result received, immediate state', {
247
+ step: immediateState.currentStep,
248
+ hasResult: !!immediateState.validationResult
249
+ });
248
250
  setState(immediateState);
249
251
 
250
- // If we're already at RESULT, clear intervals immediately
251
252
  if (immediateState.currentStep === SDKStep.RESULT || immediateState.currentStep === SDKStep.ERROR) {
252
253
  if (finalPollInterval) clearInterval(finalPollInterval);
253
254
  clearInterval(pollInterval);
@@ -256,13 +257,11 @@ export const useBiometricSDK = (): UseBiometricSDKResult => {
256
257
 
257
258
  return result;
258
259
  } catch (error) {
259
- // Clear all intervals on error
260
260
  clearInterval(pollInterval);
261
261
  if (finalPollInterval) {
262
262
  clearInterval(finalPollInterval);
263
263
  }
264
- console.error('❌ [useBiometricSDK] Validation error:', error);
265
- logger.error('Validation error, state:', sdk.getState(), error);
264
+ logger.error('Validation error', error);
266
265
 
267
266
  if (isMounted.current) {
268
267
  const errorState = sdk.getState();