@sanctum-key/react-native-sdk 1.0.52 → 1.0.54

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 (132) hide show
  1. package/README.md +7 -2
  2. package/android/build/.transforms/3db9b15041d4285a820fc84462995ea1/results.bin +1 -0
  3. package/android/build/.transforms/3db9b15041d4285a820fc84462995ea1/transformed/classes/classes_dex/classes.dex +0 -0
  4. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  5. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  6. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
  7. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
  8. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
  9. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
  10. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
  11. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
  12. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
  13. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
  14. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
  15. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
  16. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
  17. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
  18. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
  19. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
  20. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
  21. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
  22. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
  23. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
  24. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
  25. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
  26. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
  27. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
  28. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
  29. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
  30. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
  31. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
  32. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
  33. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
  34. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
  35. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
  36. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
  37. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
  38. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +1 -1
  39. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
  40. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
  41. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
  42. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
  43. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
  44. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
  45. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
  46. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
  47. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
  48. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
  49. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
  50. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
  51. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
  52. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
  53. package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
  54. package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
  55. package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
  56. package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  57. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$BarcodeRegion.class +0 -0
  58. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$Companion.class +0 -0
  59. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$1$5$1.class → SanctumKeySdkModule$definition$1$6$1.class} +0 -0
  60. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$1$5$2.class → SanctumKeySdkModule$definition$1$6$2.class} +0 -0
  61. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$1.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$1.class} +0 -0
  62. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$5.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$2.class} +0 -0
  63. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$3.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$3.class} +0 -0
  64. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$4.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$4.class} +0 -0
  65. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$2.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$5.class} +0 -0
  66. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$6.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$6.class} +0 -0
  67. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunctionWithPromise$1.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$1.class} +0 -0
  68. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunctionWithPromise$3.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$2.class} +0 -0
  69. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$3.class +0 -0
  70. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$4.class +0 -0
  71. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunctionWithPromise$2.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$5.class} +0 -0
  72. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$6.class +0 -0
  73. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunctionWithPromise$4.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$7.class} +0 -0
  74. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$View$1.class → SanctumKeySdkModule$definition$lambda$16$$inlined$View$1.class} +0 -0
  75. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$lambda$4$$inlined$Prop$1.class → SanctumKeySdkModule$definition$lambda$16$lambda$15$$inlined$Prop$1.class} +0 -0
  76. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$lambda$4$$inlined$Prop$2.class → SanctumKeySdkModule$definition$lambda$16$lambda$15$$inlined$Prop$2.class} +0 -0
  77. package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule.class +0 -0
  78. package/android/build.gradle +7 -0
  79. package/android/src/main/java/kyc/sanctumkey/com/SanctumKeySdkModule.kt +428 -1
  80. package/build/package.json +1 -1
  81. package/build/src/SanctumKeySdkModule.d.ts +1 -0
  82. package/build/src/SanctumKeySdkModule.d.ts.map +1 -1
  83. package/build/src/SanctumKeySdkModule.js.map +1 -1
  84. package/build/src/components/EnhancedCameraView.d.ts.map +1 -1
  85. package/build/src/components/EnhancedCameraView.js +50 -41
  86. package/build/src/components/EnhancedCameraView.js.map +1 -1
  87. package/build/src/components/EnhancedCameraView.web.d.ts +2 -0
  88. package/build/src/components/EnhancedCameraView.web.d.ts.map +1 -1
  89. package/build/src/components/EnhancedCameraView.web.js +11 -6
  90. package/build/src/components/EnhancedCameraView.web.js.map +1 -1
  91. package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
  92. package/build/src/components/KYCElements/IDCardCapture.js +499 -78
  93. package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
  94. package/build/src/components/TemplateKYCExample.d.ts.map +1 -1
  95. package/build/src/components/TemplateKYCExample.js +17 -21
  96. package/build/src/components/TemplateKYCExample.js.map +1 -1
  97. package/build/src/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
  98. package/build/src/components/TemplateKYCFlowRefactored.js +2 -10
  99. package/build/src/components/TemplateKYCFlowRefactored.js.map +1 -1
  100. package/build/src/components/WebBarcodeScanner.d.ts +2 -0
  101. package/build/src/components/WebBarcodeScanner.d.ts.map +1 -1
  102. package/build/src/components/WebBarcodeScanner.js +99 -85
  103. package/build/src/components/WebBarcodeScanner.js.map +1 -1
  104. package/build/src/hooks/useTemplateLoader.d.ts.map +1 -1
  105. package/build/src/hooks/useTemplateLoader.js +0 -2
  106. package/build/src/hooks/useTemplateLoader.js.map +1 -1
  107. package/build/src/modules/api/KYCService.d.ts +1 -0
  108. package/build/src/modules/api/KYCService.d.ts.map +1 -1
  109. package/build/src/modules/api/KYCService.js +1 -1
  110. package/build/src/modules/api/KYCService.js.map +1 -1
  111. package/build/src/modules/api/TemplateService.d.ts.map +1 -1
  112. package/build/src/modules/api/TemplateService.js +2 -1
  113. package/build/src/modules/api/TemplateService.js.map +1 -1
  114. package/build/src/modules/api/types.d.ts +35 -27
  115. package/build/src/modules/api/types.d.ts.map +1 -1
  116. package/build/src/modules/api/types.js.map +1 -1
  117. package/package.json +1 -1
  118. package/plugin/build/withVisionCamera.d.ts +1 -0
  119. package/plugin/build/withVisionCamera.js +13 -1
  120. package/plugin/src/withVisionCamera.js +18 -2
  121. package/plugin/src/withVisionCamera.ts +19 -2
  122. package/src/SanctumKeySdkModule.ts +1 -0
  123. package/src/components/EnhancedCameraView.tsx +52 -41
  124. package/src/components/EnhancedCameraView.web.tsx +15 -5
  125. package/src/components/KYCElements/IDCardCapture.tsx +552 -75
  126. package/src/components/TemplateKYCExample.tsx +23 -25
  127. package/src/components/TemplateKYCFlowRefactored.tsx +2 -8
  128. package/src/components/WebBarcodeScanner.tsx +147 -198
  129. package/src/hooks/useTemplateLoader.ts +0 -2
  130. package/src/modules/api/KYCService.ts +3 -3
  131. package/src/modules/api/TemplateService.ts +3 -2
  132. package/src/modules/api/types.ts +37 -29
@@ -86,53 +86,51 @@ export function TemplateKYCExample({
86
86
  let finalPayload: any = data; // Fallback to raw data if mapping fails
87
87
 
88
88
  if ((data.status === 'success' || data.status === 'in_progress') && data.result) {
89
- // 1. Extract the dynamic root key (e.g., 'national_id', 'passport')
90
- const docKey = Object.keys(data.result)[0];
91
89
 
92
- if (docKey && data.result[docKey]) {
93
- const backendData = data.result[docKey].data;
94
- const personalInfo = backendData?.user_data?.personal_information || {};
90
+ const backendData = data.result.data;
91
+
92
+ if (backendData) {
93
+ const personalInfo = backendData.user_data?.personal_information || {};
94
+ const activeSessionId = kyc_session_id || existingSessionId || backendData.session_id || "";
95
+
95
96
 
96
- // Ensure we capture the session ID from whichever prop was provided
97
- const activeSessionId = kyc_session_id || existingSessionId || "";
97
+ const docType = (backendData as any).document_type || (backendData as any).documentType;
98
98
 
99
- // 2. Strict mapping to your expected format
100
99
  finalPayload = {
101
100
  data: {
102
- verification_id: backendData?.verification_id,
103
- verification_status: backendData?.verification_status,
101
+ document_type: docType,
102
+ verification_id: backendData.verification_id,
103
+ verification_status: backendData.verification_status,
104
104
  session_id: activeSessionId,
105
105
  user_data: {
106
106
  personal_information: {
107
- first_name: personalInfo.first_name || undefined,
107
+ first_name: personalInfo.first_name || personalInfo.given_name || undefined,
108
+ last_name: personalInfo.last_name || personalInfo.surname || undefined,
108
109
  given_name: personalInfo.given_name || undefined,
109
- last_name: personalInfo.last_name || undefined,
110
- surname: personalInfo.last_name || undefined, // fallback
110
+ surname: personalInfo.surname || undefined,
111
111
  address: personalInfo.address || undefined,
112
- city: personalInfo.city || undefined,
113
- postal_code: personalInfo.postal_code || undefined,
114
112
  expiry_date: personalInfo.expiry_date || undefined,
115
113
  issue_date: personalInfo.issue_date || undefined,
116
- date_of_birth: personalInfo.date_of_birth || undefined,
117
- birth_date: personalInfo.date_of_birth || undefined, // fallback
118
- country: personalInfo.country || undefined,
119
- document_number: (personalInfo as any).document_number || undefined,
120
- nationality: (personalInfo as any).nationality || undefined,
114
+ date_of_birth: personalInfo.date_of_birth || personalInfo.birth_date || undefined,
115
+ birth_date: personalInfo.birth_date || undefined,
116
+ document_number: personalInfo.document_number || undefined,
117
+ nationality: personalInfo.nationality || undefined,
118
+ sex: personalInfo.sex || undefined,
121
119
  }
122
120
  }
123
121
  }
124
122
  };
125
123
 
126
- sdkLogger.info("Wrapper formatted completion payload successfully", {
127
- verification_id: finalPayload.data.verification_id
124
+ sdkLogger.info("Wrapper formatteddddd completion payload successfully", {
125
+ data: finalPayload
128
126
  });
129
127
  }
130
128
  } else {
131
129
  sdkLogger.warn("Wrapper received completion without a success result object", { status: data.status });
132
130
  }
133
131
 
134
- onComplete(finalPayload as any);
135
- };
132
+ onComplete(finalPayload);
133
+ };
136
134
 
137
135
  const handleCancel = () => {
138
136
  console.log('KYC Template flow cancelled');
@@ -140,7 +138,7 @@ export function TemplateKYCExample({
140
138
  };
141
139
 
142
140
  const handleError = (error: string) => {
143
- console.error('KYC Template error:', error);
141
+ sdkLogger.error('KYC Template error:', error);
144
142
  onError(error);
145
143
  };
146
144
 
@@ -125,11 +125,7 @@ export const TemplateKYCFlow: React.FC<TemplateKYCFlowProps> = ({
125
125
 
126
126
  const template = providedTemplate || loadedTemplate;
127
127
 
128
- useEffect(() => {
129
- if (template) {
130
- sdkLogger.info("Template loaded successfully", { componentCount: template.components.length });
131
- }
132
- }, [template]);
128
+
133
129
 
134
130
  if (templateId && isLoading && !template) {
135
131
  return (
@@ -178,12 +174,11 @@ export const TemplateKYCFlow: React.FC<TemplateKYCFlowProps> = ({
178
174
  onError={(err) => {
179
175
  sdkLogger.error("KYC Flow Error", { error: err });
180
176
  sdkLogger.flush();
177
+ logger.log('Error', err)
181
178
  if (onError) onError(err);
182
179
  }}
183
180
  onCancel={OnCancel}
184
181
  initialLanguage={language}
185
- // 🚨 3. Pass the resolved active API key down to the provider!
186
- // The context/hooks will automatically use this key.
187
182
  apiKey={activeApiKey}
188
183
  testApiKey={TEST_API_KEY}
189
184
  env={env}
@@ -203,7 +198,6 @@ const TemplateKYCFlowContent: React.FC<{ onCancel?: () => void }> = ({ onCancel
203
198
  const { state, actions, currentComponent, progress } = useTemplateKYCFlowContext();
204
199
  const { t } = useI18n();
205
200
 
206
- console.log(`sessionnnn id: ${state.session.session_id}`)
207
201
 
208
202
  useEffect(() => {
209
203
  if (state.session?.session_id) {
@@ -1,4 +1,5 @@
1
1
  import React, { useCallback, useEffect, useRef } from 'react';
2
+ import type { CodeType } from 'react-native-vision-camera';
2
3
  import {
3
4
  MultiFormatReader,
4
5
  BarcodeFormat,
@@ -13,261 +14,209 @@ interface WebBarcodeScannerProps {
13
14
  videoRef: React.RefObject<HTMLVideoElement | null>;
14
15
  active: boolean;
15
16
  onBarcodeScanned: (value: string) => void;
17
+ formats?: CodeType[];
16
18
  }
17
19
 
20
+ interface RoiProfile {
21
+ width: number;
22
+ height: number;
23
+ contrast: number;
24
+ }
25
+
26
+ const ROI_PROFILES: RoiProfile[] = [
27
+ // Full frame catches barcodes before the user has centered them.
28
+ { width: 1, height: 1, contrast: 1 },
29
+ // Most ID barcodes sit in the wide center strip shown by the overlay.
30
+ { width: 0.98, height: 0.64, contrast: 1 },
31
+ // A tighter, contrast-enhanced pass helps very dense or low-contrast PDF417.
32
+ { width: 0.94, height: 0.46, contrast: 1.55 },
33
+ ];
34
+
35
+ const ROTATIONS = [180, 90, -90];
36
+ const DEFAULT_FORMATS: CodeType[] = ['pdf-417'];
37
+
38
+ const ZXING_FORMATS: Partial<Record<CodeType, BarcodeFormat>> = {
39
+ 'pdf-417': BarcodeFormat.PDF_417,
40
+ 'code-128': BarcodeFormat.CODE_128,
41
+ 'code-39': BarcodeFormat.CODE_39,
42
+ 'code-93': BarcodeFormat.CODE_93,
43
+ codabar: BarcodeFormat.CODABAR,
44
+ 'ean-13': BarcodeFormat.EAN_13,
45
+ 'ean-8': BarcodeFormat.EAN_8,
46
+ itf: BarcodeFormat.ITF,
47
+ 'itf-14': BarcodeFormat.ITF,
48
+ 'upc-a': BarcodeFormat.UPC_A,
49
+ 'upc-e': BarcodeFormat.UPC_E,
50
+ qr: BarcodeFormat.QR_CODE,
51
+ aztec: BarcodeFormat.AZTEC,
52
+ 'data-matrix': BarcodeFormat.DATA_MATRIX,
53
+ 'gs1-data-bar': BarcodeFormat.RSS_14,
54
+ 'gs1-data-bar-limited': BarcodeFormat.RSS_14,
55
+ 'gs1-data-bar-expanded': BarcodeFormat.RSS_EXPANDED,
56
+ };
57
+
18
58
  export const WebBarcodeScanner: React.FC<WebBarcodeScannerProps> = ({
19
59
  videoRef,
20
60
  active,
21
61
  onBarcodeScanned,
62
+ formats = DEFAULT_FORMATS,
22
63
  }) => {
23
64
  const readerRef = useRef<MultiFormatReader | null>(null);
24
-
25
65
  const canvasRef = useRef<HTMLCanvasElement | null>(null);
26
-
27
- const lastValueRef = useRef<string | null>(null);
28
-
66
+ const rotationCanvasRef = useRef<HTMLCanvasElement | null>(null);
67
+ const lastValueRef = useRef<{ value: string | null; emittedAt: number }>({ value: null, emittedAt: 0 });
68
+ const attemptRef = useRef(0);
69
+ const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
29
70
  const stoppedRef = useRef(false);
30
-
31
71
  const callbackRef = useRef(onBarcodeScanned);
32
72
 
33
73
  useEffect(() => {
34
74
  callbackRef.current = onBarcodeScanned;
35
75
  }, [onBarcodeScanned]);
36
76
 
37
- const decodeBitmap = useCallback(
38
- (canvas: HTMLCanvasElement) => {
39
- if (!readerRef.current) {
40
- return null;
77
+ const decodeBitmap = useCallback((canvas: HTMLCanvasElement) => {
78
+ if (!readerRef.current || canvas.width === 0 || canvas.height === 0) return null;
79
+
80
+ const source = new HTMLCanvasElementLuminanceSource(canvas);
81
+ const attempts = [
82
+ new BinaryBitmap(new HybridBinarizer(source)),
83
+ new BinaryBitmap(new GlobalHistogramBinarizer(source)),
84
+ ];
85
+
86
+ for (const bitmap of attempts) {
87
+ try {
88
+ const result = readerRef.current.decodeWithState(bitmap);
89
+ const text = result?.getText();
90
+ if (text) return text;
91
+ } catch {
92
+ // Try the next binarization strategy/rotation.
41
93
  }
94
+ }
42
95
 
43
- const source = new HTMLCanvasElementLuminanceSource(canvas);
44
-
45
- const attempts = [
46
- new BinaryBitmap(
47
- new HybridBinarizer(source)
48
- ),
49
- new BinaryBitmap(
50
- new GlobalHistogramBinarizer(source)
51
- ),
52
- ];
53
-
54
- for (const bitmap of attempts) {
55
- try {
56
- const result =
57
- readerRef.current.decodeWithState(bitmap);
58
-
59
- if (result?.getText()) {
60
- return result.getText();
61
- }
62
- } catch {
63
- // continue
64
- }
65
- }
66
-
67
- return null;
68
- },
69
- []
70
- );
71
-
72
- const drawROI = useCallback(
73
- (
74
- video: HTMLVideoElement,
75
- canvas: HTMLCanvasElement
76
- ) => {
77
- const ctx = canvas.getContext('2d', {
78
- willReadFrequently: true,
79
- });
80
-
81
- if (!ctx) {
82
- return false;
83
- }
84
-
85
- const roi = 0.8;
86
-
87
- const sw = Math.floor(
88
- video.videoWidth * roi
89
- );
90
-
91
- const sh = Math.floor(
92
- video.videoHeight * roi
93
- );
94
-
95
- const sx = Math.floor(
96
- (video.videoWidth - sw) / 2
97
- );
96
+ return null;
97
+ }, []);
98
+
99
+ const drawROI = useCallback((video: HTMLVideoElement, canvas: HTMLCanvasElement, profile: RoiProfile) => {
100
+ const ctx = canvas.getContext('2d', { willReadFrequently: true });
101
+ if (!ctx) return false;
102
+
103
+ const sourceWidth = Math.max(1, Math.floor(video.videoWidth * profile.width));
104
+ const sourceHeight = Math.max(1, Math.floor(video.videoHeight * profile.height));
105
+ const sourceX = Math.floor((video.videoWidth - sourceWidth) / 2);
106
+ const sourceY = Math.floor((video.videoHeight - sourceHeight) / 2);
107
+
108
+ // Nearest-neighbour enlargement gives ZXing more pixels per narrow module
109
+ // on sub-1080p browser streams without allocating an unbounded canvas.
110
+ const desiredScale = sourceWidth < 1600 ? Math.min(1.75, 1600 / sourceWidth) : 1;
111
+ const boundedScale = Math.min(desiredScale, 2800 / Math.max(sourceWidth, sourceHeight));
112
+ const outputWidth = Math.max(1, Math.floor(sourceWidth * boundedScale));
113
+ const outputHeight = Math.max(1, Math.floor(sourceHeight * boundedScale));
114
+
115
+ if (canvas.width !== outputWidth || canvas.height !== outputHeight) {
116
+ canvas.width = outputWidth;
117
+ canvas.height = outputHeight;
118
+ }
98
119
 
99
- const sy = Math.floor(
100
- (video.videoHeight - sh) / 2
101
- );
120
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
121
+ ctx.clearRect(0, 0, outputWidth, outputHeight);
122
+ ctx.imageSmoothingEnabled = false;
123
+ ctx.filter = profile.contrast === 1 ? 'none' : `grayscale(1) contrast(${profile.contrast})`;
124
+ ctx.drawImage(
125
+ video,
126
+ sourceX,
127
+ sourceY,
128
+ sourceWidth,
129
+ sourceHeight,
130
+ 0,
131
+ 0,
132
+ outputWidth,
133
+ outputHeight,
134
+ );
135
+ ctx.filter = 'none';
136
+ return true;
137
+ }, []);
102
138
 
103
- if (
104
- canvas.width !== sw ||
105
- canvas.height !== sh
106
- ) {
107
- canvas.width = sw;
108
- canvas.height = sh;
109
- }
139
+ const rotateCanvas = useCallback((sourceCanvas: HTMLCanvasElement, degrees: number) => {
140
+ if (!rotationCanvasRef.current) rotationCanvasRef.current = document.createElement('canvas');
110
141
 
111
- ctx.drawImage(
112
- video,
113
- sx,
114
- sy,
115
- sw,
116
- sh,
117
- 0,
118
- 0,
119
- sw,
120
- sh
121
- );
122
-
123
- return true;
124
- },
125
- []
126
- );
127
-
128
- // Add a persistent rotation canvas ref at the top
129
- const rotationCanvasRef = useRef<HTMLCanvasElement | null>(null);
130
-
131
- // Update rotateCanvas to re-use the persistent canvas
132
- const rotateCanvas = useCallback(
133
- (sourceCanvas: HTMLCanvasElement, degrees: number) => {
134
- if (!rotationCanvasRef.current) {
135
- rotationCanvasRef.current = document.createElement('canvas');
136
- }
137
142
  const rotated = rotationCanvasRef.current;
138
- const ctx = rotated.getContext('2d');
139
- if (!ctx) return null;
143
+ const swapDimensions = Math.abs(degrees) === 90;
144
+ rotated.width = swapDimensions ? sourceCanvas.height : sourceCanvas.width;
145
+ rotated.height = swapDimensions ? sourceCanvas.width : sourceCanvas.height;
140
146
 
141
- const radians = (degrees * Math.PI) / 180;
142
- if (degrees === 90 || degrees === -90) {
143
- rotated.width = sourceCanvas.height;
144
- rotated.height = sourceCanvas.width;
145
- } else {
146
- rotated.width = sourceCanvas.width;
147
- rotated.height = sourceCanvas.height;
148
- }
147
+ const ctx = rotated.getContext('2d', { willReadFrequently: true });
148
+ if (!ctx) return null;
149
149
 
150
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
150
151
  ctx.clearRect(0, 0, rotated.width, rotated.height);
151
152
  ctx.translate(rotated.width / 2, rotated.height / 2);
152
- ctx.rotate(radians);
153
+ ctx.rotate((degrees * Math.PI) / 180);
153
154
  ctx.drawImage(sourceCanvas, -sourceCanvas.width / 2, -sourceCanvas.height / 2);
154
155
  return rotated;
155
- },
156
- []
157
- );
158
-
159
-
156
+ }, []);
160
157
 
161
158
  const tryDecode = useCallback(() => {
162
159
  const video = videoRef.current;
163
-
164
160
  const canvas = canvasRef.current;
161
+ if (!video || !canvas || video.readyState < 2 || video.videoWidth === 0 || video.videoHeight === 0) return null;
165
162
 
166
- if (
167
- !video ||
168
- !canvas ||
169
- video.readyState < 2
170
- ) {
171
- return null;
172
- }
163
+ const attempt = attemptRef.current++;
164
+ const profile = ROI_PROFILES[attempt % ROI_PROFILES.length];
165
+ if (!drawROI(video, canvas, profile)) return null;
173
166
 
174
- const ok = drawROI(video, canvas);
167
+ const directValue = decodeBitmap(canvas);
168
+ if (directValue) return directValue;
175
169
 
176
- if (!ok) {
177
- return null;
178
- }
170
+ // Spread rotation work over successive frames to keep the UI responsive.
171
+ const rotation = ROTATIONS[attempt % ROTATIONS.length];
172
+ const rotated = rotateCanvas(canvas, rotation);
173
+ return rotated ? decodeBitmap(rotated) : null;
174
+ }, [decodeBitmap, drawROI, rotateCanvas, videoRef]);
179
175
 
180
- let value = decodeBitmap(canvas);
176
+ const tick = useCallback(() => {
177
+ if (stoppedRef.current) return;
181
178
 
179
+ const value = tryDecode();
182
180
  if (value) {
183
- return value;
184
- }
185
-
186
- const rotations = [90, -90, 180];
187
-
188
- for (const rotation of rotations) {
189
- const rotated = rotateCanvas(
190
- canvas,
191
- rotation
192
- );
193
-
194
- if (!rotated) {
195
- continue;
196
- }
197
-
198
- value = decodeBitmap(rotated);
199
-
200
- if (value) {
201
- return value;
181
+ const now = Date.now();
182
+ const previous = lastValueRef.current;
183
+ if (value !== previous.value || now - previous.emittedAt > 1500) {
184
+ lastValueRef.current = { value, emittedAt: now };
185
+ callbackRef.current(value);
202
186
  }
203
187
  }
204
188
 
205
- return null;
206
- }, [
207
- videoRef,
208
- drawROI,
209
- decodeBitmap,
210
- rotateCanvas,
211
- ]);
212
-
213
- const tick = useCallback(() => {
214
- if (stoppedRef.current) return;
215
-
216
- const value = tryDecode();
217
- if (value && value !== lastValueRef.current) {
218
- lastValueRef.current = value;
219
- callbackRef.current(value);
220
- // If you want it to stop scanning on success, leave 'return;'
221
- // but ensure your parent component handles unmounting the scanner!
222
- return;
223
- }
224
-
225
- setTimeout(tick, 100);
189
+ timerRef.current = setTimeout(tick, 180);
226
190
  }, [tryDecode]);
227
191
 
228
192
  useEffect(() => {
229
- if (!active) {
230
- return;
231
- }
193
+ if (!active) return;
232
194
 
233
195
  stoppedRef.current = false;
196
+ attemptRef.current = 0;
197
+ lastValueRef.current = { value: null, emittedAt: 0 };
198
+ if (!canvasRef.current) canvasRef.current = document.createElement('canvas');
234
199
 
235
- lastValueRef.current = null;
236
-
237
- if (!canvasRef.current) {
238
- canvasRef.current =
239
- document.createElement('canvas');
240
- }
241
-
200
+ const possibleFormats = Array.from(new Set(
201
+ formats.map(format => ZXING_FORMATS[format]).filter((format): format is BarcodeFormat => format !== undefined),
202
+ ));
242
203
  const hints = new Map();
204
+ hints.set(DecodeHintType.POSSIBLE_FORMATS, possibleFormats.length > 0 ? possibleFormats : [BarcodeFormat.PDF_417]);
205
+ hints.set(DecodeHintType.TRY_HARDER, true);
243
206
 
244
- hints.set(
245
- DecodeHintType.POSSIBLE_FORMATS,
246
- [BarcodeFormat.PDF_417]
247
- );
248
-
249
- hints.set(
250
- DecodeHintType.TRY_HARDER,
251
- true
252
- );
253
-
254
- const reader =
255
- new MultiFormatReader();
256
-
207
+ const reader = new MultiFormatReader();
257
208
  reader.setHints(hints);
258
-
259
209
  readerRef.current = reader;
260
-
261
210
  tick();
262
211
 
263
212
  return () => {
264
213
  stoppedRef.current = true;
265
-
214
+ if (timerRef.current) clearTimeout(timerRef.current);
215
+ timerRef.current = null;
266
216
  readerRef.current?.reset();
267
-
268
217
  readerRef.current = null;
269
218
  };
270
- }, [active, tick]);
219
+ }, [active, formats, tick]);
271
220
 
272
221
  return null;
273
- };
222
+ };
@@ -61,10 +61,8 @@ export function useTemplateLoader(): UseTemplateLoaderReturn {
61
61
 
62
62
  // Set the template
63
63
  setTemplate(transformedTemplate);
64
- logger.log(`Template loaded successfully: ${templateId}`);
65
64
  } catch (err: any) {
66
65
  const errorMessage = err.message || 'Failed to load template';
67
- logger.error(`Error loading template ${templateId}:`, errorMessage);
68
66
  setError(errorMessage);
69
67
  setTemplate(null);
70
68
  } finally {
@@ -279,14 +279,14 @@ export class KYCService {
279
279
  }
280
280
  }
281
281
 
282
- async extractBarcode(params: { fileUri: string; token: string; docType: string; postfix?: string }, env: KycEnvironment = 'PRODUCTION'): Promise<any> {
282
+ async extractBarcode(params: { fileUri: string; token: string; docType: string; postfix?: string; timeoutMs?: number }, env: KycEnvironment = 'PRODUCTION'): Promise<any> {
283
283
  const formData = new FormData();
284
284
  await appendFileToFormData(formData, 'file', params.fileUri, `id_${params.postfix || 'back'}_photo.jpg`, 'image/jpeg');
285
285
 
286
286
  const url = `${this.barcodeServiceURL}/decode_barcode/?doc_type=${encodeURIComponent(params.docType)}`;
287
287
 
288
288
  try {
289
- return await this.crossPlatformMultipartUpload<any>(url, formData, params.token, 60000);
289
+ return await this.crossPlatformMultipartUpload<any>(url, formData, params.token, params.timeoutMs ?? 60000);
290
290
  } catch (e: any) {
291
291
  throw e;
292
292
  }
@@ -651,4 +651,4 @@ export const clearAuthToken = () => {
651
651
 
652
652
  export const errorMessage = (error: any) => {
653
653
  return error.response?.data?.message || error.response?.data?.detail || error.response?.data?.error || error.response?.data || error.message;
654
- }
654
+ }
@@ -1,6 +1,6 @@
1
1
  import axios from 'axios';
2
2
  import { BackendKYCTemplate, TemplateAPIResponse } from '../../types/KYC.types';
3
- import { logger } from '../../utils/logger';
3
+ import { logger, sdkLogger } from '../../utils/logger';
4
4
  import { errorMessage } from './KYCService';
5
5
  import KYCConfig from '../../config/KYCConfig';
6
6
 
@@ -82,7 +82,8 @@ export class TemplateServiceClass {
82
82
  logger.log(`Template ${templateId} fetched successfully`);
83
83
  return template;
84
84
  } catch (error: any) {
85
- logger.error(`Error fetching template ${templateId}:`, JSON.stringify(errorMessage(error), null, 2));
85
+ logger.error(`Error fetching template ${templateId}:`, JSON.stringify(errorMessage(error), null, 2))
86
+ sdkLogger.error(`Error fetching template ${templateId}:`, JSON.stringify(errorMessage(error), null, 2));
86
87
 
87
88
  // Extract backend error message if available
88
89
  const backendMessage = errorMessage(error);
@@ -26,34 +26,42 @@ export type VerificationSessionData = Record<string, any>;
26
26
 
27
27
 
28
28
  export interface VerificationResult {
29
- [key: string]: {
30
- data: {
31
- verification_id: string;
32
- verification_status: string;
33
- completion_timestamp: string;
34
- user_data: {
35
- personal_information: {
36
- full_name: string;
37
- first_name: string | null;
38
- given_name: string | null;
39
- last_name: string | null;
40
- date_of_birth: string;
41
- sex: string;
42
- expiry_date: string ;
43
- issue_date: string;
44
- issue_place: string | null;
45
- place_of_birth: string | null;
46
- address: string | null;
47
- city: string | null;
48
- postal_code: string | null;
49
- country: string | null;
50
- };
51
- };
52
- selfie_info: {
53
- is_match: boolean;
54
- similarity: number;
55
- image: string;
56
- };
29
+ message?: string;
30
+ status?: string;
31
+ referenceId?: string;
32
+ issues?: string[];
33
+ data?: {
34
+ session_id?: string;
35
+ verification_id?: string;
36
+ verification_status?: string;
37
+ document_type?: string;
38
+ completion_timestamp?: string;
39
+ user_data?: {
40
+ personal_information?: {
41
+ full_name?: string | null;
42
+ first_name?: string | null;
43
+ last_name?: string | null;
44
+ given_name?: string | null;
45
+ surname?: string | null;
46
+ date_of_birth?: string | null;
47
+ birth_date?: string | null;
48
+ sex?: string | null;
49
+ expiry_date?: string | null;
50
+ issue_date?: string | null;
51
+ issue_place?: string | null;
52
+ place_of_birth?: string | null;
53
+ address?: string | null;
54
+ city?: string | null;
55
+ postal_code?: string | null;
56
+ country?: string | null;
57
+ nationality?: string | null;
58
+ document_number?: string | null;
57
59
  };
60
+ };
61
+ selfie_info?: {
62
+ is_match?: boolean;
63
+ similarity?: number;
64
+ image?: string;
65
+ };
58
66
  };
59
- }
67
+ }