@moveris/shared 3.6.0 → 3.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -9
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +25 -4
- package/dist/index.mjs +25 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ const result = await client.fastCheck(frames, {
|
|
|
30
30
|
source: 'live',
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
-
console.log(result.verdict); // 'live' or '
|
|
33
|
+
console.log(result.verdict); // 'live', 'fake', or 'inconclusive'
|
|
34
34
|
console.log(result.confidence); // 0-1
|
|
35
35
|
console.log(result.score); // 0-100
|
|
36
36
|
```
|
|
@@ -260,13 +260,14 @@ type FrameSource = 'media' | 'live';
|
|
|
260
260
|
Liveness determination result.
|
|
261
261
|
|
|
262
262
|
```typescript
|
|
263
|
-
type Verdict = 'live' | 'fake';
|
|
263
|
+
type Verdict = 'live' | 'fake' | 'inconclusive';
|
|
264
264
|
```
|
|
265
265
|
|
|
266
|
-
| Value
|
|
267
|
-
|
|
|
268
|
-
| `'live'`
|
|
269
|
-
| `'fake'`
|
|
266
|
+
| Value | Description |
|
|
267
|
+
| ---------------- | -------------------------------------------------------------------------------- |
|
|
268
|
+
| `'live'` | Real person detected |
|
|
269
|
+
| `'fake'` | Spoofing attempt detected (photo, video, mask, etc.) |
|
|
270
|
+
| `'inconclusive'` | API processed successfully but could not determine a verdict — retry recommended |
|
|
270
271
|
|
|
271
272
|
#### LivenessState
|
|
272
273
|
|
|
@@ -288,7 +289,7 @@ Result returned from liveness verification.
|
|
|
288
289
|
|
|
289
290
|
```typescript
|
|
290
291
|
interface LivenessResult {
|
|
291
|
-
verdict: Verdict; // 'live' or '
|
|
292
|
+
verdict: Verdict; // 'live', 'fake', or 'inconclusive'
|
|
292
293
|
confidence: number; // Confidence score (0-1)
|
|
293
294
|
score: number; // Liveness score (0-100)
|
|
294
295
|
sessionId: string; // Session identifier
|
|
@@ -550,7 +551,7 @@ const status = getStatusMessage('capturing', DEFAULT_LOCALE);
|
|
|
550
551
|
| `camera_angle_low` | "Raise camera to eye level" | Camera below face (Y < 0.3) |
|
|
551
552
|
| `camera_angle_high` | "Lower camera to eye level" | Camera above face (Y > 0.7) |
|
|
552
553
|
| `camera_tilted` | "Hold camera level" | Device tilt > 15° (via transformation matrix, falls back to eye-corner landmarks) |
|
|
553
|
-
| `flat_lighting` | "Find better lighting" | Face-region dynamic range <
|
|
554
|
+
| `flat_lighting` | "Find better lighting" | Face-region dynamic range < 60 L-units — soft warning, capture continues |
|
|
554
555
|
|
|
555
556
|
---
|
|
556
557
|
|
|
@@ -683,7 +684,7 @@ const angleResult = detectCameraAngle(landmarks); // requires ≥153 landmarks
|
|
|
683
684
|
// Pass pre-sampled face-region pixels — use sampleFaceRegionPixels() in @moveris/react
|
|
684
685
|
import { analyzeDynamicRange } from '@moveris/shared';
|
|
685
686
|
const drResult = analyzeDynamicRange(rgbaPixels);
|
|
686
|
-
// { range: number (max L* − min L*), isLow: boolean (<
|
|
687
|
+
// { range: number (max L* − min L*), isLow: boolean (< 60) }
|
|
687
688
|
// Soft warning — do not use as a hard capture gate
|
|
688
689
|
```
|
|
689
690
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type Verdict = 'live' | 'fake';
|
|
1
|
+
type Verdict = 'live' | 'fake' | 'inconclusive';
|
|
2
2
|
interface ModelEntry {
|
|
3
3
|
id: string;
|
|
4
4
|
label: string;
|
|
@@ -344,7 +344,7 @@ declare const MAX_FACE_RATIO = 0.7;
|
|
|
344
344
|
declare const FACE_CROP_OUTPUT_SIZE = 224;
|
|
345
345
|
declare const MAX_FACE_PERCENTAGE_IN_CROP = 0.45;
|
|
346
346
|
declare const TARGET_FACE_PERCENTAGE_IN_CROP = 0.33;
|
|
347
|
-
declare const DYNAMIC_RANGE_WARNING_THRESHOLD =
|
|
347
|
+
declare const DYNAMIC_RANGE_WARNING_THRESHOLD = 60;
|
|
348
348
|
interface DynamicRangeAnalysis {
|
|
349
349
|
range: number;
|
|
350
350
|
isLow: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type Verdict = 'live' | 'fake';
|
|
1
|
+
type Verdict = 'live' | 'fake' | 'inconclusive';
|
|
2
2
|
interface ModelEntry {
|
|
3
3
|
id: string;
|
|
4
4
|
label: string;
|
|
@@ -344,7 +344,7 @@ declare const MAX_FACE_RATIO = 0.7;
|
|
|
344
344
|
declare const FACE_CROP_OUTPUT_SIZE = 224;
|
|
345
345
|
declare const MAX_FACE_PERCENTAGE_IN_CROP = 0.45;
|
|
346
346
|
declare const TARGET_FACE_PERCENTAGE_IN_CROP = 0.33;
|
|
347
|
-
declare const DYNAMIC_RANGE_WARNING_THRESHOLD =
|
|
347
|
+
declare const DYNAMIC_RANGE_WARNING_THRESHOLD = 60;
|
|
348
348
|
interface DynamicRangeAnalysis {
|
|
349
349
|
range: number;
|
|
350
350
|
isLow: boolean;
|
package/dist/index.js
CHANGED
|
@@ -265,7 +265,18 @@ function toHybridFrameData(frames) {
|
|
|
265
265
|
}
|
|
266
266
|
function toLivenessResult(response) {
|
|
267
267
|
if (!response.verdict) {
|
|
268
|
-
|
|
268
|
+
if (response.error) {
|
|
269
|
+
throw new LivenessApiError(response.error, "no_verdict", 500);
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
verdict: "inconclusive",
|
|
273
|
+
confidence: response.confidence ?? 0,
|
|
274
|
+
score: response.score ?? 0,
|
|
275
|
+
sessionId: response.session_id,
|
|
276
|
+
processingMs: response.processing_ms,
|
|
277
|
+
framesProcessed: "frames_processed" in response ? response.frames_processed ?? 0 : 0,
|
|
278
|
+
warnings: "warnings" in response && Array.isArray(response.warnings) ? response.warnings : void 0
|
|
279
|
+
};
|
|
269
280
|
}
|
|
270
281
|
return {
|
|
271
282
|
verdict: response.verdict,
|
|
@@ -282,8 +293,18 @@ function toLivenessResultFromStream(response) {
|
|
|
282
293
|
throw new LivenessApiError("Stream not complete", "stream_incomplete", 400);
|
|
283
294
|
}
|
|
284
295
|
if (!response.verdict) {
|
|
285
|
-
|
|
286
|
-
|
|
296
|
+
if (response.error) {
|
|
297
|
+
throw new LivenessApiError(response.error, response.error, 500);
|
|
298
|
+
}
|
|
299
|
+
return {
|
|
300
|
+
verdict: "inconclusive",
|
|
301
|
+
confidence: response.confidence ?? 0,
|
|
302
|
+
score: response.score ?? 0,
|
|
303
|
+
sessionId: response.session_id,
|
|
304
|
+
processingMs: response.processing_ms ?? 0,
|
|
305
|
+
framesProcessed: response.frames_processed ?? 0,
|
|
306
|
+
warnings: Array.isArray(response.warnings) ? response.warnings : void 0
|
|
307
|
+
};
|
|
287
308
|
}
|
|
288
309
|
return {
|
|
289
310
|
verdict: response.verdict,
|
|
@@ -1674,7 +1695,7 @@ var MAX_FACE_RATIO = 0.7;
|
|
|
1674
1695
|
var FACE_CROP_OUTPUT_SIZE = 224;
|
|
1675
1696
|
var MAX_FACE_PERCENTAGE_IN_CROP = 0.45;
|
|
1676
1697
|
var TARGET_FACE_PERCENTAGE_IN_CROP = 0.33;
|
|
1677
|
-
var DYNAMIC_RANGE_WARNING_THRESHOLD =
|
|
1698
|
+
var DYNAMIC_RANGE_WARNING_THRESHOLD = 60;
|
|
1678
1699
|
function srgbToLinear(c) {
|
|
1679
1700
|
const n = c / 255;
|
|
1680
1701
|
return n <= 0.04045 ? n / 12.92 : Math.pow((n + 0.055) / 1.055, 2.4);
|
package/dist/index.mjs
CHANGED
|
@@ -121,7 +121,18 @@ function toHybridFrameData(frames) {
|
|
|
121
121
|
}
|
|
122
122
|
function toLivenessResult(response) {
|
|
123
123
|
if (!response.verdict) {
|
|
124
|
-
|
|
124
|
+
if (response.error) {
|
|
125
|
+
throw new LivenessApiError(response.error, "no_verdict", 500);
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
verdict: "inconclusive",
|
|
129
|
+
confidence: response.confidence ?? 0,
|
|
130
|
+
score: response.score ?? 0,
|
|
131
|
+
sessionId: response.session_id,
|
|
132
|
+
processingMs: response.processing_ms,
|
|
133
|
+
framesProcessed: "frames_processed" in response ? response.frames_processed ?? 0 : 0,
|
|
134
|
+
warnings: "warnings" in response && Array.isArray(response.warnings) ? response.warnings : void 0
|
|
135
|
+
};
|
|
125
136
|
}
|
|
126
137
|
return {
|
|
127
138
|
verdict: response.verdict,
|
|
@@ -138,8 +149,18 @@ function toLivenessResultFromStream(response) {
|
|
|
138
149
|
throw new LivenessApiError("Stream not complete", "stream_incomplete", 400);
|
|
139
150
|
}
|
|
140
151
|
if (!response.verdict) {
|
|
141
|
-
|
|
142
|
-
|
|
152
|
+
if (response.error) {
|
|
153
|
+
throw new LivenessApiError(response.error, response.error, 500);
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
verdict: "inconclusive",
|
|
157
|
+
confidence: response.confidence ?? 0,
|
|
158
|
+
score: response.score ?? 0,
|
|
159
|
+
sessionId: response.session_id,
|
|
160
|
+
processingMs: response.processing_ms ?? 0,
|
|
161
|
+
framesProcessed: response.frames_processed ?? 0,
|
|
162
|
+
warnings: Array.isArray(response.warnings) ? response.warnings : void 0
|
|
163
|
+
};
|
|
143
164
|
}
|
|
144
165
|
return {
|
|
145
166
|
verdict: response.verdict,
|
|
@@ -1530,7 +1551,7 @@ var MAX_FACE_RATIO = 0.7;
|
|
|
1530
1551
|
var FACE_CROP_OUTPUT_SIZE = 224;
|
|
1531
1552
|
var MAX_FACE_PERCENTAGE_IN_CROP = 0.45;
|
|
1532
1553
|
var TARGET_FACE_PERCENTAGE_IN_CROP = 0.33;
|
|
1533
|
-
var DYNAMIC_RANGE_WARNING_THRESHOLD =
|
|
1554
|
+
var DYNAMIC_RANGE_WARNING_THRESHOLD = 60;
|
|
1534
1555
|
function srgbToLinear(c) {
|
|
1535
1556
|
const n = c / 255;
|
|
1536
1557
|
return n <= 0.04045 ? n / 12.92 : Math.pow((n + 0.055) / 1.055, 2.4);
|