@hexar/biometric-identity-sdk-core 1.0.8 → 1.0.10

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.
@@ -8,6 +8,7 @@ exports.BiometricIdentitySDK = void 0;
8
8
  const types_1 = require("./types");
9
9
  const BackendClient_1 = require("./api/BackendClient");
10
10
  const i18n_1 = require("./i18n");
11
+ const logger_1 = require("./utils/logger");
11
12
  const API_ENDPOINT = 'https://biometry.hexar.com.ar';
12
13
  class BiometricIdentitySDK {
13
14
  constructor(config) {
@@ -43,7 +44,7 @@ class BiometricIdentitySDK {
43
44
  */
44
45
  static configure(apiKey, options) {
45
46
  if (BiometricIdentitySDK.instance) {
46
- console.warn('SDK already initialized');
47
+ logger_1.logger.warn('SDK already initialized');
47
48
  return;
48
49
  }
49
50
  const language = options?.language || 'en';
@@ -74,21 +75,17 @@ class BiometricIdentitySDK {
74
75
  */
75
76
  async initialize() {
76
77
  try {
77
- console.log('Initializing Biometric Identity SDK...');
78
78
  this.updateState({ isLoading: true, progress: 0 });
79
79
  // Check backend availability
80
- console.log('Checking backend availability...');
81
80
  this.isBackendAvailable = await this.backendClient.healthCheck();
82
81
  if (!this.isBackendAvailable) {
83
82
  throw this.createError(types_1.BiometricErrorCode.NETWORK_ERROR, 'Backend server is not available. Please check your API endpoint configuration and try again.');
84
83
  }
85
- console.log('✓ Backend is available - ready for validation');
86
84
  this.updateState({
87
85
  isLoading: false,
88
86
  progress: 0,
89
87
  currentStep: types_1.SDKStep.CAPTURE_FRONT_ID
90
88
  });
91
- console.log('SDK initialized successfully');
92
89
  }
93
90
  catch (error) {
94
91
  throw this.createError(types_1.BiometricErrorCode.MODEL_LOAD_FAILED, 'Failed to initialize SDK: Backend not available', error);
@@ -104,7 +101,6 @@ class BiometricIdentitySDK {
104
101
  }
105
102
  try {
106
103
  const challenge = await this.backendClient.generateChallenge(challengeType);
107
- console.log(`Generated challenge with ${challenge.challenges.length} actions`);
108
104
  return challenge;
109
105
  }
110
106
  catch (error) {
@@ -156,7 +152,6 @@ class BiometricIdentitySDK {
156
152
  isLoading: false,
157
153
  currentStep: types_1.SDKStep.CAPTURE_BACK_ID
158
154
  });
159
- console.log('Front ID uploaded successfully');
160
155
  }
161
156
  catch (error) {
162
157
  this.handleError(error);
@@ -177,7 +172,6 @@ class BiometricIdentitySDK {
177
172
  isLoading: false,
178
173
  currentStep: types_1.SDKStep.RECORD_LIVENESS
179
174
  });
180
- console.log('Back ID uploaded successfully');
181
175
  }
182
176
  catch (error) {
183
177
  this.handleError(error);
@@ -195,7 +189,6 @@ class BiometricIdentitySDK {
195
189
  progress: 75,
196
190
  isLoading: false,
197
191
  });
198
- console.log('Video recording stored successfully');
199
192
  }
200
193
  catch (error) {
201
194
  this.handleError(error);
@@ -221,7 +214,6 @@ class BiometricIdentitySDK {
221
214
  progress: 75,
222
215
  isLoading: false,
223
216
  });
224
- console.log('Video liveness recorded successfully');
225
217
  return videoResult;
226
218
  }
227
219
  catch (error) {
@@ -254,7 +246,6 @@ class BiometricIdentitySDK {
254
246
  isLoading: false,
255
247
  currentStep: types_1.SDKStep.RESULT
256
248
  });
257
- console.log('Validation completed successfully');
258
249
  return validationResult;
259
250
  }
260
251
  catch (error) {
@@ -269,13 +260,24 @@ class BiometricIdentitySDK {
269
260
  if (!this.state.frontID || !this.state.videoData) {
270
261
  throw new Error('Required data not available');
271
262
  }
272
- console.log('Validating with backend API...');
273
263
  this.updateState({ progress: 80 });
274
264
  try {
265
+ // Limit and sample video frames to prevent payload size issues
266
+ // Take max 30 frames, sampling evenly across the video
267
+ let videoFrames = this.state.videoData.frames;
268
+ if (videoFrames.length === 0) {
269
+ throw new Error('No video frames available for validation');
270
+ }
271
+ // Sample frames if we have too many (max 30 frames to keep payload reasonable)
272
+ const MAX_FRAMES = 30;
273
+ if (videoFrames.length > MAX_FRAMES) {
274
+ const step = Math.floor(videoFrames.length / MAX_FRAMES);
275
+ videoFrames = videoFrames.filter((_, index) => index % step === 0).slice(0, MAX_FRAMES);
276
+ }
275
277
  const response = await this.backendClient.fullValidation({
276
278
  frontIdImage: this.state.frontID.data,
277
279
  backIdImage: this.state.backID?.data,
278
- videoFrames: this.state.videoData.frames,
280
+ videoFrames: videoFrames,
279
281
  videoDurationMs: this.state.videoData.duration,
280
282
  challengesCompleted: this.state.videoData.challengesCompleted || [],
281
283
  });
@@ -387,7 +389,7 @@ class BiometricIdentitySDK {
387
389
  */
388
390
  dispose() {
389
391
  // No local resources to clean up
390
- console.log('SDK disposed');
392
+ logger_1.logger.info('SDK disposed');
391
393
  }
392
394
  }
393
395
  exports.BiometricIdentitySDK = BiometricIdentitySDK;
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.FaceDetector = void 0;
8
8
  exports.calculateFaceDistance = calculateFaceDistance;
9
9
  exports.calculateFaceSimilarity = calculateFaceSimilarity;
10
+ const logger_1 = require("../utils/logger");
10
11
  class FaceDetector {
11
12
  constructor(modelPath) {
12
13
  this.modelPath = modelPath;
@@ -21,11 +22,11 @@ class FaceDetector {
21
22
  try {
22
23
  // In a real implementation, this would load the actual ONNX model
23
24
  // For now, we'll create a mock implementation
24
- console.log('Loading face detection model...');
25
+ logger_1.logger.info('Loading face detection model...');
25
26
  // Simulate model loading
26
27
  await new Promise(resolve => setTimeout(resolve, 500));
27
28
  this.isModelLoaded = true;
28
- console.log('Face detection model loaded successfully');
29
+ logger_1.logger.info('Face detection model loaded successfully');
29
30
  }
30
31
  catch (error) {
31
32
  throw new Error(`Failed to load face detection model: ${error}`);
@@ -6,6 +6,7 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.LivenessDetector = void 0;
8
8
  const FaceDetector_1 = require("./FaceDetector");
9
+ const logger_1 = require("../utils/logger");
9
10
  class LivenessDetector {
10
11
  constructor(modelPath) {
11
12
  this.modelPath = modelPath;
@@ -19,13 +20,13 @@ class LivenessDetector {
19
20
  if (this.isModelLoaded)
20
21
  return;
21
22
  try {
22
- console.log('Loading liveness detection model...');
23
+ logger_1.logger.info('Loading liveness detection model...');
23
24
  // Load face detector
24
25
  await this.faceDetector.loadModel();
25
26
  // Simulate liveness model loading
26
27
  await new Promise(resolve => setTimeout(resolve, 500));
27
28
  this.isModelLoaded = true;
28
- console.log('Liveness detection model loaded successfully');
29
+ logger_1.logger.info('Liveness detection model loaded successfully');
29
30
  }
30
31
  catch (error) {
31
32
  throw new Error(`Failed to load liveness detection model: ${error}`);
@@ -101,7 +102,7 @@ class LivenessDetector {
101
102
  return hasMotion;
102
103
  }
103
104
  catch (error) {
104
- console.error('Motion check failed:', error);
105
+ logger_1.logger.error('Motion check failed:', error);
105
106
  return false;
106
107
  }
107
108
  }
@@ -5,6 +5,7 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.BackendClient = void 0;
8
+ const logger_1 = require("../utils/logger");
8
9
  /**
9
10
  * Client for communicating with the Biometric Identity Backend
10
11
  */
@@ -28,7 +29,7 @@ class BackendClient {
28
29
  return response.status === 'healthy';
29
30
  }
30
31
  catch (error) {
31
- console.warn('Backend health check failed:', error);
32
+ logger_1.logger.warn('Backend health check failed:', error);
32
33
  return false;
33
34
  }
34
35
  }
@@ -188,6 +189,10 @@ class BackendClient {
188
189
  });
189
190
  clearTimeout(timeoutId);
190
191
  if (!response.ok) {
192
+ // Handle 413 Payload Too Large specifically
193
+ if (response.status === 413) {
194
+ 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
+ }
191
196
  const errorData = await response.json().catch(() => ({}));
192
197
  throw new Error(errorData?.error?.message ||
193
198
  errorData?.detail ||
@@ -19,6 +19,7 @@ const en_1 = require("./languages/en");
19
19
  const es_1 = require("./languages/es");
20
20
  const es_AR_1 = require("./languages/es-AR");
21
21
  const pt_BR_1 = require("./languages/pt-BR");
22
+ const logger_1 = require("../utils/logger");
22
23
  const languages = {
23
24
  'en': en_1.en,
24
25
  'es': es_1.es,
@@ -31,7 +32,7 @@ const setLanguage = (lang) => {
31
32
  currentLanguage = lang;
32
33
  }
33
34
  else {
34
- console.warn(`Language ${lang} not supported, falling back to English`);
35
+ logger_1.logger.warn(`Language ${lang} not supported, falling back to English`);
35
36
  currentLanguage = 'en';
36
37
  }
37
38
  };
package/dist/index.d.ts CHANGED
@@ -17,4 +17,5 @@ export type { BackendValidationServiceConfig } from './services/BackendValidatio
17
17
  export type { IValidationService, LivenessChallenge, DocumentValidationResult, LivenessResult, FaceMatchResult, } from './services/IValidationService';
18
18
  export { getStrings, setLanguage, getCurrentLanguage } from './i18n';
19
19
  export type { SupportedLanguage, LanguageStrings } from './i18n';
20
+ export { logger } from './utils/logger';
20
21
  export declare const SDK_VERSION = "1.0.0";
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
21
21
  return (mod && mod.__esModule) ? mod : { "default": mod };
22
22
  };
23
23
  Object.defineProperty(exports, "__esModule", { value: true });
24
- exports.SDK_VERSION = exports.getCurrentLanguage = exports.setLanguage = exports.getStrings = exports.BackendValidationService = exports.BackendClient = exports.createIntegritySignature = exports.encryptImages = exports.EncryptionService = exports.isValidDate = exports.cleanText = exports.OCREngine = exports.meetsQualityStandards = exports.DocumentValidator = exports.LivenessDetector = exports.calculateFaceDistance = exports.calculateFaceSimilarity = exports.FaceDetector = exports.default = exports.BiometricIdentitySDK = void 0;
24
+ exports.SDK_VERSION = exports.logger = exports.getCurrentLanguage = exports.setLanguage = exports.getStrings = exports.BackendValidationService = exports.BackendClient = exports.createIntegritySignature = exports.encryptImages = exports.EncryptionService = exports.isValidDate = exports.cleanText = exports.OCREngine = exports.meetsQualityStandards = exports.DocumentValidator = exports.LivenessDetector = exports.calculateFaceDistance = exports.calculateFaceSimilarity = exports.FaceDetector = exports.default = exports.BiometricIdentitySDK = void 0;
25
25
  // Main SDK class
26
26
  var BiometricIdentitySDK_1 = require("./BiometricIdentitySDK");
27
27
  Object.defineProperty(exports, "BiometricIdentitySDK", { enumerable: true, get: function () { return BiometricIdentitySDK_1.BiometricIdentitySDK; } });
@@ -60,5 +60,8 @@ var i18n_1 = require("./i18n");
60
60
  Object.defineProperty(exports, "getStrings", { enumerable: true, get: function () { return i18n_1.getStrings; } });
61
61
  Object.defineProperty(exports, "setLanguage", { enumerable: true, get: function () { return i18n_1.setLanguage; } });
62
62
  Object.defineProperty(exports, "getCurrentLanguage", { enumerable: true, get: function () { return i18n_1.getCurrentLanguage; } });
63
+ // Logger
64
+ var logger_1 = require("./utils/logger");
65
+ Object.defineProperty(exports, "logger", { enumerable: true, get: function () { return logger_1.logger; } });
63
66
  // Version
64
67
  exports.SDK_VERSION = '1.0.0';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Professional logging utility for Hexar Biometry SDK
3
+ */
4
+ export declare const logger: {
5
+ info: (message: string, ...args: any[]) => void;
6
+ warn: (message: string, ...args: any[]) => void;
7
+ error: (message: string, ...args: any[]) => void;
8
+ };
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ /**
3
+ * Professional logging utility for Hexar Biometry SDK
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.logger = void 0;
7
+ const PREFIX = 'Hexar Biometry';
8
+ function formatTimestamp() {
9
+ const now = new Date();
10
+ const hours = now.getHours().toString().padStart(2, '0');
11
+ const minutes = now.getMinutes().toString().padStart(2, '0');
12
+ const seconds = now.getSeconds().toString().padStart(2, '0');
13
+ const milliseconds = now.getMilliseconds().toString().padStart(3, '0');
14
+ return `${hours}:${minutes}:${seconds}.${milliseconds}`;
15
+ }
16
+ function formatMessage(level, message, ...args) {
17
+ const timestamp = formatTimestamp();
18
+ const prefix = `${timestamp} [${PREFIX}]`;
19
+ if (args.length > 0) {
20
+ return `${prefix} ${message} ${args.map(arg => typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)).join(' ')}`;
21
+ }
22
+ return `${prefix} ${message}`;
23
+ }
24
+ exports.logger = {
25
+ info: (message, ...args) => {
26
+ console.log(formatMessage('info', message, ...args));
27
+ },
28
+ warn: (message, ...args) => {
29
+ console.warn(formatMessage('warn', message, ...args));
30
+ },
31
+ error: (message, ...args) => {
32
+ console.error(formatMessage('error', message, ...args));
33
+ },
34
+ };
@@ -5,6 +5,7 @@
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.DocumentValidator = void 0;
7
7
  exports.meetsQualityStandards = meetsQualityStandards;
8
+ const logger_1 = require("../utils/logger");
8
9
  class DocumentValidator {
9
10
  constructor(modelPath) {
10
11
  this.modelPath = modelPath;
@@ -17,11 +18,11 @@ class DocumentValidator {
17
18
  if (this.isModelLoaded)
18
19
  return;
19
20
  try {
20
- console.log('Loading document validation model...');
21
+ logger_1.logger.info('Loading document validation model...');
21
22
  // Simulate model loading
22
23
  await new Promise(resolve => setTimeout(resolve, 300));
23
24
  this.isModelLoaded = true;
24
- console.log('Document validation model loaded successfully');
25
+ logger_1.logger.info('Document validation model loaded successfully');
25
26
  }
26
27
  catch (error) {
27
28
  throw new Error(`Failed to load document validation model: ${error}`);
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.OCREngine = void 0;
7
7
  exports.cleanText = cleanText;
8
8
  exports.isValidDate = isValidDate;
9
+ const logger_1 = require("../utils/logger");
9
10
  class OCREngine {
10
11
  constructor() {
11
12
  this.isInitialized = false;
@@ -17,12 +18,12 @@ class OCREngine {
17
18
  if (this.isInitialized)
18
19
  return;
19
20
  try {
20
- console.log('Initializing OCR engine...');
21
+ logger_1.logger.info('Initializing OCR engine...');
21
22
  // In real implementation, would initialize Tesseract.js
22
23
  // await createWorker();
23
24
  await new Promise(resolve => setTimeout(resolve, 500));
24
25
  this.isInitialized = true;
25
- console.log('OCR engine initialized successfully');
26
+ logger_1.logger.info('OCR engine initialized successfully');
26
27
  }
27
28
  catch (error) {
28
29
  throw new Error(`Failed to initialize OCR engine: ${error}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hexar/biometric-identity-sdk-core",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "Core AI engine for biometric identity verification",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -15,6 +15,7 @@ import {
15
15
  } from './types';
16
16
  import { BackendClient, ChallengeResponse, ChallengeAction } from './api/BackendClient';
17
17
  import { setLanguage, SupportedLanguage } from './i18n';
18
+ import { logger } from './utils/logger';
18
19
 
19
20
  const API_ENDPOINT = 'https://biometry.hexar.com.ar';
20
21
 
@@ -61,7 +62,7 @@ export class BiometricIdentitySDK {
61
62
  */
62
63
  static configure(apiKey: string, options?: { language?: SupportedLanguage }): void {
63
64
  if (BiometricIdentitySDK.instance) {
64
- console.warn('SDK already initialized');
65
+ logger.warn('SDK already initialized');
65
66
  return;
66
67
  }
67
68
 
@@ -97,11 +98,9 @@ export class BiometricIdentitySDK {
97
98
  */
98
99
  async initialize(): Promise<void> {
99
100
  try {
100
- console.log('Initializing Biometric Identity SDK...');
101
101
  this.updateState({ isLoading: true, progress: 0 });
102
102
 
103
103
  // Check backend availability
104
- console.log('Checking backend availability...');
105
104
  this.isBackendAvailable = await this.backendClient.healthCheck();
106
105
 
107
106
  if (!this.isBackendAvailable) {
@@ -111,7 +110,6 @@ export class BiometricIdentitySDK {
111
110
  );
112
111
  }
113
112
 
114
- console.log('✓ Backend is available - ready for validation');
115
113
 
116
114
  this.updateState({
117
115
  isLoading: false,
@@ -119,7 +117,6 @@ export class BiometricIdentitySDK {
119
117
  currentStep: SDKStep.CAPTURE_FRONT_ID
120
118
  });
121
119
 
122
- console.log('SDK initialized successfully');
123
120
  } catch (error) {
124
121
  throw this.createError(
125
122
  BiometricErrorCode.MODEL_LOAD_FAILED,
@@ -145,7 +142,6 @@ export class BiometricIdentitySDK {
145
142
 
146
143
  try {
147
144
  const challenge = await this.backendClient.generateChallenge(challengeType);
148
- console.log(`Generated challenge with ${challenge.challenges.length} actions`);
149
145
  return challenge;
150
146
  } catch (error) {
151
147
  throw this.createError(
@@ -206,7 +202,6 @@ export class BiometricIdentitySDK {
206
202
  currentStep: SDKStep.CAPTURE_BACK_ID
207
203
  });
208
204
 
209
- console.log('Front ID uploaded successfully');
210
205
  } catch (error) {
211
206
  this.handleError(error);
212
207
  throw error;
@@ -230,7 +225,6 @@ export class BiometricIdentitySDK {
230
225
  currentStep: SDKStep.RECORD_LIVENESS
231
226
  });
232
227
 
233
- console.log('Back ID uploaded successfully');
234
228
  } catch (error) {
235
229
  this.handleError(error);
236
230
  throw error;
@@ -250,7 +244,6 @@ export class BiometricIdentitySDK {
250
244
  isLoading: false,
251
245
  });
252
246
 
253
- console.log('Video recording stored successfully');
254
247
  } catch (error) {
255
248
  this.handleError(error);
256
249
  throw error;
@@ -282,7 +275,6 @@ export class BiometricIdentitySDK {
282
275
  isLoading: false,
283
276
  });
284
277
 
285
- console.log('Video liveness recorded successfully');
286
278
  return videoResult;
287
279
  } catch (error) {
288
280
  this.handleError(error);
@@ -326,7 +318,6 @@ export class BiometricIdentitySDK {
326
318
  currentStep: SDKStep.RESULT
327
319
  });
328
320
 
329
- console.log('Validation completed successfully');
330
321
  return validationResult;
331
322
 
332
323
  } catch (error) {
@@ -343,14 +334,27 @@ export class BiometricIdentitySDK {
343
334
  throw new Error('Required data not available');
344
335
  }
345
336
 
346
- console.log('Validating with backend API...');
347
337
  this.updateState({ progress: 80 });
348
338
 
349
339
  try {
340
+ // Limit and sample video frames to prevent payload size issues
341
+ // Take max 30 frames, sampling evenly across the video
342
+ let videoFrames = this.state.videoData.frames;
343
+ if (videoFrames.length === 0) {
344
+ throw new Error('No video frames available for validation');
345
+ }
346
+
347
+ // Sample frames if we have too many (max 30 frames to keep payload reasonable)
348
+ const MAX_FRAMES = 30;
349
+ if (videoFrames.length > MAX_FRAMES) {
350
+ const step = Math.floor(videoFrames.length / MAX_FRAMES);
351
+ videoFrames = videoFrames.filter((_, index) => index % step === 0).slice(0, MAX_FRAMES);
352
+ }
353
+
350
354
  const response = await this.backendClient.fullValidation({
351
355
  frontIdImage: this.state.frontID.data,
352
356
  backIdImage: this.state.backID?.data,
353
- videoFrames: this.state.videoData.frames,
357
+ videoFrames: videoFrames,
354
358
  videoDurationMs: this.state.videoData.duration,
355
359
  challengesCompleted: this.state.videoData.challengesCompleted || [],
356
360
  });
@@ -486,7 +490,7 @@ export class BiometricIdentitySDK {
486
490
  */
487
491
  dispose(): void {
488
492
  // No local resources to clean up
489
- console.log('SDK disposed');
493
+ logger.info('SDK disposed');
490
494
  }
491
495
  }
492
496
 
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import { FaceEmbedding, BoundingBox } from '../types';
7
+ import { logger } from '../utils/logger';
7
8
 
8
9
  export interface FaceDetectionResult {
9
10
  faces: FaceEmbedding[];
@@ -25,13 +26,13 @@ export class FaceDetector {
25
26
  try {
26
27
  // In a real implementation, this would load the actual ONNX model
27
28
  // For now, we'll create a mock implementation
28
- console.log('Loading face detection model...');
29
+ logger.info('Loading face detection model...');
29
30
 
30
31
  // Simulate model loading
31
32
  await new Promise(resolve => setTimeout(resolve, 500));
32
33
 
33
34
  this.isModelLoaded = true;
34
- console.log('Face detection model loaded successfully');
35
+ logger.info('Face detection model loaded successfully');
35
36
  } catch (error) {
36
37
  throw new Error(`Failed to load face detection model: ${error}`);
37
38
  }
@@ -5,6 +5,7 @@
5
5
 
6
6
  import { LivenessValidationResult, VideoResult, LivenessInstruction } from '../types';
7
7
  import { FaceDetector } from './FaceDetector';
8
+ import { logger } from '../utils/logger';
8
9
 
9
10
  export interface LivenessFrame {
10
11
  imageData: string;
@@ -28,7 +29,7 @@ export class LivenessDetector {
28
29
  if (this.isModelLoaded) return;
29
30
 
30
31
  try {
31
- console.log('Loading liveness detection model...');
32
+ logger.info('Loading liveness detection model...');
32
33
 
33
34
  // Load face detector
34
35
  await this.faceDetector.loadModel();
@@ -37,7 +38,7 @@ export class LivenessDetector {
37
38
  await new Promise(resolve => setTimeout(resolve, 500));
38
39
 
39
40
  this.isModelLoaded = true;
40
- console.log('Liveness detection model loaded successfully');
41
+ logger.info('Liveness detection model loaded successfully');
41
42
  } catch (error) {
42
43
  throw new Error(`Failed to load liveness detection model: ${error}`);
43
44
  }
@@ -125,7 +126,7 @@ export class LivenessDetector {
125
126
 
126
127
  return hasMotion;
127
128
  } catch (error) {
128
- console.error('Motion check failed:', error);
129
+ logger.error('Motion check failed:', error);
129
130
  return false;
130
131
  }
131
132
  }
@@ -10,6 +10,7 @@ import {
10
10
  DocumentData,
11
11
  BiometricConfig
12
12
  } from '../types';
13
+ import { logger } from '../utils/logger';
13
14
 
14
15
  export interface ChallengeAction {
15
16
  action: string;
@@ -153,7 +154,7 @@ export class BackendClient {
153
154
  const response = await this.request<{ status: string }>('/api/v1/health', 'GET');
154
155
  return response.status === 'healthy';
155
156
  } catch (error) {
156
- console.warn('Backend health check failed:', error);
157
+ logger.warn('Backend health check failed:', error);
157
158
  return false;
158
159
  }
159
160
  }
@@ -381,6 +382,13 @@ export class BackendClient {
381
382
  clearTimeout(timeoutId);
382
383
 
383
384
  if (!response.ok) {
385
+ // Handle 413 Payload Too Large specifically
386
+ if (response.status === 413) {
387
+ throw new Error(
388
+ `Payload too large (413). The request body exceeds the server's size limit. Try reducing the number of video frames or image sizes.`
389
+ );
390
+ }
391
+
384
392
  const errorData = await response.json().catch(() => ({})) as Record<string, any>;
385
393
  throw new Error(
386
394
  errorData?.error?.message ||
package/src/i18n/index.ts CHANGED
@@ -3,6 +3,7 @@ import { en } from './languages/en';
3
3
  import { es } from './languages/es';
4
4
  import { esAR } from './languages/es-AR';
5
5
  import { ptBR } from './languages/pt-BR';
6
+ import { logger } from '../utils/logger';
6
7
 
7
8
  const languages: Record<SupportedLanguage, LanguageStrings> = {
8
9
  'en': en,
@@ -17,7 +18,7 @@ export const setLanguage = (lang: SupportedLanguage): void => {
17
18
  if (languages[lang]) {
18
19
  currentLanguage = lang;
19
20
  } else {
20
- console.warn(`Language ${lang} not supported, falling back to English`);
21
+ logger.warn(`Language ${lang} not supported, falling back to English`);
21
22
  currentLanguage = 'en';
22
23
  }
23
24
  };
package/src/index.ts CHANGED
@@ -48,6 +48,9 @@ export type {
48
48
  export { getStrings, setLanguage, getCurrentLanguage } from './i18n';
49
49
  export type { SupportedLanguage, LanguageStrings } from './i18n';
50
50
 
51
+ // Logger
52
+ export { logger } from './utils/logger';
53
+
51
54
  // Version
52
55
  export const SDK_VERSION = '1.0.0';
53
56
 
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Professional logging utility for Hexar Biometry SDK
3
+ */
4
+
5
+ const PREFIX = 'Hexar Biometry';
6
+
7
+ type LogLevel = 'info' | 'warn' | 'error';
8
+
9
+ function formatTimestamp(): string {
10
+ const now = new Date();
11
+ const hours = now.getHours().toString().padStart(2, '0');
12
+ const minutes = now.getMinutes().toString().padStart(2, '0');
13
+ const seconds = now.getSeconds().toString().padStart(2, '0');
14
+ const milliseconds = now.getMilliseconds().toString().padStart(3, '0');
15
+ return `${hours}:${minutes}:${seconds}.${milliseconds}`;
16
+ }
17
+
18
+ function formatMessage(level: LogLevel, message: string, ...args: any[]): string {
19
+ const timestamp = formatTimestamp();
20
+ const prefix = `${timestamp} [${PREFIX}]`;
21
+
22
+ if (args.length > 0) {
23
+ return `${prefix} ${message} ${args.map(arg =>
24
+ typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
25
+ ).join(' ')}`;
26
+ }
27
+
28
+ return `${prefix} ${message}`;
29
+ }
30
+
31
+ export const logger = {
32
+ info: (message: string, ...args: any[]) => {
33
+ console.log(formatMessage('info', message, ...args));
34
+ },
35
+
36
+ warn: (message: string, ...args: any[]) => {
37
+ console.warn(formatMessage('warn', message, ...args));
38
+ },
39
+
40
+ error: (message: string, ...args: any[]) => {
41
+ console.error(formatMessage('error', message, ...args));
42
+ },
43
+ };
44
+
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import { DocumentValidationResult, BoundingBox } from '../types';
6
+ import { logger } from '../utils/logger';
6
7
 
7
8
  export class DocumentValidator {
8
9
  private model: any;
@@ -17,13 +18,13 @@ export class DocumentValidator {
17
18
  if (this.isModelLoaded) return;
18
19
 
19
20
  try {
20
- console.log('Loading document validation model...');
21
+ logger.info('Loading document validation model...');
21
22
 
22
23
  // Simulate model loading
23
24
  await new Promise(resolve => setTimeout(resolve, 300));
24
25
 
25
26
  this.isModelLoaded = true;
26
- console.log('Document validation model loaded successfully');
27
+ logger.info('Document validation model loaded successfully');
27
28
  } catch (error) {
28
29
  throw new Error(`Failed to load document validation model: ${error}`);
29
30
  }
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import { DocumentData } from '../types';
6
+ import { logger } from '../utils/logger';
6
7
 
7
8
  export interface OCRResult {
8
9
  text: string;
@@ -28,7 +29,7 @@ export class OCREngine {
28
29
  if (this.isInitialized) return;
29
30
 
30
31
  try {
31
- console.log('Initializing OCR engine...');
32
+ logger.info('Initializing OCR engine...');
32
33
 
33
34
  // In real implementation, would initialize Tesseract.js
34
35
  // await createWorker();
@@ -36,7 +37,7 @@ export class OCREngine {
36
37
  await new Promise(resolve => setTimeout(resolve, 500));
37
38
 
38
39
  this.isInitialized = true;
39
- console.log('OCR engine initialized successfully');
40
+ logger.info('OCR engine initialized successfully');
40
41
  } catch (error) {
41
42
  throw new Error(`Failed to initialize OCR engine: ${error}`);
42
43
  }