@sanctum-key/react-native-sdk 1.0.46 → 1.0.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/build/package.json +1 -1
  2. package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
  3. package/build/src/components/KYCElements/IDCardCapture.js +85 -23
  4. package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
  5. package/build/src/components/KYCElements/VerificationProgressTemplate.d.ts.map +1 -1
  6. package/build/src/components/KYCElements/VerificationProgressTemplate.js +49 -53
  7. package/build/src/components/KYCElements/VerificationProgressTemplate.js.map +1 -1
  8. package/build/src/hooks/useTemplateKYCFlow.d.ts.map +1 -1
  9. package/build/src/hooks/useTemplateKYCFlow.js +15 -1
  10. package/build/src/hooks/useTemplateKYCFlow.js.map +1 -1
  11. package/build/src/modules/api/CardAuthentification.d.ts.map +1 -1
  12. package/build/src/modules/api/CardAuthentification.js +37 -59
  13. package/build/src/modules/api/CardAuthentification.js.map +1 -1
  14. package/build/src/modules/api/KYCService.d.ts.map +1 -1
  15. package/build/src/modules/api/KYCService.js +7 -2
  16. package/build/src/modules/api/KYCService.js.map +1 -1
  17. package/build/src/types/KYC.types.d.ts +1 -0
  18. package/build/src/types/KYC.types.d.ts.map +1 -1
  19. package/build/src/types/KYC.types.js.map +1 -1
  20. package/package.json +1 -1
  21. package/src/components/KYCElements/IDCardCapture.tsx +99 -24
  22. package/src/components/KYCElements/VerificationProgressTemplate.tsx +52 -49
  23. package/src/hooks/useTemplateKYCFlow.tsx +19 -1
  24. package/src/modules/api/CardAuthentification.ts +205 -238
  25. package/src/modules/api/KYCService.ts +9 -2
  26. package/src/types/KYC.types.ts +1 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanctum-key/react-native-sdk",
3
- "version": "1.0.46",
3
+ "version": "1.0.48",
4
4
  "description": "Sanctum Key React Native SDK",
5
5
  "main": "build/src/index.js",
6
6
  "types": "build/src/index.d.ts",
