@hexar/biometric-identity-sdk-core 1.0.12 → 1.0.14
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.js +19 -3
- package/dist/api/BackendClient.js +67 -8
- package/package.json +1 -1
- package/src/BiometricIdentitySDK.ts +23 -5
- package/src/api/BackendClient.ts +85 -20
|
@@ -311,7 +311,9 @@ class BiometricIdentitySDK {
|
|
|
311
311
|
logger_1.logger.info('Sending validation request to backend', {
|
|
312
312
|
framesCount: videoFrames.length,
|
|
313
313
|
duration: this.state.videoData.duration,
|
|
314
|
-
challengesCount: this.state.videoData.challengesCompleted?.length || 0
|
|
314
|
+
challengesCount: this.state.videoData.challengesCompleted?.length || 0,
|
|
315
|
+
frontImageSize: this.state.frontID.data?.length || 0,
|
|
316
|
+
backImageSize: this.state.backID?.data?.length || 0
|
|
315
317
|
});
|
|
316
318
|
const response = await this.backendClient.fullValidation({
|
|
317
319
|
frontIdImage: this.state.frontID.data,
|
|
@@ -324,8 +326,22 @@ class BiometricIdentitySDK {
|
|
|
324
326
|
return this.backendClient.convertToValidationResult(response);
|
|
325
327
|
}
|
|
326
328
|
catch (error) {
|
|
327
|
-
logger_1.logger.error('Backend validation failed',
|
|
328
|
-
|
|
329
|
+
logger_1.logger.error('Backend validation failed', {
|
|
330
|
+
errorMessage: error?.message,
|
|
331
|
+
errorName: error?.name,
|
|
332
|
+
status: error?.status,
|
|
333
|
+
statusText: error?.statusText,
|
|
334
|
+
errorData: error?.errorData,
|
|
335
|
+
errorStack: error?.stack?.substring(0, 500)
|
|
336
|
+
});
|
|
337
|
+
const errorMessage = error?.message ||
|
|
338
|
+
(error?.status ? `Backend request failed with status ${error.status}` : 'Backend validation failed');
|
|
339
|
+
throw this.createError(types_1.BiometricErrorCode.NETWORK_ERROR, errorMessage, {
|
|
340
|
+
status: error?.status,
|
|
341
|
+
statusText: error?.statusText,
|
|
342
|
+
errorData: error?.errorData,
|
|
343
|
+
originalError: error?.message
|
|
344
|
+
});
|
|
329
345
|
}
|
|
330
346
|
}
|
|
331
347
|
/**
|
|
@@ -88,10 +88,10 @@ class BackendClient {
|
|
|
88
88
|
*/
|
|
89
89
|
async fullValidation(params) {
|
|
90
90
|
if (!this.currentSessionId) {
|
|
91
|
-
|
|
91
|
+
logger_1.logger.info('No session ID, generating challenge');
|
|
92
92
|
await this.generateChallenge();
|
|
93
93
|
}
|
|
94
|
-
|
|
94
|
+
const requestBody = {
|
|
95
95
|
front_id_image: params.frontIdImage,
|
|
96
96
|
back_id_image: params.backIdImage,
|
|
97
97
|
video_frames: params.videoFrames,
|
|
@@ -101,7 +101,20 @@ class BackendClient {
|
|
|
101
101
|
document_type: params.documentType,
|
|
102
102
|
country_code: params.countryCode,
|
|
103
103
|
device_info: params.deviceInfo,
|
|
104
|
+
};
|
|
105
|
+
logger_1.logger.info('Full validation request', {
|
|
106
|
+
hasSessionId: !!this.currentSessionId,
|
|
107
|
+
sessionId: this.currentSessionId,
|
|
108
|
+
videoFramesCount: params.videoFrames.length,
|
|
109
|
+
hasFrontImage: !!params.frontIdImage,
|
|
110
|
+
hasBackImage: !!params.backIdImage,
|
|
111
|
+
frontImageLength: params.frontIdImage?.length || 0,
|
|
112
|
+
backImageLength: params.backIdImage?.length || 0,
|
|
113
|
+
averageFrameLength: params.videoFrames.length > 0
|
|
114
|
+
? Math.round(params.videoFrames.reduce((sum, f) => sum + f.length, 0) / params.videoFrames.length)
|
|
115
|
+
: 0
|
|
104
116
|
});
|
|
117
|
+
return this.request('/api/v1/validate', 'POST', requestBody);
|
|
105
118
|
}
|
|
106
119
|
/**
|
|
107
120
|
* Convert backend response to SDK ValidationResult format
|
|
@@ -171,6 +184,12 @@ class BackendClient {
|
|
|
171
184
|
*/
|
|
172
185
|
async request(endpoint, method, body) {
|
|
173
186
|
const url = `${this.config.apiEndpoint}${endpoint}`;
|
|
187
|
+
logger_1.logger.info('Making backend request', {
|
|
188
|
+
url,
|
|
189
|
+
method,
|
|
190
|
+
hasBody: !!body,
|
|
191
|
+
bodySize: body ? JSON.stringify(body).length : 0
|
|
192
|
+
});
|
|
174
193
|
const controller = new AbortController();
|
|
175
194
|
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
176
195
|
const headers = {
|
|
@@ -187,25 +206,65 @@ class BackendClient {
|
|
|
187
206
|
body: body ? JSON.stringify(body) : undefined,
|
|
188
207
|
signal: controller.signal,
|
|
189
208
|
});
|
|
209
|
+
logger_1.logger.info('Backend response received', {
|
|
210
|
+
url,
|
|
211
|
+
status: response.status,
|
|
212
|
+
statusText: response.statusText,
|
|
213
|
+
ok: response.ok
|
|
214
|
+
});
|
|
190
215
|
clearTimeout(timeoutId);
|
|
191
216
|
if (!response.ok) {
|
|
192
|
-
|
|
217
|
+
let errorText = '';
|
|
218
|
+
let errorData = {};
|
|
219
|
+
try {
|
|
220
|
+
errorText = await response.text();
|
|
221
|
+
if (errorText) {
|
|
222
|
+
try {
|
|
223
|
+
errorData = JSON.parse(errorText);
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
errorData = { raw: errorText };
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
catch (parseError) {
|
|
231
|
+
logger_1.logger.warn('Could not parse error response', parseError);
|
|
232
|
+
}
|
|
233
|
+
const errorMessage = errorData?.error?.message ||
|
|
234
|
+
errorData?.detail ||
|
|
235
|
+
errorData?.message ||
|
|
236
|
+
errorData?.raw ||
|
|
237
|
+
`Request failed with status ${response.status}: ${response.statusText}`;
|
|
238
|
+
logger_1.logger.error('Backend request failed', {
|
|
239
|
+
url,
|
|
240
|
+
method,
|
|
241
|
+
status: response.status,
|
|
242
|
+
statusText: response.statusText,
|
|
243
|
+
errorText: errorText.substring(0, 500),
|
|
244
|
+
errorData: JSON.stringify(errorData).substring(0, 500)
|
|
245
|
+
});
|
|
246
|
+
const error = new Error(errorMessage);
|
|
247
|
+
error.status = response.status;
|
|
248
|
+
error.statusText = response.statusText;
|
|
249
|
+
error.errorData = errorData;
|
|
193
250
|
if (response.status === 413) {
|
|
194
251
|
throw new Error(`Payload too large (413). The request body exceeds the server's size limit. Try reducing the number of video frames or image sizes.`);
|
|
195
252
|
}
|
|
196
|
-
|
|
197
|
-
throw new Error(errorData?.error?.message ||
|
|
198
|
-
errorData?.detail ||
|
|
199
|
-
`Request failed with status ${response.status}`);
|
|
253
|
+
throw error;
|
|
200
254
|
}
|
|
201
255
|
return await response.json();
|
|
202
256
|
}
|
|
203
257
|
catch (error) {
|
|
204
258
|
clearTimeout(timeoutId);
|
|
205
259
|
if (error.name === 'AbortError') {
|
|
260
|
+
logger_1.logger.error('Request timeout', { url, method, timeout: this.config.timeout });
|
|
206
261
|
throw new Error('Request timeout');
|
|
207
262
|
}
|
|
208
|
-
|
|
263
|
+
if (error.message) {
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
266
|
+
logger_1.logger.error('Unexpected request error', { url, method, error });
|
|
267
|
+
throw new Error('Network request failed');
|
|
209
268
|
}
|
|
210
269
|
}
|
|
211
270
|
}
|
package/package.json
CHANGED
|
@@ -394,7 +394,9 @@ export class BiometricIdentitySDK {
|
|
|
394
394
|
logger.info('Sending validation request to backend', {
|
|
395
395
|
framesCount: videoFrames.length,
|
|
396
396
|
duration: this.state.videoData.duration,
|
|
397
|
-
challengesCount: this.state.videoData.challengesCompleted?.length || 0
|
|
397
|
+
challengesCount: this.state.videoData.challengesCompleted?.length || 0,
|
|
398
|
+
frontImageSize: this.state.frontID.data?.length || 0,
|
|
399
|
+
backImageSize: this.state.backID?.data?.length || 0
|
|
398
400
|
});
|
|
399
401
|
|
|
400
402
|
const response = await this.backendClient.fullValidation({
|
|
@@ -408,12 +410,28 @@ export class BiometricIdentitySDK {
|
|
|
408
410
|
this.updateState({ progress: 95 });
|
|
409
411
|
|
|
410
412
|
return this.backendClient.convertToValidationResult(response);
|
|
411
|
-
} catch (error) {
|
|
412
|
-
logger.error('Backend validation failed',
|
|
413
|
+
} catch (error: any) {
|
|
414
|
+
logger.error('Backend validation failed', {
|
|
415
|
+
errorMessage: error?.message,
|
|
416
|
+
errorName: error?.name,
|
|
417
|
+
status: error?.status,
|
|
418
|
+
statusText: error?.statusText,
|
|
419
|
+
errorData: error?.errorData,
|
|
420
|
+
errorStack: error?.stack?.substring(0, 500)
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
const errorMessage = error?.message ||
|
|
424
|
+
(error?.status ? `Backend request failed with status ${error.status}` : 'Backend validation failed');
|
|
425
|
+
|
|
413
426
|
throw this.createError(
|
|
414
427
|
BiometricErrorCode.NETWORK_ERROR,
|
|
415
|
-
|
|
416
|
-
|
|
428
|
+
errorMessage,
|
|
429
|
+
{
|
|
430
|
+
status: error?.status,
|
|
431
|
+
statusText: error?.statusText,
|
|
432
|
+
errorData: error?.errorData,
|
|
433
|
+
originalError: error?.message
|
|
434
|
+
}
|
|
417
435
|
);
|
|
418
436
|
}
|
|
419
437
|
}
|
package/src/api/BackendClient.ts
CHANGED
|
@@ -261,24 +261,39 @@ export class BackendClient {
|
|
|
261
261
|
deviceInfo?: Record<string, any>;
|
|
262
262
|
}): Promise<FullValidationResponse> {
|
|
263
263
|
if (!this.currentSessionId) {
|
|
264
|
-
|
|
264
|
+
logger.info('No session ID, generating challenge');
|
|
265
265
|
await this.generateChallenge();
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
+
const requestBody = {
|
|
269
|
+
front_id_image: params.frontIdImage,
|
|
270
|
+
back_id_image: params.backIdImage,
|
|
271
|
+
video_frames: params.videoFrames,
|
|
272
|
+
video_duration_ms: params.videoDurationMs,
|
|
273
|
+
session_id: this.currentSessionId,
|
|
274
|
+
challenges_completed: params.challengesCompleted || [],
|
|
275
|
+
document_type: params.documentType,
|
|
276
|
+
country_code: params.countryCode,
|
|
277
|
+
device_info: params.deviceInfo,
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
logger.info('Full validation request', {
|
|
281
|
+
hasSessionId: !!this.currentSessionId,
|
|
282
|
+
sessionId: this.currentSessionId,
|
|
283
|
+
videoFramesCount: params.videoFrames.length,
|
|
284
|
+
hasFrontImage: !!params.frontIdImage,
|
|
285
|
+
hasBackImage: !!params.backIdImage,
|
|
286
|
+
frontImageLength: params.frontIdImage?.length || 0,
|
|
287
|
+
backImageLength: params.backIdImage?.length || 0,
|
|
288
|
+
averageFrameLength: params.videoFrames.length > 0
|
|
289
|
+
? Math.round(params.videoFrames.reduce((sum, f) => sum + f.length, 0) / params.videoFrames.length)
|
|
290
|
+
: 0
|
|
291
|
+
});
|
|
292
|
+
|
|
268
293
|
return this.request<FullValidationResponse>(
|
|
269
294
|
'/api/v1/validate',
|
|
270
295
|
'POST',
|
|
271
|
-
|
|
272
|
-
front_id_image: params.frontIdImage,
|
|
273
|
-
back_id_image: params.backIdImage,
|
|
274
|
-
video_frames: params.videoFrames,
|
|
275
|
-
video_duration_ms: params.videoDurationMs,
|
|
276
|
-
session_id: this.currentSessionId,
|
|
277
|
-
challenges_completed: params.challengesCompleted || [],
|
|
278
|
-
document_type: params.documentType,
|
|
279
|
-
country_code: params.countryCode,
|
|
280
|
-
device_info: params.deviceInfo,
|
|
281
|
-
}
|
|
296
|
+
requestBody
|
|
282
297
|
);
|
|
283
298
|
}
|
|
284
299
|
|
|
@@ -359,6 +374,13 @@ export class BackendClient {
|
|
|
359
374
|
): Promise<T> {
|
|
360
375
|
const url = `${this.config.apiEndpoint}${endpoint}`;
|
|
361
376
|
|
|
377
|
+
logger.info('Making backend request', {
|
|
378
|
+
url,
|
|
379
|
+
method,
|
|
380
|
+
hasBody: !!body,
|
|
381
|
+
bodySize: body ? JSON.stringify(body).length : 0
|
|
382
|
+
});
|
|
383
|
+
|
|
362
384
|
const controller = new AbortController();
|
|
363
385
|
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
364
386
|
|
|
@@ -378,23 +400,60 @@ export class BackendClient {
|
|
|
378
400
|
body: body ? JSON.stringify(body) : undefined,
|
|
379
401
|
signal: controller.signal as RequestInit['signal'],
|
|
380
402
|
});
|
|
403
|
+
|
|
404
|
+
logger.info('Backend response received', {
|
|
405
|
+
url,
|
|
406
|
+
status: response.status,
|
|
407
|
+
statusText: response.statusText,
|
|
408
|
+
ok: response.ok
|
|
409
|
+
});
|
|
381
410
|
|
|
382
411
|
clearTimeout(timeoutId);
|
|
383
412
|
|
|
384
413
|
if (!response.ok) {
|
|
385
|
-
|
|
414
|
+
let errorText = '';
|
|
415
|
+
let errorData: Record<string, any> = {};
|
|
416
|
+
|
|
417
|
+
try {
|
|
418
|
+
errorText = await response.text();
|
|
419
|
+
if (errorText) {
|
|
420
|
+
try {
|
|
421
|
+
errorData = JSON.parse(errorText);
|
|
422
|
+
} catch {
|
|
423
|
+
errorData = { raw: errorText };
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
} catch (parseError) {
|
|
427
|
+
logger.warn('Could not parse error response', parseError);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
const errorMessage = errorData?.error?.message ||
|
|
431
|
+
errorData?.detail ||
|
|
432
|
+
errorData?.message ||
|
|
433
|
+
errorData?.raw ||
|
|
434
|
+
`Request failed with status ${response.status}: ${response.statusText}`;
|
|
435
|
+
|
|
436
|
+
logger.error('Backend request failed', {
|
|
437
|
+
url,
|
|
438
|
+
method,
|
|
439
|
+
status: response.status,
|
|
440
|
+
statusText: response.statusText,
|
|
441
|
+
errorText: errorText.substring(0, 500),
|
|
442
|
+
errorData: JSON.stringify(errorData).substring(0, 500)
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
const error = new Error(errorMessage);
|
|
446
|
+
(error as any).status = response.status;
|
|
447
|
+
(error as any).statusText = response.statusText;
|
|
448
|
+
(error as any).errorData = errorData;
|
|
449
|
+
|
|
386
450
|
if (response.status === 413) {
|
|
387
451
|
throw new Error(
|
|
388
452
|
`Payload too large (413). The request body exceeds the server's size limit. Try reducing the number of video frames or image sizes.`
|
|
389
453
|
);
|
|
390
454
|
}
|
|
391
455
|
|
|
392
|
-
|
|
393
|
-
throw new Error(
|
|
394
|
-
errorData?.error?.message ||
|
|
395
|
-
errorData?.detail ||
|
|
396
|
-
`Request failed with status ${response.status}`
|
|
397
|
-
);
|
|
456
|
+
throw error;
|
|
398
457
|
}
|
|
399
458
|
|
|
400
459
|
return await response.json() as T;
|
|
@@ -402,10 +461,16 @@ export class BackendClient {
|
|
|
402
461
|
clearTimeout(timeoutId);
|
|
403
462
|
|
|
404
463
|
if (error.name === 'AbortError') {
|
|
464
|
+
logger.error('Request timeout', { url, method, timeout: this.config.timeout });
|
|
405
465
|
throw new Error('Request timeout');
|
|
406
466
|
}
|
|
407
467
|
|
|
408
|
-
|
|
468
|
+
if (error.message) {
|
|
469
|
+
throw error;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
logger.error('Unexpected request error', { url, method, error });
|
|
473
|
+
throw new Error('Network request failed');
|
|
409
474
|
}
|
|
410
475
|
}
|
|
411
476
|
}
|