@incodetech/core 2.0.0-alpha.11 → 2.0.0-alpha.13

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 (34) hide show
  1. package/dist/{OpenViduLogger-5b7KqNTo.esm.js → OpenViduLogger-CRbRNZA7.esm.js} +1 -1
  2. package/dist/OpenViduLogger-Dy5P806a.esm.js +3 -0
  3. package/dist/{warmup-Cijuyvoc.d.ts → StateMachine-pi8byl8C.d.ts} +4 -1
  4. package/dist/{addEvent-s2Za-pK3.esm.js → addEvent-BGKc_lHF.esm.js} +1 -1
  5. package/dist/{deepsightLoader-Bn2D0REl.esm.js → deepsightLoader-B36_XZ7r.esm.js} +3 -3
  6. package/dist/{recordingsRepository-CTjaf-ER.esm.js → deepsightService-BWxcc4OC.esm.js} +2 -33
  7. package/dist/email.d.ts +1 -1
  8. package/dist/email.esm.js +3 -3
  9. package/dist/{endpoints-B0ltwtb5.esm.js → endpoints-D9TGnxRK.esm.js} +336 -21
  10. package/dist/flow.d.ts +4 -303
  11. package/dist/flow.esm.js +4 -5
  12. package/dist/id-DHVSW_wJ.esm.js +1825 -0
  13. package/dist/id.d.ts +6 -0
  14. package/dist/id.esm.js +8 -0
  15. package/dist/index-CbF_uI-x.d.ts +618 -0
  16. package/dist/index.d.ts +8 -3
  17. package/dist/index.esm.js +7 -4
  18. package/dist/{lib-CykGFCEr.esm.js → lib-BJoLTN_W.esm.js} +2 -2
  19. package/dist/phone.d.ts +1 -1
  20. package/dist/phone.esm.js +3 -3
  21. package/dist/recordingsRepository-D5MURoVB.esm.js +40 -0
  22. package/dist/selfie.d.ts +22 -324
  23. package/dist/selfie.esm.js +34 -23
  24. package/dist/{permissionServices-BhD0KxsO.esm.js → streamingEvents-B3hNanPl.esm.js} +34 -3
  25. package/dist/types-BpCrZLU6.d.ts +302 -0
  26. package/dist/types-DZbrbPgj.d.ts +335 -0
  27. package/package.json +6 -2
  28. package/dist/OpenViduLogger-20ZYS-mT.esm.js +0 -3
  29. package/dist/StateMachine-BqPpBhOz.d.ts +0 -2
  30. package/dist/getBrowser-CLEzz0Hi.esm.js +0 -8
  31. package/dist/types-Dif6MQmX.d.ts +0 -5
  32. /package/dist/{Manager-Cy9-TMC9.d.ts → Manager-BZUZTRPx.d.ts} +0 -0
  33. /package/dist/{chunk-C_Yo44FK.esm.js → chunk-FbsBJI8u.esm.js} +0 -0
  34. /package/dist/{xstate.esm-2T5fOCTq.esm.js → xstate.esm-2hDiAXvZ.esm.js} +0 -0
@@ -0,0 +1,1825 @@
1
+ import { A as isIOS, C as enumerateVideoDevices, E as createManager, M as isSafari, O as isAndroid, S as applyTrackConstraints, T as stopCameraStream, c as DEFAULT_ID_CAPTURE_MODEL_VERSION, h as OpenViduRecordingProvider, j as isIPhone14OrHigher, k as isDesktop, l as DEFAULT_ID_CAPTURE_THRESHOLDS, n as api, t as endpoints, v as StreamCanvasProcessingSession, w as requestCameraAccess, x as IncodeCanvas, y as StreamCanvasCapture } from "./endpoints-D9TGnxRK.esm.js";
2
+ import { n as startRecording, r as stopRecording$1, t as createRecordingSession } from "./recordingsRepository-D5MURoVB.esm.js";
3
+ import { i as getDeviceClass, n as checkPermission, o as getWindowDimensions, r as requestPermission, t as streamingEvents } from "./streamingEvents-B3hNanPl.esm.js";
4
+ import { a as createActor, i as fromPromise, n as assign, r as fromCallback, t as setup } from "./xstate.esm-2hDiAXvZ.esm.js";
5
+ import { t as addEvent } from "./addEvent-BGKc_lHF.esm.js";
6
+
7
+ //#region src/modules/id/idCameraStream.ts
8
+ const BACK_CAMERA_KEYWORDS = [
9
+ "rear",
10
+ "back",
11
+ "rück",
12
+ "arrière",
13
+ "trasera",
14
+ "trás",
15
+ "traseira",
16
+ "posteriore",
17
+ "后面",
18
+ "後面",
19
+ "背面",
20
+ "后置",
21
+ "後置",
22
+ "背置",
23
+ "задней",
24
+ "الخلفية",
25
+ "후",
26
+ "arka",
27
+ "achterzijde",
28
+ "หลัง",
29
+ "baksidan",
30
+ "bagside",
31
+ "sau",
32
+ "bak",
33
+ "tylny",
34
+ "takakamera",
35
+ "belakang",
36
+ "אחורית",
37
+ "πίσω",
38
+ "spate",
39
+ "hátsó",
40
+ "zadní",
41
+ "darrere",
42
+ "zadná",
43
+ "задня",
44
+ "stražnja",
45
+ "बैक"
46
+ ];
47
+ function isBackCameraLabel(label) {
48
+ const lowercaseLabel = label.toLowerCase();
49
+ return BACK_CAMERA_KEYWORDS.some((keyword) => lowercaseLabel.includes(keyword));
50
+ }
51
+ function classifyCamera(device, index, totalDevices) {
52
+ let cameraType;
53
+ if (device.label === "") cameraType = totalDevices === 1 || index + 1 <= totalDevices / 2 ? "front" : "back";
54
+ else cameraType = isBackCameraLabel(device.label) ? "back" : "front";
55
+ return {
56
+ deviceId: device.deviceId,
57
+ label: device.label,
58
+ cameraType
59
+ };
60
+ }
61
+ async function getCameras() {
62
+ const videoDevices = await enumerateVideoDevices();
63
+ const cameras = videoDevices.map((d, i) => classifyCamera(d, i, videoDevices.length));
64
+ if (cameras.length > 1 && !cameras.some((c) => c.cameraType === "back")) {
65
+ const resolutions = cameras.map((c) => {
66
+ const match = c.label.match(/\b([0-9]+)MP?\b/i);
67
+ return match ? parseInt(match[1], 10) : NaN;
68
+ });
69
+ let backCameraIndex = cameras.length - 1;
70
+ if (!resolutions.some(isNaN)) backCameraIndex = resolutions.lastIndexOf(Math.max(...resolutions));
71
+ cameras[backCameraIndex].cameraType = "back";
72
+ }
73
+ return cameras;
74
+ }
75
+ function selectMainCameraFromStream(track, cameras) {
76
+ const settings = track.getSettings();
77
+ const activeCamera = cameras.find((c) => c.deviceId === settings.deviceId || c.label !== "" && c.label === track.label);
78
+ if (!activeCamera) return void 0;
79
+ if ((settings.facingMode === "environment" || isBackCameraLabel(track.label)) && cameras.length > 1) {
80
+ cameras.forEach((camera) => {
81
+ if (camera.deviceId === activeCamera.deviceId) camera.cameraType = "back";
82
+ else if (!isBackCameraLabel(camera.label)) camera.cameraType = "front";
83
+ });
84
+ return cameras.filter((c) => c.cameraType === "back").sort((a, b) => a.label.localeCompare(b.label))[0];
85
+ }
86
+ if (cameras.length === 1) return activeCamera;
87
+ }
88
+ function getAndroidVideoConstraints(level) {
89
+ const base = {
90
+ resizeMode: "none",
91
+ facingMode: "environment"
92
+ };
93
+ switch (level) {
94
+ case 0: return {
95
+ ...base,
96
+ height: { ideal: 720 },
97
+ aspectRatio: { ideal: 19.5 / 9 }
98
+ };
99
+ case 1: return {
100
+ ...base,
101
+ width: {
102
+ min: 3200,
103
+ ideal: 3840,
104
+ max: 4096
105
+ },
106
+ height: {
107
+ min: 1800,
108
+ ideal: 2160,
109
+ max: 2400
110
+ }
111
+ };
112
+ case 2: return {
113
+ ...base,
114
+ width: {
115
+ min: 1400,
116
+ ideal: 1920,
117
+ max: 2160
118
+ },
119
+ height: {
120
+ min: 900,
121
+ ideal: 1080,
122
+ max: 1440
123
+ }
124
+ };
125
+ case 3: return {
126
+ ...base,
127
+ width: {
128
+ min: 640,
129
+ ideal: 640,
130
+ max: 800
131
+ },
132
+ height: {
133
+ min: 480,
134
+ ideal: 480,
135
+ max: 600
136
+ }
137
+ };
138
+ case 4: return {
139
+ ...base,
140
+ width: {
141
+ min: 640,
142
+ ideal: 800,
143
+ max: 960
144
+ },
145
+ height: {
146
+ min: 480,
147
+ ideal: 480,
148
+ max: 480
149
+ }
150
+ };
151
+ default: return {};
152
+ }
153
+ }
154
+ function delay(ms) {
155
+ return new Promise((resolve) => setTimeout(resolve, ms));
156
+ }
157
+ async function getAndroidBackCameraStream(fallbackLevel = 0) {
158
+ if (fallbackLevel > 4) throw new Error("Failed to get camera after all fallback attempts");
159
+ try {
160
+ const initialStream = await requestCameraAccess({ video: getAndroidVideoConstraints(fallbackLevel) });
161
+ const track = initialStream.getVideoTracks()[0];
162
+ const mainCamera = selectMainCameraFromStream(track, await getCameras());
163
+ stopCameraStream(initialStream);
164
+ if (!mainCamera) throw new Error("Could not identify main camera");
165
+ let idealWidth = 1280;
166
+ let idealHeight = 720;
167
+ if (fallbackLevel > 1) {
168
+ const constraints = getAndroidVideoConstraints(fallbackLevel);
169
+ const width = constraints.width;
170
+ const height = constraints.height;
171
+ idealWidth = width?.ideal ?? 1280;
172
+ idealHeight = height?.ideal ?? 720;
173
+ }
174
+ return await requestCameraAccess({ video: {
175
+ deviceId: { exact: mainCamera.deviceId },
176
+ width: { ideal: idealWidth },
177
+ height: { ideal: idealHeight }
178
+ } });
179
+ } catch (error) {
180
+ const errorName = error instanceof Error ? error.name : "UnknownError";
181
+ const nextLevel = Math.min(fallbackLevel + 1, 4);
182
+ if (errorName === "NotReadableError") {
183
+ await delay(300);
184
+ return getAndroidBackCameraStream(nextLevel);
185
+ }
186
+ if (errorName === "AbortError") {
187
+ await delay(300);
188
+ return getAndroidBackCameraStream(fallbackLevel);
189
+ }
190
+ return getAndroidBackCameraStream(nextLevel);
191
+ }
192
+ }
193
+ async function applyIOSFocusHack(stream) {
194
+ const videoTrack = stream.getVideoTracks()[0];
195
+ try {
196
+ await applyTrackConstraints(videoTrack, { advanced: [{ focusDistance: 1 }] });
197
+ } catch {}
198
+ }
199
+ function getIOSConstraints() {
200
+ return {
201
+ audio: false,
202
+ video: {
203
+ resizeMode: "none",
204
+ facingMode: "environment",
205
+ height: { ideal: isIPhone14OrHigher() ? 1080 : 720 },
206
+ aspectRatio: { ideal: 19.5 / 9 }
207
+ }
208
+ };
209
+ }
210
+ async function getIOSCameraStream() {
211
+ const stream = await requestCameraAccess(getIOSConstraints());
212
+ await applyIOSFocusHack(stream);
213
+ return stream;
214
+ }
215
+ function getDesktopConstraints(options) {
216
+ const { deviceId } = options;
217
+ return {
218
+ audio: isSafari(),
219
+ video: {
220
+ facingMode: "user",
221
+ deviceId: deviceId ? { exact: deviceId } : void 0,
222
+ height: { ideal: 1080 },
223
+ width: { ideal: 1920 }
224
+ }
225
+ };
226
+ }
227
+ async function getDesktopCameraStream(options) {
228
+ return requestCameraAccess(getDesktopConstraints(options));
229
+ }
230
+ async function getIdCameraStream(deviceId) {
231
+ if (isIOS()) return getIOSCameraStream();
232
+ if (isAndroid()) return getAndroidBackCameraStream(0);
233
+ if (isDesktop()) return getDesktopCameraStream({ deviceId });
234
+ return getDesktopCameraStream({ deviceId });
235
+ }
236
+
237
+ //#endregion
238
+ //#region src/modules/id/types.ts
239
+ const ID_ERROR_CODES = {
240
+ UPLOAD_ERROR: "UPLOAD_ERROR",
241
+ CLASSIFICATION_FAILED: "CLASSIFICATION_FAILED",
242
+ LOW_SHARPNESS: "LOW_SHARPNESS",
243
+ GLARE_DETECTED: "GLARE_DETECTED",
244
+ WRONG_DOCUMENT_SIDE: "WRONG_DOCUMENT_SIDE",
245
+ ID_TYPE_UNACCEPTABLE: "ID_TYPE_UNACCEPTABLE",
246
+ READABILITY_ISSUE: "READABILITY_ISSUE",
247
+ RETRY_EXHAUSTED_CONTINUE_TO_BACK: "RETRY_EXHAUSTED_CONTINUE_TO_BACK",
248
+ RETRY_EXHAUSTED_SKIP_BACK: "RETRY_EXHAUSTED_SKIP_BACK",
249
+ NO_MORE_TRIES: "NO_MORE_TRIES",
250
+ UNEXPECTED_ERROR: "UNEXPECTED_ERROR",
251
+ NO_TOKEN: "NO_TOKEN",
252
+ PERMISSION_DENIED: "PERMISSION_DENIED",
253
+ USER_CANCELLED: "USER_CANCELLED",
254
+ SERVER: "SERVER_ERROR"
255
+ };
256
+
257
+ //#endregion
258
+ //#region src/modules/id/idCaptureServices.ts
259
+ const SHARPNESS_THRESHOLD = 10;
260
+ const GLARE_THRESHOLD = 10;
261
+ const DEFAULT_ID_CAPTURE_THRESHOLDS$1 = {
262
+ blurThreshold: .2,
263
+ blurChangeThreshold: .2,
264
+ glareThreshold: .3,
265
+ clsThreshold: .98,
266
+ sideThreshold: .8,
267
+ iouThreshold: .8,
268
+ framesAggregationInterval: 3e3,
269
+ minFaceIdQualityScore: .62
270
+ };
271
+ const DEFAULT_ID_CAPTURE_SETTINGS = {
272
+ isFixedMask: false,
273
+ isIPhone14OrHigher: false,
274
+ idType: "",
275
+ blurCheckEnabled: false,
276
+ glareCheckEnabled: false,
277
+ faceQualityCheckEnabled: true,
278
+ iouCheckEnabled: true
279
+ };
280
+ async function initializeIdCapture(provider, config) {
281
+ await provider.initialize({});
282
+ provider.setThresholds({
283
+ ...DEFAULT_ID_CAPTURE_THRESHOLDS$1,
284
+ ...config.thresholds,
285
+ idDetectedTimeout: config.thresholds?.idDetectedTimeout ?? config.deviceIdleTimeout * 1e3,
286
+ autocaptureTimeout: config.thresholds?.autocaptureTimeout ?? config.autoCaptureTimeout * 1e3
287
+ });
288
+ if (config.settings) provider.setSettings({
289
+ ...DEFAULT_ID_CAPTURE_SETTINGS,
290
+ ...config.settings
291
+ });
292
+ return {
293
+ stream: await getIdCameraStream(),
294
+ provider
295
+ };
296
+ }
297
+ function stopStream(stream) {
298
+ for (const track of stream.getTracks()) track.stop();
299
+ }
300
+ function validateUploadResponse(response, sessionState) {
301
+ if (response.failReason === "ID_TYPE_UNACCEPTABLE") return {
302
+ error: true,
303
+ message: "ID type is not acceptable",
304
+ messageDescription: "Please use a valid ID type",
305
+ errorKey: ID_ERROR_CODES.ID_TYPE_UNACCEPTABLE
306
+ };
307
+ if (response.failReason === "WRONG_DOCUMENT_SIDE") return {
308
+ error: true,
309
+ message: "Wrong side of document",
310
+ messageDescription: response.side === "back" ? "Please show the back side of your ID" : "Please show the front side of your ID",
311
+ errorKey: ID_ERROR_CODES.WRONG_DOCUMENT_SIDE
312
+ };
313
+ if (!response.classification) return {
314
+ error: true,
315
+ message: "ID classification failed",
316
+ errorKey: ID_ERROR_CODES.CLASSIFICATION_FAILED
317
+ };
318
+ const sharpnessThreshold = getDeviceClass() === "desktop" ? -1 : SHARPNESS_THRESHOLD;
319
+ if (response.sharpness !== void 0 && sharpnessThreshold >= 0 && response.sharpness < sharpnessThreshold) return {
320
+ error: true,
321
+ message: "Image is not sharp enough",
322
+ messageDescription: "Please ensure the image is clear and well-focused",
323
+ errorKey: ID_ERROR_CODES.LOW_SHARPNESS
324
+ };
325
+ if (response.glare !== void 0 && response.glare < GLARE_THRESHOLD && !sessionState?.skipGlareFront && !sessionState?.skipGlareBack) return {
326
+ error: true,
327
+ message: "Glare detected on ID",
328
+ messageDescription: "Please avoid bright reflections on your ID",
329
+ errorKey: ID_ERROR_CODES.GLARE_DETECTED
330
+ };
331
+ }
332
+ async function getExtraImages(params) {
333
+ const extraImages = params.ageAssurance ? [params.type === "back" ? "croppedBackID" : "croppedFrontID"] : [];
334
+ try {
335
+ const res = await api.post(endpoints.getImages, { images: ["croppedIDFace", ...extraImages] }, { signal: params.signal });
336
+ if (!res.ok) throw new Error(`Failed to get extra images: ${res.status}`);
337
+ return res.data ?? {
338
+ croppedIDFace: "",
339
+ croppedFrontID: "",
340
+ croppedBackID: ""
341
+ };
342
+ } catch {
343
+ return {
344
+ croppedIDFace: "",
345
+ croppedFrontID: "",
346
+ croppedBackID: ""
347
+ };
348
+ }
349
+ }
350
+ const getRealQualityValue = (value) => (1 - value) * 100;
351
+ async function uploadIdImage(params) {
352
+ const { type, image, onProgress, signal, metadata, ageAssurance, glare, sharpness, shouldSkipGlareBack } = params;
353
+ addEvent({
354
+ code: "captureAttemptFinished",
355
+ module: "ID",
356
+ payload: { logs: [] }
357
+ });
358
+ const endpoint = type === "front" ? endpoints.frontId : endpoints.backId;
359
+ const body = {
360
+ base64Image: image,
361
+ metadata,
362
+ clientInfo: { deviceClass: getDeviceClass() }
363
+ };
364
+ const queryParams = { imageType: "id" };
365
+ if (shouldSkipGlareBack && type === "back") queryParams.glare = 0;
366
+ else if (glare !== void 0) queryParams.glare = getRealQualityValue(glare);
367
+ if (sharpness !== void 0) queryParams.sharpness = getRealQualityValue(sharpness);
368
+ try {
369
+ const res = await api.post(endpoint, body, {
370
+ signal,
371
+ query: queryParams,
372
+ onUploadProgress: onProgress
373
+ });
374
+ if (!res.ok) throw new Error(`POST ${endpoint} failed: ${res.status} ${res.statusText}`);
375
+ const response = res.data;
376
+ const extraImages = await getExtraImages({
377
+ type,
378
+ ageAssurance,
379
+ signal
380
+ });
381
+ const fullResponse = {
382
+ ...response,
383
+ originalImage: image,
384
+ frontIdImage: type === "front" ? image : void 0,
385
+ backIdImage: extraImages.croppedBackID,
386
+ ...extraImages
387
+ };
388
+ onProgress?.(100);
389
+ return fullResponse;
390
+ } catch (error) {
391
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
392
+ throw new Error(`${ID_ERROR_CODES.UPLOAD_ERROR}: ${errorMessage}`);
393
+ }
394
+ }
395
+ function buildStandardResolution(width, height) {
396
+ return height > width ? {
397
+ width: 1080,
398
+ height: 1920
399
+ } : {
400
+ width: 1920,
401
+ height: 1080
402
+ };
403
+ }
404
+ function buildResolutionFromStream(stream) {
405
+ const track = stream.getVideoTracks()[0];
406
+ if (!track) return "1080x1920";
407
+ const settings = track.getSettings();
408
+ const width = settings.width;
409
+ const height = settings.height;
410
+ if (typeof width === "number" && typeof height === "number") {
411
+ const standard = buildStandardResolution(width, height);
412
+ return `${standard.width}x${standard.height}`;
413
+ }
414
+ return "1080x1920";
415
+ }
416
+ async function startRecordingSession(params) {
417
+ if (params.config.enableIdRecording !== true) return;
418
+ if (params.existing) return params.existing;
419
+ const provider = params.config.recording?.capability ?? new OpenViduRecordingProvider();
420
+ const clonedStream = params.stream.clone();
421
+ const hasAudio = clonedStream.getAudioTracks().length > 0;
422
+ const resolution = buildResolutionFromStream(clonedStream);
423
+ const session = await createRecordingSession(params.type);
424
+ const connection = await provider.connect({
425
+ sessionToken: session.token,
426
+ stream: clonedStream,
427
+ events: {
428
+ onSessionConnected: (sessionId) => {
429
+ addEvent({
430
+ code: streamingEvents.strSessionDidConnect,
431
+ payload: {
432
+ message: "Recording session connected",
433
+ sessionId
434
+ }
435
+ });
436
+ },
437
+ onSessionDisconnected: (sessionId) => {
438
+ addEvent({
439
+ code: streamingEvents.strSessionDidDisconnect,
440
+ payload: {
441
+ message: "Recording session disconnected",
442
+ sessionId
443
+ }
444
+ });
445
+ },
446
+ onSessionException: (event) => {
447
+ addEvent({
448
+ code: streamingEvents.strSessionDidFailWithError,
449
+ payload: {
450
+ message: "Recording session failed due to an error",
451
+ eventName: event.name,
452
+ type: "OpenViduException",
453
+ errorMessage: event.message,
454
+ sessionId: event.sessionId
455
+ }
456
+ });
457
+ },
458
+ onPublisherCreated: (p) => {
459
+ addEvent({
460
+ code: streamingEvents.strStreamPublisherCreated,
461
+ payload: {
462
+ message: "Recording publisher created",
463
+ sessionId: p.sessionId,
464
+ streamId: p.streamId
465
+ }
466
+ });
467
+ },
468
+ onPublisherError: (p) => {
469
+ addEvent({
470
+ code: streamingEvents.strStreamPublisherDidFailWithError,
471
+ payload: {
472
+ message: "Recording publisher failed due to an error",
473
+ sessionId: p.sessionId,
474
+ streamId: p.streamId,
475
+ error: { message: p.message ?? "Unknown error" }
476
+ }
477
+ });
478
+ }
479
+ }
480
+ });
481
+ await startRecording({
482
+ videoRecordingId: session.videoRecordingId,
483
+ type: params.type,
484
+ resolution,
485
+ hasAudio
486
+ });
487
+ addEvent({
488
+ code: streamingEvents.strStreamVideoCaptureStart,
489
+ payload: {
490
+ message: "Recording capture started",
491
+ resolution,
492
+ videoRecordingId: session.videoRecordingId,
493
+ sessionId: session.sessionId,
494
+ streamId: connection.publisher.getStreamId()
495
+ }
496
+ });
497
+ return {
498
+ token: session.token,
499
+ sessionId: session.sessionId,
500
+ videoRecordingId: session.videoRecordingId,
501
+ connection,
502
+ resolution,
503
+ hasAudio
504
+ };
505
+ }
506
+ function stopRecording(session) {
507
+ (async () => {
508
+ try {
509
+ addEvent({
510
+ code: streamingEvents.strStreamVideoCaptureStop,
511
+ payload: {
512
+ message: "Recording capture stopped",
513
+ videoRecordingId: session.videoRecordingId,
514
+ sessionId: session.sessionId,
515
+ streamId: session.connection.publisher.getStreamId()
516
+ }
517
+ });
518
+ await stopRecording$1(session.videoRecordingId);
519
+ addEvent({
520
+ code: streamingEvents.strStreamPublisherDestroyed,
521
+ payload: {
522
+ message: "Recording publisher destroyed",
523
+ sessionId: session.sessionId,
524
+ streamId: session.connection.publisher.getStreamId()
525
+ }
526
+ });
527
+ } finally {
528
+ await session.connection.disconnect();
529
+ addEvent({
530
+ code: streamingEvents.strSessionDidDisconnect,
531
+ payload: {
532
+ message: "Recording session disconnected",
533
+ sessionId: session.sessionId
534
+ }
535
+ });
536
+ }
537
+ })();
538
+ }
539
+ async function processId(isSecondId = false, queueName = "", signal) {
540
+ const endpoint = isSecondId ? endpoints.processSecondId : endpoints.processId;
541
+ const url = queueName ? `${endpoint}?queueName=${queueName}` : endpoint;
542
+ return { isDocumentExpired: (await api.post(url, {}, { signal })).data?.isDocumentExpired ?? false };
543
+ }
544
+
545
+ //#endregion
546
+ //#region src/modules/id/idCaptureStateMachine.ts
547
+ function getIdErrorCodeFromUnknown(error) {
548
+ if (error instanceof Error) {
549
+ const message = error.message;
550
+ for (const [, value] of Object.entries(ID_ERROR_CODES)) if (message.includes(value)) return value;
551
+ }
552
+ }
553
+ const _idCaptureMachine = setup({
554
+ types: {
555
+ context: {},
556
+ events: {},
557
+ input: {}
558
+ },
559
+ actors: {
560
+ checkPermission: fromPromise(async () => {
561
+ return checkPermission();
562
+ }),
563
+ requestPermission: fromPromise(async () => {
564
+ return requestPermission();
565
+ }),
566
+ initializeCamera: fromPromise(async ({ input }) => {
567
+ return initializeIdCapture(input.provider, input.config);
568
+ }),
569
+ runDetection: fromCallback(({ input, sendBack }) => {
570
+ if (!input.frameCapturer || !input.provider) {
571
+ sendBack({
572
+ type: "DETECTION_UPDATE",
573
+ status: "error"
574
+ });
575
+ return () => {};
576
+ }
577
+ const provider = input.provider;
578
+ let session;
579
+ let currentCanvas = null;
580
+ let bestCanvas = null;
581
+ let storedQualityElements = {};
582
+ let isCapturing = false;
583
+ let notificationTimeout = null;
584
+ let currentNotificationStatus = null;
585
+ const NOTIFICATION_DURATION_MS = 500;
586
+ const clearNotificationTimeout = () => {
587
+ if (notificationTimeout) {
588
+ clearTimeout(notificationTimeout);
589
+ notificationTimeout = null;
590
+ currentNotificationStatus = null;
591
+ }
592
+ };
593
+ const sendNotification = (status) => {
594
+ if (notificationTimeout && currentNotificationStatus !== status) return;
595
+ if (notificationTimeout && currentNotificationStatus === status) clearTimeout(notificationTimeout);
596
+ currentNotificationStatus = status;
597
+ sendBack({
598
+ type: "DETECTION_UPDATE",
599
+ status
600
+ });
601
+ notificationTimeout = setTimeout(() => {
602
+ notificationTimeout = null;
603
+ currentNotificationStatus = null;
604
+ sendBack({
605
+ type: "DETECTION_UPDATE",
606
+ status: "detecting"
607
+ });
608
+ }, NOTIFICATION_DURATION_MS);
609
+ };
610
+ const canvas = input.frameCapturer.getLatestCanvas();
611
+ const windowDimensions = getWindowDimensions(canvas?.width() ?? 1280, canvas?.height() ?? 720);
612
+ const DEFAULT_GEOMETRY = {
613
+ areaDown: 25e3,
614
+ areaUp: 55e3,
615
+ areaIOSPassportUp: 3e4,
616
+ areaIOSPassportDown: 2e4,
617
+ widthIOSUp: 160,
618
+ widthIOSDown: 85,
619
+ widthDown: 110,
620
+ widthUp: 205
621
+ };
622
+ if (input.config.geometry) provider.setGeometry({
623
+ ...input.config.geometry,
624
+ windowOuterWidth: windowDimensions.outerWidth,
625
+ windowOuterHeight: windowDimensions.outerHeight,
626
+ windowInnerWidth: windowDimensions.innerWidth,
627
+ windowInnerHeight: windowDimensions.innerHeight
628
+ });
629
+ else provider.setGeometry({
630
+ ...DEFAULT_GEOMETRY,
631
+ windowOuterWidth: windowDimensions.outerWidth,
632
+ windowOuterHeight: windowDimensions.outerHeight,
633
+ windowInnerWidth: windowDimensions.innerWidth,
634
+ windowInnerHeight: windowDimensions.innerHeight
635
+ });
636
+ const idType = input.currentMode === "back" ? "BackId" : input.currentMode === "passport" || input.currentMode === "front" && input.config.onlyFront ? "Passport" : "FrontId";
637
+ provider.setSettings({
638
+ isFixedMask: input.config.settings?.isFixedMask ?? false,
639
+ isIPhone14OrHigher: input.config.settings?.isIPhone14OrHigher ?? false,
640
+ idType,
641
+ blurCheckEnabled: input.config.settings?.blurCheckEnabled ?? false,
642
+ glareCheckEnabled: input.config.settings?.glareCheckEnabled ?? false,
643
+ faceQualityCheckEnabled: input.config.settings?.faceQualityCheckEnabled ?? true,
644
+ iouCheckEnabled: input.config.settings?.iouCheckEnabled ?? true
645
+ });
646
+ const thresholds = {
647
+ ...DEFAULT_ID_CAPTURE_THRESHOLDS,
648
+ ...input.config.thresholds,
649
+ idDetectedTimeout: (input.config.deviceIdleTimeout ?? 10) * 1e3,
650
+ autocaptureTimeout: (input.config.autoCaptureTimeout ?? 5) * 1e3
651
+ };
652
+ provider.setThresholds(thresholds);
653
+ const modelType = input.config.modelVersion ?? DEFAULT_ID_CAPTURE_MODEL_VERSION;
654
+ provider.setModelType(modelType);
655
+ provider.setCallbacks({
656
+ onFarAway: () => {
657
+ if (!isCapturing) sendNotification("farAway");
658
+ },
659
+ onDetectionStarted: () => {},
660
+ onMaskChange: (_show, _mask, _top, orientation) => {
661
+ sendBack({
662
+ type: "ORIENTATION_CHANGE",
663
+ orientation
664
+ });
665
+ },
666
+ onBlur: () => {
667
+ if (!isCapturing) sendNotification("blur");
668
+ },
669
+ onGlare: () => {
670
+ if (!isCapturing) sendNotification("glare");
671
+ },
672
+ onIdNotDetected: () => {
673
+ if (!isCapturing) sendBack({
674
+ type: "DETECTION_UPDATE",
675
+ status: "idNotDetected"
676
+ });
677
+ },
678
+ onSwitchToManualCapture: () => {
679
+ isCapturing = false;
680
+ sendBack({
681
+ type: "DETECTION_UPDATE",
682
+ status: "manualCapture"
683
+ });
684
+ },
685
+ onCapturing: () => {
686
+ clearNotificationTimeout();
687
+ isCapturing = true;
688
+ sendBack({
689
+ type: "DETECTION_UPDATE",
690
+ status: "capturing"
691
+ });
692
+ },
693
+ onBestFrame: (blur, glare, orientation) => {
694
+ if (currentCanvas) {
695
+ bestCanvas = currentCanvas.clone();
696
+ storedQualityElements = {
697
+ glare,
698
+ sharpness: blur
699
+ };
700
+ }
701
+ if (orientation === "horizontal" || orientation === "vertical") sendBack({
702
+ type: "ORIENTATION_CHANGE",
703
+ orientation
704
+ });
705
+ },
706
+ onCapture: () => {
707
+ isCapturing = false;
708
+ if (bestCanvas) sendBack({
709
+ type: "DETECTION_SUCCESS",
710
+ canvas: bestCanvas,
711
+ qualityElements: storedQualityElements
712
+ });
713
+ else if (currentCanvas) sendBack({
714
+ type: "DETECTION_SUCCESS",
715
+ canvas: currentCanvas.clone(),
716
+ qualityElements: {}
717
+ });
718
+ },
719
+ onIdTypeChange: (idType$1) => {
720
+ sendBack({
721
+ type: "ID_TYPE_CHANGE",
722
+ idType: idType$1
723
+ });
724
+ },
725
+ onIdSideChange: (side) => {
726
+ if (isCapturing) return;
727
+ sendBack({
728
+ type: "ID_SIDE_CHANGE",
729
+ side
730
+ });
731
+ },
732
+ onCapturingCounterValueChange: (value) => {
733
+ sendBack({
734
+ type: "COUNTER_VALUE_CHANGE",
735
+ value
736
+ });
737
+ }
738
+ });
739
+ sendBack({
740
+ type: "DETECTION_UPDATE",
741
+ status: "detecting"
742
+ });
743
+ session = new StreamCanvasProcessingSession({
744
+ capturer: input.frameCapturer,
745
+ provider: {
746
+ processFrame: async (frame) => {
747
+ currentCanvas = IncodeCanvas.fromImageData(frame);
748
+ sendBack({
749
+ type: "DETECTION_FRAME",
750
+ frame
751
+ });
752
+ await provider.processFrame(frame);
753
+ },
754
+ reset: () => {
755
+ if (notificationTimeout) {
756
+ clearTimeout(notificationTimeout);
757
+ notificationTimeout = null;
758
+ currentNotificationStatus = null;
759
+ }
760
+ currentCanvas = null;
761
+ bestCanvas = null;
762
+ storedQualityElements = {};
763
+ isCapturing = false;
764
+ provider.reset();
765
+ }
766
+ },
767
+ onFrame: (frame) => sendBack({
768
+ type: "DETECTION_FRAME",
769
+ frame
770
+ })
771
+ });
772
+ sendBack({
773
+ type: "DETECTION_RESET_READY",
774
+ reset: () => {
775
+ provider.reset();
776
+ }
777
+ });
778
+ return () => {
779
+ clearNotificationTimeout();
780
+ session?.dispose();
781
+ };
782
+ }),
783
+ uploadIdImage: fromPromise(async ({ input, signal }) => {
784
+ const image = input.canvas.getBase64Image();
785
+ if (!image) throw new Error(ID_ERROR_CODES.UPLOAD_ERROR);
786
+ return uploadIdImage({
787
+ image,
788
+ type: input.type,
789
+ sendBase64: true,
790
+ glare: input.qualityElements?.glare,
791
+ sharpness: input.qualityElements?.sharpness,
792
+ ageAssurance: false,
793
+ signal,
794
+ onProgress: input.onProgress
795
+ });
796
+ }),
797
+ processId: fromPromise(async ({ input, signal }) => {
798
+ return processId(input.isSecondId, "", signal);
799
+ }),
800
+ startRecording: fromPromise(async ({ input }) => {
801
+ if (!input.stream) return;
802
+ const type = input.currentMode === "back" ? "backId" : "frontId";
803
+ return startRecordingSession({
804
+ config: input.config,
805
+ stream: input.stream,
806
+ existing: input.existing,
807
+ type
808
+ });
809
+ }),
810
+ checkMotionSensor: fromCallback(({ input, sendBack }) => {
811
+ if (!input.motionProvider) {
812
+ sendBack({
813
+ type: "MOTION_STATUS",
814
+ status: "UNCLEAR"
815
+ });
816
+ return () => {};
817
+ }
818
+ const interval = setInterval(() => {
819
+ sendBack({
820
+ type: "MOTION_STATUS",
821
+ status: input.motionProvider.check()
822
+ });
823
+ }, 500);
824
+ return () => clearInterval(interval);
825
+ })
826
+ },
827
+ actions: {
828
+ stopMediaStream: assign(({ context }) => {
829
+ context.frameCapturer?.dispose();
830
+ if (context.stream) stopStream(context.stream);
831
+ return {
832
+ stream: void 0,
833
+ frameCapturer: void 0
834
+ };
835
+ }),
836
+ disposeProvider: ({ context }) => {
837
+ context.provider?.dispose?.();
838
+ },
839
+ resetForBackCapture: assign(({ context }) => {
840
+ context.frameCapturer?.dispose();
841
+ if (context.stream) stopStream(context.stream);
842
+ context.provider?.reset();
843
+ return {
844
+ stream: void 0,
845
+ frameCapturer: void 0,
846
+ detectionStatus: "idle",
847
+ counterValue: 0,
848
+ orientation: void 0,
849
+ resetDetection: void 0,
850
+ idType: void 0,
851
+ qualityElements: void 0,
852
+ debugFrame: void 0,
853
+ frameRect: void 0,
854
+ previewImageUrl: void 0,
855
+ uploadProgress: void 0,
856
+ manualCaptureTriggered: false
857
+ };
858
+ }),
859
+ prepareForBackCapture: assign(({ context }) => {
860
+ context.provider?.reset();
861
+ return {
862
+ detectionStatus: "idle",
863
+ counterValue: 0,
864
+ orientation: void 0,
865
+ resetDetection: void 0,
866
+ idType: void 0,
867
+ qualityElements: void 0,
868
+ debugFrame: void 0,
869
+ frameRect: void 0,
870
+ previewImageUrl: void 0,
871
+ uploadProgress: void 0,
872
+ manualCaptureTriggered: false
873
+ };
874
+ }),
875
+ setStreamAndCapturer: assign({
876
+ stream: ({ event }) => {
877
+ if ("output" in event) return event.output.stream;
878
+ },
879
+ provider: ({ event }) => {
880
+ if ("output" in event) return event.output.provider;
881
+ },
882
+ frameCapturer: ({ event }) => {
883
+ if ("output" in event) {
884
+ const output = event.output;
885
+ if (output.stream) return new StreamCanvasCapture(output.stream);
886
+ }
887
+ }
888
+ }),
889
+ trackTutorialId: () => {
890
+ addEvent({
891
+ code: "tutorialVideoStarted",
892
+ payload: { tutorialFrontID: true }
893
+ });
894
+ },
895
+ trackContinue: () => {},
896
+ resetContext: assign(({ context }) => {
897
+ context.provider?.reset();
898
+ return {
899
+ stream: void 0,
900
+ provider: context.provider,
901
+ frameCapturer: void 0,
902
+ error: void 0,
903
+ detectionStatus: "idle",
904
+ counterValue: 0,
905
+ orientation: void 0,
906
+ capturedImages: {},
907
+ uploadResponse: void 0,
908
+ recordingSession: void 0,
909
+ attemptsRemaining: context.config.captureAttempts,
910
+ uploadError: void 0,
911
+ permissionResult: void 0,
912
+ resetDetection: void 0,
913
+ idType: void 0,
914
+ qualityElements: void 0,
915
+ previewImageUrl: void 0,
916
+ uploadProgress: void 0,
917
+ currentMode: context.config.onlyBack ? "back" : !context.config.enableId && context.config.enablePassport ? "passport" : "front",
918
+ selectedDocumentType: void 0,
919
+ manualCaptureTriggered: false
920
+ };
921
+ }),
922
+ resetDetection: ({ context }) => {
923
+ context.resetDetection?.();
924
+ },
925
+ captureImage: assign({ qualityElements: ({ event }) => {
926
+ if ("qualityElements" in event) return event.qualityElements;
927
+ } }),
928
+ storeCapturedCanvasInProvider: ({ context, event }) => {
929
+ let canvas = null;
930
+ if ("canvas" in event && event.canvas) canvas = event.canvas;
931
+ else canvas = context.frameCapturer?.getLatestCanvas() ?? null;
932
+ if (!canvas || !context.provider) return;
933
+ const canvasWidth = canvas.width();
934
+ const canvasHeight = canvas.height();
935
+ if (!canvasWidth || !canvasHeight) return;
936
+ const originalCanvas = canvas;
937
+ let frameRect;
938
+ if (context.detectionArea) {
939
+ const viewportWidth = typeof window !== "undefined" ? window.innerWidth : 1280;
940
+ const viewportHeight = typeof window !== "undefined" ? window.innerHeight : 720;
941
+ const scaleX = viewportWidth / canvasWidth;
942
+ const scaleY = viewportHeight / canvasHeight;
943
+ const scale = Math.max(scaleX, scaleY);
944
+ const displayedWidth = canvasWidth * scale;
945
+ const displayedHeight = canvasHeight * scale;
946
+ const offsetX = (viewportWidth - displayedWidth) / 2;
947
+ const offsetY = (viewportHeight - displayedHeight) / 2;
948
+ frameRect = {
949
+ x: (context.detectionArea.x - offsetX) / scale,
950
+ y: (context.detectionArea.y - offsetY) / scale,
951
+ w: context.detectionArea.width / scale,
952
+ h: context.detectionArea.height / scale
953
+ };
954
+ } else if (context.frameRect) {
955
+ const viewportWidth = typeof window !== "undefined" ? window.innerWidth : 1280;
956
+ const viewportHeight = typeof window !== "undefined" ? window.innerHeight : 720;
957
+ const scaleX = viewportWidth / canvasWidth;
958
+ const scaleY = viewportHeight / canvasHeight;
959
+ const scale = Math.max(scaleX, scaleY);
960
+ const displayedWidth = canvasWidth * scale;
961
+ const displayedHeight = canvasHeight * scale;
962
+ const offsetX = (viewportWidth - displayedWidth) / 2;
963
+ const offsetY = (viewportHeight - displayedHeight) / 2;
964
+ frameRect = {
965
+ x: (context.frameRect.x - offsetX) / scale,
966
+ y: (context.frameRect.y - offsetY) / scale,
967
+ w: context.frameRect.w / scale,
968
+ h: context.frameRect.h / scale
969
+ };
970
+ } else {
971
+ const quadValue = (context.provider.getLastProcessResult?.())?.quad;
972
+ const hasQuad = !!quadValue;
973
+ const quadSize = quadValue?.size ? quadValue.size() : quadValue?.length ?? 0;
974
+ if (hasQuad && quadSize >= 4 && quadValue.get) {
975
+ const p0 = quadValue.get(0);
976
+ const p1 = quadValue.get(1);
977
+ const p2 = quadValue.get(2);
978
+ const p3 = quadValue.get(3);
979
+ const minX = Math.min(p0.x, p1.x, p2.x, p3.x);
980
+ const maxX = Math.max(p0.x, p1.x, p2.x, p3.x);
981
+ const minY = Math.min(p0.y, p1.y, p2.y, p3.y);
982
+ const maxY = Math.max(p0.y, p1.y, p2.y, p3.y);
983
+ frameRect = {
984
+ x: minX,
985
+ y: minY,
986
+ w: maxX - minX,
987
+ h: maxY - minY
988
+ };
989
+ } else {
990
+ const viewportWidth = typeof window !== "undefined" ? window.innerWidth : 1280;
991
+ const viewportHeight = typeof window !== "undefined" ? window.innerHeight : 720;
992
+ const frameViewportWidth = Math.min(387, viewportWidth * .9);
993
+ const frameViewportHeight = frameViewportWidth / (35 / 22);
994
+ const frameViewportX = (viewportWidth - frameViewportWidth) / 2;
995
+ const frameViewportY = (viewportHeight - frameViewportHeight) / 2;
996
+ frameRect = {
997
+ x: canvasWidth * frameViewportX / viewportWidth,
998
+ y: canvasHeight * frameViewportY / viewportHeight,
999
+ w: canvasWidth * frameViewportWidth / viewportWidth,
1000
+ h: canvasHeight * frameViewportHeight / viewportHeight
1001
+ };
1002
+ }
1003
+ }
1004
+ const transformedCanvas = context.provider.transformPerspective(originalCanvas, frameRect);
1005
+ context.provider.setCapturedCanvases(originalCanvas, transformedCanvas);
1006
+ },
1007
+ captureLatestFrame: ({ context }) => {
1008
+ context.frameCapturer?.getLatestCanvas();
1009
+ },
1010
+ clearUploadFailure: assign({
1011
+ uploadError: () => void 0,
1012
+ detectionStatus: () => "idle",
1013
+ previewImageUrl: ({ context }) => {
1014
+ if (context.previewImageUrl) URL.revokeObjectURL(context.previewImageUrl);
1015
+ },
1016
+ uploadProgress: () => void 0
1017
+ }),
1018
+ decrementAttemptsRemaining: assign(({ context }) => ({ attemptsRemaining: context.attemptsRemaining - 1 })),
1019
+ setUploadErrorFromUploadValidation: assign({ uploadError: ({ context }) => {
1020
+ if (!context.uploadResponse) return ID_ERROR_CODES.SERVER;
1021
+ return validateUploadResponse(context.uploadResponse, {
1022
+ skipGlareFront: context.uploadResponse.skipGlareFront,
1023
+ skipGlareBack: context.uploadResponse.skipGlareBack
1024
+ })?.errorKey ?? ID_ERROR_CODES.SERVER;
1025
+ } }),
1026
+ stopMediaRecording: ({ context }) => {
1027
+ if (context.recordingSession) stopRecording(context.recordingSession);
1028
+ },
1029
+ clearRecordingSession: assign({ recordingSession: () => void 0 }),
1030
+ setSelectedDocument: assign({ selectedDocumentType: ({ event }) => {
1031
+ if ("documentType" in event) return event.documentType;
1032
+ } }),
1033
+ setCurrentMode: assign({ currentMode: ({ event, context }) => {
1034
+ if ("documentType" in event) {
1035
+ if (event.documentType === "passport") return "passport";
1036
+ return "front";
1037
+ }
1038
+ if (event.type === "FRONT_COMPLETE") return "back";
1039
+ return context.currentMode;
1040
+ } }),
1041
+ storeCapturedImage: assign({
1042
+ capturedImages: ({ context, event }) => {
1043
+ if (!context.currentMode) return context.capturedImages;
1044
+ const transformedImage = (context.provider?.getCapturedCanvas())?.getBase64Image(1, true);
1045
+ let fallbackImage = "";
1046
+ if ("output" in event) fallbackImage = event.output.originalImage ?? "";
1047
+ const imageData = {
1048
+ imageBase64: transformedImage ?? fallbackImage,
1049
+ blob: new Blob(),
1050
+ url: "",
1051
+ metadata: ""
1052
+ };
1053
+ if (context.currentMode === "front" || context.currentMode === "passport") return {
1054
+ ...context.capturedImages,
1055
+ front: imageData
1056
+ };
1057
+ return {
1058
+ ...context.capturedImages,
1059
+ back: imageData
1060
+ };
1061
+ },
1062
+ previewImageUrl: ({ context, event }) => {
1063
+ const transformedCanvas = context.provider?.getCapturedCanvas();
1064
+ if (transformedCanvas) {
1065
+ transformedCanvas.updateBlob();
1066
+ const blobData = transformedCanvas.getBlobData();
1067
+ if (blobData?.url) return blobData.url;
1068
+ }
1069
+ if ("canvas" in event && event.canvas) {
1070
+ const canvas = event.canvas;
1071
+ canvas.updateBlob();
1072
+ const blobData = canvas.getBlobData();
1073
+ if (blobData?.url) return blobData.url;
1074
+ }
1075
+ return context.previewImageUrl;
1076
+ }
1077
+ }),
1078
+ setDetectionStatus: assign({ detectionStatus: ({ event, context }) => {
1079
+ if (event.type === "DETECTION_UPDATE") {
1080
+ const newStatus = event.status;
1081
+ const currentStatus = context.detectionStatus;
1082
+ if ((newStatus === "blur" || newStatus === "glare") && (currentStatus === "wrongSide" || currentStatus === "farAway")) return currentStatus;
1083
+ if ((newStatus === "wrongSide" || newStatus === "farAway") && (currentStatus === "blur" || currentStatus === "glare")) return newStatus;
1084
+ return newStatus;
1085
+ }
1086
+ return "idle";
1087
+ } }),
1088
+ setCounterValue: assign({ counterValue: ({ event }) => {
1089
+ if ("value" in event) return event.value;
1090
+ return 0;
1091
+ } }),
1092
+ setIdType: assign({ idType: ({ event }) => {
1093
+ if ("idType" in event) return event.idType;
1094
+ } }),
1095
+ setOrientation: assign({ orientation: ({ event }) => {
1096
+ if ("orientation" in event) return event.orientation;
1097
+ } }),
1098
+ setFrameRect: assign({ frameRect: ({ event }) => {
1099
+ if ("frameRect" in event) return event.frameRect;
1100
+ } }),
1101
+ setDetectionArea: assign({ detectionArea: ({ event }) => {
1102
+ if ("detectionArea" in event) return event.detectionArea;
1103
+ } }),
1104
+ setMotionStatus: assign({ motionStatus: ({ event }) => {
1105
+ if ("status" in event && event.type === "MOTION_STATUS") return event.status;
1106
+ } })
1107
+ },
1108
+ guards: {
1109
+ hasShowTutorial: ({ context }) => context.config.showTutorial,
1110
+ hasShowDocumentChooser: ({ context }) => context.config.showDocumentChooserScreen ?? false,
1111
+ isPermissionGranted: ({ event }) => {
1112
+ if ("output" in event) return event.output === "granted";
1113
+ return false;
1114
+ },
1115
+ isPermissionDeniedError: ({ event }) => {
1116
+ if ("error" in event) {
1117
+ const error = event.error;
1118
+ return error?.name === "NotAllowedError" || error?.name === "PermissionDeniedError";
1119
+ }
1120
+ return false;
1121
+ },
1122
+ hasStream: ({ context }) => context.stream !== void 0,
1123
+ hasAttemptsRemaining: ({ context }) => context.attemptsRemaining > 0,
1124
+ hasCapturedImage: ({ context }) => {
1125
+ return context.provider?.getCapturedCanvas() !== null;
1126
+ },
1127
+ hasUploadValidationError: ({ context }) => {
1128
+ if (!context.uploadResponse) return false;
1129
+ return validateUploadResponse(context.uploadResponse, {
1130
+ skipGlareFront: context.uploadResponse.skipGlareFront,
1131
+ skipGlareBack: context.uploadResponse.skipGlareBack
1132
+ }) !== void 0;
1133
+ },
1134
+ isFrontMode: ({ context }) => context.currentMode === "front" || context.currentMode === "passport",
1135
+ isOnlyFront: ({ context }) => context.config.onlyFront,
1136
+ shouldContinueToBack: ({ context }) => {
1137
+ if (context.currentMode === "passport") return false;
1138
+ if (context.currentMode !== "front") return false;
1139
+ if (context.config.onlyFront) return false;
1140
+ if (context.config.onlyBack) return false;
1141
+ if (!context.config.enableId && context.config.enablePassport) return false;
1142
+ if (context.uploadResponse?.skipBackIdCapture) return false;
1143
+ return true;
1144
+ }
1145
+ }
1146
+ }).createMachine({
1147
+ id: "idCapture",
1148
+ initial: "idle",
1149
+ context: ({ input }) => {
1150
+ const currentMode = input.config.onlyBack ? "back" : !input.config.enableId && input.config.enablePassport ? "passport" : "front";
1151
+ return {
1152
+ config: input.config,
1153
+ currentMode,
1154
+ selectedDocumentType: void 0,
1155
+ stream: void 0,
1156
+ provider: input.provider,
1157
+ frameCapturer: void 0,
1158
+ error: void 0,
1159
+ detectionStatus: "idle",
1160
+ counterValue: 0,
1161
+ orientation: void 0,
1162
+ capturedImages: {},
1163
+ uploadResponse: void 0,
1164
+ recordingSession: void 0,
1165
+ attemptsRemaining: input.config.captureAttempts,
1166
+ uploadError: void 0,
1167
+ permissionResult: void 0,
1168
+ resetDetection: void 0,
1169
+ idType: void 0,
1170
+ qualityElements: void 0,
1171
+ debugFrame: void 0,
1172
+ frameRect: void 0,
1173
+ detectionArea: void 0,
1174
+ previewImageUrl: void 0,
1175
+ uploadProgress: void 0,
1176
+ motionStatus: void 0,
1177
+ manualCaptureTriggered: false
1178
+ };
1179
+ },
1180
+ on: {
1181
+ QUIT: { target: "#idCapture.closed" },
1182
+ UPDATE_DETECTION_AREA: { actions: "setDetectionArea" }
1183
+ },
1184
+ states: {
1185
+ idle: { on: { LOAD: [
1186
+ {
1187
+ target: "chooser",
1188
+ guard: "hasShowDocumentChooser"
1189
+ },
1190
+ {
1191
+ target: "tutorial",
1192
+ guard: "hasShowTutorial"
1193
+ },
1194
+ { target: "loading" }
1195
+ ] } },
1196
+ chooser: { on: { SELECT_DOCUMENT: [{
1197
+ target: "tutorial",
1198
+ guard: "hasShowTutorial",
1199
+ actions: ["setSelectedDocument", "setCurrentMode"]
1200
+ }, {
1201
+ target: "loading",
1202
+ actions: ["setSelectedDocument", "setCurrentMode"]
1203
+ }] } },
1204
+ loading: { invoke: {
1205
+ id: "checkPermissionLoading",
1206
+ src: "checkPermission",
1207
+ onDone: [{
1208
+ target: "capture",
1209
+ guard: "isPermissionGranted",
1210
+ actions: assign({ permissionResult: ({ event }) => event.output })
1211
+ }, {
1212
+ target: "permissions",
1213
+ actions: assign({ permissionResult: ({ event }) => event.output })
1214
+ }],
1215
+ onError: {
1216
+ target: "permissions",
1217
+ actions: assign({ permissionResult: () => "prompt" })
1218
+ }
1219
+ } },
1220
+ tutorial: {
1221
+ initial: "checkingPermission",
1222
+ entry: "trackTutorialId",
1223
+ states: {
1224
+ checkingPermission: {
1225
+ invoke: {
1226
+ id: "checkPermissionTutorial",
1227
+ src: "checkPermission",
1228
+ onDone: [{
1229
+ target: "initializingCamera",
1230
+ guard: "isPermissionGranted",
1231
+ actions: assign({ permissionResult: ({ event }) => event.output })
1232
+ }, {
1233
+ target: "ready",
1234
+ actions: assign({ permissionResult: ({ event }) => event.output })
1235
+ }]
1236
+ },
1237
+ on: { NEXT_STEP: {
1238
+ target: "initializingCamera",
1239
+ actions: "trackContinue"
1240
+ } }
1241
+ },
1242
+ initializingCamera: {
1243
+ initial: "booting",
1244
+ invoke: {
1245
+ id: "tutorialInitCamera",
1246
+ src: "initializeCamera",
1247
+ input: ({ context }) => {
1248
+ if (!context.provider) throw new Error("Provider is required");
1249
+ return {
1250
+ provider: context.provider,
1251
+ config: context.config
1252
+ };
1253
+ },
1254
+ onDone: { actions: "setStreamAndCapturer" },
1255
+ onError: [{
1256
+ target: "ready",
1257
+ guard: "isPermissionDeniedError",
1258
+ actions: assign({ permissionResult: () => "denied" })
1259
+ }, {
1260
+ target: "ready",
1261
+ actions: assign({ error: ({ event }) => String(event.error) })
1262
+ }]
1263
+ },
1264
+ states: {
1265
+ booting: {
1266
+ always: [{
1267
+ target: "#tutorialCameraReady",
1268
+ guard: "hasStream"
1269
+ }],
1270
+ on: { NEXT_STEP: {
1271
+ target: "waitingForStream",
1272
+ actions: "trackContinue"
1273
+ } }
1274
+ },
1275
+ waitingForStream: { always: [{
1276
+ target: "#idCapture.capture",
1277
+ guard: "hasStream"
1278
+ }] }
1279
+ }
1280
+ },
1281
+ cameraReady: {
1282
+ id: "tutorialCameraReady",
1283
+ on: { NEXT_STEP: {
1284
+ target: "#idCapture.capture",
1285
+ actions: "trackContinue"
1286
+ } }
1287
+ },
1288
+ ready: { on: { NEXT_STEP: {
1289
+ target: "waitingForPermission",
1290
+ actions: "trackContinue"
1291
+ } } },
1292
+ waitingForPermission: { invoke: {
1293
+ id: "checkPermissionWaiting",
1294
+ src: "checkPermission",
1295
+ onDone: [{
1296
+ target: "#idCapture.capture",
1297
+ guard: "isPermissionGranted",
1298
+ actions: assign({ permissionResult: ({ event }) => event.output })
1299
+ }, {
1300
+ target: "#idCapture.permissions",
1301
+ actions: assign({ permissionResult: ({ event }) => event.output })
1302
+ }]
1303
+ } }
1304
+ }
1305
+ },
1306
+ permissions: {
1307
+ initial: "idle",
1308
+ states: {
1309
+ idle: {
1310
+ invoke: {
1311
+ id: "checkPermissionIdle",
1312
+ src: "checkPermission",
1313
+ onDone: [
1314
+ {
1315
+ target: "#idCapture.capture",
1316
+ guard: "isPermissionGranted",
1317
+ actions: assign({ permissionResult: ({ event }) => event.output })
1318
+ },
1319
+ {
1320
+ target: "denied",
1321
+ guard: ({ event }) => event.output === "denied",
1322
+ actions: assign({ permissionResult: ({ event }) => event.output })
1323
+ },
1324
+ {
1325
+ target: "waitingForUser",
1326
+ actions: assign({ permissionResult: ({ event }) => event.output })
1327
+ }
1328
+ ],
1329
+ onError: {
1330
+ target: "waitingForUser",
1331
+ actions: assign({ permissionResult: () => "prompt" })
1332
+ }
1333
+ },
1334
+ on: {
1335
+ REQUEST_PERMISSION: "requesting",
1336
+ GO_TO_LEARN_MORE: "learnMore"
1337
+ }
1338
+ },
1339
+ waitingForUser: { on: {
1340
+ REQUEST_PERMISSION: "requesting",
1341
+ GO_TO_LEARN_MORE: "learnMore"
1342
+ } },
1343
+ learnMore: { on: {
1344
+ BACK: "idle",
1345
+ REQUEST_PERMISSION: "requesting"
1346
+ } },
1347
+ requesting: { invoke: {
1348
+ id: "requestPermission",
1349
+ src: "requestPermission",
1350
+ onDone: [
1351
+ {
1352
+ target: "#idCapture.capture",
1353
+ guard: "isPermissionGranted",
1354
+ actions: assign({ permissionResult: ({ event }) => event.output })
1355
+ },
1356
+ {
1357
+ target: "denied",
1358
+ guard: ({ event }) => event.output === "denied",
1359
+ actions: assign({ permissionResult: ({ event }) => event.output })
1360
+ },
1361
+ {
1362
+ target: "idle",
1363
+ actions: assign({ permissionResult: ({ event }) => event.output })
1364
+ }
1365
+ ],
1366
+ onError: { target: "denied" }
1367
+ } },
1368
+ denied: { entry: assign({ permissionResult: () => "refresh" }) }
1369
+ }
1370
+ },
1371
+ capture: {
1372
+ initial: "checkingStream",
1373
+ exit: ["stopMediaRecording", "clearRecordingSession"],
1374
+ on: { SET_FRAME_RECT: { actions: "setFrameRect" } },
1375
+ states: {
1376
+ checkingStream: { always: [{
1377
+ target: "detecting",
1378
+ guard: "hasStream"
1379
+ }, { target: "initializing" }] },
1380
+ initializing: { invoke: {
1381
+ id: "initializeCamera",
1382
+ src: "initializeCamera",
1383
+ input: ({ context }) => {
1384
+ if (!context.provider) throw new Error("Provider is required");
1385
+ return {
1386
+ provider: context.provider,
1387
+ config: context.config
1388
+ };
1389
+ },
1390
+ onDone: {
1391
+ target: "detecting",
1392
+ actions: "setStreamAndCapturer"
1393
+ },
1394
+ onError: [{
1395
+ target: "#idCapture.permissions",
1396
+ guard: "isPermissionDeniedError",
1397
+ actions: assign({ permissionResult: () => "denied" })
1398
+ }, {
1399
+ target: "#idCapture.error",
1400
+ actions: assign({ error: ({ event }) => String(event.error) })
1401
+ }]
1402
+ } },
1403
+ detecting: {
1404
+ always: [{
1405
+ target: "manualCaptureWaiting",
1406
+ guard: ({ context }) => context.manualCaptureTriggered,
1407
+ actions: assign({ detectionStatus: () => "manualCapture" })
1408
+ }],
1409
+ entry: [assign({ detectionStatus: () => "detecting" })],
1410
+ invoke: [{
1411
+ id: "startRecording",
1412
+ src: "startRecording",
1413
+ input: ({ context }) => ({
1414
+ config: context.config,
1415
+ stream: context.stream,
1416
+ existing: context.recordingSession,
1417
+ currentMode: context.currentMode
1418
+ }),
1419
+ onDone: { actions: assign({ recordingSession: ({ context, event }) => {
1420
+ return event.output ?? context.recordingSession;
1421
+ } }) },
1422
+ onError: { actions: () => void 0 }
1423
+ }, {
1424
+ id: "runDetection",
1425
+ src: "runDetection",
1426
+ input: ({ context }) => ({
1427
+ frameCapturer: context.frameCapturer,
1428
+ provider: context.provider,
1429
+ config: context.config,
1430
+ currentMode: context.currentMode,
1431
+ detectionArea: context.detectionArea ?? context.config.detectionArea
1432
+ })
1433
+ }],
1434
+ on: {
1435
+ DETECTION_UPDATE: { actions: "setDetectionStatus" },
1436
+ DETECTION_FRAME: { actions: assign({ debugFrame: ({ event }) => event.frame }) },
1437
+ DETECTION_RESET_READY: { actions: assign({ resetDetection: ({ event }) => event.reset }) },
1438
+ DETECTION_SUCCESS: {
1439
+ target: "capturing",
1440
+ actions: assign({ qualityElements: ({ event }) => event.qualityElements })
1441
+ },
1442
+ MANUAL_CAPTURE: { target: "capturingManual" },
1443
+ SWITCH_TO_MANUAL_CAPTURE: {
1444
+ target: "manualCaptureWaiting",
1445
+ actions: assign({
1446
+ detectionStatus: () => "manualCapture",
1447
+ manualCaptureTriggered: () => true
1448
+ })
1449
+ },
1450
+ COUNTER_VALUE_CHANGE: { actions: "setCounterValue" },
1451
+ ID_TYPE_CHANGE: { actions: "setIdType" },
1452
+ ID_SIDE_CHANGE: { actions: assign({ detectionStatus: ({ event, context }) => {
1453
+ const detectedSide = event.side?.toLowerCase() || "";
1454
+ const currentMode = context.currentMode;
1455
+ if (detectedSide === "wrong") return "wrongSide";
1456
+ const isBackDetected = detectedSide.includes("back") && !detectedSide.includes("front");
1457
+ const isFrontDetected = detectedSide.includes("front") && !detectedSide.includes("back");
1458
+ if (currentMode === "front" && isBackDetected || currentMode === "back" && isFrontDetected) return "wrongSide";
1459
+ if (currentMode === "front" && isFrontDetected || currentMode === "back" && isBackDetected || currentMode === "passport") return "detecting";
1460
+ return "detecting";
1461
+ } }) },
1462
+ ORIENTATION_CHANGE: { actions: "setOrientation" }
1463
+ }
1464
+ },
1465
+ manualCaptureWaiting: { on: { MANUAL_CAPTURE: { target: "capturingManual" } } },
1466
+ capturing: {
1467
+ entry: [
1468
+ "captureImage",
1469
+ "storeCapturedCanvasInProvider",
1470
+ "storeCapturedImage"
1471
+ ],
1472
+ always: [{
1473
+ target: "uploading",
1474
+ guard: "hasCapturedImage"
1475
+ }, {
1476
+ target: "uploadError",
1477
+ actions: assign(({ context }) => ({
1478
+ uploadError: ID_ERROR_CODES.UPLOAD_ERROR,
1479
+ attemptsRemaining: context.attemptsRemaining - 1
1480
+ }))
1481
+ }]
1482
+ },
1483
+ capturingManual: {
1484
+ entry: [
1485
+ "captureLatestFrame",
1486
+ "storeCapturedCanvasInProvider",
1487
+ "storeCapturedImage"
1488
+ ],
1489
+ always: [{
1490
+ target: "uploading",
1491
+ guard: "hasCapturedImage"
1492
+ }, {
1493
+ target: "uploadError",
1494
+ actions: assign(({ context }) => ({
1495
+ uploadError: ID_ERROR_CODES.UPLOAD_ERROR,
1496
+ attemptsRemaining: context.attemptsRemaining - 1
1497
+ }))
1498
+ }]
1499
+ },
1500
+ uploading: {
1501
+ entry: assign({ uploadProgress: () => 0 }),
1502
+ invoke: {
1503
+ id: "uploadIdImage",
1504
+ src: "uploadIdImage",
1505
+ input: ({ context, self }) => {
1506
+ const canvas = context.provider?.getOriginalCapturedCanvas();
1507
+ if (!canvas) throw new Error(ID_ERROR_CODES.UPLOAD_ERROR);
1508
+ return {
1509
+ canvas,
1510
+ type: context.currentMode === "back" ? "back" : "front",
1511
+ qualityElements: context.qualityElements,
1512
+ onProgress: (progress) => {
1513
+ self.send({
1514
+ type: "UPLOAD_PROGRESS",
1515
+ progress
1516
+ });
1517
+ }
1518
+ };
1519
+ },
1520
+ onDone: {
1521
+ target: "validatingUpload",
1522
+ actions: [assign({
1523
+ uploadResponse: ({ event }) => event.output,
1524
+ uploadProgress: () => 100
1525
+ }), "storeCapturedImage"]
1526
+ },
1527
+ onError: {
1528
+ target: "uploadError",
1529
+ actions: assign(({ context, event }) => ({
1530
+ uploadError: getIdErrorCodeFromUnknown(event.error) ?? ID_ERROR_CODES.UPLOAD_ERROR,
1531
+ attemptsRemaining: context.attemptsRemaining - 1
1532
+ }))
1533
+ }
1534
+ },
1535
+ on: { UPLOAD_PROGRESS: { actions: assign({ uploadProgress: ({ event }) => event.progress }) } }
1536
+ },
1537
+ validatingUpload: { always: [{
1538
+ target: "uploadError",
1539
+ guard: "hasUploadValidationError",
1540
+ actions: ["setUploadErrorFromUploadValidation", "decrementAttemptsRemaining"]
1541
+ }, { target: "success" }] },
1542
+ uploadError: { on: { CONTINUE_FROM_ERROR: [
1543
+ {
1544
+ target: "detecting",
1545
+ guard: "hasAttemptsRemaining",
1546
+ actions: [
1547
+ "resetDetection",
1548
+ "clearUploadFailure",
1549
+ assign({ manualCaptureTriggered: () => false })
1550
+ ]
1551
+ },
1552
+ {
1553
+ target: "#idCapture.frontFinished",
1554
+ guard: "shouldContinueToBack"
1555
+ },
1556
+ { target: "#idCapture.finished" }
1557
+ ] } },
1558
+ success: { on: { NEXT_STEP: [{
1559
+ target: "#idCapture.frontFinished",
1560
+ guard: "shouldContinueToBack"
1561
+ }, { target: "#idCapture.processing" }] } }
1562
+ }
1563
+ },
1564
+ frontFinished: {
1565
+ entry: ["stopMediaRecording", "prepareForBackCapture"],
1566
+ on: { CONTINUE_TO_BACK: {
1567
+ target: "capture",
1568
+ actions: assign({ currentMode: () => "back" })
1569
+ } }
1570
+ },
1571
+ processing: {
1572
+ entry: "stopMediaStream",
1573
+ invoke: {
1574
+ id: "processId",
1575
+ src: "processId",
1576
+ input: ({ context }) => ({ isSecondId: context.config.isSecondId ?? false }),
1577
+ onDone: [{
1578
+ target: "expired",
1579
+ guard: ({ event }) => event.output.isDocumentExpired
1580
+ }, { target: "finished" }],
1581
+ onError: { target: "finished" }
1582
+ }
1583
+ },
1584
+ expired: { on: { RETRY_CAPTURE: [
1585
+ {
1586
+ target: "chooser",
1587
+ guard: "hasShowDocumentChooser",
1588
+ actions: ["resetContext"]
1589
+ },
1590
+ {
1591
+ target: "tutorial",
1592
+ guard: "hasShowTutorial",
1593
+ actions: "resetContext"
1594
+ },
1595
+ {
1596
+ target: "loading",
1597
+ actions: "resetContext"
1598
+ }
1599
+ ] } },
1600
+ finished: {
1601
+ entry: [
1602
+ "stopMediaRecording",
1603
+ "stopMediaStream",
1604
+ "disposeProvider"
1605
+ ],
1606
+ type: "final",
1607
+ on: { RESET: {
1608
+ target: "idle",
1609
+ actions: "resetContext"
1610
+ } }
1611
+ },
1612
+ closed: {
1613
+ entry: ["stopMediaStream", "disposeProvider"],
1614
+ type: "final"
1615
+ },
1616
+ error: {
1617
+ entry: ["stopMediaStream", "disposeProvider"],
1618
+ on: { RESET: {
1619
+ target: "idle",
1620
+ actions: "resetContext"
1621
+ } }
1622
+ },
1623
+ manualIdUpload: { on: { QUIT: { target: "closed" } } },
1624
+ digitalIdUpload: { on: { QUIT: { target: "closed" } } }
1625
+ }
1626
+ });
1627
+ const idCaptureMachine = _idCaptureMachine;
1628
+
1629
+ //#endregion
1630
+ //#region src/modules/id/idCaptureActor.ts
1631
+ function createIdCaptureActor(options) {
1632
+ return createActor(idCaptureMachine, { input: {
1633
+ config: options.config,
1634
+ provider: options.provider
1635
+ } }).start();
1636
+ }
1637
+
1638
+ //#endregion
1639
+ //#region src/modules/id/idCaptureManager.ts
1640
+ function getPermissionStatus(snapshot) {
1641
+ if (!snapshot.matches("permissions")) return;
1642
+ if (snapshot.matches({ permissions: "idle" })) return "idle";
1643
+ if (snapshot.matches({ permissions: "waitingForUser" })) return "idle";
1644
+ if (snapshot.matches({ permissions: "learnMore" })) return "learnMore";
1645
+ if (snapshot.matches({ permissions: "requesting" })) return "requesting";
1646
+ if (snapshot.matches({ permissions: "denied" })) return "denied";
1647
+ }
1648
+ function getCaptureStatus(snapshot) {
1649
+ const matches = {
1650
+ initializing: snapshot.matches({ capture: "initializing" }),
1651
+ detecting: snapshot.matches({ capture: "detecting" }),
1652
+ manualCaptureWaiting: snapshot.matches({ capture: "manualCaptureWaiting" }),
1653
+ capturing: snapshot.matches({ capture: "capturing" }),
1654
+ capturingManual: snapshot.matches({ capture: "capturingManual" }),
1655
+ uploading: snapshot.matches({ capture: "uploading" }),
1656
+ uploadError: snapshot.matches({ capture: "uploadError" }),
1657
+ success: snapshot.matches({ capture: "success" })
1658
+ };
1659
+ if (matches.initializing) return "initializing";
1660
+ if (matches.detecting || matches.manualCaptureWaiting) return "detecting";
1661
+ if (matches.capturing || matches.capturingManual) return "capturing";
1662
+ if (matches.uploading) return "uploading";
1663
+ if (matches.uploadError) return "uploadError";
1664
+ if (matches.success) return "success";
1665
+ }
1666
+ function getErrorMessage(errorCode) {
1667
+ if (!errorCode) return void 0;
1668
+ return {
1669
+ UPLOAD_ERROR: "Upload failed",
1670
+ CLASSIFICATION_FAILED: "ID classification failed",
1671
+ LOW_SHARPNESS: "Image is not sharp enough",
1672
+ GLARE_DETECTED: "Glare detected on ID",
1673
+ WRONG_DOCUMENT_SIDE: "Wrong side of document",
1674
+ ID_TYPE_UNACCEPTABLE: "ID type is not acceptable",
1675
+ READABILITY_ISSUE: "ID readability issue",
1676
+ RETRY_EXHAUSTED_CONTINUE_TO_BACK: "Retry exhausted",
1677
+ RETRY_EXHAUSTED_SKIP_BACK: "Retry exhausted",
1678
+ NO_MORE_TRIES: "No more tries remaining",
1679
+ UNEXPECTED_ERROR: "An unexpected error occurred",
1680
+ NO_TOKEN: "No token available",
1681
+ PERMISSION_DENIED: "Permission denied",
1682
+ USER_CANCELLED: "User cancelled",
1683
+ SERVER_ERROR: "Server error"
1684
+ }[errorCode];
1685
+ }
1686
+ function getErrorDescription(errorCode, uploadResponse) {
1687
+ if (!errorCode) return void 0;
1688
+ return {
1689
+ UPLOAD_ERROR: "Please try again",
1690
+ CLASSIFICATION_FAILED: "Please ensure your ID is clearly visible",
1691
+ LOW_SHARPNESS: "Please ensure the image is clear and well-focused",
1692
+ GLARE_DETECTED: "Please avoid bright reflections on your ID",
1693
+ WRONG_DOCUMENT_SIDE: uploadResponse?.side === "back" ? "Please show the back side of your ID" : "Please show the front side of your ID",
1694
+ ID_TYPE_UNACCEPTABLE: "Please use a valid ID type",
1695
+ READABILITY_ISSUE: "Please ensure all text is clearly visible",
1696
+ RETRY_EXHAUSTED_CONTINUE_TO_BACK: "Continuing to back side capture",
1697
+ RETRY_EXHAUSTED_SKIP_BACK: "Skipping back side capture",
1698
+ NO_MORE_TRIES: "Maximum attempts reached",
1699
+ UNEXPECTED_ERROR: "Please try again later",
1700
+ NO_TOKEN: "Session expired",
1701
+ PERMISSION_DENIED: "Camera permission is required",
1702
+ USER_CANCELLED: "Capture was cancelled",
1703
+ SERVER_ERROR: "Please try again later"
1704
+ }[errorCode];
1705
+ }
1706
+ function mapState(snapshot) {
1707
+ const { context } = snapshot;
1708
+ if (snapshot.matches("idle")) return { status: "idle" };
1709
+ if (snapshot.matches("chooser")) return { status: "chooser" };
1710
+ if (snapshot.matches("loading")) return { status: "loading" };
1711
+ if (snapshot.matches("tutorial")) return {
1712
+ status: "tutorial",
1713
+ selectedDocumentType: context.selectedDocumentType
1714
+ };
1715
+ if (snapshot.matches("closed")) return { status: "closed" };
1716
+ if (snapshot.matches("permissions")) {
1717
+ const permissionStatus = getPermissionStatus(snapshot);
1718
+ if (permissionStatus === void 0) return {
1719
+ status: "permissions",
1720
+ permissionStatus: "idle"
1721
+ };
1722
+ return {
1723
+ status: "permissions",
1724
+ permissionStatus
1725
+ };
1726
+ }
1727
+ if (snapshot.matches("capture")) {
1728
+ const captureStatus = getCaptureStatus(snapshot);
1729
+ const needsBackCapture = context.currentMode === "front" && !context.config.onlyFront && !context.config.onlyBack;
1730
+ return {
1731
+ status: "capture",
1732
+ captureStatus: captureStatus ?? "initializing",
1733
+ stream: context.stream,
1734
+ detectionStatus: context.detectionStatus,
1735
+ debugFrame: void 0,
1736
+ attemptsRemaining: context.attemptsRemaining,
1737
+ uploadError: context.uploadError,
1738
+ currentMode: context.currentMode,
1739
+ counterValue: context.counterValue,
1740
+ orientation: context.orientation,
1741
+ idType: context.idType,
1742
+ previewImageUrl: context.previewImageUrl,
1743
+ uploadProgress: context.uploadProgress ?? 0,
1744
+ uploadErrorMessage: context.uploadError ? getErrorMessage(context.uploadError) : void 0,
1745
+ uploadErrorDescription: context.uploadError ? getErrorDescription(context.uploadError, context.uploadResponse) : void 0,
1746
+ needsBackCapture,
1747
+ showCaptureButtonInAuto: context.config.showCaptureButtonInAuto ?? false,
1748
+ canRetry: context.attemptsRemaining > 0
1749
+ };
1750
+ }
1751
+ if (snapshot.matches("frontFinished")) return { status: "frontFinished" };
1752
+ if (snapshot.matches("processing")) return { status: "processing" };
1753
+ if (snapshot.matches("expired")) return { status: "expired" };
1754
+ if (snapshot.matches("finished")) return { status: "finished" };
1755
+ if (snapshot.matches("error")) return {
1756
+ status: "error",
1757
+ error: context.error ?? "Unknown error"
1758
+ };
1759
+ return { status: "idle" };
1760
+ }
1761
+ function createApi({ actor }) {
1762
+ return {
1763
+ load() {
1764
+ actor.send({ type: "LOAD" });
1765
+ },
1766
+ selectDocument(documentType) {
1767
+ actor.send({
1768
+ type: "SELECT_DOCUMENT",
1769
+ documentType
1770
+ });
1771
+ },
1772
+ nextStep() {
1773
+ actor.send({ type: "NEXT_STEP" });
1774
+ },
1775
+ requestPermission() {
1776
+ actor.send({ type: "REQUEST_PERMISSION" });
1777
+ },
1778
+ goToLearnMore() {
1779
+ actor.send({ type: "GO_TO_LEARN_MORE" });
1780
+ },
1781
+ back() {
1782
+ actor.send({ type: "BACK" });
1783
+ },
1784
+ close() {
1785
+ actor.send({ type: "QUIT" });
1786
+ },
1787
+ reset() {
1788
+ actor.send({ type: "RESET" });
1789
+ },
1790
+ retryCapture() {
1791
+ actor.send({ type: "RETRY_CAPTURE" });
1792
+ },
1793
+ continueFromError() {
1794
+ actor.send({ type: "CONTINUE_FROM_ERROR" });
1795
+ },
1796
+ capture() {
1797
+ actor.send({ type: "MANUAL_CAPTURE" });
1798
+ },
1799
+ switchToManualCapture() {
1800
+ actor.send({ type: "SWITCH_TO_MANUAL_CAPTURE" });
1801
+ },
1802
+ continueToBack() {
1803
+ actor.send({ type: "CONTINUE_TO_BACK" });
1804
+ },
1805
+ skipBack() {
1806
+ actor.send({ type: "SKIP_BACK" });
1807
+ },
1808
+ updateDetectionArea(detectionArea) {
1809
+ actor.send({
1810
+ type: "UPDATE_DETECTION_AREA",
1811
+ detectionArea
1812
+ });
1813
+ }
1814
+ };
1815
+ }
1816
+ function createIdCaptureManager(options) {
1817
+ return createManager({
1818
+ actor: createIdCaptureActor(options),
1819
+ mapState,
1820
+ createApi
1821
+ });
1822
+ }
1823
+
1824
+ //#endregion
1825
+ export { processId as a, stopStream as c, ID_ERROR_CODES as d, initializeIdCapture as i, uploadIdImage as l, createIdCaptureActor as n, startRecordingSession as o, idCaptureMachine as r, stopRecording as s, createIdCaptureManager as t, validateUploadResponse as u };