@@ -1 +1 @@
1
- {"version":3,"file":"IDCardCapture.d.ts","sourceRoot":"","sources":["../../../../src/components/KYCElements/IDCardCapture.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+C,MAAM,OAAO,CAAC;AAIpE,OAAO,EAAE,iBAAiB,EAAoI,MAAM,uBAAuB,CAAC;AAuB5L,UAAU,cAAc;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,kBAAkB;IAC1B,SAAS,EAAE,iBAAiB,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACvC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAkCD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAo2BtD,CAAC"}
1
+ {"version":3,"file":"IDCardCapture.d.ts","sourceRoot":"","sources":["../../../../src/components/KYCElements/IDCardCapture.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+C,MAAM,OAAO,CAAC;AAIpE,OAAO,EAAE,iBAAiB,EAAoI,MAAM,uBAAuB,CAAC;AAuB5L,UAAU,cAAc;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,kBAAkB;IAC1B,SAAS,EAAE,iBAAiB,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACvC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAkCD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAm5BtD,CAAC"}
@@ -447,7 +447,7 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
447
447
  };
448
448
  const handleExitKYCFlow = () => {
449
449
  clearAuthToken();
450
- // 2. Clear all local camera/capture states
450
+ // 1. Clear local UI and camera states immediately
451
451
  setCapturedImages({});
452
452
  if (onValueChange)
453
453
  onValueChange({}); // Clear the parent's form state
@@ -458,16 +458,18 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
458
458
  setPendingCAImage(null);
459
459
  setIsProcessingCapture(false);
460
460
  setProcessingImagePath(null);
461
- // 3. Restart the flow
462
- if (actions.resetTemplate) {
463
- // This is the best method: it wipes the context and rebuilds the initial state
464
- actions.resetTemplate();
461
+ // 2. Restart the backend session and context state
462
+ if (actions.restartSession) {
463
+ // This is your new custom action that wipes the token, state, and fetches a new session
464
+ actions.restartSession();
465
465
  }
466
- else if (actions.goToComponent && state.template?.components?.length > 0) {
467
- actions.goToComponent(state.template.components[0].id);
466
+ else if (actions.resetTemplate) {
467
+ // Fallback
468
+ clearAuthToken();
469
+ actions.resetTemplate();
468
470
  }
469
471
  else {
470
- console.warn("Could not restart flow. Check your KYC context actions.");
472
+ console.warn("Could not restart flow. Ensure restartSession is added to your KYC context actions.");
471
473
  }
472
474
  };
473
475
  const handleSilentCapture = async (result) => {
@@ -594,26 +596,58 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
594
596
  }
595
597
  let hintMessage = '';
596
598
  // 2. Business Logic Errors
597
- if (rawMessage.includes('pays sélectionné') || rawMessage.includes('country mismatch')) {
598
- hintMessage = state.currentLanguage === 'en' ? 'Does not match the selected country.' : 'Ne correspond pas au pays sélectionné.';
599
+ if (rawMessage.includes('card_not_fully_in_frame') ||
600
+ rawMessage.includes('non entièrement visible') ||
601
+ rawMessage.includes('aucun visage détecté') ||
602
+ rawMessage.includes('stabiliser la caméra')) {
603
+ hintMessage = state.currentLanguage === 'en'
604
+ ? 'Ensure the entire card and your face are clearly inside the frame.'
605
+ : 'Assurez-vous que toute la carte et le visage sont clairement dans le cadre.';
606
+ }
607
+ // 2. Document/Country Mismatch
608
+ // Catches: 'pays sélectionné', 'LPIPS'
609
+ else if (rawMessage.includes('pays sélectionné')) {
610
+ hintMessage = state.currentLanguage === 'en'
611
+ ? 'This document does not match the selected country.'
612
+ : 'Ce document ne correspond pas au pays sélectionné.';
599
613
  }
600
- else if (rawMessage.includes('impossible') || rawMessage.includes('unreadable')) {
601
- hintMessage = state.currentLanguage === 'en' ? 'Move to better lighting and ensure card is in frame.' : 'Améliorez l\'éclairage et assurez-vous que la carte est bien cadrée.';
614
+ // 3. Front/Back Document Mismatch
615
+ // Catches: 'ne correspond pas au recto', 'document différent'
616
+ else if (rawMessage.includes('ne correspond pas au recto') || rawMessage.includes('document différent')) {
617
+ hintMessage = state.currentLanguage === 'en'
618
+ ? 'Please scan the back of the exact same ID.'
619
+ : 'Veuillez scanner le verso de la même pièce d\'identité.';
602
620
  }
603
- else if (rawMessage.includes('card_not_fully_in_frame') || rawMessage.includes('frame')) {
604
- hintMessage = state.currentLanguage === 'en' ? 'Move closer to the document.' : 'Rapprochez-vous du document.';
621
+ // 4. Data Extraction Failures (OCR & MRZ)
622
+ // Catches: 'impossible de lire', 'impossible d'extraire', 'mrz illisible', 'lecture mrz invalide'
623
+ else if (rawMessage.includes('impossible de lire') ||
624
+ rawMessage.includes('impossible d\'extraire') ||
625
+ rawMessage.includes('mrz') ||
626
+ rawMessage.includes('extraction') ||
627
+ rawMessage.includes('illisible') ||
628
+ rawMessage.includes('invalide')) {
629
+ hintMessage = state.currentLanguage === 'en'
630
+ ? 'Cannot read document text. Avoid glare, improve lighting, and hold steady.'
631
+ : 'Impossible de lire le texte. Évitez les reflets, améliorez l\'éclairage et restez immobile.';
605
632
  }
606
- else if (rawMessage.includes('ne correspond pas au recto')) {
607
- hintMessage = state.currentLanguage === 'en' ? 'Please scan the same ID.' : 'Veuillez scanner la même pièce.';
633
+ // 5. Server Infrastructure & Downtime
634
+ // Catches: Cloudflare tunnel errors, 502/503 Gateway timeouts
635
+ else if (rawMessage.includes('cloudflare') ||
636
+ rawMessage.includes('tunnel') ||
637
+ rawMessage.includes('502') ||
638
+ rawMessage.includes('503')) {
639
+ hintMessage = state.currentLanguage === 'en'
640
+ ? 'Server is temporarily offline. Please try again in a few minutes.'
641
+ : 'Le serveur est temporairement hors ligne. Veuillez réessayer dans quelques minutes.';
608
642
  }
609
- // 3. Fallback to Network/API failure
643
+ // 6. True Network Errors vs. Fallback Processing
610
644
  else {
611
- const isNetworkError = error.isAxiosError || error.message === 'Network Error' || error.code === 'ECONNABORTED' || rawMessage.includes('network') || !error.response;
645
+ // Strictly detect Axios network drops without swallowing unknown custom errors
646
+ const isNetworkError = error?.isAxiosError || rawMessage === 'network error' || error?.code === 'econnaborted' || rawMessage.includes('network');
612
647
  if (isNetworkError) {
613
- hintMessage = state.currentLanguage === 'en' ? 'Poor connection. Retrying...' : 'Connexion faible. Nouvelle tentative...';
614
- }
615
- else {
616
- hintMessage = state.currentLanguage === 'en' ? 'Analyzing...' : 'Analyse en cours...';
648
+ hintMessage = state.currentLanguage === 'en'
649
+ ? 'Poor connection. Please check your internet.'
650
+ : 'Connexion faible. Veuillez vérifier votre internet.';
617
651
  }
618
652
  }
619
653
  setSilentCaptureResult(prev => ({ ...prev, isAnalyzing: false, success: false, error: hintMessage }));
@@ -889,7 +923,35 @@ const styles = StyleSheet.create({
889
923
  sideTitle: { fontSize: 22, fontWeight: 'bold', color: '#000', marginBottom: 12, textAlign: 'center' },
890
924
  imagePreviewWrapper: { width: '100%', borderRadius: 12, padding: 1, overflow: 'hidden', shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.12, shadowRadius: 8, elevation: 8, backgroundColor: '#f0f0f0', ...Platform.select({ web: { aspectRatio: 1.59, height: 'auto', maxWidth: 450, alignSelf: 'center' }, default: { height: 220 } }) },
891
925
  previewImage: { width: '100%', height: '100%', borderRadius: 12, resizeMode: 'cover' },
892
- floatingErrorBanner: { backgroundColor: '#FEF2F2', borderWidth: 1, borderColor: '#FCA5A5', paddingVertical: 12, paddingHorizontal: 16, borderRadius: 12, alignItems: 'center', justifyContent: 'center', width: '100%', ...Platform.select({ web: { position: 'absolute', bottom: '100%', marginBottom: 16, maxWidth: 500, alignSelf: 'center', zIndex: 100000, boxShadow: '0 4px 12px rgba(0,0,0,0.15)' }, default: { position: 'absolute', top: Platform.OS === 'ios' ? 90 : 70, left: 24, right: 24, zIndex: 10000 } }) },
926
+ floatingErrorBanner: {
927
+ backgroundColor: '#FEF2F2',
928
+ borderWidth: 1,
929
+ borderColor: '#FCA5A5',
930
+ paddingVertical: 12,
931
+ paddingHorizontal: 16,
932
+ borderRadius: 12,
933
+ alignItems: 'center',
934
+ justifyContent: 'center',
935
+ ...Platform.select({
936
+ web: {
937
+ position: 'absolute',
938
+ bottom: '100%',
939
+ marginBottom: 16,
940
+ maxWidth: 500,
941
+ width: '100%', // Safe to keep 100% on web since left/right aren't used
942
+ alignSelf: 'center',
943
+ zIndex: 100000,
944
+ boxShadow: '0 4px 12px rgba(0,0,0,0.15)'
945
+ },
946
+ default: {
947
+ position: 'absolute',
948
+ top: Platform.OS === 'ios' ? 90 : 70,
949
+ left: 24,
950
+ right: 24,
951
+ zIndex: 10000
952
+ }
953
+ })
954
+ },
893
955
  floatingErrorText: { color: '#991B1B', fontSize: 14, fontWeight: '700', textAlign: 'center' },
894
956
  processingOverlay: { flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.7)', justifyContent: 'center', alignItems: 'center', zIndex: 9999, ...Platform.select({ web: { backdropFilter: 'blur(4px)' } }) },
895
957
  processingText: { color: '#FFF', fontSize: 18, fontWeight: 'bold', marginTop: 16, textAlign: 'center' },