@transfergratis/react-native-sdk 0.1.25 → 0.1.26

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.
Files changed (88) hide show
  1. package/android/src/main/AndroidManifest.xml +12 -0
  2. package/build/components/EnhancedCameraView.web.d.ts.map +1 -1
  3. package/build/components/EnhancedCameraView.web.js +76 -21
  4. package/build/components/EnhancedCameraView.web.js.map +1 -1
  5. package/build/components/KYCElements/EmailVerificationTemplate.d.ts.map +1 -1
  6. package/build/components/KYCElements/EmailVerificationTemplate.js +48 -29
  7. package/build/components/KYCElements/EmailVerificationTemplate.js.map +1 -1
  8. package/build/components/KYCElements/IDCardCapture.d.ts.map +1 -1
  9. package/build/components/KYCElements/IDCardCapture.js +40 -11
  10. package/build/components/KYCElements/IDCardCapture.js.map +1 -1
  11. package/build/components/KYCElements/WelcomeTemplate.js +2 -1
  12. package/build/components/KYCElements/WelcomeTemplate.js.map +1 -1
  13. package/build/components/OverLay/type.d.ts +2 -0
  14. package/build/components/OverLay/type.d.ts.map +1 -1
  15. package/build/components/OverLay/type.js.map +1 -1
  16. package/build/components/TemplateKYCExample.d.ts +8 -2
  17. package/build/components/TemplateKYCExample.d.ts.map +1 -1
  18. package/build/components/TemplateKYCExample.js +2 -2
  19. package/build/components/TemplateKYCExample.js.map +1 -1
  20. package/build/components/TemplateKYCFlowRefactored.d.ts +10 -2
  21. package/build/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
  22. package/build/components/TemplateKYCFlowRefactored.js +13 -3
  23. package/build/components/TemplateKYCFlowRefactored.js.map +1 -1
  24. package/build/config/KYCConfig.js +1 -1
  25. package/build/config/KYCConfig.js.map +1 -1
  26. package/build/hooks/useTemplateKYCFlow.d.ts +14 -2
  27. package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
  28. package/build/hooks/useTemplateKYCFlow.js +175 -84
  29. package/build/hooks/useTemplateKYCFlow.js.map +1 -1
  30. package/build/i18n/en/index.d.ts +2 -0
  31. package/build/i18n/en/index.d.ts.map +1 -1
  32. package/build/i18n/en/index.js +3 -1
  33. package/build/i18n/en/index.js.map +1 -1
  34. package/build/i18n/fr/index.d.ts +2 -0
  35. package/build/i18n/fr/index.d.ts.map +1 -1
  36. package/build/i18n/fr/index.js +3 -1
  37. package/build/i18n/fr/index.js.map +1 -1
  38. package/build/i18n/types.d.ts +2 -0
  39. package/build/i18n/types.d.ts.map +1 -1
  40. package/build/i18n/types.js.map +1 -1
  41. package/build/modules/api/CardAuthentification.d.ts.map +1 -1
  42. package/build/modules/api/CardAuthentification.js +22 -2
  43. package/build/modules/api/CardAuthentification.js.map +1 -1
  44. package/build/modules/api/KYCService.d.ts +10 -0
  45. package/build/modules/api/KYCService.d.ts.map +1 -1
  46. package/build/modules/api/KYCService.js +24 -0
  47. package/build/modules/api/KYCService.js.map +1 -1
  48. package/build/modules/camera/VisionCameraModule.web.d.ts.map +1 -1
  49. package/build/modules/camera/VisionCameraModule.web.js +27 -8
  50. package/build/modules/camera/VisionCameraModule.web.js.map +1 -1
  51. package/build/types/KYC.types.d.ts +6 -2
  52. package/build/types/KYC.types.d.ts.map +1 -1
  53. package/build/types/KYC.types.js.map +1 -1
  54. package/build/utils/cropByObb.d.ts +7 -0
  55. package/build/utils/cropByObb.d.ts.map +1 -1
  56. package/build/utils/cropByObb.js +20 -1
  57. package/build/utils/cropByObb.js.map +1 -1
  58. package/build/web/WebKYCEntry.d.ts.map +1 -1
  59. package/build/web/WebKYCEntry.js +11 -5
  60. package/build/web/WebKYCEntry.js.map +1 -1
  61. package/package.json +1 -1
  62. package/plugin/build/index.d.ts +1 -0
  63. package/plugin/build/index.js +3 -1
  64. package/plugin/build/withRemovePermissions.d.ts +3 -0
  65. package/plugin/build/withRemovePermissions.js +67 -0
  66. package/plugin/src/index.ts +2 -1
  67. package/plugin/src/withRemovePermissions.js +85 -0
  68. package/plugin/src/withRemovePermissions.ts +83 -0
  69. package/plugin/tsconfig.tsbuildinfo +1 -1
  70. package/plugin.js +6 -1
  71. package/src/components/EnhancedCameraView.web.tsx +76 -21
  72. package/src/components/KYCElements/EmailVerificationTemplate.tsx +47 -33
  73. package/src/components/KYCElements/IDCardCapture.tsx +41 -10
  74. package/src/components/KYCElements/WelcomeTemplate.tsx +2 -1
  75. package/src/components/OverLay/type.ts +2 -0
  76. package/src/components/TemplateKYCExample.tsx +9 -5
  77. package/src/components/TemplateKYCFlowRefactored.tsx +24 -6
  78. package/src/config/KYCConfig.ts +1 -1
  79. package/src/hooks/useTemplateKYCFlow.tsx +189 -95
  80. package/src/i18n/en/index.ts +3 -1
  81. package/src/i18n/fr/index.ts +3 -1
  82. package/src/i18n/types.ts +2 -0
  83. package/src/modules/api/CardAuthentification.ts +23 -2
  84. package/src/modules/api/KYCService.ts +41 -0
  85. package/src/modules/camera/VisionCameraModule.web.ts +30 -12
  86. package/src/types/KYC.types.ts +7 -3
  87. package/src/utils/cropByObb.ts +20 -1
  88. package/src/web/WebKYCEntry.tsx +17 -6
@@ -524,6 +524,47 @@ export class KYCService {
524
524
  throw new Error(errorMessage(error));
525
525
  }
526
526
  }
527
+
528
+ /** Send email verification code. POST /api/v1/accounts/email/send/ */
529
+ async sendEmailVerificationCode(
530
+ email: string,
531
+ auth?: { apiKey?: string; token?: string }
532
+ ): Promise<unknown> {
533
+ const url = `${KYCConfig.getBackendUrl()}/accounts/email/send/`;
534
+ const token = auth?.apiKey ? undefined : (auth?.token ?? await authentification());
535
+ const res = await axios.post(
536
+ url,
537
+ { email },
538
+ {
539
+ headers: {
540
+ 'Content-Type': 'application/json',
541
+ ...(auth?.apiKey ? { 'Authorization': `ApiKey ${auth.apiKey}` } : { 'Authorization': `Bearer ${token}` }),
542
+ },
543
+ }
544
+ );
545
+ return res.data;
546
+ }
547
+
548
+ /** Verify email with OTP. POST /api/v1/accounts/email/verify/ */
549
+ async verifyEmailCode(
550
+ otp: string,
551
+ auth?: { apiKey?: string; token?: string }
552
+ ): Promise<unknown> {
553
+ const url = `${KYCConfig.getBackendUrl()}/accounts/email/verify/`;
554
+ const token = auth?.apiKey ? undefined : (auth?.token ?? await authentification());
555
+ const res = await axios.post(
556
+ url,
557
+ { otp },
558
+ {
559
+ headers: {
560
+ 'Content-Type': 'application/json',
561
+ ...(auth?.apiKey ? { 'Authorization': `ApiKey ${auth.apiKey}` } : { 'Authorization': `Bearer ${token}` }),
562
+ },
563
+ }
564
+ );
565
+ return res.data;
566
+ }
567
+
527
568
  // reultat de la verification
528
569
  async getVerificationResult(session_id: string): Promise<VerificationResult> {
529
570
  try {
@@ -151,17 +151,18 @@ export class VisionCameraModule {
151
151
  return false;
152
152
  }
153
153
 
154
- const stream = await navigator.mediaDevices.getUserMedia({
155
- video: {
154
+ // Use min + ideal so Android Chrome doesn't cache low resolution (e.g. 640x480)
155
+ const stream = await navigator.mediaDevices.getUserMedia({
156
+ video: {
156
157
  facingMode: 'user',
157
- width: { ideal: 1280 },
158
- height: { ideal: 720 }
159
- }
158
+ width: { min: 1280, ideal: 1920 },
159
+ height: { min: 720, ideal: 1080 },
160
+ },
160
161
  });
161
-
162
+
162
163
  // Libérer le stream de test
163
164
  stream.getTracks().forEach(track => track.stop());
164
-
165
+
165
166
  return true;
166
167
  } catch (error) {
167
168
  console.error('Error requesting camera permission:', error);
@@ -330,13 +331,30 @@ export class VisionCameraModule {
330
331
  return;
331
332
  }
332
333
 
333
- this.stream = await navigator.mediaDevices.getUserMedia({
334
+ const constraints: MediaStreamConstraints = {
334
335
  video: {
335
336
  facingMode: 'user',
336
- width: { ideal: 1280 },
337
- height: { ideal: 720 }
337
+ width: { min: 1280, ideal: 1920 },
338
+ height: { min: 720, ideal: 1080 },
339
+ },
340
+ };
341
+
342
+ try {
343
+ this.stream = await navigator.mediaDevices.getUserMedia(constraints);
344
+ } catch (err) {
345
+ const name = err instanceof Error ? err.name : '';
346
+ if (name === 'OverconstrainedError') {
347
+ this.stream = await navigator.mediaDevices.getUserMedia({
348
+ video: {
349
+ facingMode: 'user',
350
+ width: { ideal: 1920 },
351
+ height: { ideal: 1080 },
352
+ },
353
+ });
354
+ } else {
355
+ throw err;
338
356
  }
339
- });
357
+ }
340
358
 
341
359
  if (this.videoElement) {
342
360
  this.videoElement.srcObject = this.stream;
@@ -531,7 +549,7 @@ export class VisionCameraModule {
531
549
  context.drawImage(this.videoElement, 0, 0);
532
550
 
533
551
  // Convertir en base64
534
- const imageDataUrl = this.canvasElement.toDataURL('image/jpeg', 0.8);
552
+ const imageDataUrl = this.canvasElement.toDataURL('image/jpeg', 0.95);
535
553
 
536
554
  // Créer un nom de fichier unique
537
555
  const timestamp = new Date().getTime();
@@ -455,6 +455,8 @@ export interface SessionState {
455
455
  isInitialized: boolean;
456
456
  isProcessing: boolean;
457
457
  error: string | null;
458
+ /** True once loadSessionData has run (for resume flow); allows UI to show loading until country/data restored */
459
+ sessionDataRestored?: boolean;
458
460
  }
459
461
 
460
462
  export type VerificationStatus = 'idle' | 'in_progress' | 'success' | 'failed';
@@ -469,11 +471,11 @@ export interface VerificationState {
469
471
  // Actions pour le template KYC
470
472
  export interface TemplateActions {
471
473
  initializeTemplate: (template: KYCTemplate) => void;
472
- nextComponent: () => void;
474
+ nextComponent: (overrideData?: any) => void;
473
475
  previousComponent: () => void;
474
476
  goToComponent: (componentId: number) => void;
475
477
  updateComponentData: (componentId: number, data: any) => void;
476
- validateComponent: (componentId: number) => boolean;
478
+ validateComponent: (componentId: number, dataOverride?: any) => boolean;
477
479
  submitTemplate: () => Promise<void>;
478
480
  resetTemplate: () => void;
479
481
  setLanguage: (language: string) => void;
@@ -482,7 +484,7 @@ export interface TemplateActions {
482
484
  submitVerification: () => Promise<void>;
483
485
  }
484
486
 
485
- // Hook pour le template KYC
487
+ // Hook pour le template KYC (return type of useTemplateKYCFlow)
486
488
  export interface UseTemplateReturn {
487
489
  state: TemplateState;
488
490
  actions: TemplateActions;
@@ -494,6 +496,8 @@ export interface UseTemplateReturn {
494
496
  getLocalizedText: (text: LocalizedText) => string;
495
497
  initializeSession: () => Promise<void>;
496
498
  env: 'PRODUCTION' | 'SANDBOX';
499
+ /** Optional API key for backend auth (e.g. email verification endpoints). */
500
+ apiKey?: string;
497
501
  }
498
502
 
499
503
 
@@ -5,6 +5,21 @@ import { logger } from './logger';
5
5
 
6
6
  type Point = [number, number];
7
7
 
8
+ /** OBB confidence below this = card not fully in frame; don't crop, give user feedback. */
9
+ export const OBB_CONFIDENCE_THRESHOLD = 0.85;
10
+
11
+ /**
12
+ * card_obb format from API: [ [ [p1,p2,p3,p4], confidence ] ]
13
+ * Returns confidence in [0,1] or null if not present.
14
+ */
15
+ export function getObbConfidence(cardObb: any): number | null {
16
+ if (!cardObb || !Array.isArray(cardObb) || cardObb.length === 0) return null;
17
+ const first = cardObb[0];
18
+ if (!Array.isArray(first) || first.length < 2) return null;
19
+ const score = first[1];
20
+ return typeof score === 'number' ? score : null;
21
+ }
22
+
8
23
  // Compute axis-aligned bounding box from oriented quadrilateral
9
24
  function computeAabb(points: Point[]) {
10
25
  const xs = points.map(p => p[0]);
@@ -49,7 +64,11 @@ async function cropWeb(uri: string, points: Point[]): Promise<string> {
49
64
  // Fallback: return original for native (no dependency added); caller can still use bbox to draw overlay
50
65
  export async function cropByObb(uri: string, cardObb: any): Promise<{ base64?: string; bbox?: { minX: number; minY: number; width: number; height: number } }> {
51
66
  try {
52
- // card_obb format: [ [ [p1,p2,p3,p4], score ] ]
67
+ // card_obb format: [ [ [p1,p2,p3,p4], score ] ] — if confidence too low, don't crop (send full image)
68
+ const confidence = getObbConfidence(cardObb);
69
+ if (confidence !== null && confidence < OBB_CONFIDENCE_THRESHOLD) {
70
+ return {};
71
+ }
53
72
  const first = Array.isArray(cardObb) ? cardObb[0] : null;
54
73
  const points = Array.isArray(first?.[0]) ? (first[0] as Point[]) : null;
55
74
  if (!points || points.length !== 4) return {};
@@ -25,7 +25,11 @@ interface URLParams {
25
25
  env?: 'PRODUCTION' | 'SANDBOX'; // Environment mode
26
26
  template_id?: string; // Template ID for dynamic template loading
27
27
  server_env?: BackendEnvironment; // Backend environment mode
28
- step?: string; // Step index to resume verification at the correct point
28
+ step?: string; // Deprecated: use component_index.
29
+ component_index?: string; // Index in template.components (0-based) to resume at
30
+ country?: string; // Code pays pour restaurer la sélection (reprise multi-appareil)
31
+ document_type?: string; // Type de document (national_id, passport, etc.)
32
+ region?: string; // Région si applicable
29
33
  }
30
34
 
31
35
  interface VerificationSteps {
@@ -70,6 +74,10 @@ const WebKYCEntry: React.FC<WebKYCEntryProps> = ({
70
74
  template_id: urlParams.get('template_id') || undefined,
71
75
  server_env: validServerEnv,
72
76
  step: urlParams.get('step') || undefined,
77
+ component_index: urlParams.get('component_index') || undefined,
78
+ country: urlParams.get('country') || undefined,
79
+ document_type: urlParams.get('document_type') || undefined,
80
+ region: urlParams.get('region') || undefined,
73
81
  };
74
82
  }, []);
75
83
 
@@ -294,12 +302,15 @@ const WebKYCEntry: React.FC<WebKYCEntryProps> = ({
294
302
  API_KEY={urlParams.token}
295
303
  templateId={urlParams.template_id}
296
304
  env={urlParams.env || 'PRODUCTION'}
305
+ serverEnv={urlParams.server_env}
297
306
  existingSessionId={urlParams.kyc_id}
298
- initialStep={urlParams.step ? (() => {
299
- const stepNum = parseInt(urlParams.step, 10);
300
- console.log('Parsing step from URL:', { stepString: urlParams.step, stepNumber: stepNum, isNaN: isNaN(stepNum) });
301
- return isNaN(stepNum) ? undefined : stepNum;
302
- })() : undefined}
307
+ initialComponentIndex={(() => {
308
+ const raw = urlParams.component_index ?? urlParams.step;
309
+ if (raw == null || raw === '') return undefined;
310
+ const index = parseInt(raw, 10);
311
+ return Number.isNaN(index) ? undefined : index;
312
+ })()}
313
+ initialCountryResume={urlParams.country && urlParams.document_type ? { code: urlParams.country, documentType: urlParams.document_type, region: urlParams.region || undefined } : undefined}
303
314
  />
304
315
  </SafeAreaView>
305
316
  );