@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.
- package/README.md +68 -0
- package/dist/components/BiometricIdentityFlow.d.ts +17 -0
- package/dist/components/BiometricIdentityFlow.d.ts.map +1 -0
- package/dist/components/BiometricIdentityFlow.js +366 -0
- package/dist/components/CameraCapture.d.ts +15 -0
- package/dist/components/CameraCapture.d.ts.map +1 -0
- package/dist/components/CameraCapture.js +238 -0
- package/dist/components/ErrorScreen.d.ts +15 -0
- package/dist/components/ErrorScreen.d.ts.map +1 -0
- package/dist/components/ErrorScreen.js +142 -0
- package/dist/components/InstructionsScreen.d.ts +14 -0
- package/dist/components/InstructionsScreen.d.ts.map +1 -0
- package/dist/components/InstructionsScreen.js +181 -0
- package/dist/components/ResultScreen.d.ts +15 -0
- package/dist/components/ResultScreen.d.ts.map +1 -0
- package/dist/components/ResultScreen.js +182 -0
- package/dist/components/ValidationProgress.d.ts +14 -0
- package/dist/components/ValidationProgress.d.ts.map +1 -0
- package/dist/components/ValidationProgress.js +143 -0
- package/dist/components/VideoRecorder.d.ts +43 -0
- package/dist/components/VideoRecorder.d.ts.map +1 -0
- package/dist/components/VideoRecorder.js +631 -0
- package/dist/hooks/useBiometricSDK.d.ts +25 -0
- package/dist/hooks/useBiometricSDK.d.ts.map +1 -0
- package/dist/hooks/useBiometricSDK.js +173 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/package.json +27 -0
- package/src/components/BiometricIdentityFlow.tsx +557 -0
- package/src/components/CameraCapture.tsx +262 -0
- package/src/components/ErrorScreen.tsx +201 -0
- package/src/components/InstructionsScreen.tsx +269 -0
- package/src/components/ResultScreen.tsx +301 -0
- package/src/components/ValidationProgress.tsx +223 -0
- package/src/components/VideoRecorder.tsx +794 -0
- package/src/hooks/useBiometricSDK.ts +230 -0
- package/src/index.ts +24 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
BiometricIdentitySDK,
|
|
4
|
+
SDKState,
|
|
5
|
+
VideoResult,
|
|
6
|
+
} from '@hexar/biometric-identity-sdk-core';
|
|
7
|
+
|
|
8
|
+
export interface ChallengeAction {
|
|
9
|
+
action: string;
|
|
10
|
+
instruction: string;
|
|
11
|
+
duration_ms: number;
|
|
12
|
+
order: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface UseBiometricSDKResult {
|
|
16
|
+
sdk: BiometricIdentitySDK;
|
|
17
|
+
state: SDKState;
|
|
18
|
+
isInitialized: boolean;
|
|
19
|
+
isUsingBackend: boolean;
|
|
20
|
+
sessionId: string | null;
|
|
21
|
+
challenges: ChallengeAction[];
|
|
22
|
+
uploadFrontID: (imageData: string | File | Blob) => Promise<void>;
|
|
23
|
+
uploadBackID: (imageData: string | File | Blob) => Promise<void>;
|
|
24
|
+
storeVideoRecording: (videoData: VideoResult) => Promise<void>;
|
|
25
|
+
fetchChallenges: (type?: 'active' | 'passive') => Promise<ChallengeAction[]>;
|
|
26
|
+
validateIdentity: () => Promise<any>;
|
|
27
|
+
reset: () => void;
|
|
28
|
+
recordVideo: (videoData?: VideoResult) => Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const useBiometricSDK = (): UseBiometricSDKResult => {
|
|
32
|
+
const [sdk] = useState(() => BiometricIdentitySDK.createSession());
|
|
33
|
+
const [state, setState] = useState<SDKState>(sdk.getState());
|
|
34
|
+
const [isInitialized, setIsInitialized] = useState(false);
|
|
35
|
+
const [challenges, setChallenges] = useState<ChallengeAction[]>([]);
|
|
36
|
+
const isMounted = useRef(true);
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
isMounted.current = true;
|
|
40
|
+
|
|
41
|
+
const init = async () => {
|
|
42
|
+
try {
|
|
43
|
+
await sdk.initialize();
|
|
44
|
+
if (isMounted.current) {
|
|
45
|
+
setIsInitialized(true);
|
|
46
|
+
setState(sdk.getState());
|
|
47
|
+
}
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error('SDK initialization failed:', error);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
init();
|
|
54
|
+
|
|
55
|
+
return () => {
|
|
56
|
+
isMounted.current = false;
|
|
57
|
+
sdk.dispose();
|
|
58
|
+
};
|
|
59
|
+
}, [sdk]);
|
|
60
|
+
|
|
61
|
+
// Poll state updates while loading
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (!state.isLoading) return;
|
|
64
|
+
|
|
65
|
+
const interval = setInterval(() => {
|
|
66
|
+
if (isMounted.current) {
|
|
67
|
+
setState(sdk.getState());
|
|
68
|
+
}
|
|
69
|
+
}, 100);
|
|
70
|
+
|
|
71
|
+
return () => clearInterval(interval);
|
|
72
|
+
}, [sdk, state.isLoading]);
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Fetch liveness challenges from backend
|
|
76
|
+
*/
|
|
77
|
+
const fetchChallenges = useCallback(
|
|
78
|
+
async (type: 'active' | 'passive' = 'active'): Promise<ChallengeAction[]> => {
|
|
79
|
+
try {
|
|
80
|
+
const response = await sdk.generateLivenessChallenge(type);
|
|
81
|
+
|
|
82
|
+
if (response && response.challenges) {
|
|
83
|
+
const challengeActions: ChallengeAction[] = response.challenges.map(c => ({
|
|
84
|
+
action: c.action,
|
|
85
|
+
instruction: c.instruction,
|
|
86
|
+
duration_ms: c.duration_ms,
|
|
87
|
+
order: c.order,
|
|
88
|
+
}));
|
|
89
|
+
|
|
90
|
+
setChallenges(challengeActions);
|
|
91
|
+
return challengeActions;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Return default challenges if backend not available
|
|
95
|
+
const defaultChallenges: ChallengeAction[] = sdk.getDefaultChallenges().map(c => ({
|
|
96
|
+
action: c.action,
|
|
97
|
+
instruction: c.instruction,
|
|
98
|
+
duration_ms: c.duration_ms,
|
|
99
|
+
order: c.order,
|
|
100
|
+
}));
|
|
101
|
+
setChallenges(defaultChallenges);
|
|
102
|
+
return defaultChallenges;
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error('Failed to fetch challenges:', error);
|
|
105
|
+
const defaultChallenges: ChallengeAction[] = sdk.getDefaultChallenges().map(c => ({
|
|
106
|
+
action: c.action,
|
|
107
|
+
instruction: c.instruction,
|
|
108
|
+
duration_ms: c.duration_ms,
|
|
109
|
+
order: c.order,
|
|
110
|
+
}));
|
|
111
|
+
setChallenges(defaultChallenges);
|
|
112
|
+
return defaultChallenges;
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
[sdk]
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Upload front ID image
|
|
120
|
+
*/
|
|
121
|
+
const uploadFrontID = useCallback(
|
|
122
|
+
async (imageData: string | File | Blob) => {
|
|
123
|
+
await sdk.uploadFrontID(imageData);
|
|
124
|
+
if (isMounted.current) {
|
|
125
|
+
setState(sdk.getState());
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
[sdk]
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Upload back ID image
|
|
133
|
+
*/
|
|
134
|
+
const uploadBackID = useCallback(
|
|
135
|
+
async (imageData: string | File | Blob) => {
|
|
136
|
+
await sdk.uploadBackID(imageData);
|
|
137
|
+
if (isMounted.current) {
|
|
138
|
+
setState(sdk.getState());
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
[sdk]
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Store video recording result
|
|
146
|
+
*/
|
|
147
|
+
const storeVideoRecording = useCallback(
|
|
148
|
+
async (videoData: VideoResult) => {
|
|
149
|
+
// Add session ID if using backend
|
|
150
|
+
const sessionId = sdk.getSessionId();
|
|
151
|
+
if (sessionId) {
|
|
152
|
+
videoData.sessionId = sessionId;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
await sdk.storeVideoRecording(videoData);
|
|
156
|
+
if (isMounted.current) {
|
|
157
|
+
setState(sdk.getState());
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
[sdk]
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Legacy: Record video (for backwards compatibility)
|
|
165
|
+
*/
|
|
166
|
+
const recordVideo = useCallback(
|
|
167
|
+
async (videoData?: VideoResult) => {
|
|
168
|
+
if (videoData) {
|
|
169
|
+
await storeVideoRecording(videoData);
|
|
170
|
+
} else {
|
|
171
|
+
// Mock video result for backwards compatibility
|
|
172
|
+
const mockVideoResult: VideoResult = {
|
|
173
|
+
frames: Array.from({ length: 80 }, (_, i) => `frame_${i}_base64`),
|
|
174
|
+
duration: 8000,
|
|
175
|
+
instructionsFollowed: true,
|
|
176
|
+
qualityScore: 85,
|
|
177
|
+
challengesCompleted: challenges.map(c => c.action),
|
|
178
|
+
sessionId: sdk.getSessionId() || undefined,
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
await sdk.storeVideoRecording(mockVideoResult);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (isMounted.current) {
|
|
185
|
+
setState(sdk.getState());
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
[sdk, storeVideoRecording, challenges]
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Validate identity with all collected data
|
|
193
|
+
*/
|
|
194
|
+
const validateIdentity = useCallback(async () => {
|
|
195
|
+
const result = await sdk.validateIdentity();
|
|
196
|
+
if (isMounted.current) {
|
|
197
|
+
setState(sdk.getState());
|
|
198
|
+
}
|
|
199
|
+
return result;
|
|
200
|
+
}, [sdk]);
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Reset SDK state
|
|
204
|
+
*/
|
|
205
|
+
const reset = useCallback(() => {
|
|
206
|
+
sdk.reset();
|
|
207
|
+
setChallenges([]);
|
|
208
|
+
if (isMounted.current) {
|
|
209
|
+
setState(sdk.getState());
|
|
210
|
+
}
|
|
211
|
+
}, [sdk]);
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
sdk,
|
|
215
|
+
state,
|
|
216
|
+
isInitialized,
|
|
217
|
+
isUsingBackend: sdk.isUsingBackend(),
|
|
218
|
+
sessionId: sdk.getSessionId(),
|
|
219
|
+
challenges,
|
|
220
|
+
uploadFrontID,
|
|
221
|
+
uploadBackID,
|
|
222
|
+
storeVideoRecording,
|
|
223
|
+
fetchChallenges,
|
|
224
|
+
validateIdentity,
|
|
225
|
+
reset,
|
|
226
|
+
recordVideo,
|
|
227
|
+
};
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
export default useBiometricSDK;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Native Biometric Identity SDK
|
|
3
|
+
* Main entry point
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Main component
|
|
7
|
+
export { BiometricIdentityFlow } from './components/BiometricIdentityFlow';
|
|
8
|
+
export { default } from './components/BiometricIdentityFlow';
|
|
9
|
+
|
|
10
|
+
// Individual components (for custom implementations)
|
|
11
|
+
export { CameraCapture } from './components/CameraCapture';
|
|
12
|
+
export { VideoRecorder } from './components/VideoRecorder';
|
|
13
|
+
export { ValidationProgress } from './components/ValidationProgress';
|
|
14
|
+
export { ResultScreen } from './components/ResultScreen';
|
|
15
|
+
export { ErrorScreen } from './components/ErrorScreen';
|
|
16
|
+
export { InstructionsScreen } from './components/InstructionsScreen';
|
|
17
|
+
|
|
18
|
+
// Hooks
|
|
19
|
+
export { useBiometricSDK } from './hooks/useBiometricSDK';
|
|
20
|
+
|
|
21
|
+
// Re-export core types
|
|
22
|
+
export * from '@hexar/biometric-identity-sdk-core';
|
|
23
|
+
|
|
24
|
+
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2020"],
|
|
6
|
+
"jsx": "react",
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"declarationMap": true,
|
|
9
|
+
"outDir": "./dist",
|
|
10
|
+
"rootDir": "./src",
|
|
11
|
+
"strict": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"forceConsistentCasingInFileNames": true,
|
|
15
|
+
"resolveJsonModule": true,
|
|
16
|
+
"moduleResolution": "node"
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "dist"]
|
|
20
|
+
}
|