@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,182 @@
1
+ "use strict";
2
+ /**
3
+ * Result Screen Component
4
+ * Shows validation result (pass/fail)
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.ResultScreen = void 0;
11
+ const react_1 = __importDefault(require("react"));
12
+ const react_native_1 = require("react-native");
13
+ const ResultScreen = ({ result, theme, language = 'en', onClose, }) => {
14
+ const isSuccess = result.isValidFaceMatch && result.isDocumentAuthentic;
15
+ const successColor = theme?.successColor || '#10B981';
16
+ const errorColor = theme?.errorColor || '#EF4444';
17
+ return (react_1.default.createElement(react_native_1.View, { style: styles.container },
18
+ react_1.default.createElement(react_native_1.ScrollView, { contentContainerStyle: styles.content },
19
+ react_1.default.createElement(react_native_1.View, { style: [
20
+ styles.iconContainer,
21
+ { backgroundColor: isSuccess ? successColor : errorColor },
22
+ ] },
23
+ react_1.default.createElement(react_native_1.Text, { style: styles.icon }, isSuccess ? '✓' : '✗')),
24
+ react_1.default.createElement(react_native_1.Text, { style: [styles.title, { color: theme?.textColor || '#000000' }] }, isSuccess
25
+ ? (language === 'es' ? '¡Verificación Exitosa!' : 'Verification Successful!')
26
+ : (language === 'es' ? 'Verificación Fallida' : 'Verification Failed')),
27
+ react_1.default.createElement(react_native_1.Text, { style: [styles.subtitle, { color: theme?.secondaryTextColor || '#6B7280' }] }, isSuccess
28
+ ? (language === 'es'
29
+ ? 'Tu identidad ha sido verificada correctamente'
30
+ : 'Your identity has been verified successfully')
31
+ : (language === 'es'
32
+ ? 'No pudimos verificar tu identidad'
33
+ : 'We were unable to verify your identity')),
34
+ react_1.default.createElement(react_native_1.View, { style: styles.scoresContainer },
35
+ react_1.default.createElement(ScoreCard, { label: language === 'es' ? 'Coincidencia Facial' : 'Face Match', score: result.matchScore, passed: result.isValidFaceMatch, theme: theme }),
36
+ react_1.default.createElement(ScoreCard, { label: language === 'es' ? 'Presencia Vital' : 'Liveness', score: result.livenessScore, passed: result.livenessScore >= 80, theme: theme })),
37
+ result.extractedDocumentData && (react_1.default.createElement(react_native_1.View, { style: styles.dataContainer },
38
+ react_1.default.createElement(react_native_1.Text, { style: [styles.sectionTitle, { color: theme?.textColor || '#000000' }] }, language === 'es' ? 'Datos Extraídos' : 'Extracted Data'),
39
+ react_1.default.createElement(DataRow, { label: language === 'es' ? 'Nombre' : 'Name', value: `${result.extractedDocumentData.firstName} ${result.extractedDocumentData.lastName}`, theme: theme }),
40
+ react_1.default.createElement(DataRow, { label: language === 'es' ? 'Documento' : 'Document Number', value: result.extractedDocumentData.documentNumber, theme: theme }),
41
+ react_1.default.createElement(DataRow, { label: language === 'es' ? 'Fecha de Nacimiento' : 'Date of Birth', value: result.extractedDocumentData.dateOfBirth, theme: theme }),
42
+ react_1.default.createElement(DataRow, { label: language === 'es' ? 'Nacionalidad' : 'Nationality', value: result.extractedDocumentData.nationality, theme: theme }))),
43
+ result.warnings.length > 0 && (react_1.default.createElement(react_native_1.View, { style: styles.warningsContainer },
44
+ react_1.default.createElement(react_native_1.Text, { style: [styles.sectionTitle, { color: theme?.warningColor || '#F59E0B' }] }, language === 'es' ? 'Advertencias' : 'Warnings'),
45
+ result.warnings.map((warning, index) => (react_1.default.createElement(react_native_1.Text, { key: index, style: styles.warningText },
46
+ "\u2022 ",
47
+ warning.replace(/_/g, ' '))))))),
48
+ react_1.default.createElement(react_native_1.View, { style: styles.footer },
49
+ react_1.default.createElement(react_native_1.TouchableOpacity, { style: [
50
+ styles.button,
51
+ { backgroundColor: theme?.primaryColor || '#6366F1' },
52
+ ], onPress: onClose },
53
+ react_1.default.createElement(react_native_1.Text, { style: styles.buttonText }, language === 'es' ? 'Continuar' : 'Continue')))));
54
+ };
55
+ exports.ResultScreen = ResultScreen;
56
+ const ScoreCard = ({ label, score, passed, theme }) => (react_1.default.createElement(react_native_1.View, { style: scoreStyles.container },
57
+ react_1.default.createElement(react_native_1.Text, { style: scoreStyles.label }, label),
58
+ react_1.default.createElement(react_native_1.Text, { style: [
59
+ scoreStyles.score,
60
+ { color: passed ? (theme?.successColor || '#10B981') : (theme?.errorColor || '#EF4444') },
61
+ ] }, Math.round(score)),
62
+ react_1.default.createElement(react_native_1.Text, { style: scoreStyles.status }, passed ? '✓ Passed' : '✗ Failed')));
63
+ const scoreStyles = react_native_1.StyleSheet.create({
64
+ container: {
65
+ flex: 1,
66
+ backgroundColor: '#F9FAFB',
67
+ padding: 16,
68
+ borderRadius: 12,
69
+ alignItems: 'center',
70
+ marginHorizontal: 8,
71
+ },
72
+ label: {
73
+ fontSize: 14,
74
+ color: '#6B7280',
75
+ marginBottom: 8,
76
+ },
77
+ score: {
78
+ fontSize: 32,
79
+ fontWeight: 'bold',
80
+ marginBottom: 4,
81
+ },
82
+ status: {
83
+ fontSize: 12,
84
+ color: '#9CA3AF',
85
+ },
86
+ });
87
+ const DataRow = ({ label, value, theme }) => (react_1.default.createElement(react_native_1.View, { style: dataRowStyles.container },
88
+ react_1.default.createElement(react_native_1.Text, { style: [dataRowStyles.label, { color: theme?.secondaryTextColor || '#6B7280' }] }, label),
89
+ react_1.default.createElement(react_native_1.Text, { style: [dataRowStyles.value, { color: theme?.textColor || '#000000' }] }, value)));
90
+ const dataRowStyles = react_native_1.StyleSheet.create({
91
+ container: {
92
+ flexDirection: 'row',
93
+ justifyContent: 'space-between',
94
+ paddingVertical: 12,
95
+ borderBottomWidth: 1,
96
+ borderBottomColor: '#E5E7EB',
97
+ },
98
+ label: {
99
+ fontSize: 14,
100
+ fontWeight: '500',
101
+ },
102
+ value: {
103
+ fontSize: 14,
104
+ fontWeight: '600',
105
+ },
106
+ });
107
+ const styles = react_native_1.StyleSheet.create({
108
+ container: {
109
+ flex: 1,
110
+ backgroundColor: '#FFFFFF',
111
+ },
112
+ content: {
113
+ padding: 24,
114
+ alignItems: 'center',
115
+ },
116
+ iconContainer: {
117
+ width: 80,
118
+ height: 80,
119
+ borderRadius: 40,
120
+ justifyContent: 'center',
121
+ alignItems: 'center',
122
+ marginBottom: 24,
123
+ },
124
+ icon: {
125
+ fontSize: 40,
126
+ color: '#FFFFFF',
127
+ fontWeight: 'bold',
128
+ },
129
+ title: {
130
+ fontSize: 28,
131
+ fontWeight: 'bold',
132
+ marginBottom: 8,
133
+ textAlign: 'center',
134
+ },
135
+ subtitle: {
136
+ fontSize: 16,
137
+ marginBottom: 32,
138
+ textAlign: 'center',
139
+ },
140
+ scoresContainer: {
141
+ flexDirection: 'row',
142
+ width: '100%',
143
+ marginBottom: 32,
144
+ },
145
+ dataContainer: {
146
+ width: '100%',
147
+ marginBottom: 24,
148
+ },
149
+ sectionTitle: {
150
+ fontSize: 18,
151
+ fontWeight: 'bold',
152
+ marginBottom: 16,
153
+ },
154
+ warningsContainer: {
155
+ width: '100%',
156
+ backgroundColor: '#FEF3C7',
157
+ padding: 16,
158
+ borderRadius: 8,
159
+ },
160
+ warningText: {
161
+ fontSize: 14,
162
+ color: '#92400E',
163
+ marginVertical: 4,
164
+ },
165
+ footer: {
166
+ padding: 24,
167
+ borderTopWidth: 1,
168
+ borderTopColor: '#E5E7EB',
169
+ },
170
+ button: {
171
+ paddingVertical: 16,
172
+ paddingHorizontal: 32,
173
+ borderRadius: 8,
174
+ alignItems: 'center',
175
+ },
176
+ buttonText: {
177
+ color: '#FFFFFF',
178
+ fontSize: 16,
179
+ fontWeight: '600',
180
+ },
181
+ });
182
+ exports.default = exports.ResultScreen;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Validation Progress Component
3
+ * Shows AI validation progress
4
+ */
5
+ import React from 'react';
6
+ import { ThemeConfig, SupportedLanguage } from '@hexar/biometric-identity-sdk-core';
7
+ export interface ValidationProgressProps {
8
+ progress: number;
9
+ theme?: ThemeConfig;
10
+ language?: SupportedLanguage;
11
+ }
12
+ export declare const ValidationProgress: React.FC<ValidationProgressProps>;
13
+ export default ValidationProgress;
14
+ //# sourceMappingURL=ValidationProgress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ValidationProgress.d.ts","sourceRoot":"","sources":["../../src/components/ValidationProgress.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAEpF,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAmFhE,CAAC;AAqHF,eAAe,kBAAkB,CAAC"}
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ /**
3
+ * Validation Progress Component
4
+ * Shows AI validation progress
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.ValidationProgress = void 0;
11
+ const react_1 = __importDefault(require("react"));
12
+ const react_native_1 = require("react-native");
13
+ const ValidationProgress = ({ progress, theme, language = 'en', }) => {
14
+ const getStatusText = () => {
15
+ if (progress < 80)
16
+ return language === 'es' ? 'Extrayendo datos del documento...' : 'Extracting document data...';
17
+ if (progress < 85)
18
+ return language === 'es' ? 'Validando presencia vital...' : 'Validating liveness...';
19
+ if (progress < 90)
20
+ return language === 'es' ? 'Detectando rostro en documento...' : 'Detecting face in document...';
21
+ if (progress < 95)
22
+ return language === 'es' ? 'Comparando rostros...' : 'Comparing faces...';
23
+ return language === 'es' ? 'Validando autenticidad del documento...' : 'Validating document authenticity...';
24
+ };
25
+ return (react_1.default.createElement(react_native_1.View, { style: styles.container },
26
+ react_1.default.createElement(react_native_1.View, { style: styles.content },
27
+ react_1.default.createElement(react_native_1.ActivityIndicator, { size: "large", color: theme?.primaryColor || '#6366F1' }),
28
+ react_1.default.createElement(react_native_1.Text, { style: [styles.title, { color: theme?.textColor || '#000000' }] }, language === 'es' ? 'Validando Identidad' : 'Validating Identity'),
29
+ react_1.default.createElement(react_native_1.Text, { style: [styles.statusText, { color: theme?.secondaryTextColor || '#6B7280' }] }, getStatusText()),
30
+ react_1.default.createElement(react_native_1.View, { style: styles.progressBarContainer },
31
+ react_1.default.createElement(react_native_1.View, { style: styles.progressBar },
32
+ react_1.default.createElement(react_native_1.View, { style: [
33
+ styles.progressFill,
34
+ {
35
+ width: `${progress}%`,
36
+ backgroundColor: theme?.primaryColor || '#6366F1',
37
+ },
38
+ ] })),
39
+ react_1.default.createElement(react_native_1.Text, { style: [styles.progressText, { color: theme?.textColor || '#000000' }] },
40
+ Math.round(progress),
41
+ "%")),
42
+ react_1.default.createElement(react_native_1.View, { style: styles.stepsContainer },
43
+ react_1.default.createElement(ValidationStep, { icon: "\u2713", text: language === 'es' ? 'Extracción OCR' : 'OCR Extraction', completed: progress >= 80, theme: theme }),
44
+ react_1.default.createElement(ValidationStep, { icon: "\u2713", text: language === 'es' ? 'Detección de Presencia Vital' : 'Liveness Detection', completed: progress >= 85, theme: theme }),
45
+ react_1.default.createElement(ValidationStep, { icon: "\u2713", text: language === 'es' ? 'Coincidencia Facial' : 'Face Matching', completed: progress >= 95, theme: theme }),
46
+ react_1.default.createElement(ValidationStep, { icon: "\u2713", text: language === 'es' ? 'Validación de Documento' : 'Document Validation', completed: progress >= 100, theme: theme })),
47
+ react_1.default.createElement(react_native_1.Text, { style: styles.bottomText }, language === 'es'
48
+ ? 'Esto puede tomar unos segundos...'
49
+ : 'This may take a few seconds...'))));
50
+ };
51
+ exports.ValidationProgress = ValidationProgress;
52
+ const ValidationStep = ({ icon, text, completed, theme, }) => (react_1.default.createElement(react_native_1.View, { style: stepStyles.container },
53
+ react_1.default.createElement(react_native_1.View, { style: [
54
+ stepStyles.iconContainer,
55
+ completed && {
56
+ backgroundColor: theme?.successColor || '#10B981',
57
+ },
58
+ ] }, completed && react_1.default.createElement(react_native_1.Text, { style: stepStyles.icon }, icon)),
59
+ react_1.default.createElement(react_native_1.Text, { style: [stepStyles.text, completed && stepStyles.textCompleted] }, text)));
60
+ const stepStyles = react_native_1.StyleSheet.create({
61
+ container: {
62
+ flexDirection: 'row',
63
+ alignItems: 'center',
64
+ marginVertical: 8,
65
+ },
66
+ iconContainer: {
67
+ width: 24,
68
+ height: 24,
69
+ borderRadius: 12,
70
+ backgroundColor: '#E5E7EB',
71
+ justifyContent: 'center',
72
+ alignItems: 'center',
73
+ marginRight: 12,
74
+ },
75
+ icon: {
76
+ color: '#FFFFFF',
77
+ fontSize: 14,
78
+ fontWeight: 'bold',
79
+ },
80
+ text: {
81
+ fontSize: 14,
82
+ color: '#9CA3AF',
83
+ },
84
+ textCompleted: {
85
+ color: '#111827',
86
+ fontWeight: '500',
87
+ },
88
+ });
89
+ const styles = react_native_1.StyleSheet.create({
90
+ container: {
91
+ flex: 1,
92
+ backgroundColor: '#FFFFFF',
93
+ justifyContent: 'center',
94
+ alignItems: 'center',
95
+ },
96
+ content: {
97
+ width: '85%',
98
+ alignItems: 'center',
99
+ },
100
+ title: {
101
+ fontSize: 24,
102
+ fontWeight: 'bold',
103
+ marginTop: 24,
104
+ marginBottom: 8,
105
+ },
106
+ statusText: {
107
+ fontSize: 16,
108
+ marginBottom: 32,
109
+ textAlign: 'center',
110
+ },
111
+ progressBarContainer: {
112
+ width: '100%',
113
+ marginBottom: 32,
114
+ },
115
+ progressBar: {
116
+ width: '100%',
117
+ height: 8,
118
+ backgroundColor: '#E5E7EB',
119
+ borderRadius: 4,
120
+ overflow: 'hidden',
121
+ marginBottom: 8,
122
+ },
123
+ progressFill: {
124
+ height: '100%',
125
+ borderRadius: 4,
126
+ },
127
+ progressText: {
128
+ fontSize: 14,
129
+ fontWeight: '600',
130
+ textAlign: 'center',
131
+ },
132
+ stepsContainer: {
133
+ width: '100%',
134
+ marginTop: 24,
135
+ marginBottom: 32,
136
+ },
137
+ bottomText: {
138
+ fontSize: 14,
139
+ color: '#9CA3AF',
140
+ textAlign: 'center',
141
+ },
142
+ });
143
+ exports.default = exports.ValidationProgress;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Smart Video Recorder Component for Liveness Detection
3
+ * Features challenge-response flow with guided head movements
4
+ */
5
+ import React from 'react';
6
+ import { ThemeConfig, LivenessInstruction } from '@hexar/biometric-identity-sdk-core';
7
+ export interface ChallengeAction {
8
+ action: string;
9
+ instruction: string;
10
+ duration_ms: number;
11
+ order: number;
12
+ icon?: string;
13
+ }
14
+ export interface VideoRecorderProps {
15
+ theme?: ThemeConfig;
16
+ /** Total recording duration in ms (default: 8000ms for smart mode) */
17
+ duration?: number;
18
+ /** Instructions for user to follow */
19
+ instructions?: LivenessInstruction[];
20
+ /** Pre-fetched challenges from backend */
21
+ challenges?: ChallengeAction[];
22
+ /** Session ID from backend challenge */
23
+ sessionId?: string;
24
+ /** Enable smart challenge mode (default: true) */
25
+ smartMode?: boolean;
26
+ /** Callback when recording completes */
27
+ onComplete: (videoData: VideoRecordingResult) => void;
28
+ /** Callback when user cancels */
29
+ onCancel: () => void;
30
+ /** Callback to fetch challenges from backend */
31
+ onFetchChallenges?: () => Promise<ChallengeAction[]>;
32
+ }
33
+ export interface VideoRecordingResult {
34
+ frames: string[];
35
+ duration: number;
36
+ instructionsFollowed: boolean;
37
+ qualityScore: number;
38
+ challengesCompleted: string[];
39
+ sessionId?: string;
40
+ }
41
+ export declare const VideoRecorder: React.FC<VideoRecorderProps>;
42
+ export default VideoRecorder;
43
+ //# sourceMappingURL=VideoRecorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VideoRecorder.d.ts","sourceRoot":"","sources":["../../src/components/VideoRecorder.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AASxE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAGtF,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,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;AAgDD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAsdtD,CAAC;AA+NF,eAAe,aAAa,CAAC"}