@moveris/shared 2.1.1 → 2.2.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.
- package/README.md +3 -0
- package/dist/index.d.mts +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +158 -10
- package/dist/index.mjs +153 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,7 @@ const client = new LivenessClient({
|
|
|
25
25
|
|
|
26
26
|
// Perform a fast liveness check
|
|
27
27
|
const result = await client.fastCheck(frames, {
|
|
28
|
+
sessionId: 'my-session-id', // optional — auto-generated if omitted
|
|
28
29
|
model: '10',
|
|
29
30
|
source: 'live',
|
|
30
31
|
});
|
|
@@ -293,6 +294,8 @@ const sessionId = generateSessionId();
|
|
|
293
294
|
// e.g., 'a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d'
|
|
294
295
|
```
|
|
295
296
|
|
|
297
|
+
> **Session ID injection**: Every `LivenessClient` method (`fastCheck`, `fastCheckCrops`, `streamFrame`, `verify`, `hybrid50`, `hybrid150`) accepts an optional `sessionId` in its options object. If provided, that ID is used for the request; if omitted, a new UUID is generated automatically. This is useful for debugging, testing, or correlating client requests with server logs. In `@moveris/react`, the `sessionId` can be injected via the `useLiveness` hook config or the `LivenessView` / `LivenessModal` props.
|
|
298
|
+
|
|
296
299
|
#### `toFrameData(frames)`
|
|
297
300
|
|
|
298
301
|
Convert CapturedFrame array to API format.
|
package/dist/index.d.mts
CHANGED
|
@@ -429,6 +429,10 @@ declare class LivenessClient {
|
|
|
429
429
|
private readonly fetchFn;
|
|
430
430
|
constructor(config: LivenessClientConfig);
|
|
431
431
|
private request;
|
|
432
|
+
private parseErrorResponse;
|
|
433
|
+
private static unwrapErrorCode;
|
|
434
|
+
private static unwrapErrorMessage;
|
|
435
|
+
private static extractCodeFromText;
|
|
432
436
|
private requestWithRetry;
|
|
433
437
|
health(): Promise<HealthResponse>;
|
|
434
438
|
queueStats(): Promise<QueueStatsResponse>;
|
|
@@ -565,6 +569,27 @@ declare const DEFAULT_LIVENESS_CONFIG: {
|
|
|
565
569
|
readonly timeout: 30000;
|
|
566
570
|
};
|
|
567
571
|
|
|
572
|
+
declare const API_ERROR_CODES: {
|
|
573
|
+
readonly SESSION_EXPIRED: "session_expired";
|
|
574
|
+
readonly INVALID_KEY: "invalid_key";
|
|
575
|
+
readonly INVALID_MODEL: "invalid_model";
|
|
576
|
+
readonly INSUFFICIENT_FRAMES: "insufficient_frames";
|
|
577
|
+
readonly MISSING_FIELD: "missing_field";
|
|
578
|
+
readonly INVALID_FRAME: "invalid_frame";
|
|
579
|
+
readonly INVALID_SESSION: "invalid_session";
|
|
580
|
+
readonly RATE_LIMITED: "rate_limited";
|
|
581
|
+
readonly STREAM_INCOMPLETE: "stream_incomplete";
|
|
582
|
+
readonly NO_VERDICT: "no_verdict";
|
|
583
|
+
readonly TIMEOUT: "timeout";
|
|
584
|
+
readonly NETWORK_ERROR: "network_error";
|
|
585
|
+
readonly SERVER_ERROR: "server_error";
|
|
586
|
+
};
|
|
587
|
+
type ApiErrorCode = (typeof API_ERROR_CODES)[keyof typeof API_ERROR_CODES];
|
|
588
|
+
declare const ERROR_MESSAGES: Record<string, string>;
|
|
589
|
+
declare const ERROR_MESSAGES_ES: Record<string, string>;
|
|
590
|
+
declare function getApiErrorMessage(code: string | undefined, message?: string, customMessages?: Record<string, string>): string;
|
|
591
|
+
declare function isRetryableError(code: string | undefined): boolean;
|
|
592
|
+
|
|
568
593
|
declare const ALIGNMENT_THRESHOLD_CAPTURE = 0.6;
|
|
569
594
|
declare const ALIGNMENT_THRESHOLD_POOR = 0.5;
|
|
570
595
|
declare const ALIGNMENT_THRESHOLD_GOOD = 0.5;
|
|
@@ -683,4 +708,4 @@ interface RetryOptions {
|
|
|
683
708
|
declare function retryWithBackoff<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
684
709
|
declare function sleep(ms: number): Promise<void>;
|
|
685
710
|
|
|
686
|
-
export { ALIGNMENT_THRESHOLD_CAPTURE, ALIGNMENT_THRESHOLD_GOOD, ALIGNMENT_THRESHOLD_PERFECT, ALIGNMENT_THRESHOLD_POOR, API_ENDPOINTS, API_PATHS, AUTH_CONFIG, BACKLIT_RATIO_THRESHOLD, BLUR_THRESHOLD_MOBILE, BaseFrameCollector, type BlurAnalysis, type CaptureQualityState, type CapturedFrame, type CropData, DEFAULT_BLUR_THRESHOLD, DEFAULT_ENDPOINT, DEFAULT_FACE_DETECTION_TIERS, DEFAULT_GAZE_THRESHOLDS, DEFAULT_HAND_OCCLUSION_CONFIG, DEFAULT_LIVENESS_CONFIG, DEFAULT_LOCALE, DEFAULT_OVAL_REGION, DEFAULT_STABILIZER_CONFIG, DEFAULT_STATUS_MESSAGES, type DetectionResult, type DetectionSummary, type DetectorConfig, ES_LOCALE, type ErrorResponse, FACE_CENTER_VERTICAL_OFFSET, FACE_CROP_OUTPUT_SIZE, FEEDBACK_MESSAGES, FRAME_BUFFER_CONFIG, FRAME_CONFIG, type FaceAlignmentResult, type FaceBoundingBox, type FaceDetectionTiers, type FaceInOvalResult, type FaceLandmarkPoint, type FaceVisibilityResult, type FastCheckCropsRequest, type FastCheckModel, type FastCheckRequest, type FastCheckResponse, type FastCheckStreamRequest, type FastCheckStreamResponse, type FeedbackLocale, type FeedbackMessageKey, type Frame, FrameBuffer, type FrameData, type FrameQualityResult, FrameQueue, type FrameSource, GOOD_ALIGNMENT, type GazeThresholds, HIGH_ALIGNMENT, HYBRID_MODEL_CONFIGS, type HandOcclusionConfig, type HeadPose, type HealthResponse, type Hybrid150CheckRequest, type Hybrid50CheckRequest, type HybridCheckRequest, type HybridCheckResponse, type HybridFrameData, type HybridModelConfig, IDEAL_CROP_MULTIPLIER, type JobStatus, type JobStatusResponse, LANDMARK_INDEX, LANDMARK_MAX_BOUND, LANDMARK_MIN_BOUND, LOW_LIGHT_THRESHOLD, type LandmarkValidationResult, type LightingAnalysis, LivenessApiError, type LivenessCallbacks, LivenessClient, type LivenessClientConfig, type LivenessConfig, type LivenessResult, type LivenessState, MAX_CROP_MULTIPLIER, MAX_FACE_PERCENTAGE_IN_CROP, MAX_FACE_RATIO, MIN_CAPTURE_ALIGNMENT, MIN_CROP_MULTIPLIER, MIN_FACE_BOTTOM_MARGIN, MIN_FACE_RATIO, MIN_FACE_SIDE_MARGIN, MIN_FACE_TOP_MARGIN, MIN_LANDMARK_COUNT, MODEL_CONFIGS, type ModelConfig, type ModelType, OVAL_GUIDE_COLORS, OVAL_GUIDE_STYLES, type OnErrorCallback, type OnFrameCapturedCallback, type OnProgressCallback, type OnResultCallback, type OnStateChangeCallback, type OvalGuideState, type OvalRegion, type QueueStatsResponse, RETRY_CONFIG, type RetryOptions, type StabilizationProgress, type StabilizationResult, type StabilizerConfig, type StatusMessageKey, type StreamingStatus, TARGET_FACE_PERCENTAGE_IN_CROP, type Verdict, type VerifyRequest, type VerifyResponse, type VideoFrameMetadata, analyzeBlur, analyzeLighting, calculateAdaptiveCropMultiplier, calculateBrightness, calculateFaceAlignment, calculateFaceCropRegion, canCaptureFrame, checkFrameQuality, decodeBase64, encodeBase64, generateSessionId, getCaptureQualityFeedback, getFeedbackMessage, getMinFramesForModel, getOvalGuideState, getStatusMessage, hasEnoughFrames, isFaceCropFullyInFrame, isFaceFullyVisible, isFaceInOval, retryWithBackoff, rgbaToGrayscale, sleep, toFrameData, toHybridFrameData, toLivenessResult, toLivenessResultFromStream, validateApiKey, validateFaceLandmarks, validateFrameCount, validateFrameData, validateFrameIndex, validateTimestamp, validateUUID, validateUrl };
|
|
711
|
+
export { ALIGNMENT_THRESHOLD_CAPTURE, ALIGNMENT_THRESHOLD_GOOD, ALIGNMENT_THRESHOLD_PERFECT, ALIGNMENT_THRESHOLD_POOR, API_ENDPOINTS, API_ERROR_CODES, API_PATHS, AUTH_CONFIG, type ApiErrorCode, BACKLIT_RATIO_THRESHOLD, BLUR_THRESHOLD_MOBILE, BaseFrameCollector, type BlurAnalysis, type CaptureQualityState, type CapturedFrame, type CropData, DEFAULT_BLUR_THRESHOLD, DEFAULT_ENDPOINT, DEFAULT_FACE_DETECTION_TIERS, DEFAULT_GAZE_THRESHOLDS, DEFAULT_HAND_OCCLUSION_CONFIG, DEFAULT_LIVENESS_CONFIG, DEFAULT_LOCALE, DEFAULT_OVAL_REGION, DEFAULT_STABILIZER_CONFIG, DEFAULT_STATUS_MESSAGES, type DetectionResult, type DetectionSummary, type DetectorConfig, ERROR_MESSAGES, ERROR_MESSAGES_ES, ES_LOCALE, type ErrorResponse, FACE_CENTER_VERTICAL_OFFSET, FACE_CROP_OUTPUT_SIZE, FEEDBACK_MESSAGES, FRAME_BUFFER_CONFIG, FRAME_CONFIG, type FaceAlignmentResult, type FaceBoundingBox, type FaceDetectionTiers, type FaceInOvalResult, type FaceLandmarkPoint, type FaceVisibilityResult, type FastCheckCropsRequest, type FastCheckModel, type FastCheckRequest, type FastCheckResponse, type FastCheckStreamRequest, type FastCheckStreamResponse, type FeedbackLocale, type FeedbackMessageKey, type Frame, FrameBuffer, type FrameData, type FrameQualityResult, FrameQueue, type FrameSource, GOOD_ALIGNMENT, type GazeThresholds, HIGH_ALIGNMENT, HYBRID_MODEL_CONFIGS, type HandOcclusionConfig, type HeadPose, type HealthResponse, type Hybrid150CheckRequest, type Hybrid50CheckRequest, type HybridCheckRequest, type HybridCheckResponse, type HybridFrameData, type HybridModelConfig, IDEAL_CROP_MULTIPLIER, type JobStatus, type JobStatusResponse, LANDMARK_INDEX, LANDMARK_MAX_BOUND, LANDMARK_MIN_BOUND, LOW_LIGHT_THRESHOLD, type LandmarkValidationResult, type LightingAnalysis, LivenessApiError, type LivenessCallbacks, LivenessClient, type LivenessClientConfig, type LivenessConfig, type LivenessResult, type LivenessState, MAX_CROP_MULTIPLIER, MAX_FACE_PERCENTAGE_IN_CROP, MAX_FACE_RATIO, MIN_CAPTURE_ALIGNMENT, MIN_CROP_MULTIPLIER, MIN_FACE_BOTTOM_MARGIN, MIN_FACE_RATIO, MIN_FACE_SIDE_MARGIN, MIN_FACE_TOP_MARGIN, MIN_LANDMARK_COUNT, MODEL_CONFIGS, type ModelConfig, type ModelType, OVAL_GUIDE_COLORS, OVAL_GUIDE_STYLES, type OnErrorCallback, type OnFrameCapturedCallback, type OnProgressCallback, type OnResultCallback, type OnStateChangeCallback, type OvalGuideState, type OvalRegion, type QueueStatsResponse, RETRY_CONFIG, type RetryOptions, type StabilizationProgress, type StabilizationResult, type StabilizerConfig, type StatusMessageKey, type StreamingStatus, TARGET_FACE_PERCENTAGE_IN_CROP, type Verdict, type VerifyRequest, type VerifyResponse, type VideoFrameMetadata, analyzeBlur, analyzeLighting, calculateAdaptiveCropMultiplier, calculateBrightness, calculateFaceAlignment, calculateFaceCropRegion, canCaptureFrame, checkFrameQuality, decodeBase64, encodeBase64, generateSessionId, getApiErrorMessage, getCaptureQualityFeedback, getFeedbackMessage, getMinFramesForModel, getOvalGuideState, getStatusMessage, hasEnoughFrames, isFaceCropFullyInFrame, isFaceFullyVisible, isFaceInOval, isRetryableError, retryWithBackoff, rgbaToGrayscale, sleep, toFrameData, toHybridFrameData, toLivenessResult, toLivenessResultFromStream, validateApiKey, validateFaceLandmarks, validateFrameCount, validateFrameData, validateFrameIndex, validateTimestamp, validateUUID, validateUrl };
|
package/dist/index.d.ts
CHANGED
|
@@ -429,6 +429,10 @@ declare class LivenessClient {
|
|
|
429
429
|
private readonly fetchFn;
|
|
430
430
|
constructor(config: LivenessClientConfig);
|
|
431
431
|
private request;
|
|
432
|
+
private parseErrorResponse;
|
|
433
|
+
private static unwrapErrorCode;
|
|
434
|
+
private static unwrapErrorMessage;
|
|
435
|
+
private static extractCodeFromText;
|
|
432
436
|
private requestWithRetry;
|
|
433
437
|
health(): Promise<HealthResponse>;
|
|
434
438
|
queueStats(): Promise<QueueStatsResponse>;
|
|
@@ -565,6 +569,27 @@ declare const DEFAULT_LIVENESS_CONFIG: {
|
|
|
565
569
|
readonly timeout: 30000;
|
|
566
570
|
};
|
|
567
571
|
|
|
572
|
+
declare const API_ERROR_CODES: {
|
|
573
|
+
readonly SESSION_EXPIRED: "session_expired";
|
|
574
|
+
readonly INVALID_KEY: "invalid_key";
|
|
575
|
+
readonly INVALID_MODEL: "invalid_model";
|
|
576
|
+
readonly INSUFFICIENT_FRAMES: "insufficient_frames";
|
|
577
|
+
readonly MISSING_FIELD: "missing_field";
|
|
578
|
+
readonly INVALID_FRAME: "invalid_frame";
|
|
579
|
+
readonly INVALID_SESSION: "invalid_session";
|
|
580
|
+
readonly RATE_LIMITED: "rate_limited";
|
|
581
|
+
readonly STREAM_INCOMPLETE: "stream_incomplete";
|
|
582
|
+
readonly NO_VERDICT: "no_verdict";
|
|
583
|
+
readonly TIMEOUT: "timeout";
|
|
584
|
+
readonly NETWORK_ERROR: "network_error";
|
|
585
|
+
readonly SERVER_ERROR: "server_error";
|
|
586
|
+
};
|
|
587
|
+
type ApiErrorCode = (typeof API_ERROR_CODES)[keyof typeof API_ERROR_CODES];
|
|
588
|
+
declare const ERROR_MESSAGES: Record<string, string>;
|
|
589
|
+
declare const ERROR_MESSAGES_ES: Record<string, string>;
|
|
590
|
+
declare function getApiErrorMessage(code: string | undefined, message?: string, customMessages?: Record<string, string>): string;
|
|
591
|
+
declare function isRetryableError(code: string | undefined): boolean;
|
|
592
|
+
|
|
568
593
|
declare const ALIGNMENT_THRESHOLD_CAPTURE = 0.6;
|
|
569
594
|
declare const ALIGNMENT_THRESHOLD_POOR = 0.5;
|
|
570
595
|
declare const ALIGNMENT_THRESHOLD_GOOD = 0.5;
|
|
@@ -683,4 +708,4 @@ interface RetryOptions {
|
|
|
683
708
|
declare function retryWithBackoff<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
684
709
|
declare function sleep(ms: number): Promise<void>;
|
|
685
710
|
|
|
686
|
-
export { ALIGNMENT_THRESHOLD_CAPTURE, ALIGNMENT_THRESHOLD_GOOD, ALIGNMENT_THRESHOLD_PERFECT, ALIGNMENT_THRESHOLD_POOR, API_ENDPOINTS, API_PATHS, AUTH_CONFIG, BACKLIT_RATIO_THRESHOLD, BLUR_THRESHOLD_MOBILE, BaseFrameCollector, type BlurAnalysis, type CaptureQualityState, type CapturedFrame, type CropData, DEFAULT_BLUR_THRESHOLD, DEFAULT_ENDPOINT, DEFAULT_FACE_DETECTION_TIERS, DEFAULT_GAZE_THRESHOLDS, DEFAULT_HAND_OCCLUSION_CONFIG, DEFAULT_LIVENESS_CONFIG, DEFAULT_LOCALE, DEFAULT_OVAL_REGION, DEFAULT_STABILIZER_CONFIG, DEFAULT_STATUS_MESSAGES, type DetectionResult, type DetectionSummary, type DetectorConfig, ES_LOCALE, type ErrorResponse, FACE_CENTER_VERTICAL_OFFSET, FACE_CROP_OUTPUT_SIZE, FEEDBACK_MESSAGES, FRAME_BUFFER_CONFIG, FRAME_CONFIG, type FaceAlignmentResult, type FaceBoundingBox, type FaceDetectionTiers, type FaceInOvalResult, type FaceLandmarkPoint, type FaceVisibilityResult, type FastCheckCropsRequest, type FastCheckModel, type FastCheckRequest, type FastCheckResponse, type FastCheckStreamRequest, type FastCheckStreamResponse, type FeedbackLocale, type FeedbackMessageKey, type Frame, FrameBuffer, type FrameData, type FrameQualityResult, FrameQueue, type FrameSource, GOOD_ALIGNMENT, type GazeThresholds, HIGH_ALIGNMENT, HYBRID_MODEL_CONFIGS, type HandOcclusionConfig, type HeadPose, type HealthResponse, type Hybrid150CheckRequest, type Hybrid50CheckRequest, type HybridCheckRequest, type HybridCheckResponse, type HybridFrameData, type HybridModelConfig, IDEAL_CROP_MULTIPLIER, type JobStatus, type JobStatusResponse, LANDMARK_INDEX, LANDMARK_MAX_BOUND, LANDMARK_MIN_BOUND, LOW_LIGHT_THRESHOLD, type LandmarkValidationResult, type LightingAnalysis, LivenessApiError, type LivenessCallbacks, LivenessClient, type LivenessClientConfig, type LivenessConfig, type LivenessResult, type LivenessState, MAX_CROP_MULTIPLIER, MAX_FACE_PERCENTAGE_IN_CROP, MAX_FACE_RATIO, MIN_CAPTURE_ALIGNMENT, MIN_CROP_MULTIPLIER, MIN_FACE_BOTTOM_MARGIN, MIN_FACE_RATIO, MIN_FACE_SIDE_MARGIN, MIN_FACE_TOP_MARGIN, MIN_LANDMARK_COUNT, MODEL_CONFIGS, type ModelConfig, type ModelType, OVAL_GUIDE_COLORS, OVAL_GUIDE_STYLES, type OnErrorCallback, type OnFrameCapturedCallback, type OnProgressCallback, type OnResultCallback, type OnStateChangeCallback, type OvalGuideState, type OvalRegion, type QueueStatsResponse, RETRY_CONFIG, type RetryOptions, type StabilizationProgress, type StabilizationResult, type StabilizerConfig, type StatusMessageKey, type StreamingStatus, TARGET_FACE_PERCENTAGE_IN_CROP, type Verdict, type VerifyRequest, type VerifyResponse, type VideoFrameMetadata, analyzeBlur, analyzeLighting, calculateAdaptiveCropMultiplier, calculateBrightness, calculateFaceAlignment, calculateFaceCropRegion, canCaptureFrame, checkFrameQuality, decodeBase64, encodeBase64, generateSessionId, getCaptureQualityFeedback, getFeedbackMessage, getMinFramesForModel, getOvalGuideState, getStatusMessage, hasEnoughFrames, isFaceCropFullyInFrame, isFaceFullyVisible, isFaceInOval, retryWithBackoff, rgbaToGrayscale, sleep, toFrameData, toHybridFrameData, toLivenessResult, toLivenessResultFromStream, validateApiKey, validateFaceLandmarks, validateFrameCount, validateFrameData, validateFrameIndex, validateTimestamp, validateUUID, validateUrl };
|
|
711
|
+
export { ALIGNMENT_THRESHOLD_CAPTURE, ALIGNMENT_THRESHOLD_GOOD, ALIGNMENT_THRESHOLD_PERFECT, ALIGNMENT_THRESHOLD_POOR, API_ENDPOINTS, API_ERROR_CODES, API_PATHS, AUTH_CONFIG, type ApiErrorCode, BACKLIT_RATIO_THRESHOLD, BLUR_THRESHOLD_MOBILE, BaseFrameCollector, type BlurAnalysis, type CaptureQualityState, type CapturedFrame, type CropData, DEFAULT_BLUR_THRESHOLD, DEFAULT_ENDPOINT, DEFAULT_FACE_DETECTION_TIERS, DEFAULT_GAZE_THRESHOLDS, DEFAULT_HAND_OCCLUSION_CONFIG, DEFAULT_LIVENESS_CONFIG, DEFAULT_LOCALE, DEFAULT_OVAL_REGION, DEFAULT_STABILIZER_CONFIG, DEFAULT_STATUS_MESSAGES, type DetectionResult, type DetectionSummary, type DetectorConfig, ERROR_MESSAGES, ERROR_MESSAGES_ES, ES_LOCALE, type ErrorResponse, FACE_CENTER_VERTICAL_OFFSET, FACE_CROP_OUTPUT_SIZE, FEEDBACK_MESSAGES, FRAME_BUFFER_CONFIG, FRAME_CONFIG, type FaceAlignmentResult, type FaceBoundingBox, type FaceDetectionTiers, type FaceInOvalResult, type FaceLandmarkPoint, type FaceVisibilityResult, type FastCheckCropsRequest, type FastCheckModel, type FastCheckRequest, type FastCheckResponse, type FastCheckStreamRequest, type FastCheckStreamResponse, type FeedbackLocale, type FeedbackMessageKey, type Frame, FrameBuffer, type FrameData, type FrameQualityResult, FrameQueue, type FrameSource, GOOD_ALIGNMENT, type GazeThresholds, HIGH_ALIGNMENT, HYBRID_MODEL_CONFIGS, type HandOcclusionConfig, type HeadPose, type HealthResponse, type Hybrid150CheckRequest, type Hybrid50CheckRequest, type HybridCheckRequest, type HybridCheckResponse, type HybridFrameData, type HybridModelConfig, IDEAL_CROP_MULTIPLIER, type JobStatus, type JobStatusResponse, LANDMARK_INDEX, LANDMARK_MAX_BOUND, LANDMARK_MIN_BOUND, LOW_LIGHT_THRESHOLD, type LandmarkValidationResult, type LightingAnalysis, LivenessApiError, type LivenessCallbacks, LivenessClient, type LivenessClientConfig, type LivenessConfig, type LivenessResult, type LivenessState, MAX_CROP_MULTIPLIER, MAX_FACE_PERCENTAGE_IN_CROP, MAX_FACE_RATIO, MIN_CAPTURE_ALIGNMENT, MIN_CROP_MULTIPLIER, MIN_FACE_BOTTOM_MARGIN, MIN_FACE_RATIO, MIN_FACE_SIDE_MARGIN, MIN_FACE_TOP_MARGIN, MIN_LANDMARK_COUNT, MODEL_CONFIGS, type ModelConfig, type ModelType, OVAL_GUIDE_COLORS, OVAL_GUIDE_STYLES, type OnErrorCallback, type OnFrameCapturedCallback, type OnProgressCallback, type OnResultCallback, type OnStateChangeCallback, type OvalGuideState, type OvalRegion, type QueueStatsResponse, RETRY_CONFIG, type RetryOptions, type StabilizationProgress, type StabilizationResult, type StabilizerConfig, type StatusMessageKey, type StreamingStatus, TARGET_FACE_PERCENTAGE_IN_CROP, type Verdict, type VerifyRequest, type VerifyResponse, type VideoFrameMetadata, analyzeBlur, analyzeLighting, calculateAdaptiveCropMultiplier, calculateBrightness, calculateFaceAlignment, calculateFaceCropRegion, canCaptureFrame, checkFrameQuality, decodeBase64, encodeBase64, generateSessionId, getApiErrorMessage, getCaptureQualityFeedback, getFeedbackMessage, getMinFramesForModel, getOvalGuideState, getStatusMessage, hasEnoughFrames, isFaceCropFullyInFrame, isFaceFullyVisible, isFaceInOval, isRetryableError, retryWithBackoff, rgbaToGrayscale, sleep, toFrameData, toHybridFrameData, toLivenessResult, toLivenessResultFromStream, validateApiKey, validateFaceLandmarks, validateFrameCount, validateFrameData, validateFrameIndex, validateTimestamp, validateUUID, validateUrl };
|
package/dist/index.js
CHANGED
|
@@ -25,6 +25,7 @@ __export(index_exports, {
|
|
|
25
25
|
ALIGNMENT_THRESHOLD_PERFECT: () => ALIGNMENT_THRESHOLD_PERFECT,
|
|
26
26
|
ALIGNMENT_THRESHOLD_POOR: () => ALIGNMENT_THRESHOLD_POOR,
|
|
27
27
|
API_ENDPOINTS: () => API_ENDPOINTS,
|
|
28
|
+
API_ERROR_CODES: () => API_ERROR_CODES,
|
|
28
29
|
API_PATHS: () => API_PATHS,
|
|
29
30
|
AUTH_CONFIG: () => AUTH_CONFIG,
|
|
30
31
|
BACKLIT_RATIO_THRESHOLD: () => BACKLIT_RATIO_THRESHOLD,
|
|
@@ -40,6 +41,8 @@ __export(index_exports, {
|
|
|
40
41
|
DEFAULT_OVAL_REGION: () => DEFAULT_OVAL_REGION,
|
|
41
42
|
DEFAULT_STABILIZER_CONFIG: () => DEFAULT_STABILIZER_CONFIG,
|
|
42
43
|
DEFAULT_STATUS_MESSAGES: () => DEFAULT_STATUS_MESSAGES,
|
|
44
|
+
ERROR_MESSAGES: () => ERROR_MESSAGES,
|
|
45
|
+
ERROR_MESSAGES_ES: () => ERROR_MESSAGES_ES,
|
|
43
46
|
ES_LOCALE: () => ES_LOCALE,
|
|
44
47
|
FACE_CENTER_VERTICAL_OFFSET: () => FACE_CENTER_VERTICAL_OFFSET,
|
|
45
48
|
FACE_CROP_OUTPUT_SIZE: () => FACE_CROP_OUTPUT_SIZE,
|
|
@@ -84,6 +87,7 @@ __export(index_exports, {
|
|
|
84
87
|
decodeBase64: () => decodeBase64,
|
|
85
88
|
encodeBase64: () => encodeBase64,
|
|
86
89
|
generateSessionId: () => generateSessionId,
|
|
90
|
+
getApiErrorMessage: () => getApiErrorMessage,
|
|
87
91
|
getCaptureQualityFeedback: () => getCaptureQualityFeedback,
|
|
88
92
|
getFeedbackMessage: () => getFeedbackMessage,
|
|
89
93
|
getMinFramesForModel: () => getMinFramesForModel,
|
|
@@ -93,6 +97,7 @@ __export(index_exports, {
|
|
|
93
97
|
isFaceCropFullyInFrame: () => isFaceCropFullyInFrame,
|
|
94
98
|
isFaceFullyVisible: () => isFaceFullyVisible,
|
|
95
99
|
isFaceInOval: () => isFaceInOval,
|
|
100
|
+
isRetryableError: () => isRetryableError,
|
|
96
101
|
retryWithBackoff: () => retryWithBackoff,
|
|
97
102
|
rgbaToGrayscale: () => rgbaToGrayscale,
|
|
98
103
|
sleep: () => sleep,
|
|
@@ -248,7 +253,8 @@ function toLivenessResultFromStream(response) {
|
|
|
248
253
|
throw new LivenessApiError("Stream not complete", "stream_incomplete", 400);
|
|
249
254
|
}
|
|
250
255
|
if (!response.verdict) {
|
|
251
|
-
|
|
256
|
+
const errorCode = response.error ?? "no_verdict";
|
|
257
|
+
throw new LivenessApiError(response.error ?? "No verdict received", errorCode, 500);
|
|
252
258
|
}
|
|
253
259
|
return {
|
|
254
260
|
verdict: response.verdict,
|
|
@@ -269,7 +275,7 @@ function generateSessionId() {
|
|
|
269
275
|
return v.toString(16);
|
|
270
276
|
});
|
|
271
277
|
}
|
|
272
|
-
var LivenessClient = class {
|
|
278
|
+
var LivenessClient = class _LivenessClient {
|
|
273
279
|
constructor(config) {
|
|
274
280
|
this.baseUrl = (config.baseUrl ?? DEFAULT_ENDPOINT).replace(/\/$/, "");
|
|
275
281
|
this.apiKey = config.apiKey;
|
|
@@ -296,14 +302,7 @@ var LivenessClient = class {
|
|
|
296
302
|
});
|
|
297
303
|
clearTimeout(timeoutId);
|
|
298
304
|
if (!response.ok) {
|
|
299
|
-
|
|
300
|
-
throw new LivenessApiError(
|
|
301
|
-
errorData.message,
|
|
302
|
-
errorData.error,
|
|
303
|
-
response.status,
|
|
304
|
-
errorData.required,
|
|
305
|
-
errorData.received
|
|
306
|
-
);
|
|
305
|
+
throw await this.parseErrorResponse(response);
|
|
307
306
|
}
|
|
308
307
|
return await response.json();
|
|
309
308
|
} catch (error) {
|
|
@@ -321,6 +320,75 @@ var LivenessClient = class {
|
|
|
321
320
|
);
|
|
322
321
|
}
|
|
323
322
|
}
|
|
323
|
+
/**
|
|
324
|
+
* Parse an error response body, handling both JSON and non-JSON bodies.
|
|
325
|
+
*
|
|
326
|
+
* The backend sometimes wraps the real error in a generic envelope:
|
|
327
|
+
* ```json
|
|
328
|
+
* { "error": "http_error", "message": "{'error': 'session_expired', ...}" }
|
|
329
|
+
* ```
|
|
330
|
+
* This method unwraps such envelopes to extract the real error code.
|
|
331
|
+
*/
|
|
332
|
+
async parseErrorResponse(response) {
|
|
333
|
+
const status = response.status;
|
|
334
|
+
let body;
|
|
335
|
+
try {
|
|
336
|
+
body = await response.text();
|
|
337
|
+
} catch {
|
|
338
|
+
return new LivenessApiError(`Request failed with status ${status}`, "server_error", status);
|
|
339
|
+
}
|
|
340
|
+
try {
|
|
341
|
+
const data = JSON.parse(body);
|
|
342
|
+
if (data.error) {
|
|
343
|
+
const realCode = _LivenessClient.unwrapErrorCode(data.error, data.message);
|
|
344
|
+
const realMessage = _LivenessClient.unwrapErrorMessage(data.message);
|
|
345
|
+
return new LivenessApiError(
|
|
346
|
+
realMessage ?? `Request failed (${realCode})`,
|
|
347
|
+
realCode,
|
|
348
|
+
status,
|
|
349
|
+
data.required,
|
|
350
|
+
data.received
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
} catch {
|
|
354
|
+
}
|
|
355
|
+
const code = _LivenessClient.extractCodeFromText(body) ?? "server_error";
|
|
356
|
+
return new LivenessApiError(`Request failed with status ${status}`, code, status);
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* When the outer error code is a generic wrapper (e.g. "http_error"),
|
|
360
|
+
* try to extract the real error code from the message text.
|
|
361
|
+
*/
|
|
362
|
+
static unwrapErrorCode(outerCode, message) {
|
|
363
|
+
const WRAPPER_CODES = /* @__PURE__ */ new Set([
|
|
364
|
+
"http_error",
|
|
365
|
+
"upstream_error",
|
|
366
|
+
"proxy_error",
|
|
367
|
+
"internal_error"
|
|
368
|
+
]);
|
|
369
|
+
if (!WRAPPER_CODES.has(outerCode) || !message) {
|
|
370
|
+
return outerCode;
|
|
371
|
+
}
|
|
372
|
+
return _LivenessClient.extractCodeFromText(message) ?? outerCode;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Try to extract a human-readable message from a nested Python dict string.
|
|
376
|
+
* E.g.: "{'error': 'session_expired', 'message': \"Create a new session...\"}"
|
|
377
|
+
* → "Create a new session..."
|
|
378
|
+
*/
|
|
379
|
+
static unwrapErrorMessage(message) {
|
|
380
|
+
if (!message) return void 0;
|
|
381
|
+
const msgMatch = /'message'\s*:\s*"([^"]+)"/.exec(message) ?? /'message'\s*:\s*'([^']+)'/.exec(message) ?? /"message"\s*:\s*"([^"]+)"/.exec(message);
|
|
382
|
+
return msgMatch?.[1] ?? void 0;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Extract an error code from raw text using regex.
|
|
386
|
+
* Handles both Python dict (`'error': 'code'`) and JSON (`"error": "code"`).
|
|
387
|
+
*/
|
|
388
|
+
static extractCodeFromText(text) {
|
|
389
|
+
const match = /'error'\s*:\s*'([^']+)'/.exec(text) ?? /"error"\s*:\s*"([^"]+)"/.exec(text);
|
|
390
|
+
return match?.[1] ?? null;
|
|
391
|
+
}
|
|
324
392
|
/**
|
|
325
393
|
* Make a request with optional retry
|
|
326
394
|
*/
|
|
@@ -952,6 +1020,81 @@ var DEFAULT_STABILIZER_CONFIG = {
|
|
|
952
1020
|
sampleSize: 64
|
|
953
1021
|
};
|
|
954
1022
|
|
|
1023
|
+
// src/constants/errors.ts
|
|
1024
|
+
var API_ERROR_CODES = {
|
|
1025
|
+
SESSION_EXPIRED: "session_expired",
|
|
1026
|
+
INVALID_KEY: "invalid_key",
|
|
1027
|
+
INVALID_MODEL: "invalid_model",
|
|
1028
|
+
INSUFFICIENT_FRAMES: "insufficient_frames",
|
|
1029
|
+
MISSING_FIELD: "missing_field",
|
|
1030
|
+
INVALID_FRAME: "invalid_frame",
|
|
1031
|
+
INVALID_SESSION: "invalid_session",
|
|
1032
|
+
RATE_LIMITED: "rate_limited",
|
|
1033
|
+
STREAM_INCOMPLETE: "stream_incomplete",
|
|
1034
|
+
NO_VERDICT: "no_verdict",
|
|
1035
|
+
TIMEOUT: "timeout",
|
|
1036
|
+
NETWORK_ERROR: "network_error",
|
|
1037
|
+
SERVER_ERROR: "server_error"
|
|
1038
|
+
};
|
|
1039
|
+
var ERROR_MESSAGES = {
|
|
1040
|
+
[API_ERROR_CODES.SESSION_EXPIRED]: "Session expired \u2014 please restart the verification",
|
|
1041
|
+
[API_ERROR_CODES.INVALID_KEY]: "Invalid API key \u2014 contact your administrator",
|
|
1042
|
+
[API_ERROR_CODES.INVALID_MODEL]: "Invalid model configuration",
|
|
1043
|
+
[API_ERROR_CODES.INSUFFICIENT_FRAMES]: "Not enough frames captured \u2014 try again",
|
|
1044
|
+
[API_ERROR_CODES.MISSING_FIELD]: "Missing required data \u2014 please try again",
|
|
1045
|
+
[API_ERROR_CODES.INVALID_FRAME]: "Invalid frame data \u2014 please try again",
|
|
1046
|
+
[API_ERROR_CODES.INVALID_SESSION]: "Invalid session \u2014 please restart",
|
|
1047
|
+
[API_ERROR_CODES.RATE_LIMITED]: "Too many requests \u2014 wait a moment and try again",
|
|
1048
|
+
[API_ERROR_CODES.STREAM_INCOMPLETE]: "Streaming incomplete \u2014 please try again",
|
|
1049
|
+
[API_ERROR_CODES.NO_VERDICT]: "No result received \u2014 please try again",
|
|
1050
|
+
[API_ERROR_CODES.TIMEOUT]: "Request timed out \u2014 check your connection",
|
|
1051
|
+
[API_ERROR_CODES.NETWORK_ERROR]: "Network error \u2014 check your connection",
|
|
1052
|
+
[API_ERROR_CODES.SERVER_ERROR]: "Server error \u2014 please try again later"
|
|
1053
|
+
};
|
|
1054
|
+
var ERROR_MESSAGES_ES = {
|
|
1055
|
+
[API_ERROR_CODES.SESSION_EXPIRED]: "Sesi\xF3n expirada \u2014 reinicie la verificaci\xF3n",
|
|
1056
|
+
[API_ERROR_CODES.INVALID_KEY]: "Clave API inv\xE1lida \u2014 contacte al administrador",
|
|
1057
|
+
[API_ERROR_CODES.INVALID_MODEL]: "Configuraci\xF3n de modelo inv\xE1lida",
|
|
1058
|
+
[API_ERROR_CODES.INSUFFICIENT_FRAMES]: "Frames insuficientes \u2014 intente de nuevo",
|
|
1059
|
+
[API_ERROR_CODES.MISSING_FIELD]: "Datos requeridos faltantes \u2014 intente de nuevo",
|
|
1060
|
+
[API_ERROR_CODES.INVALID_FRAME]: "Frame inv\xE1lido \u2014 intente de nuevo",
|
|
1061
|
+
[API_ERROR_CODES.INVALID_SESSION]: "Sesi\xF3n inv\xE1lida \u2014 reinicie",
|
|
1062
|
+
[API_ERROR_CODES.RATE_LIMITED]: "Demasiadas solicitudes \u2014 espere un momento",
|
|
1063
|
+
[API_ERROR_CODES.STREAM_INCOMPLETE]: "Streaming incompleto \u2014 intente de nuevo",
|
|
1064
|
+
[API_ERROR_CODES.NO_VERDICT]: "Sin resultado \u2014 intente de nuevo",
|
|
1065
|
+
[API_ERROR_CODES.TIMEOUT]: "Tiempo de espera agotado \u2014 verifique su conexi\xF3n",
|
|
1066
|
+
[API_ERROR_CODES.NETWORK_ERROR]: "Error de red \u2014 verifique su conexi\xF3n",
|
|
1067
|
+
[API_ERROR_CODES.SERVER_ERROR]: "Error del servidor \u2014 intente m\xE1s tarde"
|
|
1068
|
+
};
|
|
1069
|
+
function looksLikeRawData(text) {
|
|
1070
|
+
const trimmed = text.trim();
|
|
1071
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) return true;
|
|
1072
|
+
if (/'error'\s*:/.test(trimmed)) return true;
|
|
1073
|
+
if (/"error"\s*:/.test(trimmed)) return true;
|
|
1074
|
+
return false;
|
|
1075
|
+
}
|
|
1076
|
+
var GENERIC_FALLBACK = "An unexpected error occurred \u2014 please try again";
|
|
1077
|
+
function getApiErrorMessage(code, message, customMessages) {
|
|
1078
|
+
if (code) {
|
|
1079
|
+
const custom = customMessages?.[code];
|
|
1080
|
+
if (custom) return custom;
|
|
1081
|
+
const known = ERROR_MESSAGES[code];
|
|
1082
|
+
if (known) return known;
|
|
1083
|
+
}
|
|
1084
|
+
if (message && !looksLikeRawData(message)) {
|
|
1085
|
+
return message;
|
|
1086
|
+
}
|
|
1087
|
+
return GENERIC_FALLBACK;
|
|
1088
|
+
}
|
|
1089
|
+
function isRetryableError(code) {
|
|
1090
|
+
if (!code) return true;
|
|
1091
|
+
const nonRetryable = /* @__PURE__ */ new Set([
|
|
1092
|
+
API_ERROR_CODES.INVALID_KEY,
|
|
1093
|
+
API_ERROR_CODES.INVALID_MODEL
|
|
1094
|
+
]);
|
|
1095
|
+
return !nonRetryable.has(code);
|
|
1096
|
+
}
|
|
1097
|
+
|
|
955
1098
|
// src/constants/feedback.ts
|
|
956
1099
|
var ALIGNMENT_THRESHOLD_CAPTURE = 0.6;
|
|
957
1100
|
var ALIGNMENT_THRESHOLD_POOR = 0.5;
|
|
@@ -1530,6 +1673,7 @@ function validateFaceLandmarks(landmarks) {
|
|
|
1530
1673
|
ALIGNMENT_THRESHOLD_PERFECT,
|
|
1531
1674
|
ALIGNMENT_THRESHOLD_POOR,
|
|
1532
1675
|
API_ENDPOINTS,
|
|
1676
|
+
API_ERROR_CODES,
|
|
1533
1677
|
API_PATHS,
|
|
1534
1678
|
AUTH_CONFIG,
|
|
1535
1679
|
BACKLIT_RATIO_THRESHOLD,
|
|
@@ -1545,6 +1689,8 @@ function validateFaceLandmarks(landmarks) {
|
|
|
1545
1689
|
DEFAULT_OVAL_REGION,
|
|
1546
1690
|
DEFAULT_STABILIZER_CONFIG,
|
|
1547
1691
|
DEFAULT_STATUS_MESSAGES,
|
|
1692
|
+
ERROR_MESSAGES,
|
|
1693
|
+
ERROR_MESSAGES_ES,
|
|
1548
1694
|
ES_LOCALE,
|
|
1549
1695
|
FACE_CENTER_VERTICAL_OFFSET,
|
|
1550
1696
|
FACE_CROP_OUTPUT_SIZE,
|
|
@@ -1589,6 +1735,7 @@ function validateFaceLandmarks(landmarks) {
|
|
|
1589
1735
|
decodeBase64,
|
|
1590
1736
|
encodeBase64,
|
|
1591
1737
|
generateSessionId,
|
|
1738
|
+
getApiErrorMessage,
|
|
1592
1739
|
getCaptureQualityFeedback,
|
|
1593
1740
|
getFeedbackMessage,
|
|
1594
1741
|
getMinFramesForModel,
|
|
@@ -1598,6 +1745,7 @@ function validateFaceLandmarks(landmarks) {
|
|
|
1598
1745
|
isFaceCropFullyInFrame,
|
|
1599
1746
|
isFaceFullyVisible,
|
|
1600
1747
|
isFaceInOval,
|
|
1748
|
+
isRetryableError,
|
|
1601
1749
|
retryWithBackoff,
|
|
1602
1750
|
rgbaToGrayscale,
|
|
1603
1751
|
sleep,
|
package/dist/index.mjs
CHANGED
|
@@ -135,7 +135,8 @@ function toLivenessResultFromStream(response) {
|
|
|
135
135
|
throw new LivenessApiError("Stream not complete", "stream_incomplete", 400);
|
|
136
136
|
}
|
|
137
137
|
if (!response.verdict) {
|
|
138
|
-
|
|
138
|
+
const errorCode = response.error ?? "no_verdict";
|
|
139
|
+
throw new LivenessApiError(response.error ?? "No verdict received", errorCode, 500);
|
|
139
140
|
}
|
|
140
141
|
return {
|
|
141
142
|
verdict: response.verdict,
|
|
@@ -156,7 +157,7 @@ function generateSessionId() {
|
|
|
156
157
|
return v.toString(16);
|
|
157
158
|
});
|
|
158
159
|
}
|
|
159
|
-
var LivenessClient = class {
|
|
160
|
+
var LivenessClient = class _LivenessClient {
|
|
160
161
|
constructor(config) {
|
|
161
162
|
this.baseUrl = (config.baseUrl ?? DEFAULT_ENDPOINT).replace(/\/$/, "");
|
|
162
163
|
this.apiKey = config.apiKey;
|
|
@@ -183,14 +184,7 @@ var LivenessClient = class {
|
|
|
183
184
|
});
|
|
184
185
|
clearTimeout(timeoutId);
|
|
185
186
|
if (!response.ok) {
|
|
186
|
-
|
|
187
|
-
throw new LivenessApiError(
|
|
188
|
-
errorData.message,
|
|
189
|
-
errorData.error,
|
|
190
|
-
response.status,
|
|
191
|
-
errorData.required,
|
|
192
|
-
errorData.received
|
|
193
|
-
);
|
|
187
|
+
throw await this.parseErrorResponse(response);
|
|
194
188
|
}
|
|
195
189
|
return await response.json();
|
|
196
190
|
} catch (error) {
|
|
@@ -208,6 +202,75 @@ var LivenessClient = class {
|
|
|
208
202
|
);
|
|
209
203
|
}
|
|
210
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* Parse an error response body, handling both JSON and non-JSON bodies.
|
|
207
|
+
*
|
|
208
|
+
* The backend sometimes wraps the real error in a generic envelope:
|
|
209
|
+
* ```json
|
|
210
|
+
* { "error": "http_error", "message": "{'error': 'session_expired', ...}" }
|
|
211
|
+
* ```
|
|
212
|
+
* This method unwraps such envelopes to extract the real error code.
|
|
213
|
+
*/
|
|
214
|
+
async parseErrorResponse(response) {
|
|
215
|
+
const status = response.status;
|
|
216
|
+
let body;
|
|
217
|
+
try {
|
|
218
|
+
body = await response.text();
|
|
219
|
+
} catch {
|
|
220
|
+
return new LivenessApiError(`Request failed with status ${status}`, "server_error", status);
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
const data = JSON.parse(body);
|
|
224
|
+
if (data.error) {
|
|
225
|
+
const realCode = _LivenessClient.unwrapErrorCode(data.error, data.message);
|
|
226
|
+
const realMessage = _LivenessClient.unwrapErrorMessage(data.message);
|
|
227
|
+
return new LivenessApiError(
|
|
228
|
+
realMessage ?? `Request failed (${realCode})`,
|
|
229
|
+
realCode,
|
|
230
|
+
status,
|
|
231
|
+
data.required,
|
|
232
|
+
data.received
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
} catch {
|
|
236
|
+
}
|
|
237
|
+
const code = _LivenessClient.extractCodeFromText(body) ?? "server_error";
|
|
238
|
+
return new LivenessApiError(`Request failed with status ${status}`, code, status);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* When the outer error code is a generic wrapper (e.g. "http_error"),
|
|
242
|
+
* try to extract the real error code from the message text.
|
|
243
|
+
*/
|
|
244
|
+
static unwrapErrorCode(outerCode, message) {
|
|
245
|
+
const WRAPPER_CODES = /* @__PURE__ */ new Set([
|
|
246
|
+
"http_error",
|
|
247
|
+
"upstream_error",
|
|
248
|
+
"proxy_error",
|
|
249
|
+
"internal_error"
|
|
250
|
+
]);
|
|
251
|
+
if (!WRAPPER_CODES.has(outerCode) || !message) {
|
|
252
|
+
return outerCode;
|
|
253
|
+
}
|
|
254
|
+
return _LivenessClient.extractCodeFromText(message) ?? outerCode;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Try to extract a human-readable message from a nested Python dict string.
|
|
258
|
+
* E.g.: "{'error': 'session_expired', 'message': \"Create a new session...\"}"
|
|
259
|
+
* → "Create a new session..."
|
|
260
|
+
*/
|
|
261
|
+
static unwrapErrorMessage(message) {
|
|
262
|
+
if (!message) return void 0;
|
|
263
|
+
const msgMatch = /'message'\s*:\s*"([^"]+)"/.exec(message) ?? /'message'\s*:\s*'([^']+)'/.exec(message) ?? /"message"\s*:\s*"([^"]+)"/.exec(message);
|
|
264
|
+
return msgMatch?.[1] ?? void 0;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Extract an error code from raw text using regex.
|
|
268
|
+
* Handles both Python dict (`'error': 'code'`) and JSON (`"error": "code"`).
|
|
269
|
+
*/
|
|
270
|
+
static extractCodeFromText(text) {
|
|
271
|
+
const match = /'error'\s*:\s*'([^']+)'/.exec(text) ?? /"error"\s*:\s*"([^"]+)"/.exec(text);
|
|
272
|
+
return match?.[1] ?? null;
|
|
273
|
+
}
|
|
211
274
|
/**
|
|
212
275
|
* Make a request with optional retry
|
|
213
276
|
*/
|
|
@@ -839,6 +902,81 @@ var DEFAULT_STABILIZER_CONFIG = {
|
|
|
839
902
|
sampleSize: 64
|
|
840
903
|
};
|
|
841
904
|
|
|
905
|
+
// src/constants/errors.ts
|
|
906
|
+
var API_ERROR_CODES = {
|
|
907
|
+
SESSION_EXPIRED: "session_expired",
|
|
908
|
+
INVALID_KEY: "invalid_key",
|
|
909
|
+
INVALID_MODEL: "invalid_model",
|
|
910
|
+
INSUFFICIENT_FRAMES: "insufficient_frames",
|
|
911
|
+
MISSING_FIELD: "missing_field",
|
|
912
|
+
INVALID_FRAME: "invalid_frame",
|
|
913
|
+
INVALID_SESSION: "invalid_session",
|
|
914
|
+
RATE_LIMITED: "rate_limited",
|
|
915
|
+
STREAM_INCOMPLETE: "stream_incomplete",
|
|
916
|
+
NO_VERDICT: "no_verdict",
|
|
917
|
+
TIMEOUT: "timeout",
|
|
918
|
+
NETWORK_ERROR: "network_error",
|
|
919
|
+
SERVER_ERROR: "server_error"
|
|
920
|
+
};
|
|
921
|
+
var ERROR_MESSAGES = {
|
|
922
|
+
[API_ERROR_CODES.SESSION_EXPIRED]: "Session expired \u2014 please restart the verification",
|
|
923
|
+
[API_ERROR_CODES.INVALID_KEY]: "Invalid API key \u2014 contact your administrator",
|
|
924
|
+
[API_ERROR_CODES.INVALID_MODEL]: "Invalid model configuration",
|
|
925
|
+
[API_ERROR_CODES.INSUFFICIENT_FRAMES]: "Not enough frames captured \u2014 try again",
|
|
926
|
+
[API_ERROR_CODES.MISSING_FIELD]: "Missing required data \u2014 please try again",
|
|
927
|
+
[API_ERROR_CODES.INVALID_FRAME]: "Invalid frame data \u2014 please try again",
|
|
928
|
+
[API_ERROR_CODES.INVALID_SESSION]: "Invalid session \u2014 please restart",
|
|
929
|
+
[API_ERROR_CODES.RATE_LIMITED]: "Too many requests \u2014 wait a moment and try again",
|
|
930
|
+
[API_ERROR_CODES.STREAM_INCOMPLETE]: "Streaming incomplete \u2014 please try again",
|
|
931
|
+
[API_ERROR_CODES.NO_VERDICT]: "No result received \u2014 please try again",
|
|
932
|
+
[API_ERROR_CODES.TIMEOUT]: "Request timed out \u2014 check your connection",
|
|
933
|
+
[API_ERROR_CODES.NETWORK_ERROR]: "Network error \u2014 check your connection",
|
|
934
|
+
[API_ERROR_CODES.SERVER_ERROR]: "Server error \u2014 please try again later"
|
|
935
|
+
};
|
|
936
|
+
var ERROR_MESSAGES_ES = {
|
|
937
|
+
[API_ERROR_CODES.SESSION_EXPIRED]: "Sesi\xF3n expirada \u2014 reinicie la verificaci\xF3n",
|
|
938
|
+
[API_ERROR_CODES.INVALID_KEY]: "Clave API inv\xE1lida \u2014 contacte al administrador",
|
|
939
|
+
[API_ERROR_CODES.INVALID_MODEL]: "Configuraci\xF3n de modelo inv\xE1lida",
|
|
940
|
+
[API_ERROR_CODES.INSUFFICIENT_FRAMES]: "Frames insuficientes \u2014 intente de nuevo",
|
|
941
|
+
[API_ERROR_CODES.MISSING_FIELD]: "Datos requeridos faltantes \u2014 intente de nuevo",
|
|
942
|
+
[API_ERROR_CODES.INVALID_FRAME]: "Frame inv\xE1lido \u2014 intente de nuevo",
|
|
943
|
+
[API_ERROR_CODES.INVALID_SESSION]: "Sesi\xF3n inv\xE1lida \u2014 reinicie",
|
|
944
|
+
[API_ERROR_CODES.RATE_LIMITED]: "Demasiadas solicitudes \u2014 espere un momento",
|
|
945
|
+
[API_ERROR_CODES.STREAM_INCOMPLETE]: "Streaming incompleto \u2014 intente de nuevo",
|
|
946
|
+
[API_ERROR_CODES.NO_VERDICT]: "Sin resultado \u2014 intente de nuevo",
|
|
947
|
+
[API_ERROR_CODES.TIMEOUT]: "Tiempo de espera agotado \u2014 verifique su conexi\xF3n",
|
|
948
|
+
[API_ERROR_CODES.NETWORK_ERROR]: "Error de red \u2014 verifique su conexi\xF3n",
|
|
949
|
+
[API_ERROR_CODES.SERVER_ERROR]: "Error del servidor \u2014 intente m\xE1s tarde"
|
|
950
|
+
};
|
|
951
|
+
function looksLikeRawData(text) {
|
|
952
|
+
const trimmed = text.trim();
|
|
953
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) return true;
|
|
954
|
+
if (/'error'\s*:/.test(trimmed)) return true;
|
|
955
|
+
if (/"error"\s*:/.test(trimmed)) return true;
|
|
956
|
+
return false;
|
|
957
|
+
}
|
|
958
|
+
var GENERIC_FALLBACK = "An unexpected error occurred \u2014 please try again";
|
|
959
|
+
function getApiErrorMessage(code, message, customMessages) {
|
|
960
|
+
if (code) {
|
|
961
|
+
const custom = customMessages?.[code];
|
|
962
|
+
if (custom) return custom;
|
|
963
|
+
const known = ERROR_MESSAGES[code];
|
|
964
|
+
if (known) return known;
|
|
965
|
+
}
|
|
966
|
+
if (message && !looksLikeRawData(message)) {
|
|
967
|
+
return message;
|
|
968
|
+
}
|
|
969
|
+
return GENERIC_FALLBACK;
|
|
970
|
+
}
|
|
971
|
+
function isRetryableError(code) {
|
|
972
|
+
if (!code) return true;
|
|
973
|
+
const nonRetryable = /* @__PURE__ */ new Set([
|
|
974
|
+
API_ERROR_CODES.INVALID_KEY,
|
|
975
|
+
API_ERROR_CODES.INVALID_MODEL
|
|
976
|
+
]);
|
|
977
|
+
return !nonRetryable.has(code);
|
|
978
|
+
}
|
|
979
|
+
|
|
842
980
|
// src/constants/feedback.ts
|
|
843
981
|
var ALIGNMENT_THRESHOLD_CAPTURE = 0.6;
|
|
844
982
|
var ALIGNMENT_THRESHOLD_POOR = 0.5;
|
|
@@ -1416,6 +1554,7 @@ export {
|
|
|
1416
1554
|
ALIGNMENT_THRESHOLD_PERFECT,
|
|
1417
1555
|
ALIGNMENT_THRESHOLD_POOR,
|
|
1418
1556
|
API_ENDPOINTS,
|
|
1557
|
+
API_ERROR_CODES,
|
|
1419
1558
|
API_PATHS,
|
|
1420
1559
|
AUTH_CONFIG,
|
|
1421
1560
|
BACKLIT_RATIO_THRESHOLD,
|
|
@@ -1431,6 +1570,8 @@ export {
|
|
|
1431
1570
|
DEFAULT_OVAL_REGION,
|
|
1432
1571
|
DEFAULT_STABILIZER_CONFIG,
|
|
1433
1572
|
DEFAULT_STATUS_MESSAGES,
|
|
1573
|
+
ERROR_MESSAGES,
|
|
1574
|
+
ERROR_MESSAGES_ES,
|
|
1434
1575
|
ES_LOCALE,
|
|
1435
1576
|
FACE_CENTER_VERTICAL_OFFSET,
|
|
1436
1577
|
FACE_CROP_OUTPUT_SIZE,
|
|
@@ -1475,6 +1616,7 @@ export {
|
|
|
1475
1616
|
decodeBase64,
|
|
1476
1617
|
encodeBase64,
|
|
1477
1618
|
generateSessionId,
|
|
1619
|
+
getApiErrorMessage,
|
|
1478
1620
|
getCaptureQualityFeedback,
|
|
1479
1621
|
getFeedbackMessage,
|
|
1480
1622
|
getMinFramesForModel,
|
|
@@ -1484,6 +1626,7 @@ export {
|
|
|
1484
1626
|
isFaceCropFullyInFrame,
|
|
1485
1627
|
isFaceFullyVisible,
|
|
1486
1628
|
isFaceInOval,
|
|
1629
|
+
isRetryableError,
|
|
1487
1630
|
retryWithBackoff,
|
|
1488
1631
|
rgbaToGrayscale,
|
|
1489
1632
|
sleep,
|