@sanctum-key/react-native-sdk 1.0.24 → 1.0.26

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 (73) hide show
  1. package/build/package.json +5 -2
  2. package/build/src/components/EnhancedCameraView.d.ts +7 -1
  3. package/build/src/components/EnhancedCameraView.d.ts.map +1 -1
  4. package/build/src/components/EnhancedCameraView.js +88 -30
  5. package/build/src/components/EnhancedCameraView.js.map +1 -1
  6. package/build/src/components/EnhancedCameraView.web.d.ts +5 -1
  7. package/build/src/components/EnhancedCameraView.web.d.ts.map +1 -1
  8. package/build/src/components/EnhancedCameraView.web.js +80 -295
  9. package/build/src/components/EnhancedCameraView.web.js.map +1 -1
  10. package/build/src/components/KYCElements/CameraCapture.js +1 -1
  11. package/build/src/components/KYCElements/CameraCapture.js.map +1 -1
  12. package/build/src/components/KYCElements/CountrySelection.d.ts.map +1 -1
  13. package/build/src/components/KYCElements/CountrySelection.js +38 -218
  14. package/build/src/components/KYCElements/CountrySelection.js.map +1 -1
  15. package/build/src/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
  16. package/build/src/components/KYCElements/CountrySelectionTemplate.js +5 -17
  17. package/build/src/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
  18. package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
  19. package/build/src/components/KYCElements/IDCardCapture.js +509 -95
  20. package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
  21. package/build/src/components/KYCElements/VerificationProgressTemplate.d.ts.map +1 -1
  22. package/build/src/components/KYCElements/VerificationProgressTemplate.js +93 -51
  23. package/build/src/components/KYCElements/VerificationProgressTemplate.js.map +1 -1
  24. package/build/src/components/OverLay/type.d.ts +1 -0
  25. package/build/src/components/OverLay/type.d.ts.map +1 -1
  26. package/build/src/components/OverLay/type.js.map +1 -1
  27. package/build/src/components/WebBarcodeScanner.d.ts +9 -0
  28. package/build/src/components/WebBarcodeScanner.d.ts.map +1 -0
  29. package/build/src/components/WebBarcodeScanner.js +152 -0
  30. package/build/src/components/WebBarcodeScanner.js.map +1 -0
  31. package/build/src/config/KYCConfigs.js +2 -2
  32. package/build/src/config/KYCConfigs.js.map +1 -1
  33. package/build/src/config/region_mapping.json +0 -14
  34. package/build/src/modules/api/CardAuthentification.d.ts +2 -0
  35. package/build/src/modules/api/CardAuthentification.d.ts.map +1 -1
  36. package/build/src/modules/api/CardAuthentification.js +22 -39
  37. package/build/src/modules/api/CardAuthentification.js.map +1 -1
  38. package/build/src/modules/api/KYCService.d.ts +7 -2
  39. package/build/src/modules/api/KYCService.d.ts.map +1 -1
  40. package/build/src/modules/api/KYCService.js +163 -57
  41. package/build/src/modules/api/KYCService.js.map +1 -1
  42. package/build/src/types/KYC.types.d.ts +1 -0
  43. package/build/src/types/KYC.types.d.ts.map +1 -1
  44. package/build/src/types/KYC.types.js.map +1 -1
  45. package/build/src/utils/aamvaParser.d.ts +62 -0
  46. package/build/src/utils/aamvaParser.d.ts.map +1 -0
  47. package/build/src/utils/aamvaParser.js +91 -0
  48. package/build/src/utils/aamvaParser.js.map +1 -0
  49. package/build/src/utils/cropByObb.d.ts.map +1 -1
  50. package/build/src/utils/cropByObb.js +4 -3
  51. package/build/src/utils/cropByObb.js.map +1 -1
  52. package/build/src/web/WebKYCEntry.d.ts +1 -1
  53. package/build/src/web/WebKYCEntry.d.ts.map +1 -1
  54. package/build/src/web/WebKYCEntry.js +105 -239
  55. package/build/src/web/WebKYCEntry.js.map +1 -1
  56. package/package.json +5 -2
  57. package/src/components/EnhancedCameraView.tsx +116 -42
  58. package/src/components/EnhancedCameraView.web.tsx +98 -338
  59. package/src/components/KYCElements/CameraCapture.tsx +1 -1
  60. package/src/components/KYCElements/CountrySelection.tsx +60 -240
  61. package/src/components/KYCElements/CountrySelectionTemplate.tsx +7 -20
  62. package/src/components/KYCElements/IDCardCapture.tsx +672 -151
  63. package/src/components/KYCElements/VerificationProgressTemplate.tsx +112 -65
  64. package/src/components/OverLay/type.ts +1 -1
  65. package/src/components/WebBarcodeScanner.tsx +273 -0
  66. package/src/config/KYCConfigs.ts +2 -2
  67. package/src/config/region_mapping.json +0 -14
  68. package/src/modules/api/CardAuthentification.ts +41 -56
  69. package/src/modules/api/KYCService.ts +236 -82
  70. package/src/types/KYC.types.ts +1 -0
  71. package/src/utils/aamvaParser.ts +102 -0
  72. package/src/utils/cropByObb.ts +5 -3
  73. package/src/web/WebKYCEntry.tsx +125 -301
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanctum-key/react-native-sdk",
3
- "version": "1.0.24",
3
+ "version": "1.0.26",
4
4
  "description": "Sanctum Key React Native SDK",
5
5
  "main": "build/src/index.js",
6
6
  "types": "build/src/index.d.ts",
@@ -47,6 +47,8 @@
47
47
  "access": "public"
48
48
  },
49
49
  "dependencies": {
50
+ "@zxing/browser": "^0.2.0",
51
+ "@zxing/library": "^0.22.0",
50
52
  "axios": "^1.11.0",
51
53
  "expo-blur": "~15.0.8",
52
54
  "i18n-js": "4.5.1",
@@ -63,11 +65,12 @@
63
65
  },
64
66
  "peerDependencies": {
65
67
  "expo": "*",
68
+ "expo-file-system": "*",
66
69
  "expo-image-manipulator": "*",
67
70
  "expo-location": "*",
68
71
  "react": "*",
69
72
  "react-native": "*",
70
- "react-native-svg": "^15.15.5",
73
+ "react-native-svg": "*",
71
74
  "react-native-vision-camera": "^4.7.1"
72
75
  }
73
76
  }
@@ -1,15 +1,18 @@
1
1
  import React, { useCallback, useEffect, useRef, useState } from 'react';
2
- import {
3
- View, StyleSheet, Text, AppState
4
- } from 'react-native';
5
- import { Camera, useCameraDevice } from 'react-native-vision-camera';
2
+ import { View, StyleSheet, Text, Platform } from 'react-native';
3
+ import { Camera, CodeType, useCameraDevice, useCodeScanner } from 'react-native-vision-camera';
6
4
  import VisionCameraModule from '../modules/camera/VisionCameraModule';
7
5
  import { useI18n } from '../hooks/useI18n';
8
6
  import { EnhancedCameraViewProps } from './OverLay/type';
9
- import { Button } from './ui/Button';
7
+ import { WebBarcodeScanner } from './WebBarcodeScanner';
10
8
 
9
+ export interface ExtendedCameraProps extends EnhancedCameraViewProps {
10
+ isScanningBarcode?: boolean;
11
+ onBarcodeScanned?: (data: string) => void;
12
+ barcodeTypes?: CodeType[];
13
+ }
11
14
 
12
- export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
15
+ export const EnhancedCameraView: React.FC<ExtendedCameraProps> = ({
13
16
  showCamera,
14
17
  cameraType: initialCameraType = 'front',
15
18
  style,
@@ -18,21 +21,31 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
18
21
  silentCaptureResult,
19
22
  isProcessing = false,
20
23
  overlayComponent,
24
+ isScanningBarcode = false,
25
+ onBarcodeScanned,
26
+ barcodeTypes
21
27
  }) => {
22
28
  const { t } = useI18n();
23
29
  const camera = useRef<Camera>(null);
24
-
25
- const isCapturingRef = useRef(false);
26
- const isProcessingRef = useRef(isProcessing);
27
-
28
- const [cameraType] = useState<'front' | 'back'>(initialCameraType);
30
+
31
+ const webVideoRef = useRef<HTMLVideoElement | null>(null);
32
+ const isCapturingRef = useRef(false);
33
+ const isProcessingRef = useRef(isProcessing);
34
+ const [cameraType] = useState<'front' | 'back'>(initialCameraType);
29
35
  const [hasPermission, setHasPermission] = useState<boolean | null>(null);
30
36
  const [isInitialized, setIsInitialized] = useState(false);
31
- const [refreshCamera, setRefreshCamera] = useState(false);
37
+ const [refreshCamera] = useState(false);
38
+
39
+ // 🚨 NEW STATE: Tells React when it is safe to mount the Web Scanner
40
+ const [isVideoFound, setIsVideoFound] = useState(false);
32
41
 
42
+ const scannedBarcodeRef = useRef<string | null>(null);
43
+ const containerRef = useRef<any>(null);
33
44
  const device = useCameraDevice(cameraType);
34
45
 
35
- useEffect(() => { isProcessingRef.current = isProcessing; }, [isProcessing]);
46
+ useEffect(() => {
47
+ isProcessingRef.current = isProcessing;
48
+ }, [isProcessing]);
36
49
 
37
50
  const checkPermissions = async () => {
38
51
  try {
@@ -52,29 +65,40 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
52
65
  }
53
66
  };
54
67
 
55
- useEffect(() => { if (showCamera) checkPermissions(); }, [showCamera, refreshCamera]);
56
-
57
68
  useEffect(() => {
58
- const sub = AppState.addEventListener('change', next => {
59
- if (next === 'active' && showCamera && hasPermission === false) checkPermissions();
60
- });
61
- return () => sub.remove();
62
- }, [showCamera, hasPermission]);
63
-
64
- const onInitialized = useCallback(() => setIsInitialized(true), []);
65
- const onCameraError = useCallback((error: any) => {
69
+ if (showCamera) checkPermissions();
70
+ }, [showCamera, refreshCamera]);
71
+
72
+ const onInitialized = useCallback(() => setIsInitialized(true), []);
73
+ const onCameraError = useCallback((error: any) => {
66
74
  onError?.({ message: error.message || t('camera.errorOccurred') });
67
75
  }, [onError, t]);
68
76
 
77
+ const codeScanner = useCodeScanner({
78
+ codeTypes: barcodeTypes || ['pdf-417', 'qr', 'code-128', 'code-39'],
79
+ onCodeScanned: (codes) => {
80
+ if (!isProcessingRef.current && isScanningBarcode) {
81
+ for (const code of codes) {
82
+ if (code.value && scannedBarcodeRef.current !== code.value) {
83
+ scannedBarcodeRef.current = code.value;
84
+ onBarcodeScanned?.(code.value);
85
+ break;
86
+ }
87
+ }
88
+ }
89
+ }
90
+ });
91
+
69
92
  const captureSilentPhoto = useCallback(async () => {
70
93
  if (!camera.current || !isInitialized || isProcessingRef.current || isCapturingRef.current) return;
71
94
  if (silentCaptureResult?.isAnalyzing) return;
72
95
  try {
73
96
  isCapturingRef.current = true;
74
- const photo = await camera.current.takePhoto({ enableShutterSound: false, flash: 'off' });
97
+ const photo = await camera.current.takePhoto({ enableShutterSound: false, flash: 'off' });
75
98
  const result = await VisionCameraModule.processPhotoResult(photo);
76
- onSilentCapture?.({ ...result, path: result.path || photo.path });
77
- } catch { /* silent */ } finally {
99
+ onSilentCapture?.({ ...result, path: result.path || photo.path, barcode: scannedBarcodeRef.current });
100
+ } catch {
101
+ } finally {
78
102
  isCapturingRef.current = false;
79
103
  }
80
104
  }, [isInitialized, onSilentCapture, silentCaptureResult]);
@@ -85,26 +109,67 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
85
109
  let id: ReturnType<typeof setInterval>;
86
110
  const timer = setTimeout(() => {
87
111
  if (!active) return;
88
- id = setInterval(captureSilentPhoto, 1500);
89
- }, 1000);
90
- return () => { active = false; clearTimeout(timer); if (id) clearInterval(id); };
91
- }, [showCamera, isInitialized, isProcessing, captureSilentPhoto]);
92
-
93
- if (hasPermission === null) return <View style={[styles.container, style]} />;
112
+ const intervalDelay = isScanningBarcode ? 3000 : 1500;
113
+ id = setInterval(captureSilentPhoto, intervalDelay);
114
+ }, 1500);
115
+ return () => {
116
+ active = false;
117
+ clearTimeout(timer);
118
+ if (id) clearInterval(id);
119
+ };
120
+ }, [showCamera, isInitialized, isProcessing, captureSilentPhoto, isScanningBarcode]);
121
+
122
+ // Web: Aggressive Video Element Hunter
123
+ useEffect(() => {
124
+ // 🚨 Kick off the search immediately if we are on the web and the camera should be showing
125
+ if (Platform.OS !== 'web' || !showCamera) return;
126
+
127
+ let timeoutId: ReturnType<typeof setTimeout>;
128
+
129
+ const findVideo = () => {
130
+ console.log('🔍 [WEB ENGINE] Searching for <video> element in DOM...');
131
+
132
+ let video: HTMLVideoElement | null = null;
133
+ if (containerRef.current?.querySelector) {
134
+ video = containerRef.current.querySelector('video');
135
+ }
136
+ if (!video) {
137
+ video = document.querySelector('video');
138
+ }
94
139
 
95
- if (hasPermission === false) {
96
- return (
97
- <View style={[styles.container, style, { justifyContent: 'center', alignItems: 'center' }]}>
98
- <Text style={styles.permissionMessage}>{t('camera.permissionRequired')}</Text>
99
- <Button title="Refresh Camera" onPress={() => setRefreshCamera(p => !p)} variant="primary" />
100
- </View>
101
- );
102
- }
140
+ if (video) {
141
+ console.log('✅ [WEB ENGINE] <video> element locked! Booting ZXing Scanner.');
142
+ webVideoRef.current = video;
143
+ setIsVideoFound(true); // This tells React to mount the scanner!
144
+ } else {
145
+ console.log('⏳ [WEB ENGINE] <video> not found yet, retrying in 500ms...');
146
+ timeoutId = setTimeout(findVideo, 500);
147
+ }
148
+ };
149
+
150
+ // Start hunting immediately, do NOT wait for isInitialized
151
+ findVideo();
152
+
153
+ return () => clearTimeout(timeoutId);
154
+ }, [showCamera]);
155
+
156
+ // 🚨 FIX: Memoized Web Callback to prevent infinite re-rendering loop
157
+ const handleWebBarcodeScanned = useCallback((value: string) => {
158
+ console.log(`🎉 [WEB SCANNER] SUCCESS! Decoded value:`, value);
159
+ alert(`Decoded: ${value.substring(0, 50)}...`);
160
+
161
+ if (!isProcessingRef.current && value !== scannedBarcodeRef.current) {
162
+ scannedBarcodeRef.current = value;
163
+ onBarcodeScanned?.(value);
164
+ }
165
+ }, [onBarcodeScanned]);
103
166
 
167
+ if (hasPermission === null) return <View style={[styles.container, style]} />;
168
+ if (hasPermission === false) return <View style={[styles.container, style]}><Text style={styles.permissionMessage}>{t('camera.permissionRequired')}</Text></View>;
104
169
  if (!device || !showCamera) return <View style={[styles.container, style]} />;
105
170
 
106
171
  return (
107
- <View style={[styles.container, style]}>
172
+ <View ref={containerRef} style={[styles.container, style]}>
108
173
  <Camera
109
174
  ref={camera}
110
175
  style={StyleSheet.absoluteFill}
@@ -116,8 +181,17 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
116
181
  audio={false}
117
182
  onInitialized={onInitialized}
118
183
  onError={onCameraError}
184
+ codeScanner={Platform.OS !== 'web' && isScanningBarcode ? codeScanner : undefined}
119
185
  />
120
-
186
+
187
+ {Platform.OS === 'web' && isScanningBarcode && isVideoFound && (
188
+ <WebBarcodeScanner
189
+ videoRef={webVideoRef as React.RefObject<HTMLVideoElement>}
190
+ onBarcodeScanned={handleWebBarcodeScanned}
191
+ active={!isProcessingRef.current}
192
+ />
193
+ )}
194
+
121
195
  {overlayComponent}
122
196
  </View>
123
197
  );