@hexar/biometric-identity-sdk-react-native 1.12.0 → 1.14.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"}
@@ -55,9 +55,19 @@ const CameraCapture = ({ mode, theme, language, onCapture, onCancel, }) => {
55
55
  const strings = (0, biometric_identity_sdk_core_1.getStrings)();
56
56
  // Get camera device (back camera for document capture)
57
57
  const device = (0, react_native_vision_camera_1.useCameraDevice)('back');
58
+ const [deviceReady, setDeviceReady] = (0, react_1.useState)(!!device);
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,CAw6BtD,CAAC;AA6OF,eAAe,aAAa,CAAC"}
@@ -103,6 +103,7 @@ const VideoRecorder = ({ theme, language, duration, instructions, challenges: pr
103
103
  const cameraRef = (0, react_1.useRef)(null);
104
104
  const { hasPermission: cameraPermission, requestPermission } = (0, react_native_vision_camera_1.useCameraPermission)();
105
105
  const device = (0, react_native_vision_camera_1.useCameraDevice)('front');
106
+ const [deviceReady, setDeviceReady] = (0, react_1.useState)(!!device);
106
107
  const fadeAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
107
108
  const scaleAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(1)).current;
108
109
  const pulseAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(1)).current;
@@ -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.12.0",
3
+ "version": "1.14.0",
4
4
  "description": "React Native wrapper for Biometric Identity SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -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';
@@ -38,19 +39,30 @@ export const CameraCapture: React.FC<CameraCaptureProps> = ({
38
39
  const [hasPermission, setHasPermission] = useState(false);
39
40
  const cameraRef = useRef<Camera>(null);
40
41
  const { hasPermission: cameraPermission, requestPermission } = useCameraPermission();
41
-
42
+
42
43
  if (language) {
43
44
  setLanguage(language);
44
45
  }
45
46
  const strings = getStrings();
46
-
47
+
47
48
  // Get camera device (back camera for document capture)
48
49
  const device = useCameraDevice('back');
50
+ const [deviceReady, setDeviceReady] = useState(!!device);
49
51
 
50
52
  useEffect(() => {
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,10 +128,10 @@ 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
131
  const cameraRef = useRef<Camera>(null);
132
132
  const { hasPermission: cameraPermission, requestPermission } = useCameraPermission();
133
133
  const device = useCameraDevice('front');
134
+ const [deviceReady, setDeviceReady] = useState(!!device);
134
135
 
135
136
  const fadeAnim = useRef(new Animated.Value(0)).current;
136
137
  const scaleAnim = useRef(new Animated.Value(1)).current;
@@ -183,6 +184,17 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
183
184
  checkPermissions();
184
185
  }, [cameraPermission, requestPermission]);
185
186
 
187
+ // Wait for camera device to become available (some Android OEMs
188
+ // take a few hundred ms to enumerate cameras after permission grant).
189
+ useEffect(() => {
190
+ if (device) {
191
+ setDeviceReady(true);
192
+ return;
193
+ }
194
+ const timeout = setTimeout(() => setDeviceReady(true), 5000);
195
+ return () => clearTimeout(timeout);
196
+ }, [device]);
197
+
186
198
  useEffect(() => {
187
199
  const initChallenges = async () => {
188
200
  try {
@@ -824,6 +836,19 @@ export const VideoRecorder: React.FC<VideoRecorderProps> = ({
824
836
  }
825
837
 
826
838
  if (!device) {
839
+ // Still waiting for camera to enumerate — show loading instead of error
840
+ if (!deviceReady) {
841
+ return (
842
+ <View style={styles.container}>
843
+ <View style={styles.permissionContainer}>
844
+ <ActivityIndicator size="large" color={theme?.primaryColor || '#6366F1'} />
845
+ <Text style={[styles.permissionText, { marginTop: 16 }]}>
846
+ {strings.liveness.preparing || 'Preparing camera...'}
847
+ </Text>
848
+ </View>
849
+ </View>
850
+ );
851
+ }
827
852
  return (
828
853
  <View style={styles.container}>
829
854
  <View style={styles.permissionContainer}>