@switchlabs/verify-ai-react-native 2.5.3 → 2.5.4
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/lib/components/VerifyAIScanner.js +9 -14
- package/lib/components/cameraCaptureRetry.d.ts +12 -0
- package/lib/components/cameraCaptureRetry.js +23 -0
- package/lib/types/index.d.ts +2 -0
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +2 -1
- package/src/components/VerifyAIScanner.tsx +12 -14
- package/src/components/cameraCaptureRetry.ts +37 -0
- package/src/types/index.ts +2 -0
- package/src/version.ts +1 -1
|
@@ -8,6 +8,7 @@ import { SDK_VERSION } from '../version';
|
|
|
8
8
|
import { BikeOverlay } from './BikeOverlay';
|
|
9
9
|
import { ScooterOverlay } from './ScooterOverlay';
|
|
10
10
|
import { ANDROID_ACCELEROMETER_AXIS_DOMINANCE_THRESHOLD, classifyAndroidAccelerometerOrientation, getOverlayRotationDeg, } from './scannerOrientation';
|
|
11
|
+
import { CAMERA_CAPTURE_RETRY_DELAY_MS, getCameraCaptureRetryPlan, } from './cameraCaptureRetry';
|
|
11
12
|
/** Quality used when expo-image-manipulator is not available (lower = smaller). */
|
|
12
13
|
const FALLBACK_QUALITY = 0.65;
|
|
13
14
|
/** Quality used when expo-image-manipulator IS available (resize handles size). */
|
|
@@ -19,10 +20,6 @@ const CAMERA_NOT_READY_ERROR_CODE = 'ERR_CAMERA_NOT_READY';
|
|
|
19
20
|
const CAMERA_INIT_ERROR_CODE = 'ERR_CAMERA_INIT_FAILED';
|
|
20
21
|
const DEFAULT_TERMINAL_RESULT_DISPLAY_MS = 3000;
|
|
21
22
|
const TRANSIENT_ERROR_DISPLAY_MS = 3000;
|
|
22
|
-
const CAMERA_CAPTURE_RETRY_DELAY_MS = 350;
|
|
23
|
-
const CAMERA_CAPTURE_RETRY_TORCH_SETTLE_MS = 800;
|
|
24
|
-
const IOS_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS = 3000;
|
|
25
|
-
const ANDROID_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS = 10000;
|
|
26
23
|
// iOS AVCaptureSession cold start can legitimately exceed 8s on first launch (permission
|
|
27
24
|
// prompt, first-ever session spin-up, thermal/low-power throttling). An 8s watchdog tore
|
|
28
25
|
// down sessions that were seconds from ready and restarted from scratch, which made slow
|
|
@@ -958,6 +955,7 @@ export function VerifyAIScanner({ onCapture, policy, onResult, onError, onClose,
|
|
|
958
955
|
let captureRetryTorchSuppressed = false;
|
|
959
956
|
let captureRetrySettleDelayMs = CAMERA_CAPTURE_RETRY_DELAY_MS;
|
|
960
957
|
let captureRetryRemountBackoffMs = 0;
|
|
958
|
+
let captureRetryReadyTimeoutMs = 0;
|
|
961
959
|
let lastNativeCaptureErrorMessage = null;
|
|
962
960
|
try {
|
|
963
961
|
const capturePhysicalOrientation = physicalOrientation;
|
|
@@ -1025,13 +1023,11 @@ export function VerifyAIScanner({ onCapture, policy, onResult, onError, onClose,
|
|
|
1025
1023
|
lastNativeCaptureErrorMessage = normalized.message;
|
|
1026
1024
|
if (attempt === 1 && isNativeCameraCaptureError(normalized) && !terminated) {
|
|
1027
1025
|
captureRetryAttempted = true;
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
? CAMERA_CAPTURE_RETRY_DELAY_MS
|
|
1034
|
-
: 0;
|
|
1026
|
+
const retryPlan = getCameraCaptureRetryPlan(Platform.OS, !!enableTorch);
|
|
1027
|
+
captureRetryTorchSuppressed = retryPlan.suppressTorch;
|
|
1028
|
+
captureRetrySettleDelayMs = retryPlan.settleDelayMs;
|
|
1029
|
+
captureRetryRemountBackoffMs = retryPlan.remountBackoffMs;
|
|
1030
|
+
captureRetryReadyTimeoutMs = retryPlan.readyTimeoutMs;
|
|
1035
1031
|
const retryAt = new Date().toISOString();
|
|
1036
1032
|
lastCaptureRetryAtRef.current = retryAt;
|
|
1037
1033
|
cameraRemountCountRef.current++;
|
|
@@ -1042,9 +1038,6 @@ export function VerifyAIScanner({ onCapture, policy, onResult, onError, onClose,
|
|
|
1042
1038
|
? { backoffMs: captureRetryRemountBackoffMs }
|
|
1043
1039
|
: undefined);
|
|
1044
1040
|
await sleep(captureRetrySettleDelayMs);
|
|
1045
|
-
const captureRetryReadyTimeoutMs = Platform.OS === 'android'
|
|
1046
|
-
? ANDROID_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS
|
|
1047
|
-
: IOS_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS;
|
|
1048
1041
|
captureRetryReady = await waitForCameraReady(captureRetryReadyTimeoutMs);
|
|
1049
1042
|
telemetry?.track('camera_capture_retry', {
|
|
1050
1043
|
component: 'scanner',
|
|
@@ -1142,6 +1135,7 @@ export function VerifyAIScanner({ onCapture, policy, onResult, onError, onClose,
|
|
|
1142
1135
|
capture_retry_torch_suppressed: captureRetryTorchSuppressed,
|
|
1143
1136
|
capture_retry_settle_delay_ms: captureRetrySettleDelayMs,
|
|
1144
1137
|
capture_retry_remount_backoff_ms: captureRetryRemountBackoffMs,
|
|
1138
|
+
capture_retry_ready_timeout_ms: captureRetryReadyTimeoutMs,
|
|
1145
1139
|
recovered_native_capture_failure: captureRetryAttempted ? 1 : 0,
|
|
1146
1140
|
last_native_capture_error: lastNativeCaptureErrorMessage,
|
|
1147
1141
|
}),
|
|
@@ -1218,6 +1212,7 @@ export function VerifyAIScanner({ onCapture, policy, onResult, onError, onClose,
|
|
|
1218
1212
|
capture_retry_torch_suppressed: captureRetryTorchSuppressed,
|
|
1219
1213
|
capture_retry_settle_delay_ms: captureRetrySettleDelayMs,
|
|
1220
1214
|
capture_retry_remount_backoff_ms: captureRetryRemountBackoffMs,
|
|
1215
|
+
capture_retry_ready_timeout_ms: captureRetryReadyTimeoutMs,
|
|
1221
1216
|
is_native_camera_capture_error: isNativeCameraCaptureError(error),
|
|
1222
1217
|
last_native_capture_error: lastNativeCaptureErrorMessage,
|
|
1223
1218
|
}),
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const CAMERA_CAPTURE_RETRY_DELAY_MS = 350;
|
|
2
|
+
export declare const CAMERA_CAPTURE_RETRY_TORCH_SETTLE_MS = 800;
|
|
3
|
+
export declare const IOS_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS = 3000;
|
|
4
|
+
export declare const ANDROID_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS = 10000;
|
|
5
|
+
export type CameraCaptureRetryPlatform = 'ios' | 'android' | string;
|
|
6
|
+
export interface CameraCaptureRetryPlan {
|
|
7
|
+
readyTimeoutMs: number;
|
|
8
|
+
remountBackoffMs: number;
|
|
9
|
+
settleDelayMs: number;
|
|
10
|
+
suppressTorch: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function getCameraCaptureRetryPlan(platform: CameraCaptureRetryPlatform, torchRequested: boolean): CameraCaptureRetryPlan;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const CAMERA_CAPTURE_RETRY_DELAY_MS = 350;
|
|
2
|
+
export const CAMERA_CAPTURE_RETRY_TORCH_SETTLE_MS = 800;
|
|
3
|
+
export const IOS_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS = 3000;
|
|
4
|
+
export const ANDROID_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS = 10000;
|
|
5
|
+
export function getCameraCaptureRetryPlan(platform, torchRequested) {
|
|
6
|
+
const suppressTorch = torchRequested;
|
|
7
|
+
return {
|
|
8
|
+
readyTimeoutMs: platform === 'android'
|
|
9
|
+
? ANDROID_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS
|
|
10
|
+
: IOS_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS,
|
|
11
|
+
// Flutter fully restarts its CameraController after native capture errors.
|
|
12
|
+
// On iOS/Expo Camera, a key-only remount can report ready too quickly while
|
|
13
|
+
// the native capture session is still unable to produce a photo, so force a
|
|
14
|
+
// brief unmount before the retry.
|
|
15
|
+
remountBackoffMs: platform === 'ios' || suppressTorch
|
|
16
|
+
? CAMERA_CAPTURE_RETRY_DELAY_MS
|
|
17
|
+
: 0,
|
|
18
|
+
settleDelayMs: suppressTorch
|
|
19
|
+
? CAMERA_CAPTURE_RETRY_TORCH_SETTLE_MS
|
|
20
|
+
: CAMERA_CAPTURE_RETRY_DELAY_MS,
|
|
21
|
+
suppressTorch,
|
|
22
|
+
};
|
|
23
|
+
}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ export interface VerificationResult {
|
|
|
33
33
|
policy: string;
|
|
34
34
|
violation_reasons: string[];
|
|
35
35
|
feedback: string;
|
|
36
|
+
warning_violation_reasons?: string[];
|
|
37
|
+
warning_feedback?: string | null;
|
|
36
38
|
metadata: Record<string, unknown>;
|
|
37
39
|
image_url: string | null;
|
|
38
40
|
/** Base64-encoded image data URI. Only present when `include_image_data` is requested. */
|
package/lib/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "2.5.
|
|
1
|
+
export declare const SDK_VERSION = "2.5.4";
|
package/lib/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SDK_VERSION = '2.5.
|
|
1
|
+
export const SDK_VERSION = '2.5.4';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@switchlabs/verify-ai-react-native",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.4",
|
|
4
4
|
"description": "React Native SDK for Verify AI - photo verification with AI vision processing",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
],
|
|
26
26
|
"scripts": {
|
|
27
27
|
"typecheck": "tsc --noEmit",
|
|
28
|
+
"test": "vitest run",
|
|
28
29
|
"build": "tsc",
|
|
29
30
|
"prepublishOnly": "npm run build"
|
|
30
31
|
},
|
|
@@ -32,6 +32,10 @@ import {
|
|
|
32
32
|
getOverlayRotationDeg,
|
|
33
33
|
type ScannerPhysicalOrientation,
|
|
34
34
|
} from './scannerOrientation';
|
|
35
|
+
import {
|
|
36
|
+
CAMERA_CAPTURE_RETRY_DELAY_MS,
|
|
37
|
+
getCameraCaptureRetryPlan,
|
|
38
|
+
} from './cameraCaptureRetry';
|
|
35
39
|
|
|
36
40
|
/** Quality used when expo-image-manipulator is not available (lower = smaller). */
|
|
37
41
|
const FALLBACK_QUALITY = 0.65;
|
|
@@ -44,10 +48,6 @@ const CAMERA_NOT_READY_ERROR_CODE = 'ERR_CAMERA_NOT_READY';
|
|
|
44
48
|
const CAMERA_INIT_ERROR_CODE = 'ERR_CAMERA_INIT_FAILED';
|
|
45
49
|
const DEFAULT_TERMINAL_RESULT_DISPLAY_MS = 3000;
|
|
46
50
|
const TRANSIENT_ERROR_DISPLAY_MS = 3000;
|
|
47
|
-
const CAMERA_CAPTURE_RETRY_DELAY_MS = 350;
|
|
48
|
-
const CAMERA_CAPTURE_RETRY_TORCH_SETTLE_MS = 800;
|
|
49
|
-
const IOS_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS = 3000;
|
|
50
|
-
const ANDROID_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS = 10000;
|
|
51
51
|
// iOS AVCaptureSession cold start can legitimately exceed 8s on first launch (permission
|
|
52
52
|
// prompt, first-ever session spin-up, thermal/low-power throttling). An 8s watchdog tore
|
|
53
53
|
// down sessions that were seconds from ready and restarted from scratch, which made slow
|
|
@@ -1172,6 +1172,7 @@ export function VerifyAIScanner({
|
|
|
1172
1172
|
let captureRetryTorchSuppressed = false;
|
|
1173
1173
|
let captureRetrySettleDelayMs = CAMERA_CAPTURE_RETRY_DELAY_MS;
|
|
1174
1174
|
let captureRetryRemountBackoffMs = 0;
|
|
1175
|
+
let captureRetryReadyTimeoutMs = 0;
|
|
1175
1176
|
let lastNativeCaptureErrorMessage: string | null = null;
|
|
1176
1177
|
|
|
1177
1178
|
try {
|
|
@@ -1251,13 +1252,11 @@ export function VerifyAIScanner({
|
|
|
1251
1252
|
|
|
1252
1253
|
if (attempt === 1 && isNativeCameraCaptureError(normalized) && !terminated) {
|
|
1253
1254
|
captureRetryAttempted = true;
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
? CAMERA_CAPTURE_RETRY_DELAY_MS
|
|
1260
|
-
: 0;
|
|
1255
|
+
const retryPlan = getCameraCaptureRetryPlan(Platform.OS, !!enableTorch);
|
|
1256
|
+
captureRetryTorchSuppressed = retryPlan.suppressTorch;
|
|
1257
|
+
captureRetrySettleDelayMs = retryPlan.settleDelayMs;
|
|
1258
|
+
captureRetryRemountBackoffMs = retryPlan.remountBackoffMs;
|
|
1259
|
+
captureRetryReadyTimeoutMs = retryPlan.readyTimeoutMs;
|
|
1261
1260
|
const retryAt = new Date().toISOString();
|
|
1262
1261
|
lastCaptureRetryAtRef.current = retryAt;
|
|
1263
1262
|
cameraRemountCountRef.current++;
|
|
@@ -1271,9 +1270,6 @@ export function VerifyAIScanner({
|
|
|
1271
1270
|
: undefined,
|
|
1272
1271
|
);
|
|
1273
1272
|
await sleep(captureRetrySettleDelayMs);
|
|
1274
|
-
const captureRetryReadyTimeoutMs = Platform.OS === 'android'
|
|
1275
|
-
? ANDROID_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS
|
|
1276
|
-
: IOS_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS;
|
|
1277
1273
|
captureRetryReady = await waitForCameraReady(captureRetryReadyTimeoutMs);
|
|
1278
1274
|
telemetry?.track('camera_capture_retry', {
|
|
1279
1275
|
component: 'scanner',
|
|
@@ -1397,6 +1393,7 @@ export function VerifyAIScanner({
|
|
|
1397
1393
|
capture_retry_torch_suppressed: captureRetryTorchSuppressed,
|
|
1398
1394
|
capture_retry_settle_delay_ms: captureRetrySettleDelayMs,
|
|
1399
1395
|
capture_retry_remount_backoff_ms: captureRetryRemountBackoffMs,
|
|
1396
|
+
capture_retry_ready_timeout_ms: captureRetryReadyTimeoutMs,
|
|
1400
1397
|
recovered_native_capture_failure: captureRetryAttempted ? 1 : 0,
|
|
1401
1398
|
last_native_capture_error: lastNativeCaptureErrorMessage,
|
|
1402
1399
|
}),
|
|
@@ -1479,6 +1476,7 @@ export function VerifyAIScanner({
|
|
|
1479
1476
|
capture_retry_torch_suppressed: captureRetryTorchSuppressed,
|
|
1480
1477
|
capture_retry_settle_delay_ms: captureRetrySettleDelayMs,
|
|
1481
1478
|
capture_retry_remount_backoff_ms: captureRetryRemountBackoffMs,
|
|
1479
|
+
capture_retry_ready_timeout_ms: captureRetryReadyTimeoutMs,
|
|
1482
1480
|
is_native_camera_capture_error: isNativeCameraCaptureError(error),
|
|
1483
1481
|
last_native_capture_error: lastNativeCaptureErrorMessage,
|
|
1484
1482
|
}),
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export const CAMERA_CAPTURE_RETRY_DELAY_MS = 350;
|
|
2
|
+
export const CAMERA_CAPTURE_RETRY_TORCH_SETTLE_MS = 800;
|
|
3
|
+
export const IOS_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS = 3000;
|
|
4
|
+
export const ANDROID_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS = 10000;
|
|
5
|
+
|
|
6
|
+
export type CameraCaptureRetryPlatform = 'ios' | 'android' | string;
|
|
7
|
+
|
|
8
|
+
export interface CameraCaptureRetryPlan {
|
|
9
|
+
readyTimeoutMs: number;
|
|
10
|
+
remountBackoffMs: number;
|
|
11
|
+
settleDelayMs: number;
|
|
12
|
+
suppressTorch: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function getCameraCaptureRetryPlan(
|
|
16
|
+
platform: CameraCaptureRetryPlatform,
|
|
17
|
+
torchRequested: boolean,
|
|
18
|
+
): CameraCaptureRetryPlan {
|
|
19
|
+
const suppressTorch = torchRequested;
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
readyTimeoutMs: platform === 'android'
|
|
23
|
+
? ANDROID_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS
|
|
24
|
+
: IOS_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS,
|
|
25
|
+
// Flutter fully restarts its CameraController after native capture errors.
|
|
26
|
+
// On iOS/Expo Camera, a key-only remount can report ready too quickly while
|
|
27
|
+
// the native capture session is still unable to produce a photo, so force a
|
|
28
|
+
// brief unmount before the retry.
|
|
29
|
+
remountBackoffMs: platform === 'ios' || suppressTorch
|
|
30
|
+
? CAMERA_CAPTURE_RETRY_DELAY_MS
|
|
31
|
+
: 0,
|
|
32
|
+
settleDelayMs: suppressTorch
|
|
33
|
+
? CAMERA_CAPTURE_RETRY_TORCH_SETTLE_MS
|
|
34
|
+
: CAMERA_CAPTURE_RETRY_DELAY_MS,
|
|
35
|
+
suppressTorch,
|
|
36
|
+
};
|
|
37
|
+
}
|
package/src/types/index.ts
CHANGED
|
@@ -37,6 +37,8 @@ export interface VerificationResult {
|
|
|
37
37
|
policy: string;
|
|
38
38
|
violation_reasons: string[];
|
|
39
39
|
feedback: string;
|
|
40
|
+
warning_violation_reasons?: string[];
|
|
41
|
+
warning_feedback?: string | null;
|
|
40
42
|
metadata: Record<string, unknown>;
|
|
41
43
|
image_url: string | null;
|
|
42
44
|
/** Base64-encoded image data URI. Only present when `include_image_data` is requested. */
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SDK_VERSION = '2.5.
|
|
1
|
+
export const SDK_VERSION = '2.5.4';
|