@switchlabs/verify-ai-react-native 2.5.2 → 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 +23 -17
- 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 +29 -17
- 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,14 +20,18 @@ 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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const IOS_CAMERA_STARTUP_WATCHDOG_MS =
|
|
23
|
+
// iOS AVCaptureSession cold start can legitimately exceed 8s on first launch (permission
|
|
24
|
+
// prompt, first-ever session spin-up, thermal/low-power throttling). An 8s watchdog tore
|
|
25
|
+
// down sessions that were seconds from ready and restarted from scratch, which made slow
|
|
26
|
+
// cold starts *worse* and fired camera_preview_timeout in bursts. Match Android at 10s.
|
|
27
|
+
const IOS_CAMERA_STARTUP_WATCHDOG_MS = 10000;
|
|
27
28
|
const ANDROID_CAMERA_STARTUP_WATCHDOG_MS = 10000;
|
|
28
29
|
const CAMERA_STARTUP_SLOW_TELEMETRY_MS = 3000;
|
|
30
|
+
// Base backoff between startup remounts. Each successive remount escalates this (see
|
|
31
|
+
// startupRemountBackoffMs below) so later attempts get progressively more uninterrupted
|
|
32
|
+
// time to initialize the native session instead of thrashing at a fixed interval.
|
|
29
33
|
const CAMERA_STARTUP_REMOUNT_BACKOFF_MS = 350;
|
|
34
|
+
const CAMERA_STARTUP_REMOUNT_BACKOFF_MAX_MS = 1200;
|
|
30
35
|
const CAMERA_STARTUP_WATCHDOG_MAX_REMOUNTS = 5;
|
|
31
36
|
const ANDROID_ORIENTATION_NO_EVENT_TIMEOUT_MS = 3000;
|
|
32
37
|
const ANDROID_ORIENTATION_SAMPLE_TELEMETRY_MS = 3000;
|
|
@@ -844,6 +849,9 @@ export function VerifyAIScanner({ onCapture, policy, onResult, onError, onClose,
|
|
|
844
849
|
const startupWatchdogRemountCount = startupWatchdogRemountCountRef.current + 1;
|
|
845
850
|
startupWatchdogRemountCountRef.current = startupWatchdogRemountCount;
|
|
846
851
|
cameraRemountCountRef.current++;
|
|
852
|
+
// Escalate the backoff with each attempt (350, 700, 1050, capped at 1200ms) so a
|
|
853
|
+
// camera that just needs more time isn't repeatedly interrupted at a fixed cadence.
|
|
854
|
+
const startupRemountBackoffMs = Math.min(CAMERA_STARTUP_REMOUNT_BACKOFF_MS * startupWatchdogRemountCount, CAMERA_STARTUP_REMOUNT_BACKOFF_MAX_MS);
|
|
847
855
|
telemetry?.track('camera_preview_timeout', {
|
|
848
856
|
component: 'scanner',
|
|
849
857
|
error: `Camera did not initialize within ${Math.round(watchdogMs / 1000)} seconds — remounting`,
|
|
@@ -852,12 +860,12 @@ export function VerifyAIScanner({ onCapture, policy, onResult, onError, onClose,
|
|
|
852
860
|
remount_reason: 'startup_watchdog',
|
|
853
861
|
startup_watchdog_remount_count: startupWatchdogRemountCount,
|
|
854
862
|
startup_watchdog_max_remounts: CAMERA_STARTUP_WATCHDOG_MAX_REMOUNTS,
|
|
855
|
-
startup_remount_backoff_ms:
|
|
863
|
+
startup_remount_backoff_ms: startupRemountBackoffMs,
|
|
856
864
|
torch_deferred_until_ready: enableTorch ? 1 : 0,
|
|
857
865
|
}),
|
|
858
866
|
});
|
|
859
867
|
requestCameraRemount('startup_watchdog', {
|
|
860
|
-
backoffMs:
|
|
868
|
+
backoffMs: startupRemountBackoffMs,
|
|
861
869
|
log: true,
|
|
862
870
|
});
|
|
863
871
|
}
|
|
@@ -947,6 +955,7 @@ export function VerifyAIScanner({ onCapture, policy, onResult, onError, onClose,
|
|
|
947
955
|
let captureRetryTorchSuppressed = false;
|
|
948
956
|
let captureRetrySettleDelayMs = CAMERA_CAPTURE_RETRY_DELAY_MS;
|
|
949
957
|
let captureRetryRemountBackoffMs = 0;
|
|
958
|
+
let captureRetryReadyTimeoutMs = 0;
|
|
950
959
|
let lastNativeCaptureErrorMessage = null;
|
|
951
960
|
try {
|
|
952
961
|
const capturePhysicalOrientation = physicalOrientation;
|
|
@@ -1014,13 +1023,11 @@ export function VerifyAIScanner({ onCapture, policy, onResult, onError, onClose,
|
|
|
1014
1023
|
lastNativeCaptureErrorMessage = normalized.message;
|
|
1015
1024
|
if (attempt === 1 && isNativeCameraCaptureError(normalized) && !terminated) {
|
|
1016
1025
|
captureRetryAttempted = true;
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
? CAMERA_CAPTURE_RETRY_DELAY_MS
|
|
1023
|
-
: 0;
|
|
1026
|
+
const retryPlan = getCameraCaptureRetryPlan(Platform.OS, !!enableTorch);
|
|
1027
|
+
captureRetryTorchSuppressed = retryPlan.suppressTorch;
|
|
1028
|
+
captureRetrySettleDelayMs = retryPlan.settleDelayMs;
|
|
1029
|
+
captureRetryRemountBackoffMs = retryPlan.remountBackoffMs;
|
|
1030
|
+
captureRetryReadyTimeoutMs = retryPlan.readyTimeoutMs;
|
|
1024
1031
|
const retryAt = new Date().toISOString();
|
|
1025
1032
|
lastCaptureRetryAtRef.current = retryAt;
|
|
1026
1033
|
cameraRemountCountRef.current++;
|
|
@@ -1031,9 +1038,6 @@ export function VerifyAIScanner({ onCapture, policy, onResult, onError, onClose,
|
|
|
1031
1038
|
? { backoffMs: captureRetryRemountBackoffMs }
|
|
1032
1039
|
: undefined);
|
|
1033
1040
|
await sleep(captureRetrySettleDelayMs);
|
|
1034
|
-
const captureRetryReadyTimeoutMs = Platform.OS === 'android'
|
|
1035
|
-
? ANDROID_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS
|
|
1036
|
-
: IOS_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS;
|
|
1037
1041
|
captureRetryReady = await waitForCameraReady(captureRetryReadyTimeoutMs);
|
|
1038
1042
|
telemetry?.track('camera_capture_retry', {
|
|
1039
1043
|
component: 'scanner',
|
|
@@ -1131,6 +1135,7 @@ export function VerifyAIScanner({ onCapture, policy, onResult, onError, onClose,
|
|
|
1131
1135
|
capture_retry_torch_suppressed: captureRetryTorchSuppressed,
|
|
1132
1136
|
capture_retry_settle_delay_ms: captureRetrySettleDelayMs,
|
|
1133
1137
|
capture_retry_remount_backoff_ms: captureRetryRemountBackoffMs,
|
|
1138
|
+
capture_retry_ready_timeout_ms: captureRetryReadyTimeoutMs,
|
|
1134
1139
|
recovered_native_capture_failure: captureRetryAttempted ? 1 : 0,
|
|
1135
1140
|
last_native_capture_error: lastNativeCaptureErrorMessage,
|
|
1136
1141
|
}),
|
|
@@ -1207,6 +1212,7 @@ export function VerifyAIScanner({ onCapture, policy, onResult, onError, onClose,
|
|
|
1207
1212
|
capture_retry_torch_suppressed: captureRetryTorchSuppressed,
|
|
1208
1213
|
capture_retry_settle_delay_ms: captureRetrySettleDelayMs,
|
|
1209
1214
|
capture_retry_remount_backoff_ms: captureRetryRemountBackoffMs,
|
|
1215
|
+
capture_retry_ready_timeout_ms: captureRetryReadyTimeoutMs,
|
|
1210
1216
|
is_native_camera_capture_error: isNativeCameraCaptureError(error),
|
|
1211
1217
|
last_native_capture_error: lastNativeCaptureErrorMessage,
|
|
1212
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,14 +48,18 @@ 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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const IOS_CAMERA_STARTUP_WATCHDOG_MS =
|
|
51
|
+
// iOS AVCaptureSession cold start can legitimately exceed 8s on first launch (permission
|
|
52
|
+
// prompt, first-ever session spin-up, thermal/low-power throttling). An 8s watchdog tore
|
|
53
|
+
// down sessions that were seconds from ready and restarted from scratch, which made slow
|
|
54
|
+
// cold starts *worse* and fired camera_preview_timeout in bursts. Match Android at 10s.
|
|
55
|
+
const IOS_CAMERA_STARTUP_WATCHDOG_MS = 10000;
|
|
52
56
|
const ANDROID_CAMERA_STARTUP_WATCHDOG_MS = 10000;
|
|
53
57
|
const CAMERA_STARTUP_SLOW_TELEMETRY_MS = 3000;
|
|
58
|
+
// Base backoff between startup remounts. Each successive remount escalates this (see
|
|
59
|
+
// startupRemountBackoffMs below) so later attempts get progressively more uninterrupted
|
|
60
|
+
// time to initialize the native session instead of thrashing at a fixed interval.
|
|
54
61
|
const CAMERA_STARTUP_REMOUNT_BACKOFF_MS = 350;
|
|
62
|
+
const CAMERA_STARTUP_REMOUNT_BACKOFF_MAX_MS = 1200;
|
|
55
63
|
const CAMERA_STARTUP_WATCHDOG_MAX_REMOUNTS = 5;
|
|
56
64
|
const ANDROID_ORIENTATION_NO_EVENT_TIMEOUT_MS = 3000;
|
|
57
65
|
const ANDROID_ORIENTATION_SAMPLE_TELEMETRY_MS = 3000;
|
|
@@ -1042,6 +1050,12 @@ export function VerifyAIScanner({
|
|
|
1042
1050
|
const startupWatchdogRemountCount = startupWatchdogRemountCountRef.current + 1;
|
|
1043
1051
|
startupWatchdogRemountCountRef.current = startupWatchdogRemountCount;
|
|
1044
1052
|
cameraRemountCountRef.current++;
|
|
1053
|
+
// Escalate the backoff with each attempt (350, 700, 1050, capped at 1200ms) so a
|
|
1054
|
+
// camera that just needs more time isn't repeatedly interrupted at a fixed cadence.
|
|
1055
|
+
const startupRemountBackoffMs = Math.min(
|
|
1056
|
+
CAMERA_STARTUP_REMOUNT_BACKOFF_MS * startupWatchdogRemountCount,
|
|
1057
|
+
CAMERA_STARTUP_REMOUNT_BACKOFF_MAX_MS,
|
|
1058
|
+
);
|
|
1045
1059
|
telemetry?.track('camera_preview_timeout', {
|
|
1046
1060
|
component: 'scanner',
|
|
1047
1061
|
error: `Camera did not initialize within ${Math.round(watchdogMs / 1000)} seconds — remounting`,
|
|
@@ -1050,12 +1064,12 @@ export function VerifyAIScanner({
|
|
|
1050
1064
|
remount_reason: 'startup_watchdog',
|
|
1051
1065
|
startup_watchdog_remount_count: startupWatchdogRemountCount,
|
|
1052
1066
|
startup_watchdog_max_remounts: CAMERA_STARTUP_WATCHDOG_MAX_REMOUNTS,
|
|
1053
|
-
startup_remount_backoff_ms:
|
|
1067
|
+
startup_remount_backoff_ms: startupRemountBackoffMs,
|
|
1054
1068
|
torch_deferred_until_ready: enableTorch ? 1 : 0,
|
|
1055
1069
|
}),
|
|
1056
1070
|
});
|
|
1057
1071
|
requestCameraRemount('startup_watchdog', {
|
|
1058
|
-
backoffMs:
|
|
1072
|
+
backoffMs: startupRemountBackoffMs,
|
|
1059
1073
|
log: true,
|
|
1060
1074
|
});
|
|
1061
1075
|
}
|
|
@@ -1158,6 +1172,7 @@ export function VerifyAIScanner({
|
|
|
1158
1172
|
let captureRetryTorchSuppressed = false;
|
|
1159
1173
|
let captureRetrySettleDelayMs = CAMERA_CAPTURE_RETRY_DELAY_MS;
|
|
1160
1174
|
let captureRetryRemountBackoffMs = 0;
|
|
1175
|
+
let captureRetryReadyTimeoutMs = 0;
|
|
1161
1176
|
let lastNativeCaptureErrorMessage: string | null = null;
|
|
1162
1177
|
|
|
1163
1178
|
try {
|
|
@@ -1237,13 +1252,11 @@ export function VerifyAIScanner({
|
|
|
1237
1252
|
|
|
1238
1253
|
if (attempt === 1 && isNativeCameraCaptureError(normalized) && !terminated) {
|
|
1239
1254
|
captureRetryAttempted = true;
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
? CAMERA_CAPTURE_RETRY_DELAY_MS
|
|
1246
|
-
: 0;
|
|
1255
|
+
const retryPlan = getCameraCaptureRetryPlan(Platform.OS, !!enableTorch);
|
|
1256
|
+
captureRetryTorchSuppressed = retryPlan.suppressTorch;
|
|
1257
|
+
captureRetrySettleDelayMs = retryPlan.settleDelayMs;
|
|
1258
|
+
captureRetryRemountBackoffMs = retryPlan.remountBackoffMs;
|
|
1259
|
+
captureRetryReadyTimeoutMs = retryPlan.readyTimeoutMs;
|
|
1247
1260
|
const retryAt = new Date().toISOString();
|
|
1248
1261
|
lastCaptureRetryAtRef.current = retryAt;
|
|
1249
1262
|
cameraRemountCountRef.current++;
|
|
@@ -1257,9 +1270,6 @@ export function VerifyAIScanner({
|
|
|
1257
1270
|
: undefined,
|
|
1258
1271
|
);
|
|
1259
1272
|
await sleep(captureRetrySettleDelayMs);
|
|
1260
|
-
const captureRetryReadyTimeoutMs = Platform.OS === 'android'
|
|
1261
|
-
? ANDROID_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS
|
|
1262
|
-
: IOS_CAMERA_CAPTURE_RETRY_READY_TIMEOUT_MS;
|
|
1263
1273
|
captureRetryReady = await waitForCameraReady(captureRetryReadyTimeoutMs);
|
|
1264
1274
|
telemetry?.track('camera_capture_retry', {
|
|
1265
1275
|
component: 'scanner',
|
|
@@ -1383,6 +1393,7 @@ export function VerifyAIScanner({
|
|
|
1383
1393
|
capture_retry_torch_suppressed: captureRetryTorchSuppressed,
|
|
1384
1394
|
capture_retry_settle_delay_ms: captureRetrySettleDelayMs,
|
|
1385
1395
|
capture_retry_remount_backoff_ms: captureRetryRemountBackoffMs,
|
|
1396
|
+
capture_retry_ready_timeout_ms: captureRetryReadyTimeoutMs,
|
|
1386
1397
|
recovered_native_capture_failure: captureRetryAttempted ? 1 : 0,
|
|
1387
1398
|
last_native_capture_error: lastNativeCaptureErrorMessage,
|
|
1388
1399
|
}),
|
|
@@ -1465,6 +1476,7 @@ export function VerifyAIScanner({
|
|
|
1465
1476
|
capture_retry_torch_suppressed: captureRetryTorchSuppressed,
|
|
1466
1477
|
capture_retry_settle_delay_ms: captureRetrySettleDelayMs,
|
|
1467
1478
|
capture_retry_remount_backoff_ms: captureRetryRemountBackoffMs,
|
|
1479
|
+
capture_retry_ready_timeout_ms: captureRetryReadyTimeoutMs,
|
|
1468
1480
|
is_native_camera_capture_error: isNativeCameraCaptureError(error),
|
|
1469
1481
|
last_native_capture_error: lastNativeCaptureErrorMessage,
|
|
1470
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';
|