@richard.fadiora/liveness-detection 4.3.13 → 5.0.1

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.
@@ -15,6 +15,15 @@ class LivenessEngine {
15
15
  isStepTransitioningRef = false;
16
16
  timerId = null;
17
17
  requestId = null;
18
+ heartbeatId = null;
19
+ // --- NEW SECURITY TRACKERS ---
20
+ anchorRatios = null;
21
+ lastNosePos = null;
22
+ consecutiveMissingFrames = 0;
23
+ MAX_GAP = 15; // ~250ms buffer
24
+ LIVENESS_LOCK_KEY = "liveness_active_session";
25
+ stabilityFrames = 0;
26
+ REQUIRED_STABILITY = 10; // Wait for ~10 clear frames before locking
18
27
  offscreenCanvas = document.createElement("canvas");
19
28
  CHALLENGE_POOL = ["Smile", "Blink", "Turn_Head", "Thumbs_Up"];
20
29
  constructor(config) {
@@ -36,6 +45,7 @@ class LivenessEngine {
36
45
  timeLeft: this.config.duration,
37
46
  isStepTransitioning: false,
38
47
  errorMsg: "",
48
+ snapshots: [],
39
49
  };
40
50
  this.offscreenCanvas.width = 224;
41
51
  this.offscreenCanvas.height = 224;
@@ -81,7 +91,45 @@ class LivenessEngine {
81
91
  this.webcam = video;
82
92
  console.log("[LivenessEngine] Video stream attached.");
83
93
  };
94
+ // --- NEW SECURITY METHODS ---
95
+ verifyIdentity(landmarks) {
96
+ const eyeDist = Math.sqrt(Math.pow(landmarks[33].x - landmarks[263].x, 2) +
97
+ Math.pow(landmarks[33].y - landmarks[263].y, 2));
98
+ const noseToMouth = Math.abs(landmarks[1].y - landmarks[13].y);
99
+ const currentRatio = eyeDist / (noseToMouth || 1);
100
+ if (this.anchorRatios === null) {
101
+ this.anchorRatios = currentRatio;
102
+ return true;
103
+ }
104
+ const diff = Math.abs(this.anchorRatios - currentRatio) / this.anchorRatios;
105
+ return diff < 0.10; // 10% tolerance for head tilt
106
+ }
107
+ checkMovement(landmarks) {
108
+ const nose = { x: landmarks[1].x, y: landmarks[1].y };
109
+ if (this.lastNosePos) {
110
+ const dist = Math.sqrt(Math.pow(nose.x - this.lastNosePos.x, 2) +
111
+ Math.pow(nose.y - this.lastNosePos.y, 2));
112
+ if (dist > 0.3)
113
+ return false; // Sudden teleportation
114
+ }
115
+ this.lastNosePos = nose;
116
+ return true;
117
+ }
118
+ failInstantly(reason) {
119
+ this.stop();
120
+ this.updateState({ status: "error", errorMsg: reason });
121
+ this.config.onError({ success: false, reason });
122
+ }
84
123
  start = () => {
124
+ // Multi-tab Prevention
125
+ const active = localStorage.getItem(this.LIVENESS_LOCK_KEY);
126
+ if (active && Date.now() - parseInt(active) < 3000) {
127
+ this.failInstantly("Another session is active.");
128
+ return;
129
+ }
130
+ this.heartbeatId = setInterval(() => {
131
+ localStorage.setItem(this.LIVENESS_LOCK_KEY, Date.now().toString());
132
+ }, 1000);
85
133
  if (this.state.status !== "ready" || !this.webcam) {
86
134
  console.warn("[LivenessEngine] Engine not ready or video missing.");
87
135
  return;
@@ -95,15 +143,22 @@ class LivenessEngine {
95
143
  stop = () => {
96
144
  if (this.timerId)
97
145
  clearInterval(this.timerId);
146
+ if (this.heartbeatId)
147
+ clearInterval(this.heartbeatId);
98
148
  if (this.requestId)
99
149
  cancelAnimationFrame(this.requestId);
150
+ localStorage.removeItem(this.LIVENESS_LOCK_KEY);
100
151
  this.timerId = null;
152
+ this.heartbeatId = null;
101
153
  this.requestId = null;
102
154
  };
103
155
  reset = () => {
104
156
  this.stop();
105
157
  this.currentStepRef = 0;
106
158
  this.isStepTransitioningRef = false;
159
+ this.anchorRatios = null;
160
+ this.lastNosePos = null;
161
+ this.consecutiveMissingFrames = 0;
107
162
  this.generateSequence();
108
163
  this.updateState({
109
164
  status: "ready",
@@ -111,6 +166,7 @@ class LivenessEngine {
111
166
  timeLeft: this.config.duration,
112
167
  isStepTransitioning: false,
113
168
  errorMsg: "",
169
+ snapshots: [],
114
170
  });
115
171
  };
116
172
  updateState(newState) {
@@ -141,34 +197,78 @@ class LivenessEngine {
141
197
  const now = performance.now();
142
198
  try {
143
199
  const faceRes = this.models.face.detectForVideo(this.webcam, now);
144
- const handRes = this.models.hand?.detectForVideo(this.webcam, now);
145
- const currentChallenge = this.state.sequence[this.currentStepRef];
146
- if (this.checkAction(faceRes, handRes, currentChallenge)) {
147
- this.handleStepSuccess();
148
- return; // handleStepSuccess schedules the next frame after a delay
200
+ const landmarks = faceRes.faceLandmarks?.[0];
201
+ // --- NEW SECURITY CHECKS ---
202
+ // 1. Multi-Face Security
203
+ if (faceRes.faceLandmarks && faceRes.faceLandmarks.length > 1) {
204
+ return this.failInstantly("Multiple faces detected.");
149
205
  }
206
+ // 2. Continuity & Identity Security
207
+ if (!landmarks) {
208
+ this.consecutiveMissingFrames++;
209
+ if (this.consecutiveMissingFrames > this.MAX_GAP) {
210
+ return this.failInstantly("Face lost. Session reset.");
211
+ }
212
+ }
213
+ else {
214
+ this.consecutiveMissingFrames = 0;
215
+ if (this.anchorRatios === null) {
216
+ this.stabilityFrames++;
217
+ if (this.stabilityFrames >= this.REQUIRED_STABILITY) {
218
+ this.verifyIdentity(landmarks); // This sets the anchor for the first time
219
+ }
220
+ }
221
+ else {
222
+ // Only perform the security check AFTER the anchor is established
223
+ if (!this.verifyIdentity(landmarks) || !this.checkMovement(landmarks)) {
224
+ this.failInstantly("Security violation: Identity mismatch.");
225
+ return;
226
+ }
227
+ }
228
+ // 3. Challenge Logic
229
+ const currentChallenge = this.state.sequence[this.currentStepRef];
230
+ const handRes = this.models.hand?.detectForVideo(this.webcam, now);
231
+ if (this.checkAction(faceRes, handRes, currentChallenge)) {
232
+ this.handleStepSuccess(landmarks); // Pass landmarks to capture
233
+ return;
234
+ }
235
+ }
236
+ this.requestId = requestAnimationFrame(this.detectLoop);
150
237
  }
151
238
  catch (err) {
152
239
  console.error("[LivenessEngine] Loop detection error:", err);
240
+ this.requestId = requestAnimationFrame(this.detectLoop);
153
241
  }
154
- this.requestId = requestAnimationFrame(this.detectLoop);
155
242
  };
156
- handleStepSuccess() {
243
+ handleStepSuccess(landmarks) {
157
244
  if (this.isStepTransitioningRef)
158
245
  return;
159
246
  this.isStepTransitioningRef = true;
160
- this.updateState({ isStepTransitioning: true });
247
+ // Capture Snapshot
248
+ const canvas = this.getFaceCrop(this.webcam, landmarks);
249
+ const snapshot = {
250
+ challenge: this.state.sequence[this.currentStepRef],
251
+ image: canvas.toDataURL("image/jpeg", 0.7),
252
+ timestamp: Date.now()
253
+ };
254
+ const updatedSnapshots = [...this.state.snapshots, snapshot];
255
+ this.updateState({ isStepTransitioning: true, snapshots: updatedSnapshots });
161
256
  setTimeout(() => {
257
+ // Check if engine was stopped during the timeout
258
+ if (this.state.status !== "capturing")
259
+ return;
162
260
  if (this.currentStepRef < this.state.sequence.length - 1) {
163
261
  this.currentStepRef++;
164
262
  this.isStepTransitioningRef = false;
165
263
  this.updateState({
166
264
  currentStep: this.currentStepRef,
167
265
  isStepTransitioning: false,
266
+ snapshots: updatedSnapshots,
168
267
  });
169
268
  this.requestId = requestAnimationFrame(this.detectLoop);
170
269
  }
171
270
  else {
271
+ this.updateState({ snapshots: updatedSnapshots });
172
272
  this.sendFinalProof();
173
273
  }
174
274
  }, 1500);
@@ -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 LivenessSDKResult {\r\n success: boolean;\r\n image?: string;\r\n reason?: string;\r\n skinConfidence?: number;\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}\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 \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 };\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 public start = () => {\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.requestId) cancelAnimationFrame(this.requestId);\r\n this.timerId = 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.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 });\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 const handRes = this.models.hand?.detectForVideo(this.webcam, now);\r\n\r\n const currentChallenge = this.state.sequence[this.currentStepRef];\r\n\r\n if (this.checkAction(faceRes, handRes, currentChallenge)) {\r\n this.handleStepSuccess();\r\n return; // handleStepSuccess schedules the next frame after a delay\r\n }\r\n } catch (err) {\r\n console.error(\"[LivenessEngine] Loop detection error:\", err);\r\n }\r\n\r\n this.requestId = requestAnimationFrame(this.detectLoop);\r\n };\r\n\r\n private handleStepSuccess() {\r\n if (this.isStepTransitioningRef) return;\r\n \r\n this.isStepTransitioningRef = true;\r\n this.updateState({ isStepTransitioning: true });\r\n\r\n setTimeout(() => {\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 });\r\n this.requestId = requestAnimationFrame(this.detectLoop);\r\n } else {\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":";;;;;;;AAAA;MAiCa,cAAc,CAAA;AACjB,IAAA,MAAM;IACN,MAAM,GAAiE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;IACjG,MAAM,GAA4B,IAAI;AACtC,IAAA,KAAK;IAEL,cAAc,GAAG,CAAC;IAClB,sBAAsB,GAAG,KAAK;IAC9B,OAAO,GAA0C,IAAI;IACrD,SAAS,GAAkB,IAAI;AAG/B,IAAA,eAAe,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC;IAClD,cAAc,GAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,CAAC;AAElF,IAAA,WAAA,CAAY,MAA4B,EAAA;QACtC,IAAI,CAAC,MAAM,GAAG;YACZ,MAAM,EAAE,MAAM,CAAC,MAAM;AACrB,YAAA,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,EAAE;AAC/B,YAAA,cAAc,EAAE,MAAM,CAAC,cAAc,IAAI,GAAG;AAC5C,YAAA,cAAc,EAAE,MAAM,CAAC,cAAc,IAAI,KAAK;AAC9C,YAAA,oBAAoB,EAAE,MAAM,CAAC,oBAAoB,IAAI,IAAI;AACzD,YAAA,oBAAoB,EAAE,MAAM,CAAC,oBAAoB,IAAI,IAAI;YACzD,aAAa,EAAE,MAAM,CAAC,aAAa,KAAK,MAAK,EAAE,CAAC,CAAC;YACjD,UAAU,EAAE,MAAM,CAAC,UAAU,KAAK,MAAK,EAAE,CAAC,CAAC;YAC3C,OAAO,EAAE,MAAM,CAAC,OAAO,KAAK,MAAK,EAAE,CAAC,CAAC;SACtC;QAED,IAAI,CAAC,KAAK,GAAG;AACX,YAAA,MAAM,EAAE,SAAS;AACjB,YAAA,QAAQ,EAAE,EAAE;AACZ,YAAA,WAAW,EAAE,CAAC;AACd,YAAA,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;AAC9B,YAAA,mBAAmB,EAAE,KAAK;AAC1B,YAAA,QAAQ,EAAE,EAAE;SACb;AAED,QAAA,IAAI,CAAC,eAAe,CAAC,KAAK,GAAG,GAAG;AAChC,QAAA,IAAI,CAAC,eAAe,CAAC,MAAM,GAAG,GAAG;IACnC;AAEA;;AAEG;AACI,IAAA,MAAM,UAAU,GAAA;AACrB,QAAA,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC;AACpD,QAAA,IAAI;YACF,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,cAAc,CACjD,kEAAkE,CACnE;YAED,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,MAAM,cAAc,CAAC,iBAAiB,CAAC,MAAM,EAAE;AAChE,gBAAA,WAAW,EAAE;AACX,oBAAA,cAAc,EAAE,gHAAgH;AAChI,oBAAA,QAAQ,EAAE,KAAK;AAChB,iBAAA;AACD,gBAAA,qBAAqB,EAAE,IAAI;AAC3B,gBAAA,WAAW,EAAE,OAAO;AACrB,aAAA,CAAC;YAEF,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,MAAM,cAAc,CAAC,iBAAiB,CAAC,MAAM,EAAE;AAChE,gBAAA,WAAW,EAAE;AACX,oBAAA,cAAc,EAAE,gHAAgH;AAChI,oBAAA,QAAQ,EAAE,KAAK;AAChB,iBAAA;AACD,gBAAA,WAAW,EAAE,OAAO;AACpB,gBAAA,QAAQ,EAAE,CAAC;AACZ,aAAA,CAAC;YAEF,IAAI,CAAC,gBAAgB,EAAE;;;YAGvB,IAAI,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AACrC,YAAA,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC;QAChD;QAAE,OAAO,GAAG,EAAE;AACZ,YAAA,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,GAAG,CAAC;AAClD,YAAA,IAAI,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,iCAAiC,EAAE,CAAC;QACpF;IACF;AAEA;;AAEG;AACI,IAAA,WAAW,GAAG,CAAC,KAAuB,KAAI;AAC/C,QAAA,IAAI,CAAC,MAAM,GAAG,KAAK;AACnB,QAAA,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC;AACxD,IAAA,CAAC;IAEM,KAAK,GAAG,MAAK;AAClB,QAAA,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;AACjD,YAAA,OAAO,CAAC,IAAI,CAAC,qDAAqD,CAAC;YACnE;QACF;AAEA,QAAA,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC;QACnD,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,WAAW,CAAC;QAChC,IAAI,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QACzC,IAAI,CAAC,UAAU,EAAE;QACjB,IAAI,CAAC,UAAU,EAAE;AACnB,IAAA,CAAC;IAEM,IAAI,GAAG,MAAK;QACjB,IAAI,IAAI,CAAC,OAAO;AAAE,YAAA,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC;QAC7C,IAAI,IAAI,CAAC,SAAS;AAAE,YAAA,oBAAoB,CAAC,IAAI,CAAC,SAAS,CAAC;AACxD,QAAA,IAAI,CAAC,OAAO,GAAG,IAAI;AACnB,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI;AACvB,IAAA,CAAC;IAEM,KAAK,GAAG,MAAK;QAClB,IAAI,CAAC,IAAI,EAAE;AACX,QAAA,IAAI,CAAC,cAAc,GAAG,CAAC;AACvB,QAAA,IAAI,CAAC,sBAAsB,GAAG,KAAK;QACnC,IAAI,CAAC,gBAAgB,EAAE;QACvB,IAAI,CAAC,WAAW,CAAC;AACf,YAAA,MAAM,EAAE,OAAO;AACf,YAAA,WAAW,EAAE,CAAC;AACd,YAAA,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;AAC9B,YAAA,mBAAmB,EAAE,KAAK;AAC1B,YAAA,QAAQ,EAAE,EAAE;AACb,SAAA,CAAC;AACJ,IAAA,CAAC;AAEO,IAAA,WAAW,CAAC,QAAgC,EAAA;AAClD,QAAA,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,QAAQ,EAAE;QAC3C,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;IACvC;IAEQ,gBAAgB,GAAA;AACtB,QAAA,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAChF,QAAA,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,GAAG;AACzB,QAAA,OAAO,GAAG;IACZ;IAEQ,UAAU,GAAA;QAChB,IAAI,IAAI,CAAC,OAAO;AAAE,YAAA,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC;AAC7C,QAAA,IAAI,CAAC,OAAO,GAAG,WAAW,CAAC,MAAK;YAC9B,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,EAAE;AAC3B,gBAAA,IAAI,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;YACzD;iBAAO;gBACL,IAAI,CAAC,IAAI,EAAE;gBACX,IAAI,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YACzC;QACF,CAAC,EAAE,IAAI,CAAC;IACV;IAEQ,UAAU,GAAG,MAAK;AACxB,QAAA,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI;YAAE;AAE5E,QAAA,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE;AAC7B,QAAA,IAAI;AACF,YAAA,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC;AACjE,YAAA,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC;AAElE,YAAA,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC;YAEjE,IAAI,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC,EAAE;gBACxD,IAAI,CAAC,iBAAiB,EAAE;AACxB,gBAAA,OAAO;YACT;QACF;QAAE,OAAO,GAAG,EAAE;AACZ,YAAA,OAAO,CAAC,KAAK,CAAC,wCAAwC,EAAE,GAAG,CAAC;QAC9D;QAEA,IAAI,CAAC,SAAS,GAAG,qBAAqB,CAAC,IAAI,CAAC,UAAU,CAAC;AACzD,IAAA,CAAC;IAEO,iBAAiB,GAAA;QACvB,IAAI,IAAI,CAAC,sBAAsB;YAAE;AAEjC,QAAA,IAAI,CAAC,sBAAsB,GAAG,IAAI;QAClC,IAAI,CAAC,WAAW,CAAC,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAC;QAE/C,UAAU,CAAC,MAAK;AACd,YAAA,IAAI,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;gBACxD,IAAI,CAAC,cAAc,EAAE;AACrB,gBAAA,IAAI,CAAC,sBAAsB,GAAG,KAAK;gBACnC,IAAI,CAAC,WAAW,CAAC;oBACf,WAAW,EAAE,IAAI,CAAC,cAAc;AAChC,oBAAA,mBAAmB,EAAE,KAAK;AAC3B,iBAAA,CAAC;gBACF,IAAI,CAAC,SAAS,GAAG,qBAAqB,CAAC,IAAI,CAAC,UAAU,CAAC;YACzD;iBAAO;gBACL,IAAI,CAAC,cAAc,EAAE;YACvB;QACF,CAAC,EAAE,IAAI,CAAC;IACV;AAEQ,IAAA,WAAW,CAAC,OAAY,EAAE,OAAY,EAAE,SAAoB,EAAA;QAClE,IAAI,IAAI,CAAC,sBAAsB;AAAE,YAAA,OAAO,KAAK;AAE7C,QAAA,IAAI,SAAS,KAAK,WAAW,IAAI,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,CAAC,EAAE;YAC/D,MAAM,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;YAC9B,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3E;QAEA,IAAI,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,CAAC,EAAE;YACtC,MAAM,GAAG,GAAyB,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;YAC1D,QAAQ,SAAS;AACf,gBAAA,KAAK,OAAO;oBACV,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc;AAC9D,gBAAA,KAAK,OAAO;oBACV,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;oBACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAClD,oBAAA,OAAO,CAAC,CAAC,OAAO,GAAG,QAAQ,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc;AAChE,gBAAA,KAAK,WAAW;AACd,oBAAA,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7D,oBAAA,OAAO,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,oBAAoB,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,oBAAoB;AACzF,gBAAA,SAAS,OAAO,KAAK;;QAEzB;AACA,QAAA,OAAO,KAAK;IACd;AAEQ,IAAA,MAAM,cAAc,GAAA;QAC1B,IAAI,CAAC,IAAI,EAAE;QACX,IAAI,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AAEzC,QAAA,IAAI;YACF,MAAM,KAAK,GAAW,EAAE;YACxB,IAAI,WAAW,GAAG,EAAE;AAEpB,YAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;gBAC1B,IAAI,CAAC,IAAI,CAAC,MAAM;oBAAE;AAClB,gBAAA,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,EAAE,CAAC;gBAChF,IAAI,OAAO,EAAE,aAAa,GAAG,CAAC,CAAC,EAAE;AAC/B,oBAAA,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;oBACtE,MAAM,IAAI,GAAG,MAAM,IAAI,OAAO,CAAc,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,YAAY,EAAE,GAAG,CAAC,CAAC;AACzF,oBAAA,IAAI,IAAI;AAAE,wBAAA,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;oBAC1B,IAAI,CAAC,KAAK,CAAC;AAAE,wBAAA,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC;gBAC3D;AACA,gBAAA,MAAM,IAAI,OAAO,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YAC5C;YAEA,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,mDAAgB;AACjD,YAAA,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;AAEnF,YAAA,IAAI,MAAM,CAAC,OAAO,EAAE;gBAClB,IAAI,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;gBACvC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,CAAC,eAAe,EAAE,CAAC;YACvG;iBAAO;AACL,gBAAA,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,uBAAuB;AACvD,gBAAA,IAAI,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AACvD,gBAAA,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;YACjD;QACF;QAAE,OAAO,GAAG,EAAE;AACZ,YAAA,IAAI,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,sBAAsB,EAAE,CAAC;AACvE,YAAA,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;QAClE;IACF;IAEQ,WAAW,CAAC,KAAuB,EAAE,SAA+B,EAAA;QAC1E,MAAM,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,IAAI,CAAE;AAClD,QAAA,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC;AACrD,QAAA,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC;QAEtD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;AAE5B,QAAA,MAAM,KAAK,GAAG,IAAI,GAAG,IAAI;AACzB,QAAA,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI;AAC1B,QAAA,MAAM,MAAM,GAAG,KAAK,GAAG,GAAG;QAE1B,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;AAC7B,QAAA,GAAG,CAAC,SAAS,CACX,KAAK,EACL,IAAI,GAAG,MAAM,EAAE,IAAI,GAAG,MAAM,EAC5B,KAAK,GAAG,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,CAAC,EACvC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CACf;QAED,OAAO,IAAI,CAAC,eAAe;IAC7B;AACD;;MC9SY,eAAe,CAAA;AAON,IAAA,MAAA;AANZ,IAAA,MAAM;AACN,IAAA,YAAY,GAAG,IAAI,eAAe,CAAuB,IAAI,CAAC;;AAG/D,IAAA,MAAM,GAAqC,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE;AAElF,IAAA,WAAA,CAAoB,MAAc,EAAA;QAAd,IAAA,CAAA,MAAM,GAAN,MAAM;IAAW;AAE9B,IAAA,IAAI,CAAC,MAA4B,EAAA;;AAEtC,QAAA,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,MAAK;AACjC,YAAA,IAAI,CAAC,MAAM,GAAG,IAAI,cAAc,CAAC;AAC/B,gBAAA,GAAG,MAAM;AACT,gBAAA,aAAa,EAAE,CAAC,KAAK,KAAI;;AAEvB,oBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACtD;AACD,aAAA,CAAC;AACF,YAAA,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;AAC1B,QAAA,CAAC,CAAC;IACJ;AAEO,IAAA,MAAM,CAAC,KAAuB,EAAA;AACnC,QAAA,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC;IACjC;IAEO,KAAK,GAAA;AACV,QAAA,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE;IACtB;IAEO,KAAK,GAAA;AACV,QAAA,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE;IACtB;IAEA,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE;IACrB;uGArCW,eAAe,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAA,EAAA,CAAA,MAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAf,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,eAAe,cADF,MAAM,EAAA,CAAA;;2FACnB,eAAe,EAAA,UAAA,EAAA,CAAA;kBAD3B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;MCSrB,iBAAiB,CAAA;AAyCT,IAAA,QAAA;AAxCE,IAAA,SAAS;;AAGrB,IAAA,MAAM;IACN,QAAQ,GAAG,EAAE;AACb,IAAA,cAAc;AACd,IAAA,cAAc;AACd,IAAA,oBAAoB;AACpB,IAAA,oBAAoB;;IAGpB,cAAc,GAAG,EAAE;IACnB,iBAAiB,GAAG,EAAE;IACtB,UAAU,GAAG,EAAE;IACf,UAAU,GAAG,EAAE;IACf,UAAU,GAAG,EAAE;IACf,kBAAkB,GAAG,EAAE;IACvB,WAAW,GAAG,EAAE;IAChB,gBAAgB,GAAG,EAAE;IACrB,kBAAkB,GAAG,EAAE;IACvB,mBAAmB,GAAG,EAAE;IACxB,iBAAiB,GAAG,EAAE;IACtB,mBAAmB,GAAG,EAAE;;IAGxB,cAAc,GAAG,0BAA0B;IAC3C,YAAY,GAAG,wCAAwC;IACvD,gBAAgB,GAAG,WAAW;IAC9B,gBAAgB,GAAG,oBAAoB;AACvC,IAAA,gBAAgB,GAA8B;AACvD,QAAA,OAAO,EAAE,OAAO;AAChB,QAAA,OAAO,EAAE,OAAO;AAChB,QAAA,WAAW,EAAE,WAAW;QACxB,WAAW,EAAE,WAAW;KACvB;AAES,IAAA,UAAU,GAAG,IAAI,YAAY,EAAqB;AAClD,IAAA,OAAO,GAAG,IAAI,YAAY,EAAO;AACjC,IAAA,aAAa,GAAG,IAAI,YAAY,EAAwB;AAElE,IAAA,WAAA,CAAmB,QAAyB,EAAA;QAAzB,IAAA,CAAA,QAAQ,GAAR,QAAQ;IAAoB;IAE/C,QAAQ,GAAA;;QAIN,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,IAAG;;AAEvC,YAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;AAChC,QAAA,CAAC,CAAC;IAEF;AAEA,IAAA,MAAM,eAAe,GAAA;AACnB,QAAA,IAAI;YACF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC;AACvD,gBAAA,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM;AACrD,aAAA,CAAC;AACF,YAAA,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa;AAC1C,YAAA,KAAK,CAAC,SAAS,GAAG,MAAM;AACxB,YAAA,KAAK,CAAC,gBAAgB,GAAG,MAAK;gBAC5B,KAAK,CAAC,IAAI,EAAE;AAEZ,gBAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;oBACnB,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,cAAc,EAAE,IAAI,CAAC,cAAc;oBACnC,cAAc,EAAE,IAAI,CAAC,cAAc;oBACnC,oBAAoB,EAAE,IAAI,CAAC,oBAAoB;oBAC/C,oBAAoB,EAAE,IAAI,CAAC,oBAAoB;AAC/C,oBAAA,UAAU,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;AAC9C,oBAAA,OAAO,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG;AACtC,iBAAA,CAAC;AAEF,gBAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC;AAC7B,YAAA,CAAC;QACH;QAAE,OAAO,CAAC,EAAE;AACV,YAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;QACvE;IACF;IAEA,WAAW,GAAA;QACT,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,aAAa,EAAE,SAAwB;AACtE,QAAA,MAAM,EAAE,SAAS,EAAE,CAAC,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;IACpD;uGArFW,iBAAiB,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAAA,eAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAjB,iBAAiB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,QAAA,EAAA,QAAA,EAAA,UAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,oBAAA,EAAA,sBAAA,EAAA,oBAAA,EAAA,sBAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,UAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,WAAA,EAAA,aAAA,EAAA,gBAAA,EAAA,kBAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,mBAAA,EAAA,qBAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,mBAAA,EAAA,qBAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,YAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,kBAAA,EAAA,gBAAA,EAAA,kBAAA,EAAA,gBAAA,EAAA,kBAAA,EAAA,EAAA,OAAA,EAAA,EAAA,UAAA,EAAA,YAAA,EAAA,OAAA,EAAA,SAAA,EAAA,aAAA,EAAA,eAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,WAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,QAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECb9B,i3DAsDM,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,ED9CM,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,IAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,EAAA,CAAA,SAAA,EAAA,IAAA,EAAA,OAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,IAAA,EAAA,WAAA,EAAA,CAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FAKX,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAR7B,SAAS;+BACE,eAAe,EAAA,UAAA,EACb,IAAI,EAAA,OAAA,EACP,CAAC,YAAY,CAAC,EAAA,aAAA,EAER,iBAAiB,CAAC,IAAI,EAAA,QAAA,EAAA,i3DAAA,EAAA;;sBAIpC,SAAS;uBAAC,QAAQ;;sBAGlB;;sBACA;;sBACA;;sBACA;;sBACA;;sBACA;;sBAGA;;sBACA;;sBACA;;sBACA;;sBACA;;sBACA;;sBACA;;sBACA;;sBACA;;sBACA;;sBACA;;sBACA;;sBAGA;;sBACA;;sBACA;;sBACA;;sBACA;;sBAOA;;sBACA;;sBACA;;;AEpDH;AAWA;;;;;;AAMG;AACI,MAAM,cAAc,GAAG,OAC5B,MAAc,EACd,UAAkB,EAClB,SAAsB,KACO;AAC7B,IAAA,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE;IAE/B,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,KAAI;QAC7B,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,CAAA,MAAA,EAAS,CAAC,CAAA,IAAA,CAAM,CAAC;AAClD,IAAA,CAAC,CAAC;AACF,IAAA,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAEvD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,CAAA,EAAG,MAAM,YAAY,EAAE;AAClD,QAAA,MAAM,EAAE,MAAM;AACd,QAAA,IAAI,EAAE,QAAQ;AACf,KAAA,CAAC;AAEF,IAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;AAChB,QAAA,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC;IAChD;AAEA,IAAA,MAAM,IAAI,GAAqB,MAAM,QAAQ,CAAC,IAAI,EAAE;AACpD,IAAA,OAAO,IAAI;AACb;;;;;;;ACzCA;;AAEG;;;;"}
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.10; // 10% 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 });\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) < 3000) {\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.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 const landmarks = faceRes.faceLandmarks?.[0];\r\n \r\n // --- NEW SECURITY CHECKS ---\r\n // 1. Multi-Face Security\r\n if (faceRes.faceLandmarks && faceRes.faceLandmarks.length > 1) {\r\n return this.failInstantly(\"Multiple faces detected.\");\r\n }\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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"}
@@ -3,11 +3,17 @@ import { OnDestroy, NgZone, OnInit, AfterViewInit, ElementRef, EventEmitter } fr
3
3
  import { Observable } from 'rxjs';
4
4
 
5
5
  type Challenge = "Smile" | "Blink" | "Turn_Head" | "Thumbs_Up";
6
+ interface ChallengeSnapshot {
7
+ challenge: Challenge;
8
+ image: string;
9
+ timestamp: number;
10
+ }
6
11
  interface LivenessSDKResult {
7
12
  success: boolean;
8
13
  image?: string;
9
14
  reason?: string;
10
15
  skinConfidence?: number;
16
+ snapshots?: ChallengeSnapshot[];
11
17
  }
12
18
  interface LivenessState {
13
19
  status: "loading" | "ready" | "capturing" | "verifying" | "success" | "error" | "expired";
@@ -16,6 +22,7 @@ interface LivenessState {
16
22
  timeLeft: number;
17
23
  isStepTransitioning: boolean;
18
24
  errorMsg: string;
25
+ snapshots: ChallengeSnapshot[];
19
26
  }
20
27
  interface LivenessEngineConfig {
21
28
  apiUrl: string;
@@ -37,6 +44,14 @@ declare class LivenessEngine {
37
44
  private isStepTransitioningRef;
38
45
  private timerId;
39
46
  private requestId;
47
+ private heartbeatId;
48
+ private anchorRatios;
49
+ private lastNosePos;
50
+ private consecutiveMissingFrames;
51
+ private readonly MAX_GAP;
52
+ private readonly LIVENESS_LOCK_KEY;
53
+ private stabilityFrames;
54
+ private readonly REQUIRED_STABILITY;
40
55
  private offscreenCanvas;
41
56
  private CHALLENGE_POOL;
42
57
  constructor(config: LivenessEngineConfig);
@@ -48,6 +63,9 @@ declare class LivenessEngine {
48
63
  * Phase 2: Attach Video (Call this once the Webcam is in the DOM)
49
64
  */
50
65
  attachVideo: (video: HTMLVideoElement) => void;
66
+ private verifyIdentity;
67
+ private checkMovement;
68
+ private failInstantly;
51
69
  start: () => void;
52
70
  stop: () => void;
53
71
  reset: () => void;
@@ -129,4 +147,4 @@ interface LivenessResponse {
129
147
  declare const verifyLiveness: (apiUrl: string, frameBlobs: Blob[], challenge: Challenge[]) => Promise<LivenessResponse>;
130
148
 
131
149
  export { LivenessComponent, LivenessEngine, LivenessService, verifyLiveness };
132
- export type { Challenge, LivenessEngineConfig, LivenessResponse, LivenessSDKResult, LivenessState };
150
+ export type { Challenge, ChallengeSnapshot, LivenessEngineConfig, LivenessResponse, LivenessSDKResult, LivenessState };
@@ -1,9 +1,15 @@
1
1
  export type Challenge = "Smile" | "Blink" | "Turn_Head" | "Thumbs_Up";
2
+ export interface ChallengeSnapshot {
3
+ challenge: Challenge;
4
+ image: string;
5
+ timestamp: number;
6
+ }
2
7
  export interface LivenessSDKResult {
3
8
  success: boolean;
4
9
  image?: string;
5
10
  reason?: string;
6
11
  skinConfidence?: number;
12
+ snapshots?: ChallengeSnapshot[];
7
13
  }
8
14
  export interface LivenessState {
9
15
  status: "loading" | "ready" | "capturing" | "verifying" | "success" | "error" | "expired";
@@ -12,6 +18,7 @@ export interface LivenessState {
12
18
  timeLeft: number;
13
19
  isStepTransitioning: boolean;
14
20
  errorMsg: string;
21
+ snapshots: ChallengeSnapshot[];
15
22
  }
16
23
  export interface LivenessEngineConfig {
17
24
  apiUrl: string;
@@ -33,6 +40,14 @@ export declare class LivenessEngine {
33
40
  private isStepTransitioningRef;
34
41
  private timerId;
35
42
  private requestId;
43
+ private heartbeatId;
44
+ private anchorRatios;
45
+ private lastNosePos;
46
+ private consecutiveMissingFrames;
47
+ private readonly MAX_GAP;
48
+ private readonly LIVENESS_LOCK_KEY;
49
+ private stabilityFrames;
50
+ private readonly REQUIRED_STABILITY;
36
51
  private offscreenCanvas;
37
52
  private CHALLENGE_POOL;
38
53
  constructor(config: LivenessEngineConfig);
@@ -44,6 +59,9 @@ export declare class LivenessEngine {
44
59
  * Phase 2: Attach Video (Call this once the Webcam is in the DOM)
45
60
  */
46
61
  attachVideo: (video: HTMLVideoElement) => void;
62
+ private verifyIdentity;
63
+ private checkMovement;
64
+ private failInstantly;
47
65
  start: () => void;
48
66
  stop: () => void;
49
67
  reset: () => 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,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;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;CAClB;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;IAGxC,OAAO,CAAC,eAAe,CAAoC;IAC3D,OAAO,CAAC,cAAc,CAA6D;gBAEvE,MAAM,EAAE,oBAAoB;IA0BxC;;OAEG;IACU,UAAU;IAoCvB;;OAEG;IACI,WAAW,GAAI,OAAO,gBAAgB,UAG3C;IAEK,KAAK,aAWV;IAEK,IAAI,aAKT;IAEK,KAAK,aAYV;IAEF,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,UAAU,CAmBhB;IAEF,OAAO,CAAC,iBAAiB;IAqBzB,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;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,aAgBZ;IAEA,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,UAAU,CAqDhB;IAEF,OAAO,CAAC,iBAAiB;IAqCzB,OAAO,CAAC,WAAW;YA0BL,cAAc;IAqC5B,OAAO,CAAC,WAAW;CAwBpB"}
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("./api-CWu5ff9j.cjs"),e=require("./LivenessCheck-YOJ3vZ1M.cjs");exports.verifyLiveness=s.verifyLiveness;exports.LivenessEngine=e.LivenessEngine;exports.LivenessSDK=e.LivenessSDK;exports.useLiveness=e.useLiveness;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("./api-CWu5ff9j.cjs"),e=require("./LivenessCheck-VABTGnoV.cjs");exports.verifyLiveness=s.verifyLiveness;exports.LivenessEngine=e.LivenessEngine;exports.LivenessSDK=e.LivenessSDK;exports.useLiveness=e.useLiveness;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { verifyLiveness as i } from "./api-BpiDoGOd.js";
2
- import { L as r, a as v, u as L } from "./LivenessCheck-DxxnvHvi.js";
2
+ import { L as r, a as v, u as L } from "./LivenessCheck-B7w-81bc.js";
3
3
  export {
4
4
  r as LivenessEngine,
5
5
  v as LivenessSDK,
@@ -1 +1 @@
1
- {"version":3,"file":"useLiveness.d.ts","sourceRoot":"","sources":["../../src/react/useLiveness.ts"],"names":[],"mappings":"AAEA,OAAO,MAAM,MAAM,cAAc,CAAC;AAClC,OAAO,EAAkB,oBAAoB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE7F,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACpD,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACnC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,eAAO,MAAM,WAAW,GAAI,QAAQ,oBAAoB,KAAG,eAkE1D,CAAC"}
1
+ {"version":3,"file":"useLiveness.d.ts","sourceRoot":"","sources":["../../src/react/useLiveness.ts"],"names":[],"mappings":"AAEA,OAAO,MAAM,MAAM,cAAc,CAAC;AAClC,OAAO,EAAkB,oBAAoB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE7F,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACpD,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACnC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,eAAO,MAAM,WAAW,GAAI,QAAQ,oBAAoB,KAAG,eAmE1D,CAAC"}
package/dist/react.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./LivenessCheck-YOJ3vZ1M.cjs");require("react-webcam");exports.LivenessSDK=e.LivenessSDK;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./LivenessCheck-VABTGnoV.cjs");require("react-webcam");exports.LivenessSDK=e.LivenessSDK;
package/dist/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as s } from "./LivenessCheck-DxxnvHvi.js";
1
+ import { a as s } from "./LivenessCheck-B7w-81bc.js";
2
2
  import "react-webcam";
3
3
  export {
4
4
  s as LivenessSDK
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@richard.fadiora/liveness-detection",
3
- "version": "4.3.13",
3
+ "version": "5.0.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "files": [