@richard.fadiora/liveness-detection 5.0.3 → 5.1.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.
@@ -1,8 +1,8 @@
1
- # Liveness Detection SDK v5.0.2
1
+ # Liveness Detection SDK v5.1.0
2
2
 
3
- A high-security, cross-framework **Liveness Detection SDK** designed for financial services. v5.0.2 introduces **Temporal Identity Locking** to prevent identity switching during the verification process.
3
+ A high-security, cross-framework **Liveness Detection SDK** designed for financial services. v5.1.0 introduces **Temporal Identity Locking** to prevent identity switching during the verification process.
4
4
 
5
- ## 🔒 New Security Protocols (v5.0.2)
5
+ ## 🔒 New Security Protocols (v5.1.0)
6
6
 
7
7
  This version introduces a "Zero-Trust" frontend architecture:
8
8
 
@@ -118,7 +118,7 @@ TypeScript
118
118
 
119
119
  * * *
120
120
 
121
- ## 🚨 Updated Error Reference (v4.4.0)
121
+ ## 🚨 Updated Error Reference (v5.1.0)
122
122
 
123
123
  The following codes are now emitted by the frontend engine **instantly**, without hitting the backend:
124
124
 
@@ -129,6 +129,20 @@ The following codes are now emitted by the frontend engine **instantly**, withou
129
129
  | Security violation: Identity mismatch. | Biometric ratios shifted significantly mid-session. | Prevents mid-stream person-swapping. |
130
130
  | Another session is active. | User has the verification open in another tab. | Prevents multi-device brute forcing. |
131
131
 
132
+ * * *
133
+ ### ⚠️ Security Warnings & Temporary Interruption
134
+
135
+ Version 5.0.2 implements a non-fatal warning system for non-critical security events (e.g., fleeting obscuration).
136
+
137
+ * **Temporary Interruption**: If a security violation occurs (e.g., face obscured), the `LivenessEngine` will pause detection for **2 seconds** to allow the user to adjust their position.
138
+
139
+ * **Warning Counter**: The engine tracks these events using `warningCount`. If the violations exceed `MAX_WARNINGS` (default: 3), the session will trigger a `failInstantly` event.
140
+
141
+ * **State Feedback**: During the 2-second pause, the `errorMsg` property in `LivenessState` will be populated with a temporary notification (e.g., _"Please ensure both ears are fully visible. (Warning 1/3)"_).
142
+
143
+
144
+ **Best Practice:** Always subscribe to `onStateChange` in your UI layer to ensure your user-facing components react to the `errorMsg` text.
145
+
132
146
  * * *
133
147
 
134
148
  ## 🏗️ Architectural Flow
@@ -148,7 +162,7 @@ These images are cropped to **224x224px** focusing on the face, making them opti
148
162
 
149
163
  * * *
150
164
 
151
- ## 🔧 Integration Notes for v5.0.2
165
+ ## 🔧 Integration Notes for v5.1.0
152
166
 
153
167
  * **WASM Path**: Ensure your server allows cross-origin requests for the MediaPipe `.wasm` files hosted on JSDelivr.
154
168
 
@@ -16,6 +16,10 @@ class LivenessEngine {
16
16
  timerId = null;
17
17
  requestId = null;
18
18
  heartbeatId = null;
19
+ warningCount = 0;
20
+ MAX_WARNINGS = 3;
21
+ lastWarningMsg = "";
22
+ isDetectionPaused = false;
19
23
  // --- NEW SECURITY TRACKERS ---
20
24
  anchorRatios = null;
21
25
  lastNosePos = null;
@@ -88,6 +92,7 @@ class LivenessEngine {
88
92
  * Phase 2: Attach Video (Call this once the Webcam is in the DOM)
89
93
  */
90
94
  attachVideo = (video) => {
95
+ video.setAttribute('crossorigin', 'anonymous');
91
96
  this.webcam = video;
92
97
  console.log("[LivenessEngine] Video stream attached.");
93
98
  };
@@ -102,19 +107,40 @@ class LivenessEngine {
102
107
  return true;
103
108
  }
104
109
  const diff = Math.abs(this.anchorRatios - currentRatio) / this.anchorRatios;
105
- return diff < 0.50; // 50% tolerance for head tilt
110
+ return diff < 0.70; // 70% tolerance for head tilt
106
111
  }
107
112
  checkMovement(landmarks) {
108
113
  const nose = { x: landmarks[1].x, y: landmarks[1].y };
109
114
  if (this.lastNosePos) {
110
115
  const dist = Math.sqrt(Math.pow(nose.x - this.lastNosePos.x, 2) +
111
116
  Math.pow(nose.y - this.lastNosePos.y, 2));
112
- if (dist > 0.3)
117
+ if (dist > 0.5)
113
118
  return false; // Sudden teleportation
114
119
  }
115
120
  this.lastNosePos = nose;
116
121
  return true;
117
122
  }
123
+ handleViolation(reason) {
124
+ this.warningCount++;
125
+ if (this.warningCount >= this.MAX_WARNINGS) {
126
+ this.failInstantly(reason);
127
+ }
128
+ else {
129
+ this.isDetectionPaused = true; // Set BEFORE cancelling
130
+ if (this.requestId) {
131
+ cancelAnimationFrame(this.requestId);
132
+ this.requestId = null;
133
+ }
134
+ this.updateState({ errorMsg: `${reason} (Warning ${this.warningCount}/${this.MAX_WARNINGS})` });
135
+ setTimeout(() => {
136
+ if (this.state.status !== "capturing")
137
+ return;
138
+ this.isDetectionPaused = false;
139
+ this.updateState({ errorMsg: "" });
140
+ this.detectLoop();
141
+ }, 2000); // Give user 2 seconds to adjust
142
+ }
143
+ }
118
144
  failInstantly(reason) {
119
145
  this.stop();
120
146
  this.updateState({ status: "error", errorMsg: reason, isStepTransitioning: false });
@@ -160,6 +186,8 @@ class LivenessEngine {
160
186
  this.lastNosePos = null;
161
187
  this.consecutiveMissingFrames = 0;
162
188
  this.stabilityFrames = 0;
189
+ this.warningCount = 0;
190
+ this.isDetectionPaused = false;
163
191
  this.generateSequence();
164
192
  this.updateState({
165
193
  status: "ready",
@@ -176,7 +204,7 @@ class LivenessEngine {
176
204
  }
177
205
  generateSequence() {
178
206
  const seq = [...this.CHALLENGE_POOL].sort(() => 0.5 - Math.random()).slice(0, 3);
179
- this.state.sequence = seq;
207
+ this.updateState({ sequence: seq });
180
208
  return seq;
181
209
  }
182
210
  startTimer() {
@@ -193,7 +221,7 @@ class LivenessEngine {
193
221
  }, 1000);
194
222
  }
195
223
  detectLoop = () => {
196
- if (this.state.status !== "capturing" || !this.webcam || !this.models.face)
224
+ if (this.state.status !== "capturing" || !this.webcam || !this.models.face || this.isDetectionPaused)
197
225
  return;
198
226
  const now = performance.now();
199
227
  try {
@@ -202,7 +230,7 @@ class LivenessEngine {
202
230
  // 1. Multi-Face Security
203
231
  if (faceRes.faceLandmarks && faceRes.faceLandmarks.length > 1) {
204
232
  console.warn("[LivenessEngine] Security Alert: Multiple faces detected!");
205
- this.failInstantly("Multiple faces detected. Please ensure only one person is in frame.");
233
+ this.handleViolation("Multiple faces detected. Please ensure only one person is in frame.");
206
234
  return; // CRITICAL: Stop execution here
207
235
  }
208
236
  const landmarks = faceRes.faceLandmarks?.[0];
@@ -210,7 +238,7 @@ class LivenessEngine {
210
238
  if (!landmarks) {
211
239
  this.consecutiveMissingFrames++;
212
240
  if (this.consecutiveMissingFrames > this.MAX_GAP) {
213
- return this.failInstantly("Face lost. Session reset.");
241
+ return this.handleViolation("Face lost. Session reset.");
214
242
  }
215
243
  }
216
244
  else {
@@ -224,10 +252,12 @@ class LivenessEngine {
224
252
  else {
225
253
  // Only perform the security check AFTER the anchor is established
226
254
  if (!this.verifyIdentity(landmarks) || !this.checkMovement(landmarks)) {
227
- this.failInstantly("Security violation: Identity mismatch.");
255
+ this.handleViolation("Security violation: Identity mismatch.");
228
256
  return;
229
257
  }
230
258
  }
259
+ if (this.state.errorMsg)
260
+ this.updateState({ errorMsg: "" });
231
261
  // 3. Challenge Logic
232
262
  const currentChallenge = this.state.sequence[this.currentStepRef];
233
263
  const handRes = this.models.hand?.detectForVideo(this.webcam, now);
@@ -243,12 +273,12 @@ class LivenessEngine {
243
273
  this.requestId = requestAnimationFrame(this.detectLoop);
244
274
  }
245
275
  };
246
- handleStepSuccess(landmarks) {
276
+ async handleStepSuccess(landmarks) {
247
277
  if (this.isStepTransitioningRef)
248
278
  return;
249
279
  this.isStepTransitioningRef = true;
250
280
  // Capture Snapshot
251
- const canvas = this.getFaceCrop(this.webcam, landmarks);
281
+ const canvas = await this.getFaceCrop(this.webcam, landmarks);
252
282
  const snapshot = {
253
283
  challenge: this.state.sequence[this.currentStepRef],
254
284
  image: canvas.toDataURL("image/jpeg", 0.7),
@@ -289,9 +319,9 @@ class LivenessEngine {
289
319
  case "Smile":
290
320
  return (lms[291].x - lms[61].x) > this.config.smileThreshold;
291
321
  case "Blink":
292
- const leftEar = Math.abs(lms[159].y - lms[145].y);
293
- const rightEar = Math.abs(lms[386].y - lms[374].y);
294
- return ((leftEar + rightEar) / 2) < this.config.blinkThreshold;
322
+ const leftEye = Math.abs(lms[159].y - lms[145].y);
323
+ const rightEye = Math.abs(lms[386].y - lms[374].y);
324
+ return ((leftEye + rightEye) / 2) < this.config.blinkThreshold;
295
325
  case "Turn_Head":
296
326
  const yaw = (lms[1].x - lms[33].x) / (lms[263].x - lms[33].x);
297
327
  return yaw < this.config.minturnHeadThreshold || yaw > this.config.maxturnHeadThreshold;
@@ -307,11 +337,11 @@ class LivenessEngine {
307
337
  const blobs = [];
308
338
  let finalBase64 = "";
309
339
  for (let i = 0; i < 5; i++) {
310
- if (!this.webcam)
340
+ if (!this.webcam || !this.models.face)
311
341
  break;
312
342
  const faceRes = this.models.face?.detectForVideo(this.webcam, performance.now());
313
343
  if (faceRes?.faceLandmarks?.[0]) {
314
- const canvas = this.getFaceCrop(this.webcam, faceRes.faceLandmarks[0]);
344
+ const canvas = await this.getFaceCrop(this.webcam, faceRes.faceLandmarks[0]);
315
345
  const blob = await new Promise(res => canvas.toBlob(res, "image/jpeg", 0.9));
316
346
  if (blob)
317
347
  blobs.push(blob);
@@ -337,8 +367,7 @@ class LivenessEngine {
337
367
  this.config.onError({ success: false, reason: "Network error" });
338
368
  }
339
369
  }
340
- getFaceCrop(video, landmarks) {
341
- const ctx = this.offscreenCanvas.getContext("2d");
370
+ async getFaceCrop(video, landmarks) {
342
371
  const xs = landmarks.map(l => l.x * video.videoWidth);
343
372
  const ys = landmarks.map(l => l.y * video.videoHeight);
344
373
  const minX = Math.min(...xs);
@@ -348,8 +377,26 @@ class LivenessEngine {
348
377
  const width = maxX - minX;
349
378
  const height = maxY - minY;
350
379
  const margin = width * 0.3;
351
- ctx.clearRect(0, 0, 224, 224);
352
- ctx.drawImage(video, minX - margin, minY - margin, width + margin * 2, height + margin * 2, 0, 0, 224, 224);
380
+ const sourceX = Math.max(0, minX - margin);
381
+ const sourceY = Math.max(0, minY - margin);
382
+ const sourceW = Math.min(video.videoWidth - sourceX, width + margin * 2);
383
+ const sourceH = Math.min(video.videoHeight - sourceY, height + margin * 2);
384
+ const ctx = this.offscreenCanvas.getContext("2d");
385
+ try {
386
+ // 2. Extract the bitmap (This bypasses many canvas-tainting triggers)
387
+ const bitmap = await createImageBitmap(video, sourceX, sourceY, sourceW, sourceH);
388
+ ctx.clearRect(0, 0, 224, 224);
389
+ // 3. Draw the clean bitmap to the offscreen canvas
390
+ ctx.drawImage(bitmap, 0, 0, 224, 224);
391
+ // 4. Important: close the bitmap to free memory
392
+ bitmap.close();
393
+ }
394
+ catch (e) {
395
+ console.error("[LivenessEngine] Bitmap extraction failed, falling back to direct draw", e);
396
+ // Fallback if createImageBitmap is not supported or fails
397
+ const ctx = this.offscreenCanvas.getContext("2d");
398
+ ctx.drawImage(video, sourceX, sourceY, sourceW, sourceH, 0, 0, 224, 224);
399
+ }
353
400
  return this.offscreenCanvas;
354
401
  }
355
402
  }
@@ -1 +1 @@
1
- {"version":3,"file":"richard.fadiora-liveness-detection.mjs","sources":["../../../src/core/LivenessEngine.ts","../../../src/angular/liveness.service.ts","../../../src/angular/liveness.component.ts","../../../src/angular/liveness.component.html","../../../src/api.ts","../../../src/richard.fadiora-liveness-detection.ts"],"sourcesContent":["// src/core/LivenessEngine.ts\r\nimport { FaceLandmarker, HandLandmarker, FilesetResolver, NormalizedLandmark } from \"@mediapipe/tasks-vision\";\r\n\r\nexport type Challenge = \"Smile\" | \"Blink\" | \"Turn_Head\" | \"Thumbs_Up\";\r\n\r\nexport interface ChallengeSnapshot {\r\n challenge: Challenge;\r\n image: string; // Base64 data URL\r\n timestamp: number;\r\n}\r\n\r\nexport interface LivenessSDKResult {\r\n success: boolean;\r\n image?: string;\r\n reason?: string;\r\n skinConfidence?: number;\r\n snapshots?: ChallengeSnapshot[];\r\n}\r\n\r\nexport interface LivenessState {\r\n status: \"loading\" | \"ready\" | \"capturing\" | \"verifying\" | \"success\" | \"error\" | \"expired\";\r\n sequence: Challenge[];\r\n currentStep: number;\r\n timeLeft: number;\r\n isStepTransitioning: boolean;\r\n errorMsg: string;\r\n snapshots: ChallengeSnapshot[];\r\n}\r\n\r\nexport interface LivenessEngineConfig {\r\n apiUrl: string;\r\n duration?: number;\r\n smileThreshold?: number;\r\n blinkThreshold?: number;\r\n minturnHeadThreshold?: number;\r\n maxturnHeadThreshold?: number;\r\n onStateChange?: (state: LivenessState) => void;\r\n onComplete?: (result: LivenessSDKResult) => void;\r\n onError?: (error: LivenessSDKResult) => void;\r\n}\r\n\r\nexport class LivenessEngine {\r\n private config: Required<LivenessEngineConfig>;\r\n private models: { face: FaceLandmarker | null; hand: HandLandmarker | null } = { face: null, hand: null };\r\n private webcam: HTMLVideoElement | null = null;\r\n private state: LivenessState;\r\n \r\n private currentStepRef = 0;\r\n private isStepTransitioningRef = false;\r\n private timerId: ReturnType<typeof setInterval> | null = null;\r\n private requestId: number | null = null;\r\n private heartbeatId: ReturnType<typeof setInterval> | null = null;\r\n \r\n // --- NEW SECURITY TRACKERS ---\r\n private anchorRatios: number | null = null;\r\n private lastNosePos: { x: number; y: number } | null = null;\r\n private consecutiveMissingFrames = 0;\r\n private readonly MAX_GAP = 15; // ~250ms buffer\r\n private readonly LIVENESS_LOCK_KEY = \"liveness_active_session\";\r\n private stabilityFrames = 0;\r\n private readonly REQUIRED_STABILITY = 10; // Wait for ~10 clear frames before locking\r\n \r\n private offscreenCanvas = document.createElement(\"canvas\");\r\n private CHALLENGE_POOL: Challenge[] = [\"Smile\", \"Blink\", \"Turn_Head\", \"Thumbs_Up\"];\r\n\r\n constructor(config: LivenessEngineConfig) {\r\n this.config = {\r\n apiUrl: config.apiUrl,\r\n duration: config.duration ?? 60,\r\n smileThreshold: config.smileThreshold ?? 0.2,\r\n blinkThreshold: config.blinkThreshold ?? 0.012,\r\n minturnHeadThreshold: config.minturnHeadThreshold ?? 0.15,\r\n maxturnHeadThreshold: config.maxturnHeadThreshold ?? 0.85,\r\n onStateChange: config.onStateChange || (() => {}),\r\n onComplete: config.onComplete || (() => {}),\r\n onError: config.onError || (() => {}),\r\n };\r\n\r\n this.state = {\r\n status: \"loading\",\r\n sequence: [],\r\n currentStep: 0,\r\n timeLeft: this.config.duration,\r\n isStepTransitioning: false,\r\n errorMsg: \"\",\r\n snapshots: [],\r\n };\r\n \r\n this.offscreenCanvas.width = 224;\r\n this.offscreenCanvas.height = 224;\r\n }\r\n\r\n /**\r\n * Phase 1: Load AI Assets (Call this immediately on mount)\r\n */\r\n public async loadModels() {\r\n console.log(\"[LivenessEngine] Loading AI Models...\");\r\n try {\r\n const vision = await FilesetResolver.forVisionTasks(\r\n \"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.3/wasm\"\r\n );\r\n\r\n this.models.face = await FaceLandmarker.createFromOptions(vision, {\r\n baseOptions: {\r\n modelAssetPath: \"https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task\",\r\n delegate: \"GPU\",\r\n },\r\n outputFaceBlendshapes: true,\r\n runningMode: \"VIDEO\",\r\n });\r\n\r\n this.models.hand = await HandLandmarker.createFromOptions(vision, {\r\n baseOptions: {\r\n modelAssetPath: \"https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task\",\r\n delegate: \"GPU\",\r\n },\r\n runningMode: \"VIDEO\",\r\n numHands: 1,\r\n });\r\n\r\n this.generateSequence();\r\n // Stay in 'loading' or move to a 'ready_to_mount' status if you prefer\r\n // For now, we move to ready to signal the UI can show the camera\r\n this.updateState({ status: \"ready\" });\r\n console.log(\"[LivenessEngine] Models Loaded.\");\r\n } catch (err) {\r\n console.error(\"[LivenessEngine] Init Error:\", err);\r\n this.updateState({ status: \"error\", errorMsg: \"Failed to load security assets.\" });\r\n }\r\n }\r\n\r\n /**\r\n * Phase 2: Attach Video (Call this once the Webcam is in the DOM)\r\n */\r\n public attachVideo = (video: HTMLVideoElement) => {\r\n this.webcam = video;\r\n console.log(\"[LivenessEngine] Video stream attached.\");\r\n };\r\n\r\n // --- NEW SECURITY METHODS ---\r\n\r\n private verifyIdentity(landmarks: NormalizedLandmark[]): boolean {\r\n const eyeDist = Math.sqrt(\r\n Math.pow(landmarks[33].x - landmarks[263].x, 2) + \r\n Math.pow(landmarks[33].y - landmarks[263].y, 2)\r\n );\r\n const noseToMouth = Math.abs(landmarks[1].y - landmarks[13].y);\r\n const currentRatio = eyeDist / (noseToMouth || 1);\r\n\r\n if (this.anchorRatios === null) {\r\n this.anchorRatios = currentRatio;\r\n return true;\r\n }\r\n\r\n const diff = Math.abs(this.anchorRatios - currentRatio) / this.anchorRatios;\r\n return diff < 0.50; // 50% tolerance for head tilt\r\n }\r\n\r\n private checkMovement(landmarks: NormalizedLandmark[]): boolean {\r\n const nose = { x: landmarks[1].x, y: landmarks[1].y };\r\n if (this.lastNosePos) {\r\n const dist = Math.sqrt(\r\n Math.pow(nose.x - this.lastNosePos.x, 2) + \r\n Math.pow(nose.y - this.lastNosePos.y, 2)\r\n );\r\n if (dist > 0.3) return false; // Sudden teleportation\r\n }\r\n this.lastNosePos = nose;\r\n return true;\r\n }\r\n\r\n private failInstantly(reason: string) {\r\n this.stop();\r\n this.updateState({ status: \"error\", errorMsg: reason, isStepTransitioning: false });\r\n this.config.onError({ success: false, reason });\r\n }\r\n\r\n public start = () => {\r\n // Multi-tab Prevention\r\n const active = localStorage.getItem(this.LIVENESS_LOCK_KEY);\r\n if (active && Date.now() - parseInt(active) < 5000) {\r\n this.failInstantly(\"Another session is active.\");\r\n return;\r\n }\r\n\r\n this.heartbeatId = setInterval(() => {\r\n localStorage.setItem(this.LIVENESS_LOCK_KEY, Date.now().toString());\r\n }, 1000);\r\n\r\n if (this.state.status !== \"ready\" || !this.webcam) {\r\n console.warn(\"[LivenessEngine] Engine not ready or video missing.\");\r\n return;\r\n }\r\n\r\n console.log(\"[LivenessEngine] Session Starting...\");\r\n this.state.status = \"capturing\"; // Sync internal status immediately\r\n this.updateState({ status: \"capturing\" });\r\n this.startTimer();\r\n this.detectLoop();\r\n };\r\n\r\n public stop = () => {\r\n if (this.timerId) clearInterval(this.timerId);\r\n if (this.heartbeatId) clearInterval(this.heartbeatId);\r\n if (this.requestId) cancelAnimationFrame(this.requestId);\r\n localStorage.removeItem(this.LIVENESS_LOCK_KEY);\r\n\r\n this.timerId = null;\r\n this.heartbeatId = null;\r\n this.requestId = null;\r\n };\r\n\r\n public reset = () => {\r\n this.stop();\r\n this.currentStepRef = 0;\r\n this.isStepTransitioningRef = false;\r\n this.anchorRatios = null;\r\n this.lastNosePos = null;\r\n this.consecutiveMissingFrames = 0;\r\n this.stabilityFrames = 0;\r\n this.generateSequence();\r\n this.updateState({\r\n status: \"ready\",\r\n currentStep: 0,\r\n timeLeft: this.config.duration,\r\n isStepTransitioning: false,\r\n errorMsg: \"\",\r\n snapshots: [],\r\n });\r\n};\r\n\r\n private updateState(newState: Partial<LivenessState>) {\r\n this.state = { ...this.state, ...newState };\r\n this.config.onStateChange(this.state);\r\n }\r\n\r\n private generateSequence(): Challenge[] {\r\n const seq = [...this.CHALLENGE_POOL].sort(() => 0.5 - Math.random()).slice(0, 3);\r\n this.state.sequence = seq;\r\n return seq;\r\n }\r\n\r\n private startTimer() {\r\n if (this.timerId) clearInterval(this.timerId);\r\n this.timerId = setInterval(() => {\r\n if (this.state.timeLeft > 0) {\r\n this.updateState({ timeLeft: this.state.timeLeft - 1 });\r\n } else {\r\n this.stop();\r\n this.updateState({ status: \"expired\" });\r\n }\r\n }, 1000);\r\n }\r\n\r\n private detectLoop = () => {\r\n if (this.state.status !== \"capturing\" || !this.webcam || !this.models.face) return;\r\n\r\n const now = performance.now();\r\n try {\r\n const faceRes = this.models.face.detectForVideo(this.webcam, now);\r\n \r\n // --- NEW SECURITY CHECKS ---\r\n // 1. Multi-Face Security\r\n if (faceRes.faceLandmarks && faceRes.faceLandmarks.length > 1) {\r\n console.warn(\"[LivenessEngine] Security Alert: Multiple faces detected!\");\r\n this.failInstantly(\"Multiple faces detected. Please ensure only one person is in frame.\");\r\n return; // CRITICAL: Stop execution here\r\n }\r\n \r\n const landmarks = faceRes.faceLandmarks?.[0];\r\n\r\n // 2. Continuity & Identity Security\r\n if (!landmarks) {\r\n this.consecutiveMissingFrames++;\r\n if (this.consecutiveMissingFrames > this.MAX_GAP) {\r\n return this.failInstantly(\"Face lost. Session reset.\");\r\n }\r\n } else {\r\n this.consecutiveMissingFrames = 0;\r\n\r\n if (this.anchorRatios === null) {\r\n this.stabilityFrames++;\r\n if (this.stabilityFrames >= this.REQUIRED_STABILITY) {\r\n this.verifyIdentity(landmarks); // This sets the anchor for the first time\r\n }\r\n } else {\r\n // Only perform the security check AFTER the anchor is established\r\n if (!this.verifyIdentity(landmarks) || !this.checkMovement(landmarks)) {\r\n this.failInstantly(\"Security violation: Identity mismatch.\");\r\n return;\r\n }\r\n }\r\n\r\n // 3. Challenge Logic\r\n const currentChallenge = this.state.sequence[this.currentStepRef];\r\n const handRes = this.models.hand?.detectForVideo(this.webcam, now);\r\n\r\n if (this.checkAction(faceRes, handRes, currentChallenge)) {\r\n this.handleStepSuccess(landmarks); // Pass landmarks to capture\r\n return; \r\n }\r\n }\r\n\r\n this.requestId = requestAnimationFrame(this.detectLoop);\r\n\r\n } catch (err) {\r\n console.error(\"[LivenessEngine] Loop detection error:\", err);\r\n this.requestId = requestAnimationFrame(this.detectLoop);\r\n }\r\n\r\n };\r\n\r\n private handleStepSuccess(landmarks: NormalizedLandmark[]) {\r\n if (this.isStepTransitioningRef) return;\r\n \r\n this.isStepTransitioningRef = true;\r\n\r\n // Capture Snapshot\r\n const canvas = this.getFaceCrop(this.webcam!, landmarks);\r\n const snapshot: ChallengeSnapshot = {\r\n challenge: this.state.sequence[this.currentStepRef],\r\n image: canvas.toDataURL(\"image/jpeg\", 0.7),\r\n timestamp: Date.now()\r\n };\r\n\r\n const updatedSnapshots = [...this.state.snapshots, snapshot];\r\n\r\n this.updateState({ isStepTransitioning: true, snapshots: updatedSnapshots });\r\n\r\n setTimeout(() => {\r\n // Check if engine was stopped during the timeout\r\n if (this.state.status !== \"capturing\") return;\r\n\r\n if (this.currentStepRef < this.state.sequence.length - 1) {\r\n this.currentStepRef++;\r\n this.isStepTransitioningRef = false;\r\n this.updateState({\r\n currentStep: this.currentStepRef,\r\n isStepTransitioning: false,\r\n snapshots: updatedSnapshots,\r\n });\r\n this.requestId = requestAnimationFrame(this.detectLoop);\r\n } else {\r\n this.updateState({ snapshots: updatedSnapshots });\r\n this.sendFinalProof();\r\n }\r\n }, 1500);\r\n }\r\n\r\n private checkAction(faceRes: any, handRes: any, challenge: Challenge): boolean {\r\n if (this.isStepTransitioningRef) return false;\r\n\r\n if (challenge === \"Thumbs_Up\" && handRes?.landmarks?.length > 0) {\r\n const l = handRes.landmarks[0];\r\n return l[4].y < l[2].y && [8, 12, 16, 20].every(i => l[i].y > l[i - 2].y);\r\n }\r\n\r\n if (faceRes?.faceLandmarks?.length > 0) {\r\n const lms: NormalizedLandmark[] = faceRes.faceLandmarks[0];\r\n switch (challenge) {\r\n case \"Smile\":\r\n return (lms[291].x - lms[61].x) > this.config.smileThreshold;\r\n case \"Blink\":\r\n const leftEar = Math.abs(lms[159].y - lms[145].y);\r\n const rightEar = Math.abs(lms[386].y - lms[374].y);\r\n return ((leftEar + rightEar) / 2) < this.config.blinkThreshold;\r\n case \"Turn_Head\":\r\n const yaw = (lms[1].x - lms[33].x) / (lms[263].x - lms[33].x);\r\n return yaw < this.config.minturnHeadThreshold || yaw > this.config.maxturnHeadThreshold;\r\n default: return false;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n private async sendFinalProof() {\r\n this.stop();\r\n this.updateState({ status: \"verifying\" });\r\n\r\n try {\r\n const blobs: Blob[] = [];\r\n let finalBase64 = \"\";\r\n\r\n for (let i = 0; i < 5; i++) {\r\n if (!this.webcam) break;\r\n const faceRes = this.models.face?.detectForVideo(this.webcam, performance.now());\r\n if (faceRes?.faceLandmarks?.[0]) {\r\n const canvas = this.getFaceCrop(this.webcam, faceRes.faceLandmarks[0]);\r\n const blob = await new Promise<Blob | null>(res => canvas.toBlob(res, \"image/jpeg\", 0.9));\r\n if (blob) blobs.push(blob);\r\n if (i === 4) finalBase64 = canvas.toDataURL(\"image/jpeg\");\r\n }\r\n await new Promise(r => setTimeout(r, 100));\r\n }\r\n\r\n const { verifyLiveness } = await import(\"../api\");\r\n const result = await verifyLiveness(this.config.apiUrl, blobs, this.state.sequence);\r\n\r\n if (result.is_live) {\r\n this.updateState({ status: \"success\" });\r\n this.config.onComplete({ success: true, image: finalBase64, skinConfidence: result.skin_confidence });\r\n } else {\r\n const reason = result.reason || \"Liveness check failed\";\r\n this.updateState({ status: \"error\", errorMsg: reason });\r\n this.config.onError({ success: false, reason });\r\n }\r\n } catch (err) {\r\n this.updateState({ status: \"error\", errorMsg: \"Verification failed.\" });\r\n this.config.onError({ success: false, reason: \"Network error\" });\r\n }\r\n }\r\n\r\n private getFaceCrop(video: HTMLVideoElement, landmarks: NormalizedLandmark[]): HTMLCanvasElement {\r\n const ctx = this.offscreenCanvas.getContext(\"2d\")!;\r\n const xs = landmarks.map(l => l.x * video.videoWidth);\r\n const ys = landmarks.map(l => l.y * video.videoHeight);\r\n \r\n const minX = Math.min(...xs);\r\n const maxX = Math.max(...xs);\r\n const minY = Math.min(...ys);\r\n const maxY = Math.max(...ys);\r\n \r\n const width = maxX - minX;\r\n const height = maxY - minY;\r\n const margin = width * 0.3;\r\n\r\n ctx.clearRect(0, 0, 224, 224);\r\n ctx.drawImage(\r\n video,\r\n minX - margin, minY - margin, \r\n width + margin * 2, height + margin * 2,\r\n 0, 0, 224, 224\r\n );\r\n\r\n return this.offscreenCanvas;\r\n }\r\n}","import { Injectable, NgZone, OnDestroy } from '@angular/core';\r\nimport { BehaviorSubject, Observable } from 'rxjs';\r\nimport { LivenessEngine, LivenessState, LivenessEngineConfig } from '../core/LivenessEngine';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class LivenessService implements OnDestroy {\r\n private engine!: LivenessEngine;\r\n private stateSubject = new BehaviorSubject<LivenessState | null>(null);\r\n \r\n // Components will subscribe to this\r\n public state$: Observable<LivenessState | null> = this.stateSubject.asObservable();\r\n\r\n constructor(private ngZone: NgZone) {}\r\n\r\n public init(config: LivenessEngineConfig) {\r\n // Run inside runOutsideAngular to prevent 60fps change detection triggers\r\n this.ngZone.runOutsideAngular(() => {\r\n this.engine = new LivenessEngine({\r\n ...config,\r\n onStateChange: (state) => {\r\n // Bring state changes BACK into the zone so the UI updates\r\n this.ngZone.run(() => this.stateSubject.next(state));\r\n }\r\n });\r\n this.engine.loadModels();\r\n });\r\n }\r\n\r\n public attach(video: HTMLVideoElement) {\r\n this.engine?.attachVideo(video);\r\n }\r\n\r\n public start() {\r\n this.engine?.start();\r\n }\r\n\r\n public reset() {\r\n this.engine?.reset();\r\n }\r\n\r\n ngOnDestroy() {\r\n this.engine?.stop();\r\n }\r\n}","import { Component, ElementRef, ViewChild, AfterViewInit, Input, Output, EventEmitter, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';\r\nimport { LivenessService } from './liveness.service';\r\nimport { LivenessSDKResult, Challenge, LivenessState } from '../core/LivenessEngine';\r\nimport { CommonModule } from '@angular/common'\r\n\r\n@Component({\r\n selector: 'LivenessCheck',\r\n standalone: true, // Make it standalone\r\n imports: [CommonModule], // Add CommonModule here to fix NG8002\r\n templateUrl: './liveness.component.html',\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\n\r\nexport class LivenessComponent implements OnInit, AfterViewInit, OnDestroy {\r\n @ViewChild('webcam') webcamRef!: ElementRef<HTMLVideoElement>;\r\n\r\n // --- Logic Configuration ---\r\n @Input() apiUrl!: string;\r\n @Input() duration = 60;\r\n @Input() smileThreshold?: number;\r\n @Input() blinkThreshold?: number;\r\n @Input() minturnHeadThreshold?: number;\r\n @Input() maxturnHeadThreshold?: number;\r\n\r\n // --- Styling Configuration (Class Names) ---\r\n @Input() containerClass = '';\r\n @Input() videoWrapperClass = '';\r\n @Input() videoClass = '';\r\n @Input() timerClass = '';\r\n @Input() stateClass = '';\r\n @Input() challengeTextClass = '';\r\n @Input() buttonClass = '';\r\n @Input() retryButtonClass = '';\r\n @Input() statusOverlayClass = '';\r\n @Input() successMessageClass = '';\r\n @Input() errorMessageClass = '';\r\n @Input() instructionBoxClass = '';\r\n\r\n // --- Content Configuration ---\r\n @Input() successMessage = 'Verification Successful!';\r\n @Input() errorMessage = 'Verification failed. Please try again.';\r\n @Input() retryButtonLabel = 'Try Again';\r\n @Input() startButtonLabel = 'Start Verification';\r\n @Input() challengeMapping: Record<Challenge, string> = {\r\n 'Smile': 'Smile',\r\n 'Blink': 'Blink',\r\n 'Turn_Head': 'Turn Head',\r\n 'Thumbs_Up': 'Thumbs Up' // Default with a space\r\n };\r\n\r\n @Output() onComplete = new EventEmitter<LivenessSDKResult>();\r\n @Output() onError = new EventEmitter<any>();\r\n @Output() onStateChange = new EventEmitter<LivenessState | null>();\r\n\r\n constructor(public liveness: LivenessService) {}\r\n\r\n ngOnInit() {\r\n // Pass the custom thresholds directly to the service\r\n \r\n\r\n this.liveness.state$.subscribe(state => {\r\n // This bridges the Service to the Component's @Output\r\n this.onStateChange.emit(state);\r\n });\r\n\r\n }\r\n\r\n async ngAfterViewInit() {\r\n try {\r\n const stream = await navigator.mediaDevices.getUserMedia({ \r\n video: { width: 640, height: 480, facingMode: 'user' } \r\n });\r\n const video = this.webcamRef.nativeElement;\r\n video.srcObject = stream;\r\n video.onloadedmetadata = () => {\r\n video.play();\r\n\r\n this.liveness.init({\r\n apiUrl: this.apiUrl,\r\n duration: this.duration,\r\n smileThreshold: this.smileThreshold,\r\n blinkThreshold: this.blinkThreshold,\r\n minturnHeadThreshold: this.minturnHeadThreshold,\r\n maxturnHeadThreshold: this.maxturnHeadThreshold,\r\n onComplete: (res) => this.onComplete.emit(res),\r\n onError: (err) => this.onError.emit(err)\r\n });\r\n\r\n this.liveness.attach(video);\r\n };\r\n } catch (e) {\r\n this.onError.emit({ success: false, reason: 'Camera access denied' });\r\n }\r\n }\r\n\r\n ngOnDestroy() {\r\n const stream = this.webcamRef?.nativeElement?.srcObject as MediaStream;\r\n stream?.getTracks().forEach(track => track.stop());\r\n }\r\n}","<div [ngClass]=\"containerClass\">\r\n <div [ngClass]=\"videoWrapperClass\">\r\n <video #webcam \r\n autoplay \r\n playsinline \r\n muted \r\n [ngClass]=\"videoClass\" \r\n style=\"transform: scaleX(-1);\">\r\n </video>\r\n\r\n <ng-container *ngIf=\"(liveness.state$ | async) as state\">\r\n <div [ngClass]=\"statusOverlayClass\">\r\n \r\n <div class=\"instruction-box\">\r\n <h2 class=\"status-text\" [ngClass] = \"stateClass\">{{ state.status | uppercase }}</h2>\r\n \r\n <p *ngIf=\"state.status === 'capturing'\" \r\n [ngClass]=\"challengeTextClass\">\r\n {{ challengeMapping[state.sequence[state.currentStep]] }}\r\n </p>\r\n\r\n <p *ngIf=\"state.status === 'success'\"\r\n [ngClass]=\"successMessageClass\">\r\n {{ successMessage }}\r\n </p>\r\n \r\n <p *ngIf=\"state.status === 'error' || state.status === 'expired'\" \r\n [ngClass]=\"errorMessageClass\">\r\n {{ errorMessage }}\r\n </p>\r\n </div>\r\n\r\n <div *ngIf=\"state.status === 'capturing'\" \r\n [ngClass]=\"timerClass\">\r\n {{ state.timeLeft }}\r\n </div>\r\n\r\n <div class=\"action-area\">\r\n <button *ngIf=\"state.status === 'ready'\" \r\n (click)=\"liveness.start()\"\r\n [ngClass]=\"buttonClass\">\r\n {{ startButtonLabel }}\r\n </button>\r\n \r\n <button *ngIf=\"state.status === 'error' || state.status === 'expired'\" \r\n (click)=\"liveness.reset()\"\r\n [ngClass]=\"retryButtonClass\">\r\n {{ retryButtonLabel }}\r\n </button>\r\n </div>\r\n\r\n </div>\r\n </ng-container>\r\n </div>\r\n</div>","// src/api.ts\r\n\r\nimport { Challenge } from \"./core/LivenessEngine\";\r\n\r\nexport interface LivenessResponse {\r\n is_live: boolean;\r\n reason?: string;\r\n skin_confidence?: number;\r\n [key: string]: any; // allow extra fields if backend returns more\r\n}\r\n\r\n/**\r\n * Sends captured frames to the backend API for liveness verification.\r\n * @param apiUrl - Base URL of the liveness backend\r\n * @param frameBlobs - Array of Blob objects representing captured frames\r\n * @param challenge - The current challenge string\r\n * @returns LivenessResponse from backend\r\n */\r\nexport const verifyLiveness = async (\r\n apiUrl: string,\r\n frameBlobs: Blob[],\r\n challenge: Challenge[]\r\n): Promise<LivenessResponse> => {\r\n const formData = new FormData();\r\n\r\n frameBlobs.forEach((blob, i) => {\r\n formData.append('files', blob, `frame_${i}.jpg`);\r\n });\r\n formData.append('challenge', JSON.stringify(challenge));\r\n\r\n const response = await fetch(`${apiUrl}/v1/verify`, {\r\n method: 'POST',\r\n body: formData,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(\"Network response was not ok\");\r\n }\r\n\r\n const data: LivenessResponse = await response.json();\r\n return data;\r\n};","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.LivenessService"],"mappings":"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"}
1
+ {"version":3,"file":"richard.fadiora-liveness-detection.mjs","sources":["../../../src/core/LivenessEngine.ts","../../../src/angular/liveness.service.ts","../../../src/angular/liveness.component.ts","../../../src/angular/liveness.component.html","../../../src/api.ts","../../../src/richard.fadiora-liveness-detection.ts"],"sourcesContent":["// src/core/LivenessEngine.ts\r\nimport { FaceLandmarker, HandLandmarker, FilesetResolver, NormalizedLandmark } from \"@mediapipe/tasks-vision\";\r\n\r\nexport type Challenge = \"Smile\" | \"Blink\" | \"Turn_Head\" | \"Thumbs_Up\";\r\n\r\nexport interface ChallengeSnapshot {\r\n challenge: Challenge;\r\n image: string; // Base64 data URL\r\n timestamp: number;\r\n}\r\n\r\nexport interface LivenessSDKResult {\r\n success: boolean;\r\n image?: string;\r\n reason?: string;\r\n skinConfidence?: number;\r\n snapshots?: ChallengeSnapshot[];\r\n}\r\n\r\nexport interface LivenessState {\r\n status: \"loading\" | \"ready\" | \"capturing\" | \"verifying\" | \"success\" | \"error\" | \"expired\";\r\n sequence: Challenge[];\r\n currentStep: number;\r\n timeLeft: number;\r\n isStepTransitioning: boolean;\r\n errorMsg: string;\r\n snapshots: ChallengeSnapshot[];\r\n}\r\n\r\nexport interface LivenessEngineConfig {\r\n apiUrl: string;\r\n duration?: number;\r\n smileThreshold?: number;\r\n blinkThreshold?: number;\r\n minturnHeadThreshold?: number;\r\n maxturnHeadThreshold?: number;\r\n onStateChange?: (state: LivenessState) => void;\r\n onComplete?: (result: LivenessSDKResult) => void;\r\n onError?: (error: LivenessSDKResult) => void;\r\n}\r\n\r\nexport class LivenessEngine {\r\n private config: Required<LivenessEngineConfig>;\r\n private models: { face: FaceLandmarker | null; hand: HandLandmarker | null } = { face: null, hand: null };\r\n private webcam: HTMLVideoElement | null = null;\r\n private state: LivenessState;\r\n \r\n private currentStepRef = 0;\r\n private isStepTransitioningRef = false;\r\n private timerId: ReturnType<typeof setInterval> | null = null;\r\n private requestId: number | null = null;\r\n private heartbeatId: ReturnType<typeof setInterval> | null = null;\r\n\r\n private warningCount = 0;\r\n private readonly MAX_WARNINGS = 3;\r\n private lastWarningMsg = \"\";\r\n private isDetectionPaused = false;\r\n \r\n // --- NEW SECURITY TRACKERS ---\r\n private anchorRatios: number | null = null;\r\n private lastNosePos: { x: number; y: number } | null = null;\r\n private consecutiveMissingFrames = 0;\r\n private readonly MAX_GAP = 15; // ~250ms buffer\r\n private readonly LIVENESS_LOCK_KEY = \"liveness_active_session\";\r\n private stabilityFrames = 0;\r\n private readonly REQUIRED_STABILITY = 10; // Wait for ~10 clear frames before locking\r\n \r\n private offscreenCanvas = document.createElement(\"canvas\");\r\n private CHALLENGE_POOL: Challenge[] = [\"Smile\", \"Blink\", \"Turn_Head\", \"Thumbs_Up\"];\r\n\r\n constructor(config: LivenessEngineConfig) {\r\n this.config = {\r\n apiUrl: config.apiUrl,\r\n duration: config.duration ?? 60,\r\n smileThreshold: config.smileThreshold ?? 0.2,\r\n blinkThreshold: config.blinkThreshold ?? 0.012,\r\n minturnHeadThreshold: config.minturnHeadThreshold ?? 0.15,\r\n maxturnHeadThreshold: config.maxturnHeadThreshold ?? 0.85,\r\n onStateChange: config.onStateChange || (() => {}),\r\n onComplete: config.onComplete || (() => {}),\r\n onError: config.onError || (() => {}),\r\n };\r\n\r\n this.state = {\r\n status: \"loading\",\r\n sequence: [],\r\n currentStep: 0,\r\n timeLeft: this.config.duration,\r\n isStepTransitioning: false,\r\n errorMsg: \"\",\r\n snapshots: [],\r\n };\r\n \r\n this.offscreenCanvas.width = 224;\r\n this.offscreenCanvas.height = 224;\r\n }\r\n\r\n /**\r\n * Phase 1: Load AI Assets (Call this immediately on mount)\r\n */\r\n public async loadModels() {\r\n console.log(\"[LivenessEngine] Loading AI Models...\");\r\n try {\r\n const vision = await FilesetResolver.forVisionTasks(\r\n \"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.3/wasm\"\r\n );\r\n\r\n this.models.face = await FaceLandmarker.createFromOptions(vision, {\r\n baseOptions: {\r\n modelAssetPath: \"https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task\",\r\n delegate: \"GPU\",\r\n },\r\n outputFaceBlendshapes: true,\r\n runningMode: \"VIDEO\",\r\n });\r\n\r\n this.models.hand = await HandLandmarker.createFromOptions(vision, {\r\n baseOptions: {\r\n modelAssetPath: \"https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task\",\r\n delegate: \"GPU\",\r\n },\r\n runningMode: \"VIDEO\",\r\n numHands: 1,\r\n });\r\n\r\n this.generateSequence();\r\n // Stay in 'loading' or move to a 'ready_to_mount' status if you prefer\r\n // For now, we move to ready to signal the UI can show the camera\r\n this.updateState({ status: \"ready\" });\r\n console.log(\"[LivenessEngine] Models Loaded.\");\r\n } catch (err) {\r\n console.error(\"[LivenessEngine] Init Error:\", err);\r\n this.updateState({ status: \"error\", errorMsg: \"Failed to load security assets.\" });\r\n }\r\n }\r\n\r\n /**\r\n * Phase 2: Attach Video (Call this once the Webcam is in the DOM)\r\n */\r\n public attachVideo = (video: HTMLVideoElement) => {\r\n video.setAttribute('crossorigin', 'anonymous');\r\n this.webcam = video;\r\n console.log(\"[LivenessEngine] Video stream attached.\");\r\n };\r\n\r\n // --- NEW SECURITY METHODS ---\r\n private verifyIdentity(landmarks: NormalizedLandmark[]): boolean {\r\n const eyeDist = Math.sqrt(\r\n Math.pow(landmarks[33].x - landmarks[263].x, 2) + \r\n Math.pow(landmarks[33].y - landmarks[263].y, 2)\r\n );\r\n const noseToMouth = Math.abs(landmarks[1].y - landmarks[13].y);\r\n const currentRatio = eyeDist / (noseToMouth || 1);\r\n\r\n if (this.anchorRatios === null) {\r\n this.anchorRatios = currentRatio;\r\n return true;\r\n }\r\n\r\n const diff = Math.abs(this.anchorRatios - currentRatio) / this.anchorRatios;\r\n return diff < 0.70; // 70% tolerance for head tilt\r\n }\r\n\r\n private checkMovement(landmarks: NormalizedLandmark[]): boolean {\r\n const nose = { x: landmarks[1].x, y: landmarks[1].y };\r\n if (this.lastNosePos) {\r\n const dist = Math.sqrt(\r\n Math.pow(nose.x - this.lastNosePos.x, 2) + \r\n Math.pow(nose.y - this.lastNosePos.y, 2)\r\n );\r\n if (dist > 0.5) return false; // Sudden teleportation\r\n }\r\n this.lastNosePos = nose;\r\n return true;\r\n }\r\n\r\n private handleViolation(reason: string) {\r\n this.warningCount++;\r\n\r\n if (this.warningCount >= this.MAX_WARNINGS) {\r\n this.failInstantly(reason);\r\n } else {\r\n this.isDetectionPaused = true; // Set BEFORE cancelling\r\n if (this.requestId) {\r\n cancelAnimationFrame(this.requestId);\r\n this.requestId = null;\r\n }\r\n this.updateState({ errorMsg: `${reason} (Warning ${this.warningCount}/${this.MAX_WARNINGS})` });\r\n \r\n setTimeout(() => {\r\n if (this.state.status !== \"capturing\") return\r\n this.isDetectionPaused = false;\r\n this.updateState({ errorMsg: \"\" });\r\n this.detectLoop();\r\n }, 2000); // Give user 2 seconds to adjust\r\n }\r\n}\r\n\r\n private failInstantly(reason: string) {\r\n this.stop();\r\n this.updateState({ status: \"error\", errorMsg: reason, isStepTransitioning: false });\r\n this.config.onError({ success: false, reason });\r\n }\r\n\r\n public start = () => {\r\n // Multi-tab Prevention\r\n const active = localStorage.getItem(this.LIVENESS_LOCK_KEY);\r\n if (active && Date.now() - parseInt(active) < 5000) {\r\n this.failInstantly(\"Another session is active.\");\r\n return;\r\n }\r\n\r\n this.heartbeatId = setInterval(() => {\r\n localStorage.setItem(this.LIVENESS_LOCK_KEY, Date.now().toString());\r\n }, 1000);\r\n\r\n if (this.state.status !== \"ready\" || !this.webcam) {\r\n console.warn(\"[LivenessEngine] Engine not ready or video missing.\");\r\n return;\r\n }\r\n\r\n console.log(\"[LivenessEngine] Session Starting...\");\r\n this.state.status = \"capturing\"; // Sync internal status immediately\r\n this.updateState({ status: \"capturing\" });\r\n this.startTimer();\r\n this.detectLoop();\r\n };\r\n\r\n public stop = () => {\r\n if (this.timerId) clearInterval(this.timerId);\r\n if (this.heartbeatId) clearInterval(this.heartbeatId);\r\n if (this.requestId) cancelAnimationFrame(this.requestId);\r\n localStorage.removeItem(this.LIVENESS_LOCK_KEY);\r\n\r\n this.timerId = null;\r\n this.heartbeatId = null;\r\n this.requestId = null;\r\n };\r\n\r\n public reset = () => {\r\n this.stop();\r\n this.currentStepRef = 0;\r\n this.isStepTransitioningRef = false;\r\n this.anchorRatios = null;\r\n this.lastNosePos = null;\r\n this.consecutiveMissingFrames = 0;\r\n this.stabilityFrames = 0;\r\n this.warningCount = 0; \r\n this.isDetectionPaused = false;\r\n this.generateSequence();\r\n this.updateState({\r\n status: \"ready\",\r\n currentStep: 0,\r\n timeLeft: this.config.duration,\r\n isStepTransitioning: false,\r\n errorMsg: \"\",\r\n snapshots: [],\r\n });\r\n};\r\n\r\n private updateState(newState: Partial<LivenessState>) {\r\n this.state = { ...this.state, ...newState };\r\n this.config.onStateChange(this.state);\r\n }\r\n\r\n private generateSequence(): Challenge[] {\r\n const seq = [...this.CHALLENGE_POOL].sort(() => 0.5 - Math.random()).slice(0, 3);\r\n this.updateState({ sequence: seq });\r\n return seq;\r\n }\r\n\r\n private startTimer() {\r\n if (this.timerId) clearInterval(this.timerId);\r\n this.timerId = setInterval(() => {\r\n if (this.state.timeLeft > 0) {\r\n this.updateState({ timeLeft: this.state.timeLeft - 1 });\r\n } else {\r\n this.stop();\r\n this.updateState({ status: \"expired\" });\r\n }\r\n }, 1000);\r\n }\r\n\r\n private detectLoop = () => {\r\n if (this.state.status !== \"capturing\" || !this.webcam || !this.models.face || this.isDetectionPaused) return;\r\n\r\n const now = performance.now();\r\n try {\r\n const faceRes = this.models.face.detectForVideo(this.webcam, now);\r\n \r\n // --- NEW SECURITY CHECKS ---\r\n // 1. Multi-Face Security\r\n if (faceRes.faceLandmarks && faceRes.faceLandmarks.length > 1) {\r\n console.warn(\"[LivenessEngine] Security Alert: Multiple faces detected!\");\r\n this.handleViolation(\"Multiple faces detected. Please ensure only one person is in frame.\");\r\n return; // CRITICAL: Stop execution here\r\n }\r\n \r\n const landmarks = faceRes.faceLandmarks?.[0];\r\n\r\n // 2. Continuity & Identity Security\r\n if (!landmarks) {\r\n this.consecutiveMissingFrames++;\r\n if (this.consecutiveMissingFrames > this.MAX_GAP) {\r\n return this.handleViolation(\"Face lost. Session reset.\");\r\n }\r\n } else {\r\n this.consecutiveMissingFrames = 0;\r\n\r\n if (this.anchorRatios === null) {\r\n this.stabilityFrames++;\r\n if (this.stabilityFrames >= this.REQUIRED_STABILITY) {\r\n this.verifyIdentity(landmarks); // This sets the anchor for the first time\r\n }\r\n } else {\r\n // Only perform the security check AFTER the anchor is established\r\n if (!this.verifyIdentity(landmarks) || !this.checkMovement(landmarks)) {\r\n this.handleViolation(\"Security violation: Identity mismatch.\");\r\n return;\r\n }\r\n }\r\n\r\n if (this.state.errorMsg) this.updateState({ errorMsg: \"\" });\r\n\r\n // 3. Challenge Logic\r\n const currentChallenge = this.state.sequence[this.currentStepRef];\r\n const handRes = this.models.hand?.detectForVideo(this.webcam, now);\r\n\r\n if (this.checkAction(faceRes, handRes, currentChallenge)) {\r\n this.handleStepSuccess(landmarks); // Pass landmarks to capture\r\n return; \r\n }\r\n }\r\n\r\n this.requestId = requestAnimationFrame(this.detectLoop);\r\n\r\n } catch (err) {\r\n console.error(\"[LivenessEngine] Loop detection error:\", err);\r\n this.requestId = requestAnimationFrame(this.detectLoop);\r\n }\r\n\r\n };\r\n\r\n private async handleStepSuccess(landmarks: NormalizedLandmark[]) {\r\n if (this.isStepTransitioningRef) return;\r\n \r\n this.isStepTransitioningRef = true;\r\n\r\n // Capture Snapshot\r\n const canvas = await this.getFaceCrop(this.webcam!, landmarks);\r\n const snapshot: ChallengeSnapshot = {\r\n challenge: this.state.sequence[this.currentStepRef],\r\n image: canvas.toDataURL(\"image/jpeg\", 0.7),\r\n timestamp: Date.now()\r\n };\r\n\r\n const updatedSnapshots = [...this.state.snapshots, snapshot];\r\n\r\n this.updateState({ isStepTransitioning: true, snapshots: updatedSnapshots });\r\n\r\n setTimeout(() => {\r\n // Check if engine was stopped during the timeout\r\n if (this.state.status !== \"capturing\") return;\r\n\r\n if (this.currentStepRef < this.state.sequence.length - 1) {\r\n this.currentStepRef++;\r\n this.isStepTransitioningRef = false;\r\n this.updateState({\r\n currentStep: this.currentStepRef,\r\n isStepTransitioning: false,\r\n snapshots: updatedSnapshots,\r\n });\r\n this.requestId = requestAnimationFrame(this.detectLoop);\r\n } else {\r\n this.updateState({ snapshots: updatedSnapshots });\r\n this.sendFinalProof();\r\n }\r\n }, 1500);\r\n }\r\n\r\n private checkAction(faceRes: any, handRes: any, challenge: Challenge): boolean {\r\n if (this.isStepTransitioningRef) return false;\r\n\r\n if (challenge === \"Thumbs_Up\" && handRes?.landmarks?.length > 0) {\r\n const l = handRes.landmarks[0];\r\n return l[4].y < l[2].y && [8, 12, 16, 20].every(i => l[i].y > l[i - 2].y);\r\n }\r\n\r\n if (faceRes?.faceLandmarks?.length > 0) {\r\n const lms: NormalizedLandmark[] = faceRes.faceLandmarks[0];\r\n switch (challenge) {\r\n case \"Smile\":\r\n return (lms[291].x - lms[61].x) > this.config.smileThreshold;\r\n case \"Blink\":\r\n const leftEye = Math.abs(lms[159].y - lms[145].y);\r\n const rightEye = Math.abs(lms[386].y - lms[374].y);\r\n return ((leftEye + rightEye) / 2) < this.config.blinkThreshold;\r\n case \"Turn_Head\":\r\n const yaw = (lms[1].x - lms[33].x) / (lms[263].x - lms[33].x);\r\n return yaw < this.config.minturnHeadThreshold || yaw > this.config.maxturnHeadThreshold;\r\n default: return false;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n private async sendFinalProof() {\r\n this.stop();\r\n this.updateState({ status: \"verifying\" });\r\n\r\n try {\r\n const blobs: Blob[] = [];\r\n let finalBase64 = \"\";\r\n\r\n for (let i = 0; i < 5; i++) {\r\n if (!this.webcam || !this.models.face) break;\r\n const faceRes = this.models.face?.detectForVideo(this.webcam, performance.now());\r\n if (faceRes?.faceLandmarks?.[0]) {\r\n const canvas = await this.getFaceCrop(this.webcam, faceRes.faceLandmarks[0]);\r\n const blob = await new Promise<Blob | null>(res => canvas.toBlob(res, \"image/jpeg\", 0.9));\r\n if (blob) blobs.push(blob);\r\n if (i === 4) finalBase64 = canvas.toDataURL(\"image/jpeg\");\r\n }\r\n await new Promise(r => setTimeout(r, 100));\r\n }\r\n\r\n const { verifyLiveness } = await import(\"../api\");\r\n const result = await verifyLiveness(this.config.apiUrl, blobs, this.state.sequence);\r\n\r\n if (result.is_live) {\r\n this.updateState({ status: \"success\" });\r\n this.config.onComplete({ success: true, image: finalBase64, skinConfidence: result.skin_confidence });\r\n } else {\r\n const reason = result.reason || \"Liveness check failed\";\r\n this.updateState({ status: \"error\", errorMsg: reason });\r\n this.config.onError({ success: false, reason });\r\n }\r\n } catch (err) {\r\n this.updateState({ status: \"error\", errorMsg: \"Verification failed.\" });\r\n this.config.onError({ success: false, reason: \"Network error\" });\r\n }\r\n }\r\n\r\n private async getFaceCrop(video: HTMLVideoElement, landmarks: NormalizedLandmark[]): Promise<HTMLCanvasElement> {\r\n \r\n const xs = landmarks.map(l => l.x * video.videoWidth);\r\n const ys = landmarks.map(l => l.y * video.videoHeight);\r\n \r\n const minX = Math.min(...xs);\r\n const maxX = Math.max(...xs);\r\n const minY = Math.min(...ys);\r\n const maxY = Math.max(...ys);\r\n \r\n const width = maxX - minX;\r\n const height = maxY - minY;\r\n const margin = width * 0.3;\r\n\r\n const sourceX = Math.max(0, minX - margin);\r\n const sourceY = Math.max(0, minY - margin);\r\n const sourceW = Math.min(video.videoWidth - sourceX, width + margin * 2);\r\n const sourceH = Math.min(video.videoHeight - sourceY, height + margin * 2);\r\n\r\n const ctx = this.offscreenCanvas.getContext(\"2d\")!;\r\n\r\n try {\r\n // 2. Extract the bitmap (This bypasses many canvas-tainting triggers)\r\n const bitmap = await createImageBitmap(video, sourceX, sourceY, sourceW, sourceH);\r\n \r\n ctx.clearRect(0, 0, 224, 224);\r\n \r\n // 3. Draw the clean bitmap to the offscreen canvas\r\n ctx.drawImage(bitmap, 0, 0, 224, 224);\r\n \r\n // 4. Important: close the bitmap to free memory\r\n bitmap.close();\r\n } catch (e) {\r\n console.error(\"[LivenessEngine] Bitmap extraction failed, falling back to direct draw\", e);\r\n // Fallback if createImageBitmap is not supported or fails\r\n const ctx = this.offscreenCanvas.getContext(\"2d\")!;\r\n ctx.drawImage(video, sourceX, sourceY, sourceW, sourceH, 0, 0, 224, 224);\r\n }\r\n\r\n return this.offscreenCanvas;\r\n }\r\n}","import { Injectable, NgZone, OnDestroy } from '@angular/core';\r\nimport { BehaviorSubject, Observable } from 'rxjs';\r\nimport { LivenessEngine, LivenessState, LivenessEngineConfig } from '../core/LivenessEngine';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class LivenessService implements OnDestroy {\r\n private engine!: LivenessEngine;\r\n private stateSubject = new BehaviorSubject<LivenessState | null>(null);\r\n \r\n // Components will subscribe to this\r\n public state$: Observable<LivenessState | null> = this.stateSubject.asObservable();\r\n\r\n constructor(private ngZone: NgZone) {}\r\n\r\n public init(config: LivenessEngineConfig) {\r\n // Run inside runOutsideAngular to prevent 60fps change detection triggers\r\n this.ngZone.runOutsideAngular(() => {\r\n this.engine = new LivenessEngine({\r\n ...config,\r\n onStateChange: (state) => {\r\n // Bring state changes BACK into the zone so the UI updates\r\n this.ngZone.run(() => this.stateSubject.next(state));\r\n }\r\n });\r\n this.engine.loadModels();\r\n });\r\n }\r\n\r\n public attach(video: HTMLVideoElement) {\r\n this.engine?.attachVideo(video);\r\n }\r\n\r\n public start() {\r\n this.engine?.start();\r\n }\r\n\r\n public reset() {\r\n this.engine?.reset();\r\n }\r\n\r\n ngOnDestroy() {\r\n this.engine?.stop();\r\n }\r\n}","import { Component, ElementRef, ViewChild, AfterViewInit, Input, Output, EventEmitter, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';\r\nimport { LivenessService } from './liveness.service';\r\nimport { LivenessSDKResult, Challenge, LivenessState } from '../core/LivenessEngine';\r\nimport { CommonModule } from '@angular/common'\r\n\r\n@Component({\r\n selector: 'LivenessCheck',\r\n standalone: true, // Make it standalone\r\n imports: [CommonModule], // Add CommonModule here to fix NG8002\r\n templateUrl: './liveness.component.html',\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\n\r\nexport class LivenessComponent implements OnInit, AfterViewInit, OnDestroy {\r\n @ViewChild('webcam') webcamRef!: ElementRef<HTMLVideoElement>;\r\n\r\n // --- Logic Configuration ---\r\n @Input() apiUrl!: string;\r\n @Input() duration = 60;\r\n @Input() smileThreshold?: number;\r\n @Input() blinkThreshold?: number;\r\n @Input() minturnHeadThreshold?: number;\r\n @Input() maxturnHeadThreshold?: number;\r\n\r\n // --- Styling Configuration (Class Names) ---\r\n @Input() containerClass = '';\r\n @Input() videoWrapperClass = '';\r\n @Input() videoClass = '';\r\n @Input() timerClass = '';\r\n @Input() stateClass = '';\r\n @Input() challengeTextClass = '';\r\n @Input() buttonClass = '';\r\n @Input() retryButtonClass = '';\r\n @Input() statusOverlayClass = '';\r\n @Input() successMessageClass = '';\r\n @Input() errorMessageClass = '';\r\n @Input() instructionBoxClass = '';\r\n\r\n // --- Content Configuration ---\r\n @Input() successMessage = 'Verification Successful!';\r\n @Input() errorMessage = 'Verification failed. Please try again.';\r\n @Input() retryButtonLabel = 'Try Again';\r\n @Input() startButtonLabel = 'Start Verification';\r\n @Input() challengeMapping: Record<Challenge, string> = {\r\n 'Smile': 'Smile',\r\n 'Blink': 'Blink',\r\n 'Turn_Head': 'Turn Head',\r\n 'Thumbs_Up': 'Thumbs Up' // Default with a space\r\n };\r\n\r\n @Output() onComplete = new EventEmitter<LivenessSDKResult>();\r\n @Output() onError = new EventEmitter<any>();\r\n @Output() onStateChange = new EventEmitter<LivenessState | null>();\r\n\r\n constructor(public liveness: LivenessService) {}\r\n\r\n ngOnInit() {\r\n // Pass the custom thresholds directly to the service\r\n \r\n\r\n this.liveness.state$.subscribe(state => {\r\n // This bridges the Service to the Component's @Output\r\n this.onStateChange.emit(state);\r\n });\r\n\r\n }\r\n\r\n async ngAfterViewInit() {\r\n try {\r\n const stream = await navigator.mediaDevices.getUserMedia({ \r\n video: { width: 640, height: 480, facingMode: 'user' } \r\n });\r\n const video = this.webcamRef.nativeElement;\r\n video.srcObject = stream;\r\n video.onloadedmetadata = () => {\r\n video.play();\r\n\r\n this.liveness.init({\r\n apiUrl: this.apiUrl,\r\n duration: this.duration,\r\n smileThreshold: this.smileThreshold,\r\n blinkThreshold: this.blinkThreshold,\r\n minturnHeadThreshold: this.minturnHeadThreshold,\r\n maxturnHeadThreshold: this.maxturnHeadThreshold,\r\n onComplete: (res) => this.onComplete.emit(res),\r\n onError: (err) => this.onError.emit(err)\r\n });\r\n\r\n this.liveness.attach(video);\r\n };\r\n } catch (e) {\r\n this.onError.emit({ success: false, reason: 'Camera access denied' });\r\n }\r\n }\r\n\r\n ngOnDestroy() {\r\n const stream = this.webcamRef?.nativeElement?.srcObject as MediaStream;\r\n stream?.getTracks().forEach(track => track.stop());\r\n }\r\n}","<div [ngClass]=\"containerClass\">\r\n <div [ngClass]=\"videoWrapperClass\">\r\n <video #webcam \r\n autoplay \r\n playsinline \r\n muted \r\n [ngClass]=\"videoClass\" \r\n style=\"transform: scaleX(-1);\">\r\n </video>\r\n\r\n <ng-container *ngIf=\"(liveness.state$ | async) as state\">\r\n <div [ngClass]=\"statusOverlayClass\">\r\n \r\n <div class=\"instruction-box\">\r\n <h2 class=\"status-text\" [ngClass] = \"stateClass\">{{ state.status | uppercase }}</h2>\r\n \r\n <p *ngIf=\"state.status === 'capturing'\" \r\n [ngClass]=\"challengeTextClass\">\r\n {{ challengeMapping[state.sequence[state.currentStep]] }}\r\n </p>\r\n\r\n <p *ngIf=\"state.status === 'success'\"\r\n [ngClass]=\"successMessageClass\">\r\n {{ successMessage }}\r\n </p>\r\n \r\n <p *ngIf=\"state.status === 'error' || state.status === 'expired'\" \r\n [ngClass]=\"errorMessageClass\">\r\n {{ errorMessage }}\r\n </p>\r\n </div>\r\n\r\n <div *ngIf=\"state.status === 'capturing'\" \r\n [ngClass]=\"timerClass\">\r\n {{ state.timeLeft }}\r\n </div>\r\n\r\n <div class=\"action-area\">\r\n <button *ngIf=\"state.status === 'ready'\" \r\n (click)=\"liveness.start()\"\r\n [ngClass]=\"buttonClass\">\r\n {{ startButtonLabel }}\r\n </button>\r\n \r\n <button *ngIf=\"state.status === 'error' || state.status === 'expired'\" \r\n (click)=\"liveness.reset()\"\r\n [ngClass]=\"retryButtonClass\">\r\n {{ retryButtonLabel }}\r\n </button>\r\n </div>\r\n\r\n </div>\r\n </ng-container>\r\n </div>\r\n</div>","// src/api.ts\r\n\r\nimport { Challenge } from \"./core/LivenessEngine\";\r\n\r\nexport interface LivenessResponse {\r\n is_live: boolean;\r\n reason?: string;\r\n skin_confidence?: number;\r\n [key: string]: any; // allow extra fields if backend returns more\r\n}\r\n\r\n/**\r\n * Sends captured frames to the backend API for liveness verification.\r\n * @param apiUrl - Base URL of the liveness backend\r\n * @param frameBlobs - Array of Blob objects representing captured frames\r\n * @param challenge - The current challenge string\r\n * @returns LivenessResponse from backend\r\n */\r\nexport const verifyLiveness = async (\r\n apiUrl: string,\r\n frameBlobs: Blob[],\r\n challenge: Challenge[]\r\n): Promise<LivenessResponse> => {\r\n const formData = new FormData();\r\n\r\n frameBlobs.forEach((blob, i) => {\r\n formData.append('files', blob, `frame_${i}.jpg`);\r\n });\r\n formData.append('challenge', JSON.stringify(challenge));\r\n\r\n const response = await fetch(`${apiUrl}/v1/verify`, {\r\n method: 'POST',\r\n body: formData,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(\"Network response was not ok\");\r\n }\r\n\r\n const data: LivenessResponse = await response.json();\r\n return data;\r\n};","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.LivenessService"],"mappings":"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"}
@@ -45,6 +45,10 @@ declare class LivenessEngine {
45
45
  private timerId;
46
46
  private requestId;
47
47
  private heartbeatId;
48
+ private warningCount;
49
+ private readonly MAX_WARNINGS;
50
+ private lastWarningMsg;
51
+ private isDetectionPaused;
48
52
  private anchorRatios;
49
53
  private lastNosePos;
50
54
  private consecutiveMissingFrames;
@@ -65,6 +69,7 @@ declare class LivenessEngine {
65
69
  attachVideo: (video: HTMLVideoElement) => void;
66
70
  private verifyIdentity;
67
71
  private checkMovement;
72
+ private handleViolation;
68
73
  private failInstantly;
69
74
  start: () => void;
70
75
  stop: () => void;
@@ -41,6 +41,10 @@ export declare class LivenessEngine {
41
41
  private timerId;
42
42
  private requestId;
43
43
  private heartbeatId;
44
+ private warningCount;
45
+ private readonly MAX_WARNINGS;
46
+ private lastWarningMsg;
47
+ private isDetectionPaused;
44
48
  private anchorRatios;
45
49
  private lastNosePos;
46
50
  private consecutiveMissingFrames;
@@ -61,6 +65,7 @@ export declare class LivenessEngine {
61
65
  attachVideo: (video: HTMLVideoElement) => void;
62
66
  private verifyIdentity;
63
67
  private checkMovement;
68
+ private handleViolation;
64
69
  private failInstantly;
65
70
  start: () => void;
66
71
  stop: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"LivenessEngine.d.ts","sourceRoot":"","sources":["../../src/core/LivenessEngine.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,WAAW,GAAG,WAAW,CAAC;AAEtE,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,iBAAiB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,WAAW,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IAC1F,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,iBAAiB,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC/C,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC9C;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,MAAM,CAA4F;IAC1G,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,KAAK,CAAgB;IAE7B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,sBAAsB,CAAS;IACvC,OAAO,CAAC,OAAO,CAA+C;IAC9D,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,WAAW,CAA+C;IAGlE,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,WAAW,CAAyC;IAC5D,OAAO,CAAC,wBAAwB,CAAK;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAM;IAC9B,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA6B;IAC/D,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAM;IAEzC,OAAO,CAAC,eAAe,CAAoC;IAC3D,OAAO,CAAC,cAAc,CAA6D;gBAEvE,MAAM,EAAE,oBAAoB;IA2BxC;;OAEG;IACU,UAAU;IAoCvB;;OAEG;IACI,WAAW,GAAI,OAAO,gBAAgB,UAG3C;IAIF,OAAO,CAAC,cAAc;IAiBtB,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,aAAa;IAMd,KAAK,aAsBV;IAEK,IAAI,aAST;IAEK,KAAK,aAiBZ;IAEA,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,UAAU,CAwDhB;IAEF,OAAO,CAAC,iBAAiB;IAqCzB,OAAO,CAAC,WAAW;YA0BL,cAAc;IAqC5B,OAAO,CAAC,WAAW;CAwBpB"}
1
+ {"version":3,"file":"LivenessEngine.d.ts","sourceRoot":"","sources":["../../src/core/LivenessEngine.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,WAAW,GAAG,WAAW,CAAC;AAEtE,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,iBAAiB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,WAAW,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IAC1F,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,iBAAiB,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC/C,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC9C;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,MAAM,CAA4F;IAC1G,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,KAAK,CAAgB;IAE7B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,sBAAsB,CAAS;IACvC,OAAO,CAAC,OAAO,CAA+C;IAC9D,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,WAAW,CAA+C;IAElE,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAK;IAClC,OAAO,CAAC,cAAc,CAAM;IAC5B,OAAO,CAAC,iBAAiB,CAAS;IAGlC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,WAAW,CAAyC;IAC5D,OAAO,CAAC,wBAAwB,CAAK;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAM;IAC9B,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA6B;IAC/D,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAM;IAEzC,OAAO,CAAC,eAAe,CAAoC;IAC3D,OAAO,CAAC,cAAc,CAA6D;gBAEvE,MAAM,EAAE,oBAAoB;IA2BxC;;OAEG;IACU,UAAU;IAoCvB;;OAEG;IACI,WAAW,GAAI,OAAO,gBAAgB,UAI3C;IAGF,OAAO,CAAC,cAAc;IAiBtB,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,eAAe;IAsBvB,OAAO,CAAC,aAAa;IAMd,KAAK,aAsBV;IAEK,IAAI,aAST;IAEK,KAAK,aAmBZ;IAEA,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,UAAU,CA0DhB;YAEY,iBAAiB;IAqC/B,OAAO,CAAC,WAAW;YA0BL,cAAc;YAqCd,WAAW;CAyC1B"}
package/dist/index.cjs CHANGED
@@ -1,3 +1,3 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const k=require("./api-CWu5ff9j.cjs"),U=require("./LivenessEngine-BqatmbVS.cjs"),u=require("@angular/core"),q=require("@angular/common");var S=function(r,e){return S=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,n){t.__proto__=n}||function(t,n){for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(t[o]=n[o])},S(r,e)};function v(r,e){if(typeof e!="function"&&e!==null)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");S(r,e);function t(){this.constructor=r}r.prototype=e===null?Object.create(e):(t.prototype=e.prototype,new t)}function _(r){var e=typeof Symbol=="function"&&Symbol.iterator,t=e&&r[e],n=0;if(t)return t.call(r);if(r&&typeof r.length=="number")return{next:function(){return r&&n>=r.length&&(r=void 0),{value:r&&r[n++],done:!r}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")}function w(r,e){var t=typeof Symbol=="function"&&r[Symbol.iterator];if(!t)return r;var n=t.call(r),o,s=[],i;try{for(;(e===void 0||e-- >0)&&!(o=n.next()).done;)s.push(o.value)}catch(c){i={error:c}}finally{try{o&&!o.done&&(t=n.return)&&t.call(n)}finally{if(i)throw i.error}}return s}function E(r,e,t){if(t||arguments.length===2)for(var n=0,o=e.length,s;n<o;n++)(s||!(n in e))&&(s||(s=Array.prototype.slice.call(e,0,n)),s[n]=e[n]);return r.concat(s||Array.prototype.slice.call(e))}function h(r){return typeof r=="function"}function B(r){var e=function(n){Error.call(n),n.stack=new Error().stack},t=r(e);return t.prototype=Object.create(Error.prototype),t.prototype.constructor=t,t}var C=B(function(r){return function(t){r(this),this.message=t?t.length+` errors occurred during unsubscription:
2
- `+t.map(function(n,o){return o+1+") "+n.toString()}).join(`
3
- `):"",this.name="UnsubscriptionError",this.errors=t}});function O(r,e){if(r){var t=r.indexOf(e);0<=t&&r.splice(t,1)}}var m=function(){function r(e){this.initialTeardown=e,this.closed=!1,this._parentage=null,this._finalizers=null}return r.prototype.unsubscribe=function(){var e,t,n,o,s;if(!this.closed){this.closed=!0;var i=this._parentage;if(i)if(this._parentage=null,Array.isArray(i))try{for(var c=_(i),p=c.next();!p.done;p=c.next()){var g=p.value;g.remove(this)}}catch(l){e={error:l}}finally{try{p&&!p.done&&(t=c.return)&&t.call(c)}finally{if(e)throw e.error}}else i.remove(this);var I=this.initialTeardown;if(h(I))try{I()}catch(l){s=l instanceof C?l.errors:[l]}var T=this._finalizers;if(T){this._finalizers=null;try{for(var d=_(T),f=d.next();!f.done;f=d.next()){var F=f.value;try{x(F)}catch(l){s=s??[],l instanceof C?s=E(E([],w(s)),w(l.errors)):s.push(l)}}}catch(l){n={error:l}}finally{try{f&&!f.done&&(o=d.return)&&o.call(d)}finally{if(n)throw n.error}}}if(s)throw new C(s)}},r.prototype.add=function(e){var t;if(e&&e!==this)if(this.closed)x(e);else{if(e instanceof r){if(e.closed||e._hasParent(this))return;e._addParent(this)}(this._finalizers=(t=this._finalizers)!==null&&t!==void 0?t:[]).push(e)}},r.prototype._hasParent=function(e){var t=this._parentage;return t===e||Array.isArray(t)&&t.includes(e)},r.prototype._addParent=function(e){var t=this._parentage;this._parentage=Array.isArray(t)?(t.push(e),t):t?[t,e]:e},r.prototype._removeParent=function(e){var t=this._parentage;t===e?this._parentage=null:Array.isArray(t)&&O(t,e)},r.prototype.remove=function(e){var t=this._finalizers;t&&O(t,e),e instanceof r&&e._removeParent(this)},r.EMPTY=function(){var e=new r;return e.closed=!0,e}(),r}(),V=m.EMPTY;function H(r){return r instanceof m||r&&"closed"in r&&h(r.remove)&&h(r.add)&&h(r.unsubscribe)}function x(r){h(r)?r():r.unsubscribe()}var Y={Promise:void 0},$={setTimeout:function(r,e){for(var t=[],n=2;n<arguments.length;n++)t[n-2]=arguments[n];return setTimeout.apply(void 0,E([r,e],w(t)))},clearTimeout:function(r){return clearTimeout(r)},delegate:void 0};function Z(r){$.setTimeout(function(){throw r})}function P(){}function b(r){r()}var D=function(r){v(e,r);function e(t){var n=r.call(this)||this;return n.isStopped=!1,t?(n.destination=t,H(t)&&t.add(n)):n.destination=J,n}return e.create=function(t,n,o){return new L(t,n,o)},e.prototype.next=function(t){this.isStopped||this._next(t)},e.prototype.error=function(t){this.isStopped||(this.isStopped=!0,this._error(t))},e.prototype.complete=function(){this.isStopped||(this.isStopped=!0,this._complete())},e.prototype.unsubscribe=function(){this.closed||(this.isStopped=!0,r.prototype.unsubscribe.call(this),this.destination=null)},e.prototype._next=function(t){this.destination.next(t)},e.prototype._error=function(t){try{this.destination.error(t)}finally{this.unsubscribe()}},e.prototype._complete=function(){try{this.destination.complete()}finally{this.unsubscribe()}},e}(m),W=function(){function r(e){this.partialObserver=e}return r.prototype.next=function(e){var t=this.partialObserver;if(t.next)try{t.next(e)}catch(n){y(n)}},r.prototype.error=function(e){var t=this.partialObserver;if(t.error)try{t.error(e)}catch(n){y(n)}else y(e)},r.prototype.complete=function(){var e=this.partialObserver;if(e.complete)try{e.complete()}catch(t){y(t)}},r}(),L=function(r){v(e,r);function e(t,n,o){var s=r.call(this)||this,i;return h(t)||!t?i={next:t??void 0,error:n??void 0,complete:o??void 0}:i=t,s.destination=new W(i),s}return e}(D);function y(r){Z(r)}function G(r){throw r}var J={closed:!0,next:P,error:G,complete:P},K=function(){return typeof Symbol=="function"&&Symbol.observable||"@@observable"}();function Q(r){return r}function X(r){return r.length===0?Q:r.length===1?r[0]:function(t){return r.reduce(function(n,o){return o(n)},t)}}var j=function(){function r(e){e&&(this._subscribe=e)}return r.prototype.lift=function(e){var t=new r;return t.source=this,t.operator=e,t},r.prototype.subscribe=function(e,t,n){var o=this,s=N(e)?e:new L(e,t,n);return b(function(){var i=o,c=i.operator,p=i.source;s.add(c?c.call(s,p):p?o._subscribe(s):o._trySubscribe(s))}),s},r.prototype._trySubscribe=function(e){try{return this._subscribe(e)}catch(t){e.error(t)}},r.prototype.forEach=function(e,t){var n=this;return t=A(t),new t(function(o,s){var i=new L({next:function(c){try{e(c)}catch(p){s(p),i.unsubscribe()}},error:s,complete:o});n.subscribe(i)})},r.prototype._subscribe=function(e){var t;return(t=this.source)===null||t===void 0?void 0:t.subscribe(e)},r.prototype[K]=function(){return this},r.prototype.pipe=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];return X(e)(this)},r.prototype.toPromise=function(e){var t=this;return e=A(e),new e(function(n,o){var s;t.subscribe(function(i){return s=i},function(i){return o(i)},function(){return n(s)})})},r.create=function(e){return new r(e)},r}();function A(r){var e;return(e=r??Y.Promise)!==null&&e!==void 0?e:Promise}function z(r){return r&&h(r.next)&&h(r.error)&&h(r.complete)}function N(r){return r&&r instanceof D||z(r)&&H(r)}var tt=B(function(r){return function(){r(this),this.name="ObjectUnsubscribedError",this.message="object unsubscribed"}}),R=function(r){v(e,r);function e(){var t=r.call(this)||this;return t.closed=!1,t.currentObservers=null,t.observers=[],t.isStopped=!1,t.hasError=!1,t.thrownError=null,t}return e.prototype.lift=function(t){var n=new M(this,this);return n.operator=t,n},e.prototype._throwIfClosed=function(){if(this.closed)throw new tt},e.prototype.next=function(t){var n=this;b(function(){var o,s;if(n._throwIfClosed(),!n.isStopped){n.currentObservers||(n.currentObservers=Array.from(n.observers));try{for(var i=_(n.currentObservers),c=i.next();!c.done;c=i.next()){var p=c.value;p.next(t)}}catch(g){o={error:g}}finally{try{c&&!c.done&&(s=i.return)&&s.call(i)}finally{if(o)throw o.error}}}})},e.prototype.error=function(t){var n=this;b(function(){if(n._throwIfClosed(),!n.isStopped){n.hasError=n.isStopped=!0,n.thrownError=t;for(var o=n.observers;o.length;)o.shift().error(t)}})},e.prototype.complete=function(){var t=this;b(function(){if(t._throwIfClosed(),!t.isStopped){t.isStopped=!0;for(var n=t.observers;n.length;)n.shift().complete()}})},e.prototype.unsubscribe=function(){this.isStopped=this.closed=!0,this.observers=this.currentObservers=null},Object.defineProperty(e.prototype,"observed",{get:function(){var t;return((t=this.observers)===null||t===void 0?void 0:t.length)>0},enumerable:!1,configurable:!0}),e.prototype._trySubscribe=function(t){return this._throwIfClosed(),r.prototype._trySubscribe.call(this,t)},e.prototype._subscribe=function(t){return this._throwIfClosed(),this._checkFinalizedStatuses(t),this._innerSubscribe(t)},e.prototype._innerSubscribe=function(t){var n=this,o=this,s=o.hasError,i=o.isStopped,c=o.observers;return s||i?V:(this.currentObservers=null,c.push(t),new m(function(){n.currentObservers=null,O(c,t)}))},e.prototype._checkFinalizedStatuses=function(t){var n=this,o=n.hasError,s=n.thrownError,i=n.isStopped;o?t.error(s):i&&t.complete()},e.prototype.asObservable=function(){var t=new j;return t.source=this,t},e.create=function(t,n){return new M(t,n)},e}(j),M=function(r){v(e,r);function e(t,n){var o=r.call(this)||this;return o.destination=t,o.source=n,o}return e.prototype.next=function(t){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,t)},e.prototype.error=function(t){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,t)},e.prototype.complete=function(){var t,n;(n=(t=this.destination)===null||t===void 0?void 0:t.complete)===null||n===void 0||n.call(t)},e.prototype._subscribe=function(t){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(t))!==null&&o!==void 0?o:V},e}(R),et=function(r){v(e,r);function e(t){var n=r.call(this)||this;return n._value=t,n}return Object.defineProperty(e.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),e.prototype._subscribe=function(t){var n=r.prototype._subscribe.call(this,t);return!n.closed&&t.next(this._value),n},e.prototype.getValue=function(){var t=this,n=t.hasError,o=t.thrownError,s=t._value;if(n)throw o;return this._throwIfClosed(),s},e.prototype.next=function(t){r.prototype.next.call(this,this._value=t)},e}(R),rt=Object.getOwnPropertyDescriptor,nt=(r,e,t,n)=>{for(var o=n>1?void 0:n?rt(e,t):e,s=r.length-1,i;s>=0;s--)(i=r[s])&&(o=i(o)||o);return o};exports.LivenessService=class{constructor(e){this.ngZone=e,this.stateSubject=new et(null),this.state$=this.stateSubject.asObservable()}init(e){this.ngZone.runOutsideAngular(()=>{this.engine=new U.LivenessEngine({...e,onStateChange:t=>{this.ngZone.run(()=>this.stateSubject.next(t))}}),this.engine.loadModels()})}attach(e){var t;(t=this.engine)==null||t.attachVideo(e)}start(){var e;(e=this.engine)==null||e.start()}reset(){var e;(e=this.engine)==null||e.reset()}ngOnDestroy(){var e;(e=this.engine)==null||e.stop()}};exports.LivenessService=nt([u.Injectable({providedIn:"root"})],exports.LivenessService);var ot=Object.defineProperty,st=Object.getOwnPropertyDescriptor,a=(r,e,t,n)=>{for(var o=n>1?void 0:n?st(e,t):e,s=r.length-1,i;s>=0;s--)(i=r[s])&&(o=(n?i(e,t,o):i(o))||o);return n&&o&&ot(e,t,o),o};exports.LivenessComponent=class{constructor(e){this.liveness=e,this.duration=60,this.containerClass="",this.videoWrapperClass="",this.videoClass="",this.timerClass="",this.stateClass="",this.challengeTextClass="",this.buttonClass="",this.retryButtonClass="",this.statusOverlayClass="",this.successMessageClass="",this.errorMessageClass="",this.instructionBoxClass="",this.successMessage="Verification Successful!",this.errorMessage="Verification failed. Please try again.",this.retryButtonLabel="Try Again",this.startButtonLabel="Start Verification",this.challengeMapping={Smile:"Smile",Blink:"Blink",Turn_Head:"Turn Head",Thumbs_Up:"Thumbs Up"},this.onComplete=new u.EventEmitter,this.onError=new u.EventEmitter,this.onStateChange=new u.EventEmitter}ngOnInit(){this.liveness.state$.subscribe(e=>{this.onStateChange.emit(e)})}async ngAfterViewInit(){try{const e=await navigator.mediaDevices.getUserMedia({video:{width:640,height:480,facingMode:"user"}}),t=this.webcamRef.nativeElement;t.srcObject=e,t.onloadedmetadata=()=>{t.play(),this.liveness.init({apiUrl:this.apiUrl,duration:this.duration,smileThreshold:this.smileThreshold,blinkThreshold:this.blinkThreshold,minturnHeadThreshold:this.minturnHeadThreshold,maxturnHeadThreshold:this.maxturnHeadThreshold,onComplete:n=>this.onComplete.emit(n),onError:n=>this.onError.emit(n)}),this.liveness.attach(t)}}catch{this.onError.emit({success:!1,reason:"Camera access denied"})}}ngOnDestroy(){var t,n;const e=(n=(t=this.webcamRef)==null?void 0:t.nativeElement)==null?void 0:n.srcObject;e==null||e.getTracks().forEach(o=>o.stop())}};a([u.ViewChild("webcam")],exports.LivenessComponent.prototype,"webcamRef",2);a([u.Input()],exports.LivenessComponent.prototype,"apiUrl",2);a([u.Input()],exports.LivenessComponent.prototype,"duration",2);a([u.Input()],exports.LivenessComponent.prototype,"smileThreshold",2);a([u.Input()],exports.LivenessComponent.prototype,"blinkThreshold",2);a([u.Input()],exports.LivenessComponent.prototype,"minturnHeadThreshold",2);a([u.Input()],exports.LivenessComponent.prototype,"maxturnHeadThreshold",2);a([u.Input()],exports.LivenessComponent.prototype,"containerClass",2);a([u.Input()],exports.LivenessComponent.prototype,"videoWrapperClass",2);a([u.Input()],exports.LivenessComponent.prototype,"videoClass",2);a([u.Input()],exports.LivenessComponent.prototype,"timerClass",2);a([u.Input()],exports.LivenessComponent.prototype,"stateClass",2);a([u.Input()],exports.LivenessComponent.prototype,"challengeTextClass",2);a([u.Input()],exports.LivenessComponent.prototype,"buttonClass",2);a([u.Input()],exports.LivenessComponent.prototype,"retryButtonClass",2);a([u.Input()],exports.LivenessComponent.prototype,"statusOverlayClass",2);a([u.Input()],exports.LivenessComponent.prototype,"successMessageClass",2);a([u.Input()],exports.LivenessComponent.prototype,"errorMessageClass",2);a([u.Input()],exports.LivenessComponent.prototype,"instructionBoxClass",2);a([u.Input()],exports.LivenessComponent.prototype,"successMessage",2);a([u.Input()],exports.LivenessComponent.prototype,"errorMessage",2);a([u.Input()],exports.LivenessComponent.prototype,"retryButtonLabel",2);a([u.Input()],exports.LivenessComponent.prototype,"startButtonLabel",2);a([u.Input()],exports.LivenessComponent.prototype,"challengeMapping",2);a([u.Output()],exports.LivenessComponent.prototype,"onComplete",2);a([u.Output()],exports.LivenessComponent.prototype,"onError",2);a([u.Output()],exports.LivenessComponent.prototype,"onStateChange",2);exports.LivenessComponent=a([u.Component({selector:"LivenessCheck",standalone:!0,imports:[q.CommonModule],templateUrl:"./liveness.component.html",encapsulation:u.ViewEncapsulation.None})],exports.LivenessComponent);exports.verifyLiveness=k.verifyLiveness;exports.LivenessEngine=U.LivenessEngine;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const k=require("./api-CWu5ff9j.cjs"),m=require("./LivenessCheck-6oh9vnb0.cjs"),u=require("@angular/core"),q=require("@angular/common");var _=function(r,t){return _=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,n){e.__proto__=n}||function(e,n){for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])},_(r,t)};function v(r,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");_(r,t);function e(){this.constructor=r}r.prototype=t===null?Object.create(t):(e.prototype=t.prototype,new e)}function w(r){var t=typeof Symbol=="function"&&Symbol.iterator,e=t&&r[t],n=0;if(e)return e.call(r);if(r&&typeof r.length=="number")return{next:function(){return r&&n>=r.length&&(r=void 0),{value:r&&r[n++],done:!r}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function E(r,t){var e=typeof Symbol=="function"&&r[Symbol.iterator];if(!e)return r;var n=e.call(r),o,s=[],i;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)s.push(o.value)}catch(c){i={error:c}}finally{try{o&&!o.done&&(e=n.return)&&e.call(n)}finally{if(i)throw i.error}}return s}function L(r,t,e){if(e||arguments.length===2)for(var n=0,o=t.length,s;n<o;n++)(s||!(n in t))&&(s||(s=Array.prototype.slice.call(t,0,n)),s[n]=t[n]);return r.concat(s||Array.prototype.slice.call(t))}function h(r){return typeof r=="function"}function B(r){var t=function(n){Error.call(n),n.stack=new Error().stack},e=r(t);return e.prototype=Object.create(Error.prototype),e.prototype.constructor=e,e}var S=B(function(r){return function(e){r(this),this.message=e?e.length+` errors occurred during unsubscription:
2
+ `+e.map(function(n,o){return o+1+") "+n.toString()}).join(`
3
+ `):"",this.name="UnsubscriptionError",this.errors=e}});function O(r,t){if(r){var e=r.indexOf(t);0<=e&&r.splice(e,1)}}var g=function(){function r(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return r.prototype.unsubscribe=function(){var t,e,n,o,s;if(!this.closed){this.closed=!0;var i=this._parentage;if(i)if(this._parentage=null,Array.isArray(i))try{for(var c=w(i),p=c.next();!p.done;p=c.next()){var C=p.value;C.remove(this)}}catch(l){t={error:l}}finally{try{p&&!p.done&&(e=c.return)&&e.call(c)}finally{if(t)throw t.error}}else i.remove(this);var T=this.initialTeardown;if(h(T))try{T()}catch(l){s=l instanceof S?l.errors:[l]}var x=this._finalizers;if(x){this._finalizers=null;try{for(var d=w(x),f=d.next();!f.done;f=d.next()){var F=f.value;try{P(F)}catch(l){s=s??[],l instanceof S?s=L(L([],E(s)),E(l.errors)):s.push(l)}}}catch(l){n={error:l}}finally{try{f&&!f.done&&(o=d.return)&&o.call(d)}finally{if(n)throw n.error}}}if(s)throw new S(s)}},r.prototype.add=function(t){var e;if(t&&t!==this)if(this.closed)P(t);else{if(t instanceof r){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(e=this._finalizers)!==null&&e!==void 0?e:[]).push(t)}},r.prototype._hasParent=function(t){var e=this._parentage;return e===t||Array.isArray(e)&&e.includes(t)},r.prototype._addParent=function(t){var e=this._parentage;this._parentage=Array.isArray(e)?(e.push(t),e):e?[e,t]:t},r.prototype._removeParent=function(t){var e=this._parentage;e===t?this._parentage=null:Array.isArray(e)&&O(e,t)},r.prototype.remove=function(t){var e=this._finalizers;e&&O(e,t),t instanceof r&&t._removeParent(this)},r.EMPTY=function(){var t=new r;return t.closed=!0,t}(),r}(),V=g.EMPTY;function D(r){return r instanceof g||r&&"closed"in r&&h(r.remove)&&h(r.add)&&h(r.unsubscribe)}function P(r){h(r)?r():r.unsubscribe()}var Y={Promise:void 0},$={setTimeout:function(r,t){for(var e=[],n=2;n<arguments.length;n++)e[n-2]=arguments[n];return setTimeout.apply(void 0,L([r,t],E(e)))},clearTimeout:function(r){return clearTimeout(r)},delegate:void 0};function Z(r){$.setTimeout(function(){throw r})}function j(){}function b(r){r()}var H=function(r){v(t,r);function t(e){var n=r.call(this)||this;return n.isStopped=!1,e?(n.destination=e,D(e)&&e.add(n)):n.destination=G,n}return t.create=function(e,n,o){return new I(e,n,o)},t.prototype.next=function(e){this.isStopped||this._next(e)},t.prototype.error=function(e){this.isStopped||(this.isStopped=!0,this._error(e))},t.prototype.complete=function(){this.isStopped||(this.isStopped=!0,this._complete())},t.prototype.unsubscribe=function(){this.closed||(this.isStopped=!0,r.prototype.unsubscribe.call(this),this.destination=null)},t.prototype._next=function(e){this.destination.next(e)},t.prototype._error=function(e){try{this.destination.error(e)}finally{this.unsubscribe()}},t.prototype._complete=function(){try{this.destination.complete()}finally{this.unsubscribe()}},t}(g),K=function(){function r(t){this.partialObserver=t}return r.prototype.next=function(t){var e=this.partialObserver;if(e.next)try{e.next(t)}catch(n){y(n)}},r.prototype.error=function(t){var e=this.partialObserver;if(e.error)try{e.error(t)}catch(n){y(n)}else y(t)},r.prototype.complete=function(){var t=this.partialObserver;if(t.complete)try{t.complete()}catch(e){y(e)}},r}(),I=function(r){v(t,r);function t(e,n,o){var s=r.call(this)||this,i;return h(e)||!e?i={next:e??void 0,error:n??void 0,complete:o??void 0}:i=e,s.destination=new K(i),s}return t}(H);function y(r){Z(r)}function W(r){throw r}var G={closed:!0,next:j,error:W,complete:j},J=function(){return typeof Symbol=="function"&&Symbol.observable||"@@observable"}();function Q(r){return r}function X(r){return r.length===0?Q:r.length===1?r[0]:function(e){return r.reduce(function(n,o){return o(n)},e)}}var A=function(){function r(t){t&&(this._subscribe=t)}return r.prototype.lift=function(t){var e=new r;return e.source=this,e.operator=t,e},r.prototype.subscribe=function(t,e,n){var o=this,s=N(t)?t:new I(t,e,n);return b(function(){var i=o,c=i.operator,p=i.source;s.add(c?c.call(s,p):p?o._subscribe(s):o._trySubscribe(s))}),s},r.prototype._trySubscribe=function(t){try{return this._subscribe(t)}catch(e){t.error(e)}},r.prototype.forEach=function(t,e){var n=this;return e=M(e),new e(function(o,s){var i=new I({next:function(c){try{t(c)}catch(p){s(p),i.unsubscribe()}},error:s,complete:o});n.subscribe(i)})},r.prototype._subscribe=function(t){var e;return(e=this.source)===null||e===void 0?void 0:e.subscribe(t)},r.prototype[J]=function(){return this},r.prototype.pipe=function(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];return X(t)(this)},r.prototype.toPromise=function(t){var e=this;return t=M(t),new t(function(n,o){var s;e.subscribe(function(i){return s=i},function(i){return o(i)},function(){return n(s)})})},r.create=function(t){return new r(t)},r}();function M(r){var t;return(t=r??Y.Promise)!==null&&t!==void 0?t:Promise}function z(r){return r&&h(r.next)&&h(r.error)&&h(r.complete)}function N(r){return r&&r instanceof H||z(r)&&D(r)}var ee=B(function(r){return function(){r(this),this.name="ObjectUnsubscribedError",this.message="object unsubscribed"}}),R=function(r){v(t,r);function t(){var e=r.call(this)||this;return e.closed=!1,e.currentObservers=null,e.observers=[],e.isStopped=!1,e.hasError=!1,e.thrownError=null,e}return t.prototype.lift=function(e){var n=new U(this,this);return n.operator=e,n},t.prototype._throwIfClosed=function(){if(this.closed)throw new ee},t.prototype.next=function(e){var n=this;b(function(){var o,s;if(n._throwIfClosed(),!n.isStopped){n.currentObservers||(n.currentObservers=Array.from(n.observers));try{for(var i=w(n.currentObservers),c=i.next();!c.done;c=i.next()){var p=c.value;p.next(e)}}catch(C){o={error:C}}finally{try{c&&!c.done&&(s=i.return)&&s.call(i)}finally{if(o)throw o.error}}}})},t.prototype.error=function(e){var n=this;b(function(){if(n._throwIfClosed(),!n.isStopped){n.hasError=n.isStopped=!0,n.thrownError=e;for(var o=n.observers;o.length;)o.shift().error(e)}})},t.prototype.complete=function(){var e=this;b(function(){if(e._throwIfClosed(),!e.isStopped){e.isStopped=!0;for(var n=e.observers;n.length;)n.shift().complete()}})},t.prototype.unsubscribe=function(){this.isStopped=this.closed=!0,this.observers=this.currentObservers=null},Object.defineProperty(t.prototype,"observed",{get:function(){var e;return((e=this.observers)===null||e===void 0?void 0:e.length)>0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(e){return this._throwIfClosed(),r.prototype._trySubscribe.call(this,e)},t.prototype._subscribe=function(e){return this._throwIfClosed(),this._checkFinalizedStatuses(e),this._innerSubscribe(e)},t.prototype._innerSubscribe=function(e){var n=this,o=this,s=o.hasError,i=o.isStopped,c=o.observers;return s||i?V:(this.currentObservers=null,c.push(e),new g(function(){n.currentObservers=null,O(c,e)}))},t.prototype._checkFinalizedStatuses=function(e){var n=this,o=n.hasError,s=n.thrownError,i=n.isStopped;o?e.error(s):i&&e.complete()},t.prototype.asObservable=function(){var e=new A;return e.source=this,e},t.create=function(e,n){return new U(e,n)},t}(A),U=function(r){v(t,r);function t(e,n){var o=r.call(this)||this;return o.destination=e,o.source=n,o}return t.prototype.next=function(e){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,e)},t.prototype.error=function(e){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,e)},t.prototype.complete=function(){var e,n;(n=(e=this.destination)===null||e===void 0?void 0:e.complete)===null||n===void 0||n.call(e)},t.prototype._subscribe=function(e){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(e))!==null&&o!==void 0?o:V},t}(R),te=function(r){v(t,r);function t(e){var n=r.call(this)||this;return n._value=e,n}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(e){var n=r.prototype._subscribe.call(this,e);return!n.closed&&e.next(this._value),n},t.prototype.getValue=function(){var e=this,n=e.hasError,o=e.thrownError,s=e._value;if(n)throw o;return this._throwIfClosed(),s},t.prototype.next=function(e){r.prototype.next.call(this,this._value=e)},t}(R),re=Object.getOwnPropertyDescriptor,ne=(r,t,e,n)=>{for(var o=n>1?void 0:n?re(t,e):t,s=r.length-1,i;s>=0;s--)(i=r[s])&&(o=i(o)||o);return o};exports.LivenessService=class{constructor(t){this.ngZone=t,this.stateSubject=new te(null),this.state$=this.stateSubject.asObservable()}init(t){this.ngZone.runOutsideAngular(()=>{this.engine=new m.LivenessEngine({...t,onStateChange:e=>{this.ngZone.run(()=>this.stateSubject.next(e))}}),this.engine.loadModels()})}attach(t){var e;(e=this.engine)==null||e.attachVideo(t)}start(){var t;(t=this.engine)==null||t.start()}reset(){var t;(t=this.engine)==null||t.reset()}ngOnDestroy(){var t;(t=this.engine)==null||t.stop()}};exports.LivenessService=ne([u.Injectable({providedIn:"root"})],exports.LivenessService);var oe=Object.defineProperty,se=Object.getOwnPropertyDescriptor,a=(r,t,e,n)=>{for(var o=n>1?void 0:n?se(t,e):t,s=r.length-1,i;s>=0;s--)(i=r[s])&&(o=(n?i(t,e,o):i(o))||o);return n&&o&&oe(t,e,o),o};exports.LivenessComponent=class{constructor(t){this.liveness=t,this.duration=60,this.containerClass="",this.videoWrapperClass="",this.videoClass="",this.timerClass="",this.stateClass="",this.challengeTextClass="",this.buttonClass="",this.retryButtonClass="",this.statusOverlayClass="",this.successMessageClass="",this.errorMessageClass="",this.instructionBoxClass="",this.successMessage="Verification Successful!",this.errorMessage="Verification failed. Please try again.",this.retryButtonLabel="Try Again",this.startButtonLabel="Start Verification",this.challengeMapping={Smile:"Smile",Blink:"Blink",Turn_Head:"Turn Head",Thumbs_Up:"Thumbs Up"},this.onComplete=new u.EventEmitter,this.onError=new u.EventEmitter,this.onStateChange=new u.EventEmitter}ngOnInit(){this.liveness.state$.subscribe(t=>{this.onStateChange.emit(t)})}async ngAfterViewInit(){try{const t=await navigator.mediaDevices.getUserMedia({video:{width:640,height:480,facingMode:"user"}}),e=this.webcamRef.nativeElement;e.srcObject=t,e.onloadedmetadata=()=>{e.play(),this.liveness.init({apiUrl:this.apiUrl,duration:this.duration,smileThreshold:this.smileThreshold,blinkThreshold:this.blinkThreshold,minturnHeadThreshold:this.minturnHeadThreshold,maxturnHeadThreshold:this.maxturnHeadThreshold,onComplete:n=>this.onComplete.emit(n),onError:n=>this.onError.emit(n)}),this.liveness.attach(e)}}catch{this.onError.emit({success:!1,reason:"Camera access denied"})}}ngOnDestroy(){var e,n;const t=(n=(e=this.webcamRef)==null?void 0:e.nativeElement)==null?void 0:n.srcObject;t==null||t.getTracks().forEach(o=>o.stop())}};a([u.ViewChild("webcam")],exports.LivenessComponent.prototype,"webcamRef",2);a([u.Input()],exports.LivenessComponent.prototype,"apiUrl",2);a([u.Input()],exports.LivenessComponent.prototype,"duration",2);a([u.Input()],exports.LivenessComponent.prototype,"smileThreshold",2);a([u.Input()],exports.LivenessComponent.prototype,"blinkThreshold",2);a([u.Input()],exports.LivenessComponent.prototype,"minturnHeadThreshold",2);a([u.Input()],exports.LivenessComponent.prototype,"maxturnHeadThreshold",2);a([u.Input()],exports.LivenessComponent.prototype,"containerClass",2);a([u.Input()],exports.LivenessComponent.prototype,"videoWrapperClass",2);a([u.Input()],exports.LivenessComponent.prototype,"videoClass",2);a([u.Input()],exports.LivenessComponent.prototype,"timerClass",2);a([u.Input()],exports.LivenessComponent.prototype,"stateClass",2);a([u.Input()],exports.LivenessComponent.prototype,"challengeTextClass",2);a([u.Input()],exports.LivenessComponent.prototype,"buttonClass",2);a([u.Input()],exports.LivenessComponent.prototype,"retryButtonClass",2);a([u.Input()],exports.LivenessComponent.prototype,"statusOverlayClass",2);a([u.Input()],exports.LivenessComponent.prototype,"successMessageClass",2);a([u.Input()],exports.LivenessComponent.prototype,"errorMessageClass",2);a([u.Input()],exports.LivenessComponent.prototype,"instructionBoxClass",2);a([u.Input()],exports.LivenessComponent.prototype,"successMessage",2);a([u.Input()],exports.LivenessComponent.prototype,"errorMessage",2);a([u.Input()],exports.LivenessComponent.prototype,"retryButtonLabel",2);a([u.Input()],exports.LivenessComponent.prototype,"startButtonLabel",2);a([u.Input()],exports.LivenessComponent.prototype,"challengeMapping",2);a([u.Output()],exports.LivenessComponent.prototype,"onComplete",2);a([u.Output()],exports.LivenessComponent.prototype,"onError",2);a([u.Output()],exports.LivenessComponent.prototype,"onStateChange",2);exports.LivenessComponent=a([u.Component({selector:"LivenessCheck",standalone:!0,imports:[q.CommonModule],templateUrl:"./liveness.component.html",encapsulation:u.ViewEncapsulation.None})],exports.LivenessComponent);exports.verifyLiveness=k.verifyLiveness;exports.LivenessEngine=m.LivenessEngine;exports.LivenessSDK=m.LivenessSDK;exports.useLiveness=m.useLiveness;