@hexar/biometric-identity-sdk-react-native 1.11.0 → 1.13.0

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":"CameraCapture.d.ts","sourceRoot":"","sources":["../../src/components/CameraCapture.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAsC,MAAM,OAAO,CAAC;AAY3D,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAmC,MAAM,oCAAoC,CAAC;AAIrH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA8OtD,CAAC;AA0JF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"CameraCapture.d.ts","sourceRoot":"","sources":["../../src/components/CameraCapture.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAsC,MAAM,OAAO,CAAC;AAa3D,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAmC,MAAM,oCAAoC,CAAC;AAIrH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAqQtD,CAAC;AA0JF,eAAe,aAAa,CAAC"}
@@ -47,6 +47,7 @@ const { width, height } = react_native_1.Dimensions.get('window');
47
47
  const CameraCapture = ({ mode, theme, language, onCapture, onCancel, }) => {
48
48
  const [isCapturing, setIsCapturing] = (0, react_1.useState)(false);
49
49
  const [hasPermission, setHasPermission] = (0, react_1.useState)(false);
50
+ const [deviceReady, setDeviceReady] = (0, react_1.useState)(false);
50
51
  const cameraRef = (0, react_1.useRef)(null);
51
52
  const { hasPermission: cameraPermission, requestPermission } = (0, react_native_vision_camera_1.useCameraPermission)();
52
53
  if (language) {
@@ -58,6 +59,15 @@ const CameraCapture = ({ mode, theme, language, onCapture, onCancel, }) => {
58
59
  (0, react_1.useEffect)(() => {
59
60
  checkPermissions();
60
61
  }, []);
62
+ // Wait for camera device to become available
63
+ (0, react_1.useEffect)(() => {
64
+ if (device) {
65
+ setDeviceReady(true);
66
+ return;
67
+ }
68
+ const timeout = setTimeout(() => setDeviceReady(true), 5000);
69
+ return () => clearTimeout(timeout);
70
+ }, [device]);
61
71
  const checkPermissions = async () => {
62
72
  try {
63
73
  // First check if we already have permission from the hook
@@ -172,6 +182,12 @@ const CameraCapture = ({ mode, theme, language, onCapture, onCancel, }) => {
172
182
  react_1.default.createElement(react_native_1.Text, { style: styles.buttonText }, strings.common.cancel || 'Cancel')))));
173
183
  }
174
184
  if (!device) {
185
+ if (!deviceReady) {
186
+ return (react_1.default.createElement(react_native_1.View, { style: styles.container },
187
+ react_1.default.createElement(react_native_1.View, { style: styles.permissionContainer },
188
+ react_1.default.createElement(react_native_1.ActivityIndicator, { size: "large", color: theme?.primaryColor || '#6366F1' }),
189
+ react_1.default.createElement(react_native_1.Text, { style: [styles.permissionText, { marginTop: 16 }] }, strings.liveness.preparing || 'Preparing camera...'))));
190
+ }
175
191
  return (react_1.default.createElement(react_native_1.View, { style: styles.container },
176
192
  react_1.default.createElement(react_native_1.View, { style: styles.permissionContainer },
177
193
  react_1.default.createElement(react_native_1.Text, { style: styles.permissionText }, strings.errors.cameraNotAvailable || 'Camera not available'),
@@ -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;AA2CD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAg5BtD,CAAC;AA6OF,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;AAcxE,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;AA2CD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAy6BtD,CAAC;AA6OF,eAAe,aAAa,CAAC"}
@@ -100,6 +100,7 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
100
100
  const [frames, setFrames] = (0, react_1.useState)([]);
101
101
  const framesRef = (0, react_1.useRef)([]);
102
102
  const [hasPermission, setHasPermission] = (0, react_1.useState)(false);
103
+ const [deviceReady, setDeviceReady] = (0, react_1.useState)(false);
103
104
  const cameraRef = (0, react_1.useRef)(null);
104
105
  const { hasPermission: cameraPermission, requestPermission } = (0, react_native_vision_camera_1.useCameraPermission)();
105
106
  const device = (0, react_native_vision_camera_1.useCameraDevice)('front');
@@ -144,6 +145,16 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
144
145
  };
145
146
  checkPermissions();
146
147
  }, [cameraPermission, requestPermission]);
148
+ // Wait for camera device to become available (some Android OEMs
149
+ // take a few hundred ms to enumerate cameras after permission grant).
150
+ (0, react_1.useEffect)(() => {
151
+ if (device) {
152
+ setDeviceReady(true);
153
+ return;
154
+ }
155
+ const timeout = setTimeout(() => setDeviceReady(true), 5000);
156
+ return () => clearTimeout(timeout);
157
+ }, [device]);
147
158
  (0, react_1.useEffect)(() => {
148
159
  const initChallenges = async () => {
149
160
  try {
@@ -687,6 +698,13 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
687
698
  react_1.default.createElement(react_native_1.Text, { style: [styles.cancelButtonText, { color: theme?.errorColor || '#EF4444' }] }, strings.common.cancel || 'Cancel')))));
688
699
  }
689
700
  if (!device) {
701
+ // Still waiting for camera to enumerate — show loading instead of error
702
+ if (!deviceReady) {
703
+ return (react_1.default.createElement(react_native_1.View, { style: styles.container },
704
+ react_1.default.createElement(react_native_1.View, { style: styles.permissionContainer },
705
+ react_1.default.createElement(react_native_1.ActivityIndicator, { size: "large", color: theme?.primaryColor || '#6366F1' }),
706
+ react_1.default.createElement(react_native_1.Text, { style: [styles.permissionText, { marginTop: 16 }] }, strings.liveness.preparing || 'Preparing camera...'))));
707
+ }
690
708
  return (react_1.default.createElement(react_native_1.View, { style: styles.container },
691
709
  react_1.default.createElement(react_native_1.View, { style: styles.permissionContainer },
692
710
  react_1.default.createElement(react_native_1.Text, { style: styles.permissionText }, strings.errors.cameraNotAvailable || 'Camera not available'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hexar/biometric-identity-sdk-react-native",
3
- "version": "1.11.0",
3
+ "version": "1.13.0",
4
4
  "description": "React Native wrapper for Biometric Identity SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -14,6 +14,7 @@
14
14
  "@hexar/biometric-identity-sdk-core": ">=1.7.0",
15
15
  "react": ">=18.0.0",
16
16
  "react-native": ">=0.70.0",
17
+ "react-native-fs": ">=2.20.0",
17
18
  "react-native-permissions": ">=4.0.0",
18
19
  "react-native-vision-camera": ">=4.0.0"
19
20
  },
@@ -12,6 +12,7 @@ import {
12
12
  Dimensions,
13
13
  Platform,
14
14
  Alert,
15
+ ActivityIndicator,
15
16
  } from 'react-native';
16
17
  import { Camera, useCameraDevice, useCameraPermission } from 'react-native-vision-camera';
17
18
  import { request, PERMISSIONS, RESULTS } from 'react-native-permissions';
@@ -36,14 +37,15 @@ export const CameraCapture: React.FC<CameraCaptureProps> = ({
36
37
  }) => {
37
38
  const [isCapturing, setIsCapturing] = useState(false);
38
39
  const [hasPermission, setHasPermission] = useState(false);
40
+ const [deviceReady, setDeviceReady] = useState(false);
39
41
  const cameraRef = useRef<Camera>(null);
40
42
  const { hasPermission: cameraPermission, requestPermission } = useCameraPermission();
41
-
43
+
42
44
  if (language) {
43
45
  setLanguage(language);
44
46
  }
45
47
  const strings = getStrings();
46
-
48
+
47
49
  // Get camera device (back camera for document capture)
48
50
  const device = useCameraDevice('back');
49
51
 
@@ -51,6 +53,16 @@ export const CameraCapture: React.FC<CameraCaptureProps> = ({
51
53
  checkPermissions();
52
54
  }, []);
53
55
 
56
+ // Wait for camera device to become available
57
+ useEffect(() => {
58
+ if (device) {
59
+ setDeviceReady(true);
60
+ return;
61
+ }
62
+ const timeout = setTimeout(() => setDeviceReady(true), 5000);
63
+ return () => clearTimeout(timeout);
64
+ }, [device]);
65
+
54
66
  const checkPermissions = async () => {
55
67
  try {
56
68
  // First check if we already have permission from the hook
@@ -190,6 +202,18 @@ export const CameraCapture: React.FC<CameraCaptureProps> = ({
190
202
  }
191
203
 
192
204
  if (!device) {
205
+ if (!deviceReady) {
206
+ return (
207
+ <View style={styles.container}>
208
+ <View style={styles.permissionContainer}>
209
+ <ActivityIndicator size="large" color={theme?.primaryColor || '#6366F1'} />
210
+ <Text style={[styles.permissionText, { marginTop: 16 }]}>
211
+ {strings.liveness.preparing || 'Preparing camera...'}
212
+ </Text>
213
+ </View>
214
+ </View>
215
+ );
216
+ }
193
217
  return (
194
218
  <View style={styles.container}>
195
219
  <View style={styles.permissionContainer}>
@@ -13,6 +13,7 @@ import {
13
13
  Easing,
14
14
  Platform,
15
15
  Alert,
16
+ ActivityIndicator,
16
17
  } from 'react-native';
17
18
  import { Camera, useCameraDevice, useCameraPermission } from 'react-native-vision-camera';
18
19
  import { request, PERMISSIONS, RESULTS } from 'react-native-permissions';
@@ -127,7 +128,8 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
127
128
  const [frames, setFrames] = useState<string[]>([]);
128
129
  const framesRef = useRef<string[]>([]);
129
130
  const [hasPermission, setHasPermission] = useState(false);
130
-
131
+ const [deviceReady, setDeviceReady] = useState(false);
132
+
131
133
  const cameraRef = useRef<Camera>(null);
132
134
  const { hasPermission: cameraPermission, requestPermission } = useCameraPermission();
133
135
  const device = useCameraDevice('front');
@@ -183,6 +185,17 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
183
185
  checkPermissions();
184
186
  }, [cameraPermission, requestPermission]);
185
187
 
188
+ // Wait for camera device to become available (some Android OEMs
189
+ // take a few hundred ms to enumerate cameras after permission grant).
190
+ useEffect(() => {
191
+ if (device) {
192
+ setDeviceReady(true);
193
+ return;
194
+ }
195
+ const timeout = setTimeout(() => setDeviceReady(true), 5000);
196
+ return () => clearTimeout(timeout);
197
+ }, [device]);
198
+
186
199
  useEffect(() => {
187
200
  const initChallenges = async () => {
188
201
  try {
@@ -824,6 +837,19 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
824
837
  }
825
838
 
826
839
  if (!device) {
840
+ // Still waiting for camera to enumerate — show loading instead of error
841
+ if (!deviceReady) {
842
+ return (
843
+ <View style={styles.container}>
844
+ <View style={styles.permissionContainer}>
845
+ <ActivityIndicator size="large" color={theme?.primaryColor || '#6366F1'} />
846
+ <Text style={[styles.permissionText, { marginTop: 16 }]}>
847
+ {strings.liveness.preparing || 'Preparing camera...'}
848
+ </Text>
849
+ </View>
850
+ </View>
851
+ );
852
+ }
827
853
  return (
828
854
  <View style={styles.container}>
829
855
  <View style={styles.permissionContainer}>