@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.
Files changed (59) hide show
  1. package/dist/BiometricIdentitySDK.d.ts +111 -0
  2. package/dist/BiometricIdentitySDK.js +395 -0
  3. package/dist/ai-models/FaceDetector.d.ts +59 -0
  4. package/dist/ai-models/FaceDetector.js +167 -0
  5. package/dist/ai-models/LivenessDetector.d.ts +61 -0
  6. package/dist/ai-models/LivenessDetector.js +218 -0
  7. package/dist/api/BackendClient.d.ts +178 -0
  8. package/dist/api/BackendClient.js +199 -0
  9. package/dist/api/index.d.ts +5 -0
  10. package/dist/api/index.js +8 -0
  11. package/dist/encryption/index.d.ts +38 -0
  12. package/dist/encryption/index.js +99 -0
  13. package/dist/i18n/index.d.ts +6 -0
  14. package/dist/i18n/index.js +47 -0
  15. package/dist/i18n/languages/en.d.ts +2 -0
  16. package/dist/i18n/languages/en.js +112 -0
  17. package/dist/i18n/languages/es-AR.d.ts +2 -0
  18. package/dist/i18n/languages/es-AR.js +112 -0
  19. package/dist/i18n/languages/es.d.ts +2 -0
  20. package/dist/i18n/languages/es.js +112 -0
  21. package/dist/i18n/languages/pt-BR.d.ts +2 -0
  22. package/dist/i18n/languages/pt-BR.js +112 -0
  23. package/dist/i18n/types.d.ts +110 -0
  24. package/dist/i18n/types.js +2 -0
  25. package/dist/index.d.ts +20 -0
  26. package/dist/index.js +64 -0
  27. package/dist/services/BackendValidationService.d.ts +84 -0
  28. package/dist/services/BackendValidationService.js +174 -0
  29. package/dist/services/IValidationService.d.ts +132 -0
  30. package/dist/services/IValidationService.js +8 -0
  31. package/dist/services/index.d.ts +8 -0
  32. package/dist/services/index.js +10 -0
  33. package/dist/types/index.d.ts +288 -0
  34. package/dist/types/index.js +34 -0
  35. package/dist/validation/DocumentValidator.d.ts +84 -0
  36. package/dist/validation/DocumentValidator.js +295 -0
  37. package/dist/validation/OCREngine.d.ts +75 -0
  38. package/dist/validation/OCREngine.js +225 -0
  39. package/package.json +24 -0
  40. package/src/BiometricIdentitySDK.ts +493 -0
  41. package/src/ai-models/FaceDetector.ts +200 -0
  42. package/src/ai-models/LivenessDetector.ts +274 -0
  43. package/src/api/BackendClient.ts +395 -0
  44. package/src/api/index.ts +15 -0
  45. package/src/encryption/index.ts +108 -0
  46. package/src/i18n/index.ts +35 -0
  47. package/src/i18n/languages/en.ts +121 -0
  48. package/src/i18n/languages/es-AR.ts +121 -0
  49. package/src/i18n/languages/es.ts +121 -0
  50. package/src/i18n/languages/pt-BR.ts +121 -0
  51. package/src/i18n/types.ts +121 -0
  52. package/src/index.ts +54 -0
  53. package/src/services/BackendValidationService.ts +228 -0
  54. package/src/services/IValidationService.ts +158 -0
  55. package/src/services/index.ts +17 -0
  56. package/src/types/index.ts +380 -0
  57. package/src/validation/DocumentValidator.ts +353 -0
  58. package/src/validation/OCREngine.ts +265 -0
  59. package/tsconfig.json +20 -0
@@ -0,0 +1,380 @@
1
+ /**
2
+ * Core type definitions for Biometric Identity SDK
3
+ */
4
+
5
+ export interface ValidationResult {
6
+ /** Face match confidence score (0-100) */
7
+ matchScore: number;
8
+
9
+ /** Whether face from video matches face in document */
10
+ isValidFaceMatch: boolean;
11
+
12
+ /** Whether document passes authenticity checks */
13
+ isDocumentAuthentic: boolean;
14
+
15
+ /** Liveness detection confidence score (0-100) */
16
+ livenessScore: number;
17
+
18
+ /** Extracted data from document OCR */
19
+ extractedDocumentData: DocumentData;
20
+
21
+ /** List of warnings detected during validation */
22
+ warnings: string[];
23
+
24
+ /** Timestamp of validation */
25
+ timestamp: number;
26
+
27
+ /** Detailed breakdown of validation steps */
28
+ details?: ValidationDetails;
29
+ }
30
+
31
+ export interface DocumentData {
32
+ firstName: string;
33
+ lastName: string;
34
+ documentNumber: string;
35
+ dateOfBirth: string;
36
+ expirationDate: string;
37
+ nationality: string;
38
+ documentType?: string;
39
+ gender?: string;
40
+ address?: string;
41
+ issuingCountry?: string;
42
+ rawText?: string;
43
+ }
44
+
45
+ export interface ValidationDetails {
46
+ faceDetection: {
47
+ detected: boolean;
48
+ confidence: number;
49
+ boundingBox?: BoundingBox;
50
+ };
51
+ documentQuality: {
52
+ hasGlare: boolean;
53
+ hasBlur: boolean;
54
+ hasCropping: boolean;
55
+ hasReflections: boolean;
56
+ edgeDetectionScore: number;
57
+ };
58
+ tamperDetection: {
59
+ isTampered: boolean;
60
+ tamperScore: number;
61
+ suspiciousRegions: BoundingBox[];
62
+ };
63
+ hologramDetection?: {
64
+ detected: boolean;
65
+ confidence: number;
66
+ };
67
+ livenessChecks: {
68
+ passedMotionCheck: boolean;
69
+ passedTextureCheck: boolean;
70
+ passedDepthCheck: boolean;
71
+ };
72
+ }
73
+
74
+ export interface BoundingBox {
75
+ x: number;
76
+ y: number;
77
+ width: number;
78
+ height: number;
79
+ }
80
+
81
+ import { SupportedLanguage } from '../i18n';
82
+
83
+ export interface BiometricConfig {
84
+ apiEndpoint?: string;
85
+ apiKey?: string;
86
+ language?: SupportedLanguage;
87
+ enableBackendValidation?: boolean;
88
+ enableLocalStorage?: boolean;
89
+ encryptionKey?: string;
90
+ minMatchScore?: number;
91
+ minLivenessScore?: number;
92
+ validationTimeout?: number;
93
+ modelPaths?: {
94
+ faceDetection?: string;
95
+ faceRecognition?: string;
96
+ livenessDetection?: string;
97
+ };
98
+ }
99
+
100
+ export interface ThemeConfig {
101
+ /** Primary brand color */
102
+ primaryColor?: string;
103
+
104
+ /** Background color */
105
+ backgroundColor?: string;
106
+
107
+ /** Text color */
108
+ textColor?: string;
109
+
110
+ /** Secondary text color */
111
+ secondaryTextColor?: string;
112
+
113
+ /** Button border radius */
114
+ buttonRadius?: number;
115
+
116
+ /** Font family */
117
+ fontFamily?: string;
118
+
119
+ /** Custom logo */
120
+ logo?: string | any;
121
+
122
+ /** Success color */
123
+ successColor?: string;
124
+
125
+ /** Error color */
126
+ errorColor?: string;
127
+
128
+ /** Warning color */
129
+ warningColor?: string;
130
+ }
131
+
132
+ export interface VideoLivenessOptions {
133
+ /** Duration of video recording in milliseconds */
134
+ duration?: number;
135
+
136
+ /** Instructions for user to follow */
137
+ instructions?: LivenessInstruction[];
138
+
139
+ /** Frame rate for video capture */
140
+ frameRate?: number;
141
+
142
+ /** Quality of video (0-1) */
143
+ quality?: number;
144
+ }
145
+
146
+ export type LivenessInstruction =
147
+ | 'look_left'
148
+ | 'look_right'
149
+ | 'look_up'
150
+ | 'look_down'
151
+ | 'smile'
152
+ | 'blink'
153
+ | 'turn_head_left'
154
+ | 'turn_head_right';
155
+
156
+ export interface VideoResult {
157
+ /** Video frames as base64 encoded images */
158
+ frames: string[];
159
+
160
+ /** Duration of captured video */
161
+ duration: number;
162
+
163
+ /** Whether all instructions were followed */
164
+ instructionsFollowed: boolean;
165
+
166
+ /** Quality score of the video */
167
+ qualityScore: number;
168
+
169
+ /** List of completed challenge actions (for active liveness) */
170
+ challengesCompleted?: string[];
171
+
172
+ /** Session ID from backend challenge (if using backend) */
173
+ sessionId?: string;
174
+ }
175
+
176
+ export interface ImageData {
177
+ /** Base64 encoded image data */
178
+ data: string;
179
+
180
+ /** Image width */
181
+ width: number;
182
+
183
+ /** Image height */
184
+ height: number;
185
+
186
+ /** MIME type */
187
+ mimeType: string;
188
+
189
+ /** File size in bytes */
190
+ size: number;
191
+ }
192
+
193
+ export interface EncryptedData {
194
+ /** Encrypted data payload */
195
+ data: string;
196
+
197
+ /** Initialization vector */
198
+ iv: string;
199
+
200
+ /** Authentication tag */
201
+ tag?: string;
202
+
203
+ /** Encryption algorithm used */
204
+ algorithm: string;
205
+ }
206
+
207
+ export interface BiometricError extends Error {
208
+ code: BiometricErrorCode;
209
+ details?: any;
210
+ }
211
+
212
+ export enum BiometricErrorCode {
213
+ CAMERA_PERMISSION_DENIED = 'CAMERA_PERMISSION_DENIED',
214
+ CAMERA_NOT_AVAILABLE = 'CAMERA_NOT_AVAILABLE',
215
+ FACE_NOT_DETECTED = 'FACE_NOT_DETECTED',
216
+ MULTIPLE_FACES_DETECTED = 'MULTIPLE_FACES_DETECTED',
217
+ DOCUMENT_NOT_DETECTED = 'DOCUMENT_NOT_DETECTED',
218
+ POOR_IMAGE_QUALITY = 'POOR_IMAGE_QUALITY',
219
+ LIVENESS_CHECK_FAILED = 'LIVENESS_CHECK_FAILED',
220
+ FACE_MATCH_FAILED = 'FACE_MATCH_FAILED',
221
+ DOCUMENT_TAMPERED = 'DOCUMENT_TAMPERED',
222
+ OCR_FAILED = 'OCR_FAILED',
223
+ VALIDATION_TIMEOUT = 'VALIDATION_TIMEOUT',
224
+ NETWORK_ERROR = 'NETWORK_ERROR',
225
+ MODEL_LOAD_FAILED = 'MODEL_LOAD_FAILED',
226
+ ENCRYPTION_FAILED = 'ENCRYPTION_FAILED',
227
+ UNKNOWN_ERROR = 'UNKNOWN_ERROR',
228
+ }
229
+
230
+ export interface FaceEmbedding {
231
+ /** 512-dimensional face embedding vector */
232
+ vector: number[];
233
+
234
+ /** Confidence score of face detection */
235
+ confidence: number;
236
+
237
+ /** Bounding box of detected face */
238
+ boundingBox: BoundingBox;
239
+ }
240
+
241
+ export interface DocumentValidationResult {
242
+ /** Whether document is authentic */
243
+ isAuthentic: boolean;
244
+
245
+ /** Overall authenticity score (0-100) */
246
+ authenticityScore: number;
247
+
248
+ /** Quality assessment */
249
+ quality: {
250
+ hasGlare: boolean;
251
+ hasBlur: boolean;
252
+ hasCropping: boolean;
253
+ hasReflections: boolean;
254
+ edgeScore: number;
255
+ };
256
+
257
+ /** Tamper detection results */
258
+ tamper: {
259
+ detected: boolean;
260
+ score: number;
261
+ regions: BoundingBox[];
262
+ };
263
+
264
+ /** Hologram detection (if applicable) */
265
+ hologram?: {
266
+ detected: boolean;
267
+ confidence: number;
268
+ };
269
+ }
270
+
271
+ export interface LivenessValidationResult {
272
+ /** Whether liveness check passed */
273
+ isLive: boolean;
274
+
275
+ /** Overall liveness score (0-100) */
276
+ livenessScore: number;
277
+
278
+ /** Individual check results */
279
+ checks: {
280
+ motionCheck: boolean;
281
+ textureCheck: boolean;
282
+ depthCheck: boolean;
283
+ blinkCheck?: boolean;
284
+ };
285
+
286
+ /** Detected face in video */
287
+ faceEmbedding: FaceEmbedding;
288
+ }
289
+
290
+ export interface SDKState {
291
+ /** Current step in the flow */
292
+ currentStep: SDKStep;
293
+
294
+ /** Front ID image */
295
+ frontID?: ImageData;
296
+
297
+ /** Back ID image */
298
+ backID?: ImageData;
299
+
300
+ /** Video liveness data */
301
+ videoData?: VideoResult;
302
+
303
+ /** Validation result */
304
+ validationResult?: ValidationResult;
305
+
306
+ /** Error state */
307
+ error?: BiometricError;
308
+
309
+ /** Loading state */
310
+ isLoading: boolean;
311
+
312
+ /** Progress percentage (0-100) */
313
+ progress: number;
314
+ }
315
+
316
+ export enum SDKStep {
317
+ INIT = 'INIT',
318
+ CAPTURE_FRONT_ID = 'CAPTURE_FRONT_ID',
319
+ CAPTURE_BACK_ID = 'CAPTURE_BACK_ID',
320
+ RECORD_LIVENESS = 'RECORD_LIVENESS',
321
+ VALIDATING = 'VALIDATING',
322
+ RESULT = 'RESULT',
323
+ ERROR = 'ERROR',
324
+ }
325
+
326
+ export interface ModelConfig {
327
+ /** Model name */
328
+ name: string;
329
+
330
+ /** Model path or URL */
331
+ path: string;
332
+
333
+ /** Model version */
334
+ version: string;
335
+
336
+ /** Input shape */
337
+ inputShape: number[];
338
+
339
+ /** Output shape */
340
+ outputShape: number[];
341
+ }
342
+
343
+ export interface BackendValidationRequest {
344
+ /** Encrypted front ID image */
345
+ frontID: EncryptedData;
346
+
347
+ /** Encrypted back ID image */
348
+ backID: EncryptedData;
349
+
350
+ /** Encrypted video frames */
351
+ videoFrames: EncryptedData;
352
+
353
+ /** Local validation result */
354
+ localValidationResult: ValidationResult;
355
+
356
+ /** SDK version */
357
+ sdkVersion: string;
358
+
359
+ /** Timestamp */
360
+ timestamp: number;
361
+ }
362
+
363
+ export interface BackendValidationResponse {
364
+ /** Whether validation was approved */
365
+ approved: boolean;
366
+
367
+ /** Match score from backend */
368
+ matchScore: number;
369
+
370
+ /** Additional checks performed by backend */
371
+ additionalChecks?: Record<string, any>;
372
+
373
+ /** Backend validation timestamp */
374
+ timestamp: number;
375
+
376
+ /** Backend session ID */
377
+ sessionId: string;
378
+ }
379
+
380
+
@@ -0,0 +1,353 @@
1
+ /**
2
+ * Document Validation - Detect tampering, quality issues, and authenticity
3
+ */
4
+
5
+ import { DocumentValidationResult, BoundingBox } from '../types';
6
+
7
+ export class DocumentValidator {
8
+ private model: any;
9
+ private isModelLoaded: boolean = false;
10
+
11
+ constructor(private modelPath?: string) {}
12
+
13
+ /**
14
+ * Load document validation models
15
+ */
16
+ async loadModel(): Promise<void> {
17
+ if (this.isModelLoaded) return;
18
+
19
+ try {
20
+ console.log('Loading document validation model...');
21
+
22
+ // Simulate model loading
23
+ await new Promise(resolve => setTimeout(resolve, 300));
24
+
25
+ this.isModelLoaded = true;
26
+ console.log('Document validation model loaded successfully');
27
+ } catch (error) {
28
+ throw new Error(`Failed to load document validation model: ${error}`);
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Validate document authenticity and quality
34
+ */
35
+ async validateDocument(imageData: string | Buffer): Promise<DocumentValidationResult> {
36
+ if (!this.isModelLoaded) {
37
+ await this.loadModel();
38
+ }
39
+
40
+ try {
41
+ // Perform parallel quality checks
42
+ const [qualityResult, tamperResult, hologramResult] = await Promise.all([
43
+ this.checkQuality(imageData),
44
+ this.detectTampering(imageData),
45
+ this.detectHologram(imageData),
46
+ ]);
47
+
48
+ // Calculate overall authenticity score
49
+ const authenticityScore = this.calculateAuthenticityScore(
50
+ qualityResult,
51
+ tamperResult,
52
+ hologramResult
53
+ );
54
+
55
+ const isAuthentic = authenticityScore >= 70 && !tamperResult.detected;
56
+
57
+ return {
58
+ isAuthentic,
59
+ authenticityScore,
60
+ quality: qualityResult,
61
+ tamper: tamperResult,
62
+ hologram: hologramResult,
63
+ };
64
+ } catch (error) {
65
+ throw new Error(`Document validation failed: ${error}`);
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Check document image quality
71
+ */
72
+ private async checkQuality(imageData: string | Buffer): Promise<{
73
+ hasGlare: boolean;
74
+ hasBlur: boolean;
75
+ hasCropping: boolean;
76
+ hasReflections: boolean;
77
+ edgeScore: number;
78
+ }> {
79
+ // In real implementation:
80
+ // 1. Detect bright spots (glare)
81
+ // 2. Calculate blur metric (Laplacian variance)
82
+ // 3. Detect document edges and check if complete
83
+ // 4. Detect reflective areas
84
+
85
+ const hasGlare = await this.detectGlare(imageData);
86
+ const hasBlur = await this.detectBlur(imageData);
87
+ const hasCropping = await this.detectCropping(imageData);
88
+ const hasReflections = await this.detectReflections(imageData);
89
+ const edgeScore = await this.calculateEdgeScore(imageData);
90
+
91
+ return {
92
+ hasGlare,
93
+ hasBlur,
94
+ hasCropping,
95
+ hasReflections,
96
+ edgeScore,
97
+ };
98
+ }
99
+
100
+ /**
101
+ * Detect glare in document image
102
+ */
103
+ private async detectGlare(imageData: string | Buffer): Promise<boolean> {
104
+ // In real implementation:
105
+ // 1. Convert to grayscale
106
+ // 2. Find pixels above high threshold (> 240)
107
+ // 3. Calculate percentage of bright pixels
108
+ // 4. Check if bright regions form patches (glare patterns)
109
+
110
+ // Mock implementation
111
+ const randomScore = Math.random();
112
+ return randomScore < 0.15; // 15% chance of glare
113
+ }
114
+
115
+ /**
116
+ * Detect blur in document image
117
+ */
118
+ private async detectBlur(imageData: string | Buffer): Promise<boolean> {
119
+ // In real implementation:
120
+ // 1. Apply Laplacian operator
121
+ // 2. Calculate variance of Laplacian
122
+ // 3. Low variance indicates blur
123
+
124
+ // Mock implementation
125
+ const randomScore = Math.random();
126
+ return randomScore < 0.10; // 10% chance of blur
127
+ }
128
+
129
+ /**
130
+ * Detect if document is cropped
131
+ */
132
+ private async detectCropping(imageData: string | Buffer): Promise<boolean> {
133
+ // In real implementation:
134
+ // 1. Detect document edges using Canny edge detection
135
+ // 2. Find document contours
136
+ // 3. Check if all four corners are visible
137
+
138
+ // Mock implementation
139
+ const randomScore = Math.random();
140
+ return randomScore < 0.08; // 8% chance of cropping
141
+ }
142
+
143
+ /**
144
+ * Detect reflections on document
145
+ */
146
+ private async detectReflections(imageData: string | Buffer): Promise<boolean> {
147
+ // In real implementation:
148
+ // 1. Analyze specular highlights
149
+ // 2. Detect glossy surface patterns
150
+ // 3. Check for uneven lighting
151
+
152
+ // Mock implementation
153
+ const randomScore = Math.random();
154
+ return randomScore < 0.12; // 12% chance of reflections
155
+ }
156
+
157
+ /**
158
+ * Calculate edge detection score
159
+ */
160
+ private async calculateEdgeScore(imageData: string | Buffer): Promise<number> {
161
+ // In real implementation:
162
+ // 1. Apply Canny edge detection
163
+ // 2. Calculate edge pixel density
164
+ // 3. Normalize to 0-100 scale
165
+
166
+ // Mock implementation - random score between 70-98
167
+ return Math.round(70 + Math.random() * 28);
168
+ }
169
+
170
+ /**
171
+ * Detect document tampering
172
+ */
173
+ private async detectTampering(imageData: string | Buffer): Promise<{
174
+ detected: boolean;
175
+ score: number;
176
+ regions: BoundingBox[];
177
+ }> {
178
+ // In real implementation:
179
+ // 1. Error Level Analysis (ELA)
180
+ // 2. Clone detection
181
+ // 3. JPEG artifact analysis
182
+ // 4. Metadata analysis
183
+ // 5. Font consistency check
184
+ // 6. Color histogram analysis
185
+
186
+ const tamperScore = await this.calculateTamperScore(imageData);
187
+ const suspiciousRegions = await this.findSuspiciousRegions(imageData);
188
+
189
+ return {
190
+ detected: tamperScore > 60,
191
+ score: tamperScore,
192
+ regions: suspiciousRegions,
193
+ };
194
+ }
195
+
196
+ /**
197
+ * Calculate tampering score
198
+ */
199
+ private async calculateTamperScore(imageData: string | Buffer): Promise<number> {
200
+ // In real implementation:
201
+ // 1. Analyze compression artifacts
202
+ // 2. Check for inconsistent noise patterns
203
+ // 3. Detect copy-paste regions
204
+ // 4. Validate text rendering consistency
205
+
206
+ // Mock implementation - most documents are authentic
207
+ const randomScore = Math.random();
208
+ return randomScore < 0.95 ? Math.round(Math.random() * 30) : Math.round(60 + Math.random() * 40);
209
+ }
210
+
211
+ /**
212
+ * Find suspicious regions in document
213
+ */
214
+ private async findSuspiciousRegions(imageData: string | Buffer): Promise<BoundingBox[]> {
215
+ // In real implementation:
216
+ // 1. Apply ELA and find high-error regions
217
+ // 2. Detect cloned regions
218
+ // 3. Find inconsistent JPEG blocks
219
+
220
+ // Mock implementation - usually no suspicious regions
221
+ const randomScore = Math.random();
222
+ if (randomScore < 0.95) {
223
+ return [];
224
+ }
225
+
226
+ // Return 1-2 suspicious regions
227
+ return [
228
+ {
229
+ x: Math.round(Math.random() * 200),
230
+ y: Math.round(Math.random() * 100),
231
+ width: 50 + Math.round(Math.random() * 100),
232
+ height: 30 + Math.round(Math.random() * 50),
233
+ },
234
+ ];
235
+ }
236
+
237
+ /**
238
+ * Detect hologram on document
239
+ */
240
+ private async detectHologram(imageData: string | Buffer): Promise<{
241
+ detected: boolean;
242
+ confidence: number;
243
+ } | undefined> {
244
+ // In real implementation:
245
+ // 1. Detect rainbow color patterns
246
+ // 2. Analyze light reflection patterns
247
+ // 3. Check for 3D effects
248
+ // 4. Validate hologram location on document
249
+
250
+ // Mock implementation
251
+ const randomScore = Math.random();
252
+
253
+ if (randomScore > 0.3) {
254
+ return {
255
+ detected: true,
256
+ confidence: 75 + Math.round(Math.random() * 20),
257
+ };
258
+ }
259
+
260
+ return {
261
+ detected: false,
262
+ confidence: Math.round(Math.random() * 50),
263
+ };
264
+ }
265
+
266
+ /**
267
+ * Calculate overall authenticity score
268
+ */
269
+ private calculateAuthenticityScore(
270
+ quality: any,
271
+ tamper: any,
272
+ hologram: any
273
+ ): number {
274
+ let score = 100;
275
+
276
+ // Deduct points for quality issues
277
+ if (quality.hasGlare) score -= 15;
278
+ if (quality.hasBlur) score -= 20;
279
+ if (quality.hasCropping) score -= 25;
280
+ if (quality.hasReflections) score -= 10;
281
+
282
+ // Edge score impact
283
+ if (quality.edgeScore < 70) score -= 15;
284
+ else if (quality.edgeScore < 80) score -= 10;
285
+
286
+ // Tampering severely impacts score
287
+ if (tamper.detected) {
288
+ score -= 40;
289
+ } else {
290
+ score -= Math.round(tamper.score * 0.3);
291
+ }
292
+
293
+ // Hologram bonus (if detected and confident)
294
+ if (hologram?.detected && hologram.confidence > 70) {
295
+ score = Math.min(100, score + 5);
296
+ }
297
+
298
+ return Math.max(0, Math.round(score));
299
+ }
300
+
301
+ /**
302
+ * Detect document type (passport, ID card, driver's license, etc.)
303
+ */
304
+ async detectDocumentType(imageData: string | Buffer): Promise<string> {
305
+ // In real implementation:
306
+ // 1. Use template matching
307
+ // 2. Detect document layout patterns
308
+ // 3. OCR specific regions to identify type
309
+
310
+ // Mock implementation
311
+ const types = ['passport', 'national_id', 'drivers_license'];
312
+ return types[Math.floor(Math.random() * types.length)];
313
+ }
314
+
315
+ /**
316
+ * Validate document expiration
317
+ */
318
+ validateExpiration(expirationDate: string): boolean {
319
+ try {
320
+ const expiry = new Date(expirationDate);
321
+ const now = new Date();
322
+ return expiry > now;
323
+ } catch {
324
+ return false;
325
+ }
326
+ }
327
+
328
+ /**
329
+ * Clean up resources
330
+ */
331
+ dispose(): void {
332
+ this.model = null;
333
+ this.isModelLoaded = false;
334
+ }
335
+ }
336
+
337
+ /**
338
+ * Validate document meets minimum quality standards
339
+ */
340
+ export function meetsQualityStandards(quality: {
341
+ hasGlare: boolean;
342
+ hasBlur: boolean;
343
+ hasCropping: boolean;
344
+ hasReflections: boolean;
345
+ edgeScore: number;
346
+ }): boolean {
347
+ if (quality.hasBlur || quality.hasCropping) return false;
348
+ if (quality.hasGlare && quality.hasReflections) return false;
349
+ if (quality.edgeScore < 60) return false;
350
+ return true;
351
+ }
352
+
353
+