@hexar/biometric-identity-sdk-core 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/dist/BiometricIdentitySDK.d.ts +111 -0
- package/dist/BiometricIdentitySDK.js +395 -0
- package/dist/ai-models/FaceDetector.d.ts +59 -0
- package/dist/ai-models/FaceDetector.js +167 -0
- package/dist/ai-models/LivenessDetector.d.ts +61 -0
- package/dist/ai-models/LivenessDetector.js +218 -0
- package/dist/api/BackendClient.d.ts +178 -0
- package/dist/api/BackendClient.js +199 -0
- package/dist/api/index.d.ts +5 -0
- package/dist/api/index.js +8 -0
- package/dist/encryption/index.d.ts +38 -0
- package/dist/encryption/index.js +99 -0
- package/dist/i18n/index.d.ts +6 -0
- package/dist/i18n/index.js +47 -0
- package/dist/i18n/languages/en.d.ts +2 -0
- package/dist/i18n/languages/en.js +112 -0
- package/dist/i18n/languages/es-AR.d.ts +2 -0
- package/dist/i18n/languages/es-AR.js +112 -0
- package/dist/i18n/languages/es.d.ts +2 -0
- package/dist/i18n/languages/es.js +112 -0
- package/dist/i18n/languages/pt-BR.d.ts +2 -0
- package/dist/i18n/languages/pt-BR.js +112 -0
- package/dist/i18n/types.d.ts +110 -0
- package/dist/i18n/types.js +2 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +64 -0
- package/dist/services/BackendValidationService.d.ts +84 -0
- package/dist/services/BackendValidationService.js +174 -0
- package/dist/services/IValidationService.d.ts +132 -0
- package/dist/services/IValidationService.js +8 -0
- package/dist/services/index.d.ts +8 -0
- package/dist/services/index.js +10 -0
- package/dist/types/index.d.ts +288 -0
- package/dist/types/index.js +34 -0
- package/dist/validation/DocumentValidator.d.ts +84 -0
- package/dist/validation/DocumentValidator.js +295 -0
- package/dist/validation/OCREngine.d.ts +75 -0
- package/dist/validation/OCREngine.js +225 -0
- package/package.json +24 -0
- package/src/BiometricIdentitySDK.ts +493 -0
- package/src/ai-models/FaceDetector.ts +200 -0
- package/src/ai-models/LivenessDetector.ts +274 -0
- package/src/api/BackendClient.ts +395 -0
- package/src/api/index.ts +15 -0
- package/src/encryption/index.ts +108 -0
- package/src/i18n/index.ts +35 -0
- package/src/i18n/languages/en.ts +121 -0
- package/src/i18n/languages/es-AR.ts +121 -0
- package/src/i18n/languages/es.ts +121 -0
- package/src/i18n/languages/pt-BR.ts +121 -0
- package/src/i18n/types.ts +121 -0
- package/src/index.ts +54 -0
- package/src/services/BackendValidationService.ts +228 -0
- package/src/services/IValidationService.ts +158 -0
- package/src/services/index.ts +17 -0
- package/src/types/index.ts +380 -0
- package/src/validation/DocumentValidator.ts +353 -0
- package/src/validation/OCREngine.ts +265 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main Biometric Identity SDK Class
|
|
3
|
+
* Initialize once at app start with your API key
|
|
4
|
+
*/
|
|
5
|
+
import { ValidationResult, VideoResult, SDKState } from './types';
|
|
6
|
+
import { ChallengeResponse, ChallengeAction } from './api/BackendClient';
|
|
7
|
+
import { SupportedLanguage } from './i18n';
|
|
8
|
+
export declare class BiometricIdentitySDK {
|
|
9
|
+
private static instance;
|
|
10
|
+
private config;
|
|
11
|
+
private state;
|
|
12
|
+
private backendClient;
|
|
13
|
+
private isBackendAvailable;
|
|
14
|
+
private constructor();
|
|
15
|
+
/**
|
|
16
|
+
* Initialize SDK (call once at app start)
|
|
17
|
+
*/
|
|
18
|
+
static configure(apiKey: string, options?: {
|
|
19
|
+
language?: SupportedLanguage;
|
|
20
|
+
}): void;
|
|
21
|
+
/**
|
|
22
|
+
* Get SDK instance
|
|
23
|
+
*/
|
|
24
|
+
static getInstance(): BiometricIdentitySDK;
|
|
25
|
+
/**
|
|
26
|
+
* Create a new session (for per-user flows)
|
|
27
|
+
*/
|
|
28
|
+
static createSession(): BiometricIdentitySDK;
|
|
29
|
+
/**
|
|
30
|
+
* Initialize SDK and check backend availability
|
|
31
|
+
*/
|
|
32
|
+
initialize(): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Generate liveness challenge from backend
|
|
35
|
+
* Returns challenge actions for the user to perform
|
|
36
|
+
*/
|
|
37
|
+
generateLivenessChallenge(challengeType?: 'active' | 'passive'): Promise<ChallengeResponse>;
|
|
38
|
+
/**
|
|
39
|
+
* Get default challenges for offline mode
|
|
40
|
+
*/
|
|
41
|
+
getDefaultChallenges(): ChallengeAction[];
|
|
42
|
+
/**
|
|
43
|
+
* Get current session ID (from backend)
|
|
44
|
+
*/
|
|
45
|
+
getSessionId(): string | null;
|
|
46
|
+
/**
|
|
47
|
+
* Upload front ID image
|
|
48
|
+
*/
|
|
49
|
+
uploadFrontID(image: File | Blob | string): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Upload back ID image
|
|
52
|
+
*/
|
|
53
|
+
uploadBackID(image: File | Blob | string): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Store video recording for liveness detection
|
|
56
|
+
*/
|
|
57
|
+
storeVideoRecording(videoResult: VideoResult): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Record video for liveness detection (legacy method)
|
|
60
|
+
*/
|
|
61
|
+
recordVideoLiveness(options?: {
|
|
62
|
+
duration?: number;
|
|
63
|
+
instructions?: string[];
|
|
64
|
+
}): Promise<VideoResult>;
|
|
65
|
+
/**
|
|
66
|
+
* Validate identity using all collected data
|
|
67
|
+
* Uses backend AI for validation
|
|
68
|
+
*/
|
|
69
|
+
validateIdentity(): Promise<ValidationResult>;
|
|
70
|
+
/**
|
|
71
|
+
* Validate using backend API
|
|
72
|
+
*/
|
|
73
|
+
private validateWithBackend;
|
|
74
|
+
/**
|
|
75
|
+
* Process image (convert File/Blob to ImageData)
|
|
76
|
+
*/
|
|
77
|
+
private processImage;
|
|
78
|
+
/**
|
|
79
|
+
* Convert Blob to base64
|
|
80
|
+
*/
|
|
81
|
+
private blobToBase64;
|
|
82
|
+
/**
|
|
83
|
+
* Get current SDK state
|
|
84
|
+
*/
|
|
85
|
+
getState(): SDKState;
|
|
86
|
+
/**
|
|
87
|
+
* Check if backend is available
|
|
88
|
+
*/
|
|
89
|
+
isUsingBackend(): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Update SDK state
|
|
92
|
+
*/
|
|
93
|
+
private updateState;
|
|
94
|
+
/**
|
|
95
|
+
* Create typed error
|
|
96
|
+
*/
|
|
97
|
+
private createError;
|
|
98
|
+
/**
|
|
99
|
+
* Handle errors
|
|
100
|
+
*/
|
|
101
|
+
private handleError;
|
|
102
|
+
/**
|
|
103
|
+
* Reset SDK state
|
|
104
|
+
*/
|
|
105
|
+
reset(): void;
|
|
106
|
+
/**
|
|
107
|
+
* Clean up resources
|
|
108
|
+
*/
|
|
109
|
+
dispose(): void;
|
|
110
|
+
}
|
|
111
|
+
export default BiometricIdentitySDK;
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Main Biometric Identity SDK Class
|
|
4
|
+
* Initialize once at app start with your API key
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.BiometricIdentitySDK = void 0;
|
|
8
|
+
const types_1 = require("./types");
|
|
9
|
+
const BackendClient_1 = require("./api/BackendClient");
|
|
10
|
+
const i18n_1 = require("./i18n");
|
|
11
|
+
const API_ENDPOINT = 'https://api.hexar.biometry.com/v1';
|
|
12
|
+
class BiometricIdentitySDK {
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.isBackendAvailable = false;
|
|
15
|
+
if (!config.apiKey) {
|
|
16
|
+
throw new Error('BiometricIdentitySDK requires an API key');
|
|
17
|
+
}
|
|
18
|
+
this.config = {
|
|
19
|
+
apiEndpoint: API_ENDPOINT,
|
|
20
|
+
apiKey: config.apiKey,
|
|
21
|
+
language: config.language || 'en',
|
|
22
|
+
enableBackendValidation: true,
|
|
23
|
+
enableLocalStorage: config.enableLocalStorage || false,
|
|
24
|
+
encryptionKey: config.encryptionKey || '',
|
|
25
|
+
minMatchScore: config.minMatchScore || 85,
|
|
26
|
+
minLivenessScore: config.minLivenessScore || 80,
|
|
27
|
+
validationTimeout: config.validationTimeout || 60000,
|
|
28
|
+
modelPaths: {},
|
|
29
|
+
};
|
|
30
|
+
this.state = {
|
|
31
|
+
currentStep: types_1.SDKStep.INIT,
|
|
32
|
+
isLoading: false,
|
|
33
|
+
progress: 0,
|
|
34
|
+
};
|
|
35
|
+
this.backendClient = new BackendClient_1.BackendClient({
|
|
36
|
+
apiEndpoint: API_ENDPOINT,
|
|
37
|
+
apiKey: this.config.apiKey,
|
|
38
|
+
timeout: this.config.validationTimeout,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Initialize SDK (call once at app start)
|
|
43
|
+
*/
|
|
44
|
+
static configure(apiKey, options) {
|
|
45
|
+
if (BiometricIdentitySDK.instance) {
|
|
46
|
+
console.warn('SDK already initialized');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const language = options?.language || 'en';
|
|
50
|
+
(0, i18n_1.setLanguage)(language);
|
|
51
|
+
BiometricIdentitySDK.instance = new BiometricIdentitySDK({
|
|
52
|
+
apiKey,
|
|
53
|
+
language,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get SDK instance
|
|
58
|
+
*/
|
|
59
|
+
static getInstance() {
|
|
60
|
+
if (!BiometricIdentitySDK.instance) {
|
|
61
|
+
throw new Error('SDK not initialized. Call BiometricIdentitySDK.configure() first');
|
|
62
|
+
}
|
|
63
|
+
return BiometricIdentitySDK.instance;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Create a new session (for per-user flows)
|
|
67
|
+
*/
|
|
68
|
+
static createSession() {
|
|
69
|
+
const config = BiometricIdentitySDK.getInstance().config;
|
|
70
|
+
return new BiometricIdentitySDK(config);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Initialize SDK and check backend availability
|
|
74
|
+
*/
|
|
75
|
+
async initialize() {
|
|
76
|
+
try {
|
|
77
|
+
console.log('Initializing Biometric Identity SDK...');
|
|
78
|
+
this.updateState({ isLoading: true, progress: 0 });
|
|
79
|
+
// Check backend availability
|
|
80
|
+
console.log('Checking backend availability...');
|
|
81
|
+
this.isBackendAvailable = await this.backendClient.healthCheck();
|
|
82
|
+
if (!this.isBackendAvailable) {
|
|
83
|
+
throw this.createError(types_1.BiometricErrorCode.NETWORK_ERROR, 'Backend server is not available. Please check your API endpoint configuration and try again.');
|
|
84
|
+
}
|
|
85
|
+
console.log('✓ Backend is available - ready for validation');
|
|
86
|
+
this.updateState({
|
|
87
|
+
isLoading: false,
|
|
88
|
+
progress: 0,
|
|
89
|
+
currentStep: types_1.SDKStep.CAPTURE_FRONT_ID
|
|
90
|
+
});
|
|
91
|
+
console.log('SDK initialized successfully');
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
throw this.createError(types_1.BiometricErrorCode.MODEL_LOAD_FAILED, 'Failed to initialize SDK: Backend not available', error);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Generate liveness challenge from backend
|
|
99
|
+
* Returns challenge actions for the user to perform
|
|
100
|
+
*/
|
|
101
|
+
async generateLivenessChallenge(challengeType = 'active') {
|
|
102
|
+
if (!this.isBackendAvailable) {
|
|
103
|
+
throw this.createError(types_1.BiometricErrorCode.NETWORK_ERROR, 'Backend not available. Cannot generate challenge.');
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const challenge = await this.backendClient.generateChallenge(challengeType);
|
|
107
|
+
console.log(`Generated challenge with ${challenge.challenges.length} actions`);
|
|
108
|
+
return challenge;
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
throw this.createError(types_1.BiometricErrorCode.NETWORK_ERROR, 'Failed to generate liveness challenge', error);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get default challenges for offline mode
|
|
116
|
+
*/
|
|
117
|
+
getDefaultChallenges() {
|
|
118
|
+
return [
|
|
119
|
+
{
|
|
120
|
+
action: 'look_left',
|
|
121
|
+
instruction: 'Slowly turn your head to the LEFT',
|
|
122
|
+
duration_ms: 2500,
|
|
123
|
+
order: 1,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
action: 'look_right',
|
|
127
|
+
instruction: 'Slowly turn your head to the RIGHT',
|
|
128
|
+
duration_ms: 2500,
|
|
129
|
+
order: 2,
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
action: 'blink',
|
|
133
|
+
instruction: 'Blink your eyes naturally',
|
|
134
|
+
duration_ms: 2000,
|
|
135
|
+
order: 3,
|
|
136
|
+
},
|
|
137
|
+
];
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get current session ID (from backend)
|
|
141
|
+
*/
|
|
142
|
+
getSessionId() {
|
|
143
|
+
return this.backendClient?.getSessionId() || null;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Upload front ID image
|
|
147
|
+
*/
|
|
148
|
+
async uploadFrontID(image) {
|
|
149
|
+
try {
|
|
150
|
+
this.updateState({ isLoading: true, currentStep: types_1.SDKStep.CAPTURE_FRONT_ID });
|
|
151
|
+
const imageData = await this.processImage(image);
|
|
152
|
+
// Store the image - validation happens at the end
|
|
153
|
+
this.updateState({
|
|
154
|
+
frontID: imageData,
|
|
155
|
+
progress: 25,
|
|
156
|
+
isLoading: false,
|
|
157
|
+
currentStep: types_1.SDKStep.CAPTURE_BACK_ID
|
|
158
|
+
});
|
|
159
|
+
console.log('Front ID uploaded successfully');
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
this.handleError(error);
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Upload back ID image
|
|
168
|
+
*/
|
|
169
|
+
async uploadBackID(image) {
|
|
170
|
+
try {
|
|
171
|
+
this.updateState({ isLoading: true, currentStep: types_1.SDKStep.CAPTURE_BACK_ID });
|
|
172
|
+
const imageData = await this.processImage(image);
|
|
173
|
+
// Store the image - validation happens at the end
|
|
174
|
+
this.updateState({
|
|
175
|
+
backID: imageData,
|
|
176
|
+
progress: 50,
|
|
177
|
+
isLoading: false,
|
|
178
|
+
currentStep: types_1.SDKStep.RECORD_LIVENESS
|
|
179
|
+
});
|
|
180
|
+
console.log('Back ID uploaded successfully');
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
this.handleError(error);
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Store video recording for liveness detection
|
|
189
|
+
*/
|
|
190
|
+
async storeVideoRecording(videoResult) {
|
|
191
|
+
try {
|
|
192
|
+
this.updateState({ isLoading: true, currentStep: types_1.SDKStep.RECORD_LIVENESS });
|
|
193
|
+
this.updateState({
|
|
194
|
+
videoData: videoResult,
|
|
195
|
+
progress: 75,
|
|
196
|
+
isLoading: false,
|
|
197
|
+
});
|
|
198
|
+
console.log('Video recording stored successfully');
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
this.handleError(error);
|
|
202
|
+
throw error;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Record video for liveness detection (legacy method)
|
|
207
|
+
*/
|
|
208
|
+
async recordVideoLiveness(options) {
|
|
209
|
+
try {
|
|
210
|
+
this.updateState({ isLoading: true, currentStep: types_1.SDKStep.RECORD_LIVENESS });
|
|
211
|
+
// This would be implemented by the platform-specific wrappers
|
|
212
|
+
// For now, return a mock result
|
|
213
|
+
const videoResult = {
|
|
214
|
+
frames: [],
|
|
215
|
+
duration: options?.duration || 8000,
|
|
216
|
+
instructionsFollowed: true,
|
|
217
|
+
qualityScore: 85,
|
|
218
|
+
};
|
|
219
|
+
this.updateState({
|
|
220
|
+
videoData: videoResult,
|
|
221
|
+
progress: 75,
|
|
222
|
+
isLoading: false,
|
|
223
|
+
});
|
|
224
|
+
console.log('Video liveness recorded successfully');
|
|
225
|
+
return videoResult;
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
this.handleError(error);
|
|
229
|
+
throw error;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Validate identity using all collected data
|
|
234
|
+
* Uses backend AI for validation
|
|
235
|
+
*/
|
|
236
|
+
async validateIdentity() {
|
|
237
|
+
try {
|
|
238
|
+
if (!this.state.frontID || !this.state.videoData) {
|
|
239
|
+
throw this.createError(types_1.BiometricErrorCode.UNKNOWN_ERROR, 'Missing required data for validation. Need front ID and video.');
|
|
240
|
+
}
|
|
241
|
+
if (!this.isBackendAvailable) {
|
|
242
|
+
throw this.createError(types_1.BiometricErrorCode.NETWORK_ERROR, 'Backend not available. Cannot perform validation.');
|
|
243
|
+
}
|
|
244
|
+
this.updateState({
|
|
245
|
+
isLoading: true,
|
|
246
|
+
currentStep: types_1.SDKStep.VALIDATING,
|
|
247
|
+
progress: 75
|
|
248
|
+
});
|
|
249
|
+
// Perform backend validation
|
|
250
|
+
const validationResult = await this.validateWithBackend();
|
|
251
|
+
this.updateState({
|
|
252
|
+
validationResult,
|
|
253
|
+
progress: 100,
|
|
254
|
+
isLoading: false,
|
|
255
|
+
currentStep: types_1.SDKStep.RESULT
|
|
256
|
+
});
|
|
257
|
+
console.log('Validation completed successfully');
|
|
258
|
+
return validationResult;
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
this.handleError(error);
|
|
262
|
+
throw error;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Validate using backend API
|
|
267
|
+
*/
|
|
268
|
+
async validateWithBackend() {
|
|
269
|
+
if (!this.state.frontID || !this.state.videoData) {
|
|
270
|
+
throw new Error('Required data not available');
|
|
271
|
+
}
|
|
272
|
+
console.log('Validating with backend API...');
|
|
273
|
+
this.updateState({ progress: 80 });
|
|
274
|
+
try {
|
|
275
|
+
const response = await this.backendClient.fullValidation({
|
|
276
|
+
frontIdImage: this.state.frontID.data,
|
|
277
|
+
backIdImage: this.state.backID?.data,
|
|
278
|
+
videoFrames: this.state.videoData.frames,
|
|
279
|
+
videoDurationMs: this.state.videoData.duration,
|
|
280
|
+
challengesCompleted: this.state.videoData.challengesCompleted || [],
|
|
281
|
+
});
|
|
282
|
+
this.updateState({ progress: 95 });
|
|
283
|
+
// Convert backend response to SDK format
|
|
284
|
+
return this.backendClient.convertToValidationResult(response);
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
throw this.createError(types_1.BiometricErrorCode.NETWORK_ERROR, 'Backend validation failed', error);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Process image (convert File/Blob to ImageData)
|
|
292
|
+
*/
|
|
293
|
+
async processImage(image) {
|
|
294
|
+
try {
|
|
295
|
+
if (typeof image === 'string') {
|
|
296
|
+
// Already base64
|
|
297
|
+
return {
|
|
298
|
+
data: image,
|
|
299
|
+
width: 0,
|
|
300
|
+
height: 0,
|
|
301
|
+
mimeType: 'image/jpeg',
|
|
302
|
+
size: image.length,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
// Convert Blob/File to base64
|
|
306
|
+
const base64 = await this.blobToBase64(image);
|
|
307
|
+
return {
|
|
308
|
+
data: base64,
|
|
309
|
+
width: 0, // Would be set after image analysis
|
|
310
|
+
height: 0,
|
|
311
|
+
mimeType: image.type,
|
|
312
|
+
size: image.size,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
catch (error) {
|
|
316
|
+
throw this.createError(types_1.BiometricErrorCode.UNKNOWN_ERROR, 'Failed to process image', error);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Convert Blob to base64
|
|
321
|
+
*/
|
|
322
|
+
blobToBase64(blob) {
|
|
323
|
+
return new Promise((resolve, reject) => {
|
|
324
|
+
const reader = new FileReader();
|
|
325
|
+
reader.onloadend = () => {
|
|
326
|
+
const base64 = reader.result;
|
|
327
|
+
resolve(base64.split(',')[1] || base64);
|
|
328
|
+
};
|
|
329
|
+
reader.onerror = reject;
|
|
330
|
+
reader.readAsDataURL(blob);
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Get current SDK state
|
|
335
|
+
*/
|
|
336
|
+
getState() {
|
|
337
|
+
return { ...this.state };
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Check if backend is available
|
|
341
|
+
*/
|
|
342
|
+
isUsingBackend() {
|
|
343
|
+
return this.isBackendAvailable;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Update SDK state
|
|
347
|
+
*/
|
|
348
|
+
updateState(updates) {
|
|
349
|
+
this.state = {
|
|
350
|
+
...this.state,
|
|
351
|
+
...updates,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Create typed error
|
|
356
|
+
*/
|
|
357
|
+
createError(code, message, details) {
|
|
358
|
+
const error = new Error(message);
|
|
359
|
+
error.code = code;
|
|
360
|
+
error.details = details;
|
|
361
|
+
return error;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Handle errors
|
|
365
|
+
*/
|
|
366
|
+
handleError(error) {
|
|
367
|
+
this.updateState({
|
|
368
|
+
error: error,
|
|
369
|
+
isLoading: false,
|
|
370
|
+
currentStep: types_1.SDKStep.ERROR,
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Reset SDK state
|
|
375
|
+
*/
|
|
376
|
+
reset() {
|
|
377
|
+
this.state = {
|
|
378
|
+
currentStep: types_1.SDKStep.INIT,
|
|
379
|
+
isLoading: false,
|
|
380
|
+
progress: 0,
|
|
381
|
+
};
|
|
382
|
+
// Reset backend session
|
|
383
|
+
this.backendClient?.resetSession();
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Clean up resources
|
|
387
|
+
*/
|
|
388
|
+
dispose() {
|
|
389
|
+
// No local resources to clean up
|
|
390
|
+
console.log('SDK disposed');
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
exports.BiometricIdentitySDK = BiometricIdentitySDK;
|
|
394
|
+
BiometricIdentitySDK.instance = null;
|
|
395
|
+
exports.default = BiometricIdentitySDK;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Face Detection using AI models
|
|
3
|
+
* Uses BlazeFace model for lightweight, fast face detection
|
|
4
|
+
*/
|
|
5
|
+
import { FaceEmbedding, BoundingBox } from '../types';
|
|
6
|
+
export interface FaceDetectionResult {
|
|
7
|
+
faces: FaceEmbedding[];
|
|
8
|
+
processingTime: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class FaceDetector {
|
|
11
|
+
private modelPath?;
|
|
12
|
+
private model;
|
|
13
|
+
private isModelLoaded;
|
|
14
|
+
constructor(modelPath?: string | undefined);
|
|
15
|
+
/**
|
|
16
|
+
* Load the face detection model
|
|
17
|
+
*/
|
|
18
|
+
loadModel(): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Detect faces in an image
|
|
21
|
+
*/
|
|
22
|
+
detectFaces(imageData: string | Buffer): Promise<FaceDetectionResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Preprocess image for model input
|
|
25
|
+
*/
|
|
26
|
+
private preprocessImage;
|
|
27
|
+
/**
|
|
28
|
+
* Run model inference
|
|
29
|
+
*/
|
|
30
|
+
private runInference;
|
|
31
|
+
/**
|
|
32
|
+
* Post-process detection results
|
|
33
|
+
*/
|
|
34
|
+
private postprocessDetections;
|
|
35
|
+
/**
|
|
36
|
+
* Extract face feature vector
|
|
37
|
+
*/
|
|
38
|
+
private extractFeatureVector;
|
|
39
|
+
/**
|
|
40
|
+
* Check if image contains exactly one face
|
|
41
|
+
*/
|
|
42
|
+
validateSingleFace(imageData: string | Buffer): Promise<boolean>;
|
|
43
|
+
/**
|
|
44
|
+
* Get face bounding box from image
|
|
45
|
+
*/
|
|
46
|
+
getFaceBoundingBox(imageData: string | Buffer): Promise<BoundingBox | null>;
|
|
47
|
+
/**
|
|
48
|
+
* Clean up resources
|
|
49
|
+
*/
|
|
50
|
+
dispose(): void;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Calculate Euclidean distance between two face embeddings
|
|
54
|
+
*/
|
|
55
|
+
export declare function calculateFaceDistance(embedding1: number[], embedding2: number[]): number;
|
|
56
|
+
/**
|
|
57
|
+
* Calculate face similarity score (0-100)
|
|
58
|
+
*/
|
|
59
|
+
export declare function calculateFaceSimilarity(embedding1: number[], embedding2: number[]): number;
|