@hexar/biometric-identity-sdk-react-native 1.0.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.
Files changed (39) hide show
  1. package/README.md +68 -0
  2. package/dist/components/BiometricIdentityFlow.d.ts +17 -0
  3. package/dist/components/BiometricIdentityFlow.d.ts.map +1 -0
  4. package/dist/components/BiometricIdentityFlow.js +366 -0
  5. package/dist/components/CameraCapture.d.ts +15 -0
  6. package/dist/components/CameraCapture.d.ts.map +1 -0
  7. package/dist/components/CameraCapture.js +238 -0
  8. package/dist/components/ErrorScreen.d.ts +15 -0
  9. package/dist/components/ErrorScreen.d.ts.map +1 -0
  10. package/dist/components/ErrorScreen.js +142 -0
  11. package/dist/components/InstructionsScreen.d.ts +14 -0
  12. package/dist/components/InstructionsScreen.d.ts.map +1 -0
  13. package/dist/components/InstructionsScreen.js +181 -0
  14. package/dist/components/ResultScreen.d.ts +15 -0
  15. package/dist/components/ResultScreen.d.ts.map +1 -0
  16. package/dist/components/ResultScreen.js +182 -0
  17. package/dist/components/ValidationProgress.d.ts +14 -0
  18. package/dist/components/ValidationProgress.d.ts.map +1 -0
  19. package/dist/components/ValidationProgress.js +143 -0
  20. package/dist/components/VideoRecorder.d.ts +43 -0
  21. package/dist/components/VideoRecorder.d.ts.map +1 -0
  22. package/dist/components/VideoRecorder.js +631 -0
  23. package/dist/hooks/useBiometricSDK.d.ts +25 -0
  24. package/dist/hooks/useBiometricSDK.d.ts.map +1 -0
  25. package/dist/hooks/useBiometricSDK.js +173 -0
  26. package/dist/index.d.ts +15 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +47 -0
  29. package/package.json +27 -0
  30. package/src/components/BiometricIdentityFlow.tsx +557 -0
  31. package/src/components/CameraCapture.tsx +262 -0
  32. package/src/components/ErrorScreen.tsx +201 -0
  33. package/src/components/InstructionsScreen.tsx +269 -0
  34. package/src/components/ResultScreen.tsx +301 -0
  35. package/src/components/ValidationProgress.tsx +223 -0
  36. package/src/components/VideoRecorder.tsx +794 -0
  37. package/src/hooks/useBiometricSDK.ts +230 -0
  38. package/src/index.ts +24 -0
  39. package/tsconfig.json +20 -0
@@ -0,0 +1,631 @@
1
+ "use strict";
2
+ /**
3
+ * Smart Video Recorder Component for Liveness Detection
4
+ * Features challenge-response flow with guided head movements
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.VideoRecorder = void 0;
41
+ const react_1 = __importStar(require("react"));
42
+ const react_native_1 = require("react-native");
43
+ // Default challenge set (used if backend not available)
44
+ const DEFAULT_CHALLENGES = [
45
+ {
46
+ action: 'look_left',
47
+ instruction: 'Slowly turn your head to the LEFT',
48
+ duration_ms: 2500,
49
+ order: 1,
50
+ icon: '←',
51
+ },
52
+ {
53
+ action: 'look_right',
54
+ instruction: 'Slowly turn your head to the RIGHT',
55
+ duration_ms: 2500,
56
+ order: 2,
57
+ icon: '→',
58
+ },
59
+ {
60
+ action: 'blink',
61
+ instruction: 'Blink your eyes naturally',
62
+ duration_ms: 2000,
63
+ order: 3,
64
+ icon: '👁',
65
+ },
66
+ {
67
+ action: 'smile',
68
+ instruction: 'Smile 😊',
69
+ duration_ms: 2000,
70
+ order: 4,
71
+ icon: '😊',
72
+ },
73
+ ];
74
+ // Instruction text mapping
75
+ const INSTRUCTION_MAP = {
76
+ look_left: { text: 'Slowly turn your head LEFT', icon: '←' },
77
+ look_right: { text: 'Slowly turn your head RIGHT', icon: '→' },
78
+ look_up: { text: 'Look UP', icon: '↑' },
79
+ look_down: { text: 'Look DOWN', icon: '↓' },
80
+ turn_head_left: { text: 'Turn your head LEFT', icon: '←' },
81
+ turn_head_right: { text: 'Turn your head RIGHT', icon: '→' },
82
+ smile: { text: 'Smile 😊', icon: '😊' },
83
+ blink: { text: 'Blink your eyes naturally', icon: '👁' },
84
+ open_mouth: { text: 'Open your mouth slightly', icon: '😮' },
85
+ stay_still: { text: 'Look at the camera and stay still', icon: '📷' },
86
+ };
87
+ const VideoRecorder = ({ theme, duration, instructions, challenges: propChallenges, sessionId, smartMode = true, onComplete, onCancel, onFetchChallenges, }) => {
88
+ // State
89
+ const [phase, setPhase] = (0, react_1.useState)('loading');
90
+ const [countdown, setCountdown] = (0, react_1.useState)(3);
91
+ const [challenges, setChallenges] = (0, react_1.useState)([]);
92
+ const [currentChallengeIndex, setCurrentChallengeIndex] = (0, react_1.useState)(0);
93
+ const [challengeProgress, setChallengeProgress] = (0, react_1.useState)(0);
94
+ const [overallProgress, setOverallProgress] = (0, react_1.useState)(0);
95
+ const [completedChallenges, setCompletedChallenges] = (0, react_1.useState)([]);
96
+ const [frames, setFrames] = (0, react_1.useState)([]);
97
+ // Animations
98
+ const fadeAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
99
+ const scaleAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(1)).current;
100
+ const pulseAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(1)).current;
101
+ const arrowAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
102
+ const progressAnim = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
103
+ // Refs
104
+ const recordingStartTime = (0, react_1.useRef)(0);
105
+ const frameInterval = (0, react_1.useRef)(null);
106
+ // Calculate total duration from challenges
107
+ const totalDuration = duration || challenges.reduce((sum, c) => sum + c.duration_ms, 0) + 2000;
108
+ // Initialize challenges
109
+ (0, react_1.useEffect)(() => {
110
+ const initChallenges = async () => {
111
+ try {
112
+ let challengeList;
113
+ if (propChallenges && propChallenges.length > 0) {
114
+ // Use provided challenges
115
+ challengeList = propChallenges;
116
+ }
117
+ else if (onFetchChallenges) {
118
+ // Fetch from backend
119
+ challengeList = await onFetchChallenges();
120
+ }
121
+ else if (instructions && instructions.length > 0) {
122
+ // Convert instructions to challenges
123
+ challengeList = instructions.map((inst, idx) => ({
124
+ action: inst,
125
+ instruction: INSTRUCTION_MAP[inst]?.text || inst,
126
+ duration_ms: 2000,
127
+ order: idx + 1,
128
+ icon: INSTRUCTION_MAP[inst]?.icon,
129
+ }));
130
+ }
131
+ else {
132
+ // Use default challenges
133
+ challengeList = smartMode ? DEFAULT_CHALLENGES : [
134
+ {
135
+ action: 'stay_still',
136
+ instruction: 'Look at the camera and stay still',
137
+ duration_ms: duration || 5000,
138
+ order: 1,
139
+ icon: '📷',
140
+ },
141
+ ];
142
+ }
143
+ setChallenges(challengeList);
144
+ setPhase('countdown');
145
+ }
146
+ catch (error) {
147
+ console.error('Failed to fetch challenges:', error);
148
+ // Fallback to default
149
+ setChallenges(DEFAULT_CHALLENGES);
150
+ setPhase('countdown');
151
+ }
152
+ };
153
+ initChallenges();
154
+ }, [propChallenges, instructions, onFetchChallenges, smartMode, duration]);
155
+ // Countdown phase
156
+ (0, react_1.useEffect)(() => {
157
+ if (phase !== 'countdown')
158
+ return;
159
+ if (countdown > 0) {
160
+ // Animate countdown number
161
+ react_native_1.Animated.sequence([
162
+ react_native_1.Animated.timing(scaleAnim, {
163
+ toValue: 1.3,
164
+ duration: 200,
165
+ useNativeDriver: true,
166
+ }),
167
+ react_native_1.Animated.timing(scaleAnim, {
168
+ toValue: 1,
169
+ duration: 200,
170
+ useNativeDriver: true,
171
+ }),
172
+ ]).start();
173
+ const timer = setTimeout(() => setCountdown(countdown - 1), 1000);
174
+ return () => clearTimeout(timer);
175
+ }
176
+ else {
177
+ startRecording();
178
+ }
179
+ }, [countdown, phase]);
180
+ // Start pulse animation for recording indicator
181
+ (0, react_1.useEffect)(() => {
182
+ if (phase === 'recording') {
183
+ react_native_1.Animated.loop(react_native_1.Animated.sequence([
184
+ react_native_1.Animated.timing(pulseAnim, {
185
+ toValue: 1.2,
186
+ duration: 500,
187
+ easing: react_native_1.Easing.inOut(react_native_1.Easing.ease),
188
+ useNativeDriver: true,
189
+ }),
190
+ react_native_1.Animated.timing(pulseAnim, {
191
+ toValue: 1,
192
+ duration: 500,
193
+ easing: react_native_1.Easing.inOut(react_native_1.Easing.ease),
194
+ useNativeDriver: true,
195
+ }),
196
+ ])).start();
197
+ }
198
+ }, [phase]);
199
+ // Animate arrow for directional challenges
200
+ const animateArrow = (0, react_1.useCallback)((direction) => {
201
+ const toValue = direction.includes('left') ? -20 : direction.includes('right') ? 20 : 0;
202
+ react_native_1.Animated.loop(react_native_1.Animated.sequence([
203
+ react_native_1.Animated.timing(arrowAnim, {
204
+ toValue,
205
+ duration: 500,
206
+ easing: react_native_1.Easing.inOut(react_native_1.Easing.ease),
207
+ useNativeDriver: true,
208
+ }),
209
+ react_native_1.Animated.timing(arrowAnim, {
210
+ toValue: 0,
211
+ duration: 500,
212
+ easing: react_native_1.Easing.inOut(react_native_1.Easing.ease),
213
+ useNativeDriver: true,
214
+ }),
215
+ ])).start();
216
+ }, [arrowAnim]);
217
+ // Start recording
218
+ const startRecording = (0, react_1.useCallback)(() => {
219
+ setPhase('recording');
220
+ recordingStartTime.current = Date.now();
221
+ // Simulate frame capture (in real implementation, this would capture actual camera frames)
222
+ frameInterval.current = setInterval(() => {
223
+ setFrames(prev => [...prev, `frame_${Date.now()}`]);
224
+ }, 100); // Capture ~10 FPS
225
+ // Start first challenge
226
+ runChallenge(0);
227
+ }, []);
228
+ // Run a specific challenge
229
+ const runChallenge = (0, react_1.useCallback)((index) => {
230
+ if (index >= challenges.length) {
231
+ completeRecording();
232
+ return;
233
+ }
234
+ const challenge = challenges[index];
235
+ setCurrentChallengeIndex(index);
236
+ setChallengeProgress(0);
237
+ // Fade in instruction
238
+ react_native_1.Animated.timing(fadeAnim, {
239
+ toValue: 1,
240
+ duration: 300,
241
+ useNativeDriver: true,
242
+ }).start();
243
+ // Animate arrow for directional challenges
244
+ if (challenge.action.includes('left') || challenge.action.includes('right')) {
245
+ animateArrow(challenge.action);
246
+ }
247
+ // Progress animation for this challenge
248
+ react_native_1.Animated.timing(progressAnim, {
249
+ toValue: 100,
250
+ duration: challenge.duration_ms,
251
+ useNativeDriver: false,
252
+ }).start();
253
+ // Update progress in real-time
254
+ const progressInterval = setInterval(() => {
255
+ setChallengeProgress(prev => {
256
+ const newProgress = prev + (100 / (challenge.duration_ms / 100));
257
+ return Math.min(100, newProgress);
258
+ });
259
+ // Update overall progress
260
+ const elapsed = Date.now() - recordingStartTime.current;
261
+ const totalTime = challenges.reduce((sum, c) => sum + c.duration_ms, 0);
262
+ setOverallProgress(Math.min(100, (elapsed / totalTime) * 100));
263
+ }, 100);
264
+ // Move to next challenge after duration
265
+ setTimeout(() => {
266
+ clearInterval(progressInterval);
267
+ // Mark challenge as completed
268
+ setCompletedChallenges(prev => [...prev, challenge.action]);
269
+ // Fade out current instruction
270
+ react_native_1.Animated.timing(fadeAnim, {
271
+ toValue: 0,
272
+ duration: 200,
273
+ useNativeDriver: true,
274
+ }).start(() => {
275
+ // Reset and start next challenge
276
+ progressAnim.setValue(0);
277
+ runChallenge(index + 1);
278
+ });
279
+ }, challenge.duration_ms);
280
+ }, [challenges, fadeAnim, progressAnim, animateArrow]);
281
+ // Complete recording
282
+ const completeRecording = (0, react_1.useCallback)(() => {
283
+ if (frameInterval.current) {
284
+ clearInterval(frameInterval.current);
285
+ }
286
+ setPhase('processing');
287
+ setOverallProgress(100);
288
+ // Simulate processing delay
289
+ setTimeout(() => {
290
+ const result = {
291
+ frames,
292
+ duration: Date.now() - recordingStartTime.current,
293
+ instructionsFollowed: completedChallenges.length === challenges.length,
294
+ qualityScore: 85 + Math.random() * 10, // Simulated quality score
295
+ challengesCompleted: completedChallenges,
296
+ sessionId,
297
+ };
298
+ onComplete(result);
299
+ }, 500);
300
+ }, [frames, completedChallenges, challenges, sessionId, onComplete]);
301
+ // Current challenge
302
+ const currentChallenge = challenges[currentChallengeIndex];
303
+ // Get direction arrow for the current challenge
304
+ const getDirectionIndicator = () => {
305
+ if (!currentChallenge)
306
+ return null;
307
+ const action = currentChallenge.action;
308
+ if (action.includes('left')) {
309
+ return (react_1.default.createElement(react_native_1.Animated.View, { style: [
310
+ styles.directionArrow,
311
+ styles.leftArrow,
312
+ { transform: [{ translateX: arrowAnim }] }
313
+ ] },
314
+ react_1.default.createElement(react_native_1.Text, { style: styles.arrowText }, "\u25C0")));
315
+ }
316
+ if (action.includes('right')) {
317
+ return (react_1.default.createElement(react_native_1.Animated.View, { style: [
318
+ styles.directionArrow,
319
+ styles.rightArrow,
320
+ { transform: [{ translateX: arrowAnim }] }
321
+ ] },
322
+ react_1.default.createElement(react_native_1.Text, { style: styles.arrowText }, "\u25B6")));
323
+ }
324
+ if (action === 'look_up') {
325
+ return (react_1.default.createElement(react_native_1.View, { style: [styles.directionArrow, styles.topArrow] },
326
+ react_1.default.createElement(react_native_1.Text, { style: styles.arrowText }, "\u25B2")));
327
+ }
328
+ if (action === 'look_down') {
329
+ return (react_1.default.createElement(react_native_1.View, { style: [styles.directionArrow, styles.bottomArrow] },
330
+ react_1.default.createElement(react_native_1.Text, { style: styles.arrowText }, "\u25BC")));
331
+ }
332
+ return null;
333
+ };
334
+ return (react_1.default.createElement(react_native_1.View, { style: styles.container },
335
+ react_1.default.createElement(react_native_1.View, { style: styles.cameraContainer },
336
+ react_1.default.createElement(react_native_1.View, { style: styles.mockCamera },
337
+ react_1.default.createElement(react_native_1.Text, { style: styles.mockCameraText }, "Front Camera")),
338
+ react_1.default.createElement(react_native_1.View, { style: styles.overlay },
339
+ react_1.default.createElement(react_native_1.View, { style: [
340
+ styles.faceOval,
341
+ phase === 'recording' && {
342
+ borderColor: theme?.successColor || '#10B981',
343
+ borderStyle: 'solid',
344
+ }
345
+ ] }),
346
+ phase === 'recording' && getDirectionIndicator()),
347
+ phase === 'loading' && (react_1.default.createElement(react_native_1.View, { style: styles.centeredOverlay },
348
+ react_1.default.createElement(react_native_1.Text, { style: styles.loadingText }, "Preparing challenges..."))),
349
+ phase === 'countdown' && (react_1.default.createElement(react_native_1.View, { style: styles.countdownContainer },
350
+ react_1.default.createElement(react_native_1.Text, { style: styles.getReadyText }, "Get Ready!"),
351
+ react_1.default.createElement(react_native_1.Animated.Text, { style: [
352
+ styles.countdownText,
353
+ { transform: [{ scale: scaleAnim }] }
354
+ ] }, countdown))),
355
+ phase === 'recording' && (react_1.default.createElement(react_native_1.View, { style: styles.recordingIndicator },
356
+ react_1.default.createElement(react_native_1.Animated.View, { style: [
357
+ styles.recordingDot,
358
+ { transform: [{ scale: pulseAnim }] }
359
+ ] }),
360
+ react_1.default.createElement(react_native_1.Text, { style: styles.recordingText }, "Recording"))),
361
+ (phase === 'recording' || phase === 'processing') && (react_1.default.createElement(react_native_1.View, { style: styles.progressContainer },
362
+ react_1.default.createElement(react_native_1.View, { style: styles.progressBar },
363
+ react_1.default.createElement(react_native_1.View, { style: [
364
+ styles.progressFill,
365
+ {
366
+ width: `${overallProgress}%`,
367
+ backgroundColor: theme?.primaryColor || '#6366F1'
368
+ }
369
+ ] })),
370
+ react_1.default.createElement(react_native_1.Text, { style: styles.progressText },
371
+ Math.round(overallProgress),
372
+ "%"))),
373
+ phase === 'recording' && currentChallenge && (react_1.default.createElement(react_native_1.Animated.View, { style: [
374
+ styles.instructionContainer,
375
+ { opacity: fadeAnim }
376
+ ] },
377
+ react_1.default.createElement(react_native_1.View, { style: styles.instructionBox },
378
+ currentChallenge.icon && (react_1.default.createElement(react_native_1.Text, { style: styles.instructionIcon }, currentChallenge.icon)),
379
+ react_1.default.createElement(react_native_1.Text, { style: styles.instructionText }, currentChallenge.instruction),
380
+ react_1.default.createElement(react_native_1.View, { style: styles.challengeProgressBar },
381
+ react_1.default.createElement(react_native_1.View, { style: [
382
+ styles.challengeProgressFill,
383
+ {
384
+ width: `${challengeProgress}%`,
385
+ backgroundColor: theme?.successColor || '#10B981'
386
+ }
387
+ ] }))))),
388
+ phase === 'recording' && challenges.length > 1 && (react_1.default.createElement(react_native_1.View, { style: styles.challengeCounter },
389
+ react_1.default.createElement(react_native_1.Text, { style: styles.challengeCounterText },
390
+ currentChallengeIndex + 1,
391
+ " / ",
392
+ challenges.length))),
393
+ phase === 'processing' && (react_1.default.createElement(react_native_1.View, { style: styles.processingOverlay },
394
+ react_1.default.createElement(react_native_1.Text, { style: styles.processingText }, "Processing video...")))),
395
+ react_1.default.createElement(react_native_1.View, { style: styles.bottomContainer },
396
+ phase === 'countdown' && (react_1.default.createElement(react_1.default.Fragment, null,
397
+ react_1.default.createElement(react_native_1.Text, { style: styles.bottomText },
398
+ "You'll perform ",
399
+ challenges.length,
400
+ " action",
401
+ challenges.length > 1 ? 's' : '',
402
+ ".",
403
+ '\n',
404
+ "Follow the on-screen instructions."),
405
+ react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.cancelButton, { borderColor: theme?.errorColor || '#EF4444' }], onPress: onCancel },
406
+ react_1.default.createElement(react_native_1.Text, { style: [styles.cancelButtonText, { color: theme?.errorColor || '#EF4444' }] }, "Cancel")))),
407
+ phase === 'recording' && (react_1.default.createElement(react_native_1.Text, { style: styles.bottomText }, "Keep your face visible and follow the instructions")),
408
+ phase === 'processing' && (react_1.default.createElement(react_native_1.Text, { style: styles.bottomText }, "Almost done...")))));
409
+ };
410
+ exports.VideoRecorder = VideoRecorder;
411
+ const styles = react_native_1.StyleSheet.create({
412
+ container: {
413
+ flex: 1,
414
+ backgroundColor: '#000000',
415
+ },
416
+ cameraContainer: {
417
+ flex: 1,
418
+ position: 'relative',
419
+ },
420
+ mockCamera: {
421
+ flex: 1,
422
+ backgroundColor: '#1F2937',
423
+ justifyContent: 'center',
424
+ alignItems: 'center',
425
+ },
426
+ mockCameraText: {
427
+ color: '#FFFFFF',
428
+ fontSize: 20,
429
+ fontWeight: 'bold',
430
+ },
431
+ overlay: {
432
+ ...react_native_1.StyleSheet.absoluteFillObject,
433
+ justifyContent: 'center',
434
+ alignItems: 'center',
435
+ },
436
+ faceOval: {
437
+ width: 250,
438
+ height: 320,
439
+ borderRadius: 125,
440
+ borderWidth: 4,
441
+ borderColor: '#FFFFFF',
442
+ borderStyle: 'dashed',
443
+ },
444
+ centeredOverlay: {
445
+ ...react_native_1.StyleSheet.absoluteFillObject,
446
+ justifyContent: 'center',
447
+ alignItems: 'center',
448
+ backgroundColor: 'rgba(0, 0, 0, 0.7)',
449
+ },
450
+ loadingText: {
451
+ color: '#FFFFFF',
452
+ fontSize: 18,
453
+ },
454
+ countdownContainer: {
455
+ ...react_native_1.StyleSheet.absoluteFillObject,
456
+ justifyContent: 'center',
457
+ alignItems: 'center',
458
+ backgroundColor: 'rgba(0, 0, 0, 0.6)',
459
+ },
460
+ getReadyText: {
461
+ color: '#FFFFFF',
462
+ fontSize: 24,
463
+ fontWeight: '600',
464
+ marginBottom: 20,
465
+ },
466
+ countdownText: {
467
+ fontSize: 96,
468
+ fontWeight: 'bold',
469
+ color: '#FFFFFF',
470
+ },
471
+ recordingIndicator: {
472
+ position: 'absolute',
473
+ top: 50,
474
+ right: 20,
475
+ flexDirection: 'row',
476
+ alignItems: 'center',
477
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
478
+ paddingHorizontal: 12,
479
+ paddingVertical: 6,
480
+ borderRadius: 20,
481
+ },
482
+ recordingDot: {
483
+ width: 12,
484
+ height: 12,
485
+ borderRadius: 6,
486
+ backgroundColor: '#EF4444',
487
+ marginRight: 8,
488
+ },
489
+ recordingText: {
490
+ color: '#FFFFFF',
491
+ fontSize: 14,
492
+ fontWeight: '600',
493
+ },
494
+ progressContainer: {
495
+ position: 'absolute',
496
+ top: 100,
497
+ left: 20,
498
+ right: 20,
499
+ flexDirection: 'row',
500
+ alignItems: 'center',
501
+ },
502
+ progressBar: {
503
+ flex: 1,
504
+ height: 8,
505
+ backgroundColor: 'rgba(255, 255, 255, 0.3)',
506
+ borderRadius: 4,
507
+ overflow: 'hidden',
508
+ marginRight: 10,
509
+ },
510
+ progressFill: {
511
+ height: '100%',
512
+ borderRadius: 4,
513
+ },
514
+ progressText: {
515
+ color: '#FFFFFF',
516
+ fontSize: 12,
517
+ fontWeight: '600',
518
+ width: 40,
519
+ textAlign: 'right',
520
+ },
521
+ instructionContainer: {
522
+ position: 'absolute',
523
+ top: 140,
524
+ left: 20,
525
+ right: 20,
526
+ alignItems: 'center',
527
+ },
528
+ instructionBox: {
529
+ backgroundColor: 'rgba(0, 0, 0, 0.8)',
530
+ paddingHorizontal: 24,
531
+ paddingVertical: 16,
532
+ borderRadius: 16,
533
+ alignItems: 'center',
534
+ minWidth: 280,
535
+ },
536
+ instructionIcon: {
537
+ fontSize: 36,
538
+ marginBottom: 8,
539
+ },
540
+ instructionText: {
541
+ fontSize: 20,
542
+ fontWeight: 'bold',
543
+ color: '#FFFFFF',
544
+ textAlign: 'center',
545
+ marginBottom: 12,
546
+ },
547
+ challengeProgressBar: {
548
+ width: '100%',
549
+ height: 4,
550
+ backgroundColor: 'rgba(255, 255, 255, 0.3)',
551
+ borderRadius: 2,
552
+ overflow: 'hidden',
553
+ },
554
+ challengeProgressFill: {
555
+ height: '100%',
556
+ borderRadius: 2,
557
+ },
558
+ challengeCounter: {
559
+ position: 'absolute',
560
+ top: 50,
561
+ left: 20,
562
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
563
+ paddingHorizontal: 12,
564
+ paddingVertical: 6,
565
+ borderRadius: 20,
566
+ },
567
+ challengeCounterText: {
568
+ color: '#FFFFFF',
569
+ fontSize: 14,
570
+ fontWeight: '600',
571
+ },
572
+ directionArrow: {
573
+ position: 'absolute',
574
+ justifyContent: 'center',
575
+ alignItems: 'center',
576
+ },
577
+ leftArrow: {
578
+ left: 20,
579
+ },
580
+ rightArrow: {
581
+ right: 20,
582
+ },
583
+ topArrow: {
584
+ top: 100,
585
+ },
586
+ bottomArrow: {
587
+ bottom: 150,
588
+ },
589
+ arrowText: {
590
+ fontSize: 48,
591
+ color: '#FFFFFF',
592
+ textShadowColor: 'rgba(0, 0, 0, 0.5)',
593
+ textShadowOffset: { width: 2, height: 2 },
594
+ textShadowRadius: 4,
595
+ },
596
+ processingOverlay: {
597
+ ...react_native_1.StyleSheet.absoluteFillObject,
598
+ justifyContent: 'center',
599
+ alignItems: 'center',
600
+ backgroundColor: 'rgba(0, 0, 0, 0.7)',
601
+ },
602
+ processingText: {
603
+ color: '#FFFFFF',
604
+ fontSize: 20,
605
+ fontWeight: '600',
606
+ },
607
+ bottomContainer: {
608
+ paddingVertical: 32,
609
+ paddingHorizontal: 24,
610
+ backgroundColor: 'rgba(0, 0, 0, 0.9)',
611
+ alignItems: 'center',
612
+ },
613
+ bottomText: {
614
+ color: '#FFFFFF',
615
+ fontSize: 16,
616
+ textAlign: 'center',
617
+ marginBottom: 16,
618
+ lineHeight: 24,
619
+ },
620
+ cancelButton: {
621
+ paddingVertical: 12,
622
+ paddingHorizontal: 32,
623
+ borderRadius: 8,
624
+ borderWidth: 2,
625
+ },
626
+ cancelButtonText: {
627
+ fontSize: 16,
628
+ fontWeight: '600',
629
+ },
630
+ });
631
+ exports.default = exports.VideoRecorder;
@@ -0,0 +1,25 @@
1
+ import { BiometricIdentitySDK, SDKState, VideoResult } from '@hexar/biometric-identity-sdk-core';
2
+ export interface ChallengeAction {
3
+ action: string;
4
+ instruction: string;
5
+ duration_ms: number;
6
+ order: number;
7
+ }
8
+ export interface UseBiometricSDKResult {
9
+ sdk: BiometricIdentitySDK;
10
+ state: SDKState;
11
+ isInitialized: boolean;
12
+ isUsingBackend: boolean;
13
+ sessionId: string | null;
14
+ challenges: ChallengeAction[];
15
+ uploadFrontID: (imageData: string | File | Blob) => Promise<void>;
16
+ uploadBackID: (imageData: string | File | Blob) => Promise<void>;
17
+ storeVideoRecording: (videoData: VideoResult) => Promise<void>;
18
+ fetchChallenges: (type?: 'active' | 'passive') => Promise<ChallengeAction[]>;
19
+ validateIdentity: () => Promise<any>;
20
+ reset: () => void;
21
+ recordVideo: (videoData?: VideoResult) => Promise<void>;
22
+ }
23
+ export declare const useBiometricSDK: () => UseBiometricSDKResult;
24
+ export default useBiometricSDK;
25
+ //# sourceMappingURL=useBiometricSDK.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBiometricSDK.d.ts","sourceRoot":"","sources":["../../src/hooks/useBiometricSDK.ts"],"names":[],"mappings":"AACA,OAAO,EACL,oBAAoB,EACpB,QAAQ,EACR,WAAW,EACZ,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,qBAqMlC,CAAC;AAEF,eAAe,eAAe,CAAC"}