@hexar/biometric-identity-sdk-core 1.0.8 → 1.0.9
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 +16 -14
- package/dist/api/BackendClient.js +6 -1
- package/dist/i18n/index.js +2 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -1
- package/dist/utils/logger.d.ts +8 -0
- package/dist/utils/logger.js +34 -0
- package/package.json +1 -1
- package/src/BiometricIdentitySDK.ts +18 -14
- package/src/api/BackendClient.ts +9 -1
- package/src/i18n/index.ts +2 -1
- package/src/index.ts +3 -0
- package/src/utils/logger.ts +44 -0
|
@@ -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
|
-
|
|
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:
|
|
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
|
-
|
|
392
|
+
logger_1.logger.info('SDK disposed');
|
|
391
393
|
}
|
|
392
394
|
}
|
|
393
395
|
exports.BiometricIdentitySDK = BiometricIdentitySDK;
|
|
@@ -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
|
-
|
|
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 ||
|
package/dist/i18n/index.js
CHANGED
|
@@ -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
|
-
|
|
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,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
|
+
};
|
package/package.json
CHANGED
|
@@ -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
|
-
|
|
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:
|
|
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
|
-
|
|
493
|
+
logger.info('SDK disposed');
|
|
490
494
|
}
|
|
491
495
|
}
|
|
492
496
|
|
package/src/api/BackendClient.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
+
|