@switchlabs/verify-ai-react-native 2.4.22 → 2.4.23

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.
@@ -4,6 +4,7 @@ import { View, Text, TouchableOpacity, StyleSheet, ActivityIndicator, AppState,
4
4
  import { CameraView, useCameraPermissions, } from 'expo-camera';
5
5
  import { VerifyAIRequestError } from '../client';
6
6
  import { useTelemetry } from '../telemetry/TelemetryContext';
7
+ import { SDK_VERSION } from '../version';
7
8
  import { BikeOverlay } from './BikeOverlay';
8
9
  import { ScooterOverlay } from './ScooterOverlay';
9
10
  import { ANDROID_ACCELEROMETER_AXIS_DOMINANCE_THRESHOLD, classifyAndroidAccelerometerOrientation, getOverlayRotationDeg, } from './scannerOrientation';
@@ -326,11 +327,23 @@ export function VerifyAIScanner({ onCapture, policy, onResult, onError, onClose,
326
327
  telemetryRef.current = telemetry;
327
328
  buildScannerTelemetryMetadataRef.current = buildScannerTelemetryMetadata;
328
329
  useEffect(() => {
329
- telemetryRef.current?.track('camera_scanner_mounted', {
330
+ const reporter = telemetryRef.current;
331
+ if (reporter) {
332
+ console.log(`VerifyAI[${SDK_VERSION}]: scanner telemetry attached ` +
333
+ `baseUrl=${reporter.getBaseUrl()} apiKeyPrefix=${reporter.getApiKeyPrefix()}…`);
334
+ }
335
+ else {
336
+ console.warn(`VerifyAI[${SDK_VERSION}]: scanner telemetry is not attached; field ` +
337
+ 'diagnostics will only appear in local device logs. Pass a ' +
338
+ '`TelemetryReporter` into `<VerifyAIScanner telemetry={…} />` or ' +
339
+ 'wrap the tree in `<TelemetryContext.Provider value={reporter}>` ' +
340
+ 'to enable server-side diagnostics.');
341
+ }
342
+ reporter?.track('camera_scanner_mounted', {
330
343
  component: 'scanner',
331
344
  error: 'scanner_mounted',
332
345
  metadata: buildScannerTelemetryMetadataRef.current?.({
333
- scanner_telemetry_attached: telemetryRef.current ? 1 : 0,
346
+ scanner_telemetry_attached: reporter ? 1 : 0,
334
347
  }),
335
348
  });
336
349
  return () => {
@@ -9,6 +9,12 @@ export declare class TelemetryReporter {
9
9
  private loadedPersisted;
10
10
  private loadPersistedPromise;
11
11
  constructor(apiKey: string, baseUrl: string);
12
+ /** Telemetry POST destination — exposed so the scanner can log an init banner
13
+ * that helps field debugging confirm where events are being sent. */
14
+ getBaseUrl(): string;
15
+ /** First 6 characters of the API key, for log banners. Never returns the full key. */
16
+ getApiKeyPrefix(): string;
17
+ private logDeliveryFailure;
12
18
  /** Track an error event. Fire-and-forget — never throws. */
13
19
  track(eventType: string, opts?: {
14
20
  component?: string;
@@ -40,6 +40,20 @@ export class TelemetryReporter {
40
40
  // Load any persisted events left behind by a previous session
41
41
  this.loadPersistedBuffer();
42
42
  }
43
+ /** Telemetry POST destination — exposed so the scanner can log an init banner
44
+ * that helps field debugging confirm where events are being sent. */
45
+ getBaseUrl() {
46
+ return this.baseUrl;
47
+ }
48
+ /** First 6 characters of the API key, for log banners. Never returns the full key. */
49
+ getApiKeyPrefix() {
50
+ return this.apiKey.length >= 6 ? this.apiKey.slice(0, 6) : this.apiKey;
51
+ }
52
+ logDeliveryFailure(kind, detail, eventCount) {
53
+ const trimmed = detail.length > 200 ? detail.slice(0, 200) : detail;
54
+ console.warn(`VerifyAI[${SDK_VERSION}]: telemetry POST failed kind=${kind} ` +
55
+ `events=${eventCount} url=${this.baseUrl}/telemetry detail=${trimmed}`);
56
+ }
43
57
  /** Track an error event. Fire-and-forget — never throws. */
44
58
  track(eventType, opts = {}) {
45
59
  if (this.disposed)
@@ -113,6 +127,7 @@ export class TelemetryReporter {
113
127
  this.clearFlushTimer();
114
128
  const controller = new AbortController();
115
129
  const timeout = setTimeout(() => controller.abort(), 10000);
130
+ let loggedDeliveryFailure = false;
116
131
  try {
117
132
  const response = await fetch(`${this.baseUrl}/telemetry`, {
118
133
  method: 'POST',
@@ -124,12 +139,26 @@ export class TelemetryReporter {
124
139
  signal: controller.signal,
125
140
  });
126
141
  if (!response.ok) {
142
+ let body = '';
143
+ try {
144
+ body = await response.text();
145
+ }
146
+ catch {
147
+ // ignore
148
+ }
149
+ this.logDeliveryFailure(`http_${response.status}`, body, events.length);
150
+ loggedDeliveryFailure = true;
127
151
  throw new Error(`Telemetry request failed with status ${response.status}`);
128
152
  }
129
153
  // Success — clear persisted buffer since events are now server-side
130
154
  this.persistBuffer(); // buffer is empty at this point, so this clears the key
131
155
  }
132
- catch {
156
+ catch (error) {
157
+ if (!loggedDeliveryFailure) {
158
+ const kind = error instanceof Error ? error.name : typeof error;
159
+ const detail = error instanceof Error ? error.message : String(error);
160
+ this.logDeliveryFailure(kind, detail, events.length);
161
+ }
133
162
  for (const [dedupKey, event] of bufferedEntries) {
134
163
  const existing = this.buffer.get(dedupKey);
135
164
  if (existing) {
package/lib/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const SDK_VERSION = "2.4.22";
1
+ export declare const SDK_VERSION = "2.4.23";
package/lib/version.js CHANGED
@@ -1 +1 @@
1
- export const SDK_VERSION = '2.4.22';
1
+ export const SDK_VERSION = '2.4.23';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@switchlabs/verify-ai-react-native",
3
- "version": "2.4.22",
3
+ "version": "2.4.23",
4
4
  "description": "React Native SDK for Verify AI - photo verification with AI vision processing",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",
@@ -23,6 +23,7 @@ import type {
23
23
  import { VerifyAIRequestError } from '../client';
24
24
  import { useTelemetry } from '../telemetry/TelemetryContext';
25
25
  import type { TelemetryReporter } from '../telemetry/TelemetryReporter';
26
+ import { SDK_VERSION } from '../version';
26
27
  import { BikeOverlay } from './BikeOverlay';
27
28
  import { ScooterOverlay } from './ScooterOverlay';
28
29
  import {
@@ -439,11 +440,26 @@ export function VerifyAIScanner({
439
440
  buildScannerTelemetryMetadataRef.current = buildScannerTelemetryMetadata;
440
441
 
441
442
  useEffect(() => {
442
- telemetryRef.current?.track('camera_scanner_mounted', {
443
+ const reporter = telemetryRef.current;
444
+ if (reporter) {
445
+ console.log(
446
+ `VerifyAI[${SDK_VERSION}]: scanner telemetry attached ` +
447
+ `baseUrl=${reporter.getBaseUrl()} apiKeyPrefix=${reporter.getApiKeyPrefix()}…`,
448
+ );
449
+ } else {
450
+ console.warn(
451
+ `VerifyAI[${SDK_VERSION}]: scanner telemetry is not attached; field ` +
452
+ 'diagnostics will only appear in local device logs. Pass a ' +
453
+ '`TelemetryReporter` into `<VerifyAIScanner telemetry={…} />` or ' +
454
+ 'wrap the tree in `<TelemetryContext.Provider value={reporter}>` ' +
455
+ 'to enable server-side diagnostics.',
456
+ );
457
+ }
458
+ reporter?.track('camera_scanner_mounted', {
443
459
  component: 'scanner',
444
460
  error: 'scanner_mounted',
445
461
  metadata: buildScannerTelemetryMetadataRef.current?.({
446
- scanner_telemetry_attached: telemetryRef.current ? 1 : 0,
462
+ scanner_telemetry_attached: reporter ? 1 : 0,
447
463
  }),
448
464
  });
449
465
 
@@ -71,6 +71,25 @@ export class TelemetryReporter {
71
71
  this.loadPersistedBuffer();
72
72
  }
73
73
 
74
+ /** Telemetry POST destination — exposed so the scanner can log an init banner
75
+ * that helps field debugging confirm where events are being sent. */
76
+ getBaseUrl(): string {
77
+ return this.baseUrl;
78
+ }
79
+
80
+ /** First 6 characters of the API key, for log banners. Never returns the full key. */
81
+ getApiKeyPrefix(): string {
82
+ return this.apiKey.length >= 6 ? this.apiKey.slice(0, 6) : this.apiKey;
83
+ }
84
+
85
+ private logDeliveryFailure(kind: string, detail: string, eventCount: number): void {
86
+ const trimmed = detail.length > 200 ? detail.slice(0, 200) : detail;
87
+ console.warn(
88
+ `VerifyAI[${SDK_VERSION}]: telemetry POST failed kind=${kind} ` +
89
+ `events=${eventCount} url=${this.baseUrl}/telemetry detail=${trimmed}`,
90
+ );
91
+ }
92
+
74
93
  /** Track an error event. Fire-and-forget — never throws. */
75
94
  track(
76
95
  eventType: string,
@@ -158,6 +177,7 @@ export class TelemetryReporter {
158
177
  const controller = new AbortController();
159
178
  const timeout = setTimeout(() => controller.abort(), 10000);
160
179
 
180
+ let loggedDeliveryFailure = false;
161
181
  try {
162
182
  const response = await fetch(`${this.baseUrl}/telemetry`, {
163
183
  method: 'POST',
@@ -170,12 +190,25 @@ export class TelemetryReporter {
170
190
  });
171
191
 
172
192
  if (!response.ok) {
193
+ let body = '';
194
+ try {
195
+ body = await response.text();
196
+ } catch {
197
+ // ignore
198
+ }
199
+ this.logDeliveryFailure(`http_${response.status}`, body, events.length);
200
+ loggedDeliveryFailure = true;
173
201
  throw new Error(`Telemetry request failed with status ${response.status}`);
174
202
  }
175
203
 
176
204
  // Success — clear persisted buffer since events are now server-side
177
205
  this.persistBuffer(); // buffer is empty at this point, so this clears the key
178
- } catch {
206
+ } catch (error) {
207
+ if (!loggedDeliveryFailure) {
208
+ const kind = error instanceof Error ? error.name : typeof error;
209
+ const detail = error instanceof Error ? error.message : String(error);
210
+ this.logDeliveryFailure(kind, detail, events.length);
211
+ }
179
212
  for (const [dedupKey, event] of bufferedEntries) {
180
213
  const existing = this.buffer.get(dedupKey);
181
214
  if (existing) {
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const SDK_VERSION = '2.4.22';
1
+ export const SDK_VERSION = '2.4.23';