@switchlabs/verify-ai-react-native 2.5.6 → 2.5.7
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 +27 -1
- package/lib/client/index.js +34 -10
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +15 -6
- package/src/client/index.ts +34 -11
- package/src/version.ts +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
# @switchlabs/verify-ai-react-native
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Send a photo and a policy, get back a pass/fail verdict with a confidence
|
|
4
|
+
value, the criteria that failed, and human-readable reasoning. Built for
|
|
5
|
+
end-of-ride parking compliance, vehicle and equipment condition and damage
|
|
6
|
+
grading, proof of delivery, and rental return checks.
|
|
7
|
+
|
|
8
|
+
The SDK wraps live camera capture (no gallery-picker path in the scanner
|
|
9
|
+
flow), on-device pre-screening, an offline queue, and the REST API.
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
const result = await verify({ image: base64, policy: 'scooter_parking' });
|
|
13
|
+
if (result && !result.is_compliant) {
|
|
14
|
+
console.log(result.violation_reasons, result.feedback);
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Try it before you install anything:** upload a photo at
|
|
19
|
+
[verify.switchlabs.dev/demo](https://verify.switchlabs.dev/demo). No account,
|
|
20
|
+
no card.
|
|
21
|
+
|
|
22
|
+
**Get a key:** [free sandbox](https://verify.switchlabs.dev/login?mode=signup)
|
|
23
|
+
with $5 of credit and no credit card. Keys start with `vai_` and are sent in an
|
|
24
|
+
`X-API-Key` header.
|
|
25
|
+
|
|
26
|
+
**Pricing:** $0.008 per standard verification for the first 100,000 in a
|
|
27
|
+
calendar month, $0.006 from 100,001 to 1,000,000, and $0.005 above 1,000,000.
|
|
28
|
+
No platform fee, no monthly minimum, no annual contract.
|
|
29
|
+
[Full pricing](https://verify.switchlabs.dev/pricing).
|
|
4
30
|
|
|
5
31
|
## Install
|
|
6
32
|
|
package/lib/client/index.js
CHANGED
|
@@ -2,6 +2,13 @@ import { TelemetryReporter } from '../telemetry/TelemetryReporter';
|
|
|
2
2
|
import { SDK_VERSION } from '../version';
|
|
3
3
|
const DEFAULT_BASE_URL = 'https://verify.switchlabs.dev/api/v1';
|
|
4
4
|
const DEFAULT_TIMEOUT = 60000;
|
|
5
|
+
const MAX_IN_PROGRESS_RETRIES = 10;
|
|
6
|
+
function retryAfterMs(value) {
|
|
7
|
+
if (value !== null && /^\d+$/.test(value.trim()))
|
|
8
|
+
return Number(value) * 1000;
|
|
9
|
+
const date = value ? Date.parse(value) : NaN;
|
|
10
|
+
return Number.isFinite(date) ? Math.max(0, date - Date.now()) : 1000;
|
|
11
|
+
}
|
|
5
12
|
const VEHICLE_TYPE_LABELS = {
|
|
6
13
|
scooter: 'Scooter',
|
|
7
14
|
'e-bike': 'E-Bike',
|
|
@@ -150,17 +157,34 @@ export class VerifyAIClient {
|
|
|
150
157
|
const method = (options.method || 'GET').toUpperCase();
|
|
151
158
|
const url = `${this.baseUrl}${path}`;
|
|
152
159
|
const context = { path, url, method };
|
|
160
|
+
const deadline = Date.now() + this.timeout;
|
|
153
161
|
try {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
...options
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
162
|
+
let response;
|
|
163
|
+
let body;
|
|
164
|
+
let retries = 0;
|
|
165
|
+
while (true) {
|
|
166
|
+
response = await fetch(url, {
|
|
167
|
+
...options,
|
|
168
|
+
signal: controller.signal,
|
|
169
|
+
headers: {
|
|
170
|
+
'X-API-Key': this.apiKey,
|
|
171
|
+
...options.headers,
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
const rawBody = await response.text();
|
|
175
|
+
body = this.parseResponseBody(rawBody);
|
|
176
|
+
const code = body && typeof body === 'object' ? body.code : undefined;
|
|
177
|
+
const key = new Headers(options.headers).get('Idempotency-Key');
|
|
178
|
+
const delay = retryAfterMs(response.headers.get('Retry-After'));
|
|
179
|
+
// Only replay an identical, explicitly keyed verification reservation.
|
|
180
|
+
// Keep one timeout budget and report errors only after retries exhaust.
|
|
181
|
+
if (path !== '/verify' || method !== 'POST' || !key || response.status !== 409 ||
|
|
182
|
+
code !== 'idempotency_in_progress' || retries >= MAX_IN_PROGRESS_RETRIES ||
|
|
183
|
+
delay >= deadline - Date.now() || controller.signal.aborted)
|
|
184
|
+
break;
|
|
185
|
+
retries += 1;
|
|
186
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
187
|
+
}
|
|
164
188
|
if (!response.ok) {
|
|
165
189
|
const errorBody = (body && typeof body === 'object' ? body : null);
|
|
166
190
|
throw this.buildRequestError(stringifyErrorMessage(errorBody?.error, `Request failed with status ${response.status}`), response.status, context, {
|
package/lib/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "2.5.
|
|
1
|
+
export declare const SDK_VERSION = "2.5.7";
|
package/lib/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SDK_VERSION = '2.5.
|
|
1
|
+
export const SDK_VERSION = '2.5.7';
|
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@switchlabs/verify-ai-react-native",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.7",
|
|
4
4
|
"description": "React Native SDK for Verify AI - photo verification with AI vision processing",
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"url": "
|
|
8
|
-
"directory": "packages/verify-ai-react-native"
|
|
5
|
+
"homepage": "https://verify.switchlabs.dev/docs/sdks/react-native",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://verify.switchlabs.dev/contact"
|
|
9
8
|
},
|
|
10
9
|
"main": "./lib/index.js",
|
|
11
10
|
"types": "./lib/index.d.ts",
|
|
@@ -35,7 +34,12 @@
|
|
|
35
34
|
"photo-verification",
|
|
36
35
|
"ai-vision",
|
|
37
36
|
"parking-compliance",
|
|
38
|
-
"damage-detection"
|
|
37
|
+
"damage-detection",
|
|
38
|
+
"proof-of-delivery",
|
|
39
|
+
"image-verification",
|
|
40
|
+
"vehicle-inspection",
|
|
41
|
+
"expo",
|
|
42
|
+
"photo-verification-api"
|
|
39
43
|
],
|
|
40
44
|
"author": "Switch Labs",
|
|
41
45
|
"license": "MIT",
|
|
@@ -86,5 +90,10 @@
|
|
|
86
90
|
"react-native-fast-tflite": "^1.6.1",
|
|
87
91
|
"typescript": "^5.5.0",
|
|
88
92
|
"vitest": "^4.1.0"
|
|
93
|
+
},
|
|
94
|
+
"repository": {
|
|
95
|
+
"type": "git",
|
|
96
|
+
"url": "git+https://github.com/levyelectric/verify.git",
|
|
97
|
+
"directory": "packages/verify-ai-react-native"
|
|
89
98
|
}
|
|
90
99
|
}
|
package/src/client/index.ts
CHANGED
|
@@ -14,6 +14,13 @@ import { SDK_VERSION } from '../version';
|
|
|
14
14
|
|
|
15
15
|
const DEFAULT_BASE_URL = 'https://verify.switchlabs.dev/api/v1';
|
|
16
16
|
const DEFAULT_TIMEOUT = 60000;
|
|
17
|
+
const MAX_IN_PROGRESS_RETRIES = 10;
|
|
18
|
+
|
|
19
|
+
function retryAfterMs(value: string | null): number {
|
|
20
|
+
if (value !== null && /^\d+$/.test(value.trim())) return Number(value) * 1000;
|
|
21
|
+
const date = value ? Date.parse(value) : NaN;
|
|
22
|
+
return Number.isFinite(date) ? Math.max(0, date - Date.now()) : 1000;
|
|
23
|
+
}
|
|
17
24
|
|
|
18
25
|
const VEHICLE_TYPE_LABELS: Record<string, string> = {
|
|
19
26
|
scooter: 'Scooter',
|
|
@@ -214,19 +221,35 @@ export class VerifyAIClient {
|
|
|
214
221
|
const method = (options.method || 'GET').toUpperCase();
|
|
215
222
|
const url = `${this.baseUrl}${path}`;
|
|
216
223
|
const context: RequestContext = { path, url, method };
|
|
224
|
+
const deadline = Date.now() + this.timeout;
|
|
217
225
|
|
|
218
226
|
try {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
...options
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
227
|
+
let response: Response;
|
|
228
|
+
let body: unknown;
|
|
229
|
+
let retries = 0;
|
|
230
|
+
while (true) {
|
|
231
|
+
response = await fetch(url, {
|
|
232
|
+
...options,
|
|
233
|
+
signal: controller.signal,
|
|
234
|
+
headers: {
|
|
235
|
+
'X-API-Key': this.apiKey,
|
|
236
|
+
...options.headers,
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
const rawBody = await response.text();
|
|
241
|
+
body = this.parseResponseBody(rawBody);
|
|
242
|
+
const code = body && typeof body === 'object' ? (body as VerifyAIError).code : undefined;
|
|
243
|
+
const key = new Headers(options.headers).get('Idempotency-Key');
|
|
244
|
+
const delay = retryAfterMs(response.headers.get('Retry-After'));
|
|
245
|
+
// Only replay an identical, explicitly keyed verification reservation.
|
|
246
|
+
// Keep one timeout budget and report errors only after retries exhaust.
|
|
247
|
+
if (path !== '/verify' || method !== 'POST' || !key || response.status !== 409 ||
|
|
248
|
+
code !== 'idempotency_in_progress' || retries >= MAX_IN_PROGRESS_RETRIES ||
|
|
249
|
+
delay >= deadline - Date.now() || controller.signal.aborted) break;
|
|
250
|
+
retries += 1;
|
|
251
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
252
|
+
}
|
|
230
253
|
|
|
231
254
|
if (!response.ok) {
|
|
232
255
|
const errorBody = (body && typeof body === 'object' ? body : null) as VerifyAIError | null;
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SDK_VERSION = '2.5.
|
|
1
|
+
export const SDK_VERSION = '2.5.7';
|