@trustchex/react-native-sdk 1.475.1 → 1.478.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/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraView.kt +19 -21
- package/android/src/main/java/com/trustchex/reactnativesdk/mlkit/MLKitModule.kt +1 -0
- package/lib/module/Screens/Dynamic/LivenessDetectionScreen.js +3 -2
- package/lib/module/Screens/Static/QrCodeScanningScreen.js +12 -2
- package/lib/module/Screens/Static/ResultScreen.js +103 -107
- package/lib/module/Shared/Components/DebugOverlay.js +5 -2
- package/lib/module/Shared/Components/IdentityDocumentCamera.js +53 -22
- package/lib/module/Shared/Components/IdentityDocumentCamera.utils.js +8 -1
- package/lib/module/Shared/EIDReader/eidReader.js +15 -14
- package/lib/module/Shared/Libs/MRZ_KNOWN_ISSUES.md +34 -0
- package/lib/module/Shared/Libs/SignalingClient.js +6 -5
- package/lib/module/Shared/Libs/crypto.utils.js +25 -3
- package/lib/module/Shared/Libs/deeplink.utils.js +37 -7
- package/lib/module/Shared/Libs/http-client.js +19 -6
- package/lib/module/Shared/Libs/mrz.utils.js +193 -33
- package/lib/module/Shared/Libs/mrzFrameAggregator.js +45 -1
- package/lib/module/Shared/Libs/promise.utils.js +4 -3
- package/lib/module/Shared/Libs/shuffle.utils.js +17 -0
- package/lib/module/Shared/Services/AnalyticsService.js +8 -2
- package/lib/module/Shared/Services/DataUploadService.js +114 -127
- package/lib/module/Shared/Services/VideoSessionService.js +4 -3
- package/lib/module/Translation/Resources/en.js +1 -0
- package/lib/module/Translation/Resources/tr.js +1 -0
- package/lib/module/version.js +1 -1
- package/lib/typescript/src/Screens/Dynamic/LivenessDetectionScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Static/QrCodeScanningScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Static/ResultScreen.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/DebugOverlay.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/eidReader.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/SignalingClient.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/crypto.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/deeplink.utils.d.ts +1 -0
- package/lib/typescript/src/Shared/Libs/deeplink.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/http-client.d.ts +2 -0
- package/lib/typescript/src/Shared/Libs/http-client.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/mrzFrameAggregator.d.ts +22 -0
- package/lib/typescript/src/Shared/Libs/mrzFrameAggregator.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/promise.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/shuffle.utils.d.ts +3 -0
- package/lib/typescript/src/Shared/Libs/shuffle.utils.d.ts.map +1 -0
- package/lib/typescript/src/Shared/Services/AnalyticsService.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Services/DataUploadService.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Services/VideoSessionService.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/en.d.ts +1 -0
- package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/tr.d.ts +1 -0
- package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +13 -3
- package/src/Screens/Dynamic/LivenessDetectionScreen.tsx +4 -3
- package/src/Screens/Static/QrCodeScanningScreen.tsx +19 -2
- package/src/Screens/Static/ResultScreen.tsx +126 -161
- package/src/Shared/Components/DebugOverlay.tsx +5 -2
- package/src/Shared/Components/IdentityDocumentCamera.tsx +55 -22
- package/src/Shared/Components/IdentityDocumentCamera.utils.ts +9 -1
- package/src/Shared/EIDReader/eidReader.ts +23 -14
- package/src/Shared/Libs/MRZ_KNOWN_ISSUES.md +34 -0
- package/src/Shared/Libs/SignalingClient.ts +10 -5
- package/src/Shared/Libs/crypto.utils.ts +41 -4
- package/src/Shared/Libs/deeplink.utils.ts +39 -7
- package/src/Shared/Libs/http-client.ts +24 -8
- package/src/Shared/Libs/mrz.utils.ts +200 -34
- package/src/Shared/Libs/mrzFrameAggregator.ts +53 -1
- package/src/Shared/Libs/promise.utils.ts +11 -5
- package/src/Shared/Libs/shuffle.utils.ts +15 -0
- package/src/Shared/Services/AnalyticsService.ts +17 -1
- package/src/Shared/Services/DataUploadService.ts +155 -166
- package/src/Shared/Services/VideoSessionService.ts +15 -3
- package/src/Translation/Resources/en.ts +1 -0
- package/src/Translation/Resources/tr.ts +1 -0
- package/src/version.ts +1 -1
|
@@ -7,9 +7,10 @@ import type {
|
|
|
7
7
|
} from '../Types/identificationInfo';
|
|
8
8
|
import { getSessionKey, encryptWithAes } from '../Libs/crypto.utils';
|
|
9
9
|
import mrzUtils from '../Libs/mrz.utils';
|
|
10
|
-
import httpClient from '../Libs/http-client';
|
|
10
|
+
import httpClient, { getSessionToken } from '../Libs/http-client';
|
|
11
11
|
import { NotFoundError } from '../Libs/http-client';
|
|
12
12
|
import { runWithRetry } from '../Libs/promise.utils';
|
|
13
|
+
import { debugLog, debugWarn, logError, logWarn } from '../Libs/debug.utils';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Service to upload collected identification data to the backend.
|
|
@@ -27,15 +28,16 @@ export class DataUploadService {
|
|
|
27
28
|
private async ensureIdentificationExists(
|
|
28
29
|
identificationId: string
|
|
29
30
|
): Promise<void> {
|
|
30
|
-
|
|
31
|
-
'
|
|
31
|
+
debugLog(
|
|
32
|
+
'DataUploadService',
|
|
33
|
+
'POST',
|
|
32
34
|
`${this.apiUrl}/identifications/${identificationId}`
|
|
33
35
|
);
|
|
34
36
|
await httpClient.post(
|
|
35
37
|
`${this.apiUrl}/identifications/${identificationId}`,
|
|
36
38
|
{}
|
|
37
39
|
);
|
|
38
|
-
|
|
40
|
+
debugLog('DataUploadService', '✓ Identification created/verified');
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
/**
|
|
@@ -47,13 +49,13 @@ export class DataUploadService {
|
|
|
47
49
|
sessionKey: string
|
|
48
50
|
): Promise<void> {
|
|
49
51
|
if (!scannedDocument || scannedDocument.documentType === 'UNKNOWN') {
|
|
50
|
-
|
|
52
|
+
debugLog('DataUploadService', 'No document data to submit');
|
|
51
53
|
return;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
const mrzFields = scannedDocument.mrzFields;
|
|
55
57
|
if (!mrzFields) {
|
|
56
|
-
|
|
58
|
+
debugLog('DataUploadService', 'No MRZ fields to submit');
|
|
57
59
|
return;
|
|
58
60
|
}
|
|
59
61
|
|
|
@@ -72,10 +74,10 @@ export class DataUploadService {
|
|
|
72
74
|
mrzText: scannedDocument.mrzText,
|
|
73
75
|
};
|
|
74
76
|
|
|
75
|
-
|
|
76
|
-
'
|
|
77
|
-
|
|
78
|
-
identificationDocument.
|
|
77
|
+
debugLog(
|
|
78
|
+
'DataUploadService',
|
|
79
|
+
'Submitting document data:',
|
|
80
|
+
identificationDocument.type
|
|
79
81
|
);
|
|
80
82
|
|
|
81
83
|
const { encryptedData, nonce } = encryptWithAes(
|
|
@@ -83,8 +85,9 @@ export class DataUploadService {
|
|
|
83
85
|
sessionKey
|
|
84
86
|
);
|
|
85
87
|
|
|
86
|
-
|
|
87
|
-
'
|
|
88
|
+
debugLog(
|
|
89
|
+
'DataUploadService',
|
|
90
|
+
'POST',
|
|
88
91
|
`${this.apiUrl}/identifications/${identificationId}/documents`
|
|
89
92
|
);
|
|
90
93
|
await runWithRetry(() =>
|
|
@@ -97,7 +100,7 @@ export class DataUploadService {
|
|
|
97
100
|
)
|
|
98
101
|
);
|
|
99
102
|
|
|
100
|
-
|
|
103
|
+
debugLog('DataUploadService', '✓ Document data submitted');
|
|
101
104
|
}
|
|
102
105
|
|
|
103
106
|
/**
|
|
@@ -109,11 +112,13 @@ export class DataUploadService {
|
|
|
109
112
|
livenessDetection?: LivenessDetection,
|
|
110
113
|
onProgress?: (progress: number) => void
|
|
111
114
|
): Promise<void> {
|
|
115
|
+
const sessionToken = getSessionToken();
|
|
112
116
|
const uploadFileOptions: RNFS.UploadFileOptions = {
|
|
113
117
|
toUrl: `${this.apiUrl}/identifications/${identificationId}/media`,
|
|
114
118
|
method: 'POST',
|
|
115
119
|
headers: {
|
|
116
120
|
Accept: 'application/json',
|
|
121
|
+
...(sessionToken ? { 'X-Session-Token': sessionToken } : {}),
|
|
117
122
|
},
|
|
118
123
|
files: [],
|
|
119
124
|
progress: (res) => {
|
|
@@ -122,159 +127,142 @@ export class DataUploadService {
|
|
|
122
127
|
},
|
|
123
128
|
};
|
|
124
129
|
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
await RNFS.writeFile(decodeURIComponent(filePath), frontImage, 'base64');
|
|
130
|
-
uploadFileOptions.files.push({
|
|
131
|
-
name: 'files',
|
|
132
|
-
filename: 'DOCUMENT_FRONT_IMAGE.jpg',
|
|
133
|
-
filepath: decodeURIComponent(filePath),
|
|
134
|
-
filetype: 'image/jpeg',
|
|
135
|
-
});
|
|
136
|
-
}
|
|
130
|
+
// Plaintext identity images/video staged on disk for the multipart upload;
|
|
131
|
+
// every entry is deleted in the finally below, whether the upload succeeds
|
|
132
|
+
// or not.
|
|
133
|
+
const tempPaths: string[] = [];
|
|
137
134
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
await RNFS.writeFile(
|
|
135
|
+
const writeTempImage = async (fileName: string, base64Data: string) => {
|
|
136
|
+
const filePath = decodeURIComponent(
|
|
137
|
+
`${RNFS.TemporaryDirectoryPath}/${fileName}`
|
|
138
|
+
);
|
|
139
|
+
await RNFS.writeFile(filePath, base64Data, 'base64');
|
|
140
|
+
tempPaths.push(filePath);
|
|
143
141
|
uploadFileOptions.files.push({
|
|
144
142
|
name: 'files',
|
|
145
|
-
filename:
|
|
146
|
-
filepath:
|
|
143
|
+
filename: fileName,
|
|
144
|
+
filepath: filePath,
|
|
147
145
|
filetype: 'image/jpeg',
|
|
148
146
|
});
|
|
149
|
-
|
|
147
|
+
return filePath;
|
|
148
|
+
};
|
|
150
149
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
name: 'files',
|
|
158
|
-
filename: 'FACE_IMAGE.jpg',
|
|
159
|
-
filepath: decodeURIComponent(filePath),
|
|
160
|
-
filetype: 'image/jpeg',
|
|
161
|
-
});
|
|
162
|
-
}
|
|
150
|
+
try {
|
|
151
|
+
// Add document front image
|
|
152
|
+
const frontImage = scannedDocument?.frontImage;
|
|
153
|
+
if (frontImage && frontImage !== '') {
|
|
154
|
+
await writeTempImage('DOCUMENT_FRONT_IMAGE.jpg', frontImage);
|
|
155
|
+
}
|
|
163
156
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
decodeURIComponent(filePath),
|
|
170
|
-
secondaryFaceImage,
|
|
171
|
-
'base64'
|
|
172
|
-
);
|
|
173
|
-
uploadFileOptions.files.push({
|
|
174
|
-
name: 'files',
|
|
175
|
-
filename: 'DOCUMENT_SECONDARY_FACE_IMAGE.jpg',
|
|
176
|
-
filepath: decodeURIComponent(filePath),
|
|
177
|
-
filetype: 'image/jpeg',
|
|
178
|
-
});
|
|
179
|
-
}
|
|
157
|
+
// Add document back image
|
|
158
|
+
const backImage = scannedDocument?.backImage;
|
|
159
|
+
if (backImage && backImage !== '') {
|
|
160
|
+
await writeTempImage('DOCUMENT_BACK_IMAGE.jpg', backImage);
|
|
161
|
+
}
|
|
180
162
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
decodeURIComponent(filePath),
|
|
187
|
-
hologramImage,
|
|
188
|
-
'base64'
|
|
189
|
-
);
|
|
190
|
-
uploadFileOptions.files.push({
|
|
191
|
-
name: 'files',
|
|
192
|
-
filename: 'DOCUMENT_HOLOGRAM_IMAGE.jpg',
|
|
193
|
-
filepath: decodeURIComponent(filePath),
|
|
194
|
-
filetype: 'image/jpeg',
|
|
195
|
-
});
|
|
196
|
-
}
|
|
163
|
+
// Add face image from document
|
|
164
|
+
const faceImage = scannedDocument?.faceImage;
|
|
165
|
+
if (faceImage && faceImage !== '') {
|
|
166
|
+
await writeTempImage('FACE_IMAGE.jpg', faceImage);
|
|
167
|
+
}
|
|
197
168
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
169
|
+
// Add secondary face image from document (optional)
|
|
170
|
+
const secondaryFaceImage = scannedDocument?.secondaryFaceImage;
|
|
171
|
+
if (secondaryFaceImage && secondaryFaceImage !== '') {
|
|
172
|
+
await writeTempImage(
|
|
173
|
+
'DOCUMENT_SECONDARY_FACE_IMAGE.jpg',
|
|
174
|
+
secondaryFaceImage
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Add hologram image from document (optional)
|
|
179
|
+
const hologramImage = scannedDocument?.hologramImage;
|
|
180
|
+
if (hologramImage && hologramImage !== '') {
|
|
181
|
+
await writeTempImage('DOCUMENT_HOLOGRAM_IMAGE.jpg', hologramImage);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Add liveness images and selfie from liveness detection
|
|
185
|
+
if (livenessDetection?.instructions) {
|
|
186
|
+
for (const instruction of livenessDetection.instructions) {
|
|
187
|
+
if (instruction?.photo) {
|
|
188
|
+
const filePath = await writeTempImage(
|
|
189
|
+
`LIVENESS_${instruction.instruction}_IMAGE.jpg`,
|
|
190
|
+
instruction.photo
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
if (instruction.instruction === 'LOOK_STRAIGHT_AND_BLINK') {
|
|
194
|
+
uploadFileOptions.files.push({
|
|
195
|
+
name: 'files',
|
|
196
|
+
filename: 'SELFIE_IMAGE.jpg',
|
|
197
|
+
filepath: filePath,
|
|
198
|
+
filetype: 'image/jpeg',
|
|
199
|
+
});
|
|
200
|
+
}
|
|
222
201
|
}
|
|
223
202
|
}
|
|
224
203
|
}
|
|
225
|
-
}
|
|
226
204
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
205
|
+
// Add liveness video (optional). Only the staged copy is cleaned up here;
|
|
206
|
+
// livenessDetection.videoPath stays available for later submissions.
|
|
207
|
+
if (livenessDetection?.videoPath) {
|
|
208
|
+
let videoFilePath: string;
|
|
209
|
+
if (Platform.OS === 'ios') {
|
|
210
|
+
const tempDir = `${RNFS.TemporaryDirectoryPath}/${new Date().getTime()}`;
|
|
211
|
+
await RNFS.mkdir(tempDir);
|
|
212
|
+
tempPaths.push(tempDir);
|
|
213
|
+
videoFilePath = `${tempDir}/LIVENESS_VIDEO.mp4`;
|
|
214
|
+
} else {
|
|
215
|
+
videoFilePath = decodeURIComponent(
|
|
216
|
+
`${RNFS.TemporaryDirectoryPath}/LIVENESS_VIDEO.mp4`
|
|
217
|
+
);
|
|
218
|
+
tempPaths.push(videoFilePath);
|
|
219
|
+
}
|
|
237
220
|
|
|
238
|
-
|
|
221
|
+
await RNFS.copyFile(livenessDetection.videoPath, videoFilePath);
|
|
239
222
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
223
|
+
uploadFileOptions.files.push({
|
|
224
|
+
name: 'files',
|
|
225
|
+
filename: 'LIVENESS_VIDEO.mp4',
|
|
226
|
+
filepath: decodeURIComponent(videoFilePath),
|
|
227
|
+
filetype: 'video/mp4',
|
|
228
|
+
});
|
|
229
|
+
}
|
|
247
230
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
231
|
+
// Skip upload if no files
|
|
232
|
+
if (uploadFileOptions.files.length === 0) {
|
|
233
|
+
debugLog('DataUploadService', 'No media files to upload');
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
253
236
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
237
|
+
debugLog(
|
|
238
|
+
'DataUploadService',
|
|
239
|
+
`Uploading ${uploadFileOptions.files.length} media files to`,
|
|
240
|
+
uploadFileOptions.toUrl
|
|
241
|
+
);
|
|
242
|
+
const response = await runWithRetry(
|
|
243
|
+
() => RNFS.uploadFiles(uploadFileOptions).promise
|
|
244
|
+
);
|
|
245
|
+
debugLog(
|
|
246
|
+
'DataUploadService',
|
|
247
|
+
'Upload response status:',
|
|
248
|
+
response.statusCode
|
|
249
|
+
);
|
|
267
250
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
251
|
+
if (![200, 201, 204].includes(response.statusCode)) {
|
|
252
|
+
logError(
|
|
253
|
+
'DataUploadService',
|
|
254
|
+
`Media upload failed: ${response.statusCode}`
|
|
255
|
+
);
|
|
256
|
+
debugLog('DataUploadService', 'Failed upload response:', response.body);
|
|
257
|
+
throw new Error(`Media upload failed: ${response.statusCode}`);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
debugLog('DataUploadService', '✓ Media uploaded successfully');
|
|
261
|
+
} finally {
|
|
262
|
+
await Promise.all(
|
|
263
|
+
tempPaths.map((path) => RNFS.unlink(path).catch(() => {}))
|
|
273
264
|
);
|
|
274
|
-
throw new Error(`Media upload failed: ${response.statusCode}`);
|
|
275
265
|
}
|
|
276
|
-
|
|
277
|
-
console.log('[DataUploadService] ✓ Media uploaded successfully');
|
|
278
266
|
}
|
|
279
267
|
|
|
280
268
|
/**
|
|
@@ -289,17 +277,18 @@ export class DataUploadService {
|
|
|
289
277
|
let { authToken } = identificationInfo;
|
|
290
278
|
|
|
291
279
|
if (!identificationId) {
|
|
292
|
-
|
|
280
|
+
debugLog('DataUploadService', 'No identification ID, skipping upload');
|
|
293
281
|
return false;
|
|
294
282
|
}
|
|
295
283
|
|
|
296
|
-
|
|
297
|
-
'
|
|
284
|
+
debugLog(
|
|
285
|
+
'DataUploadService',
|
|
286
|
+
'========== UPLOADING COLLECTED DATA =========='
|
|
298
287
|
);
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
288
|
+
debugLog('DataUploadService', 'Identification ID:', identificationId);
|
|
289
|
+
debugLog('DataUploadService', 'Has document:', !!scannedDocument);
|
|
290
|
+
debugLog('DataUploadService', 'Has liveness:', !!livenessDetection);
|
|
291
|
+
debugLog('DataUploadService', 'Has auth token:', !!authToken);
|
|
303
292
|
|
|
304
293
|
try {
|
|
305
294
|
await runWithRetry(() =>
|
|
@@ -309,16 +298,17 @@ export class DataUploadService {
|
|
|
309
298
|
// Always refresh session key for current session (required for encrypted submission)
|
|
310
299
|
if (sessionId) {
|
|
311
300
|
const existingAuthToken = authToken;
|
|
312
|
-
|
|
301
|
+
debugLog('DataUploadService', 'Getting session key...');
|
|
313
302
|
try {
|
|
314
303
|
authToken = await runWithRetry(() =>
|
|
315
304
|
getSessionKey(this.apiUrl, sessionId)
|
|
316
305
|
);
|
|
317
|
-
|
|
306
|
+
debugLog('DataUploadService', '✓ Session key obtained');
|
|
318
307
|
} catch (error) {
|
|
319
308
|
if (existingAuthToken) {
|
|
320
|
-
|
|
321
|
-
'
|
|
309
|
+
debugWarn(
|
|
310
|
+
'DataUploadService',
|
|
311
|
+
'Session key refresh failed, using existing token'
|
|
322
312
|
);
|
|
323
313
|
authToken = existingAuthToken;
|
|
324
314
|
} else {
|
|
@@ -328,8 +318,9 @@ export class DataUploadService {
|
|
|
328
318
|
}
|
|
329
319
|
|
|
330
320
|
if (!authToken) {
|
|
331
|
-
|
|
332
|
-
'
|
|
321
|
+
debugLog(
|
|
322
|
+
'DataUploadService',
|
|
323
|
+
'No session key available, skipping upload'
|
|
333
324
|
);
|
|
334
325
|
return false;
|
|
335
326
|
}
|
|
@@ -357,7 +348,7 @@ export class DataUploadService {
|
|
|
357
348
|
);
|
|
358
349
|
onProgress?.(1.0);
|
|
359
350
|
|
|
360
|
-
|
|
351
|
+
debugLog('DataUploadService', '✓ All collected data uploaded');
|
|
361
352
|
|
|
362
353
|
// Mark media as uploaded during video call
|
|
363
354
|
identificationInfo.mediaUploadedDuringVideoCall = true;
|
|
@@ -367,15 +358,13 @@ export class DataUploadService {
|
|
|
367
358
|
return true;
|
|
368
359
|
} catch (error) {
|
|
369
360
|
if (error instanceof NotFoundError) {
|
|
370
|
-
|
|
371
|
-
'
|
|
361
|
+
logWarn(
|
|
362
|
+
'DataUploadService',
|
|
363
|
+
'Upload skipped: identification is not active anymore'
|
|
372
364
|
);
|
|
373
365
|
return false;
|
|
374
366
|
}
|
|
375
|
-
|
|
376
|
-
'[DataUploadService] Failed to upload collected data:',
|
|
377
|
-
error
|
|
378
|
-
);
|
|
367
|
+
logError('DataUploadService', 'Failed to upload collected data:', error);
|
|
379
368
|
return false;
|
|
380
369
|
}
|
|
381
370
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { debugLog } from '../Libs/debug.utils';
|
|
1
2
|
export interface VideoSessionInfo {
|
|
2
3
|
sessionId: string;
|
|
3
4
|
identificationId: string;
|
|
@@ -124,13 +125,20 @@ export class VideoSessionService {
|
|
|
124
125
|
const EventSource = require('react-native-sse').default;
|
|
125
126
|
|
|
126
127
|
const url = `${this.baseUrl}/api/app/mobile/video-sessions/${sessionId}/queue-status?identificationId=${this.identificationId}`;
|
|
127
|
-
|
|
128
|
+
debugLog(
|
|
129
|
+
'VideoSessionService',
|
|
130
|
+
'[VideoSessionService] Creating SSE connection to:',
|
|
131
|
+
url
|
|
132
|
+
);
|
|
128
133
|
|
|
129
134
|
const es = new EventSource(url);
|
|
130
135
|
let heartbeatInterval: ReturnType<typeof setInterval> | null = null;
|
|
131
136
|
|
|
132
137
|
es.addEventListener('open', () => {
|
|
133
|
-
|
|
138
|
+
debugLog(
|
|
139
|
+
'VideoSessionService',
|
|
140
|
+
'[VideoSessionService] Queue SSE connected'
|
|
141
|
+
);
|
|
134
142
|
// Send initial heartbeat
|
|
135
143
|
this.sendHeartbeat(sessionId).catch(() => {});
|
|
136
144
|
// Set up periodic heartbeat (every 20s to stay under 30s watchdog)
|
|
@@ -147,7 +155,11 @@ export class VideoSessionService {
|
|
|
147
155
|
es.addEventListener('message', (event: any) => {
|
|
148
156
|
try {
|
|
149
157
|
const data = JSON.parse(event.data);
|
|
150
|
-
|
|
158
|
+
debugLog(
|
|
159
|
+
'VideoSessionService',
|
|
160
|
+
'[VideoSessionService] Queue update:',
|
|
161
|
+
data
|
|
162
|
+
);
|
|
151
163
|
if (data.queuePosition !== undefined) {
|
|
152
164
|
onUpdate(data.queuePosition);
|
|
153
165
|
}
|
|
@@ -140,6 +140,7 @@ export default {
|
|
|
140
140
|
'identityDocumentCamera.alignIDBackSide':
|
|
141
141
|
'Align the back side of your ID card',
|
|
142
142
|
'identityDocumentCamera.scanCompleted': 'Scan completed!',
|
|
143
|
+
'identityDocumentCamera.mrzDetected': 'MRZ detected — hold steady',
|
|
143
144
|
'identityDocumentCamera.searchingDocument':
|
|
144
145
|
'Position document within the frame',
|
|
145
146
|
'identityDocumentCamera.faceDetected': 'Keep device steady...',
|
|
@@ -141,6 +141,7 @@ export default {
|
|
|
141
141
|
'identityDocumentCamera.alignIDBackSide':
|
|
142
142
|
'Kimlik kartınızın arka yüzünü hizalayın',
|
|
143
143
|
'identityDocumentCamera.scanCompleted': 'Tarama tamamlandı!',
|
|
144
|
+
'identityDocumentCamera.mrzDetected': 'MRZ algılandı — sabit tutun',
|
|
144
145
|
'identityDocumentCamera.searchingDocument':
|
|
145
146
|
'Belgeyi çerçeve içine yerleştirin',
|
|
146
147
|
'identityDocumentCamera.faceDetected': 'Cihazı sabit tutun...',
|
package/src/version.ts
CHANGED