@incodetech/core 2.0.0-rc.0 → 2.0.0
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/package.json +3 -3
- package/dist/Actor-CI32dTbG.d.ts +0 -2
- package/dist/BaseWasmProvider-C_DLEI40.esm.js +0 -1118
- package/dist/BrowserStorageProvider-CuOW1Er2.esm.js +0 -55
- package/dist/BrowserTimerProvider-DhNc_x02.esm.js +0 -22
- package/dist/ITimerCapability-C67ZRskg.esm.js +0 -7
- package/dist/IpifyProvider-D7jx52AL.esm.js +0 -139
- package/dist/Manager-C8PrhBOx.d.ts +0 -19
- package/dist/MotionSensorProvider-4v7xkqAp.esm.js +0 -254
- package/dist/OpenViduRecordingProvider-CMu6XVdc.esm.js +0 -87
- package/dist/StateMachine-BCQrZJhf.d.ts +0 -2
- package/dist/WasmUtilProvider-j98OJf-S.esm.js +0 -114
- package/dist/addressSearch-BpTbTWCa.esm.js +0 -430
- package/dist/ae-signature-DDDZmWXj.esm.js +0 -12
- package/dist/ae-signature.d.ts +0 -25
- package/dist/ae-signature.esm.js +0 -8
- package/dist/antifraud.d.ts +0 -57
- package/dist/antifraud.esm.js +0 -45
- package/dist/antifraudStateMachine-O0TMf6yc.esm.js +0 -39
- package/dist/api-CESGtpbH.esm.js +0 -53
- package/dist/authentication.d.ts +0 -12
- package/dist/authentication.esm.js +0 -25
- package/dist/authenticationManager-5M-fKzXx.esm.js +0 -67
- package/dist/authenticationManager-C83GNIhl.d.ts +0 -66
- package/dist/authenticationStateMachine-BMZqatiF.esm.js +0 -139
- package/dist/backCameraStream-DMdMeGk2.esm.js +0 -346
- package/dist/browserSimulation-gxD8cSpM.esm.js +0 -20
- package/dist/camera-DBSxa6ML.d.ts +0 -4
- package/dist/camera-PA2Ljri3.esm.js +0 -22
- package/dist/camera.d.ts +0 -15
- package/dist/camera.esm.js +0 -5
- package/dist/chunk-CRF6K_H_.esm.js +0 -49
- package/dist/consent.d.ts +0 -398
- package/dist/consent.esm.js +0 -79
- package/dist/consentStateMachine-CCT-B60O.esm.js +0 -151
- package/dist/cpf-PPz2Njto.esm.js +0 -38
- package/dist/cpf-ocr.d.ts +0 -204
- package/dist/cpf-ocr.esm.js +0 -177
- package/dist/cross-document-data-match.d.ts +0 -34
- package/dist/cross-document-data-match.esm.js +0 -71
- package/dist/curp-validation.d.ts +0 -188
- package/dist/curp-validation.esm.js +0 -110
- package/dist/curpValidationStateMachine-CitWLr2c.esm.js +0 -595
- package/dist/custom-fields.d.ts +0 -115
- package/dist/custom-fields.esm.js +0 -177
- package/dist/custom-watchlist.d.ts +0 -66
- package/dist/custom-watchlist.esm.js +0 -86
- package/dist/dateUtils-UoN5xswP.esm.js +0 -23
- package/dist/deepsightLoader-Cm4JIT_z.esm.js +0 -52
- package/dist/deepsightService-CEVxzehb.d.ts +0 -412
- package/dist/deepsightService-O74l4Y__.esm.js +0 -489
- package/dist/device.d.ts +0 -46
- package/dist/device.esm.js +0 -106
- package/dist/displayErrors-DqJ_IbsG.d.ts +0 -39
- package/dist/document-capture.d.ts +0 -906
- package/dist/document-capture.esm.js +0 -156
- package/dist/document-upload.d.ts +0 -331
- package/dist/document-upload.esm.js +0 -203
- package/dist/documentCaptureStateMachine-BqzTDy9k.esm.js +0 -394
- package/dist/dynamic-forms.d.ts +0 -178
- package/dist/dynamic-forms.esm.js +0 -323
- package/dist/ekyb.d.ts +0 -148
- package/dist/ekyb.esm.js +0 -127
- package/dist/ekybStateMachine-B59rQjgj.esm.js +0 -674
- package/dist/ekyc.d.ts +0 -164
- package/dist/ekyc.esm.js +0 -104
- package/dist/ekycStateMachine-oeO0Iekd.esm.js +0 -10626
- package/dist/electronic-signature.d.ts +0 -4
- package/dist/electronic-signature.esm.js +0 -7
- package/dist/electronicSignatureManager-D9OHzTpG.esm.js +0 -428
- package/dist/email.d.ts +0 -4
- package/dist/email.esm.js +0 -9
- package/dist/emailManager-DIfnS5g1.d.ts +0 -352
- package/dist/emailManager-wAV0LE-H.esm.js +0 -238
- package/dist/emailStateMachine-DOf4j58N.esm.js +0 -292
- package/dist/endpoints-CnN3SyDa.esm.js +0 -87
- package/dist/events-D6-e4vok.esm.js +0 -596
- package/dist/events.d.ts +0 -265
- package/dist/events.esm.js +0 -4
- package/dist/extensibility.d.ts +0 -122
- package/dist/extensibility.esm.js +0 -43
- package/dist/face-match.d.ts +0 -228
- package/dist/face-match.esm.js +0 -173
- package/dist/faceCaptureManagerFactory-Dh2PdGlF.esm.js +0 -290
- package/dist/faceCaptureManagerFactory-yqtpxjnN.d.ts +0 -690
- package/dist/faceCaptureSetup-B3faSpYA.esm.js +0 -873
- package/dist/faceMatchStateMachine-DNFrxTFS.esm.js +0 -127
- package/dist/flow-events.d.ts +0 -6
- package/dist/flow-events.esm.js +0 -0
- package/dist/flow.d.ts +0 -358
- package/dist/flow.esm.js +0 -825
- package/dist/flowCompletionService-DhkT4SRY.d.ts +0 -10
- package/dist/flowCompletionService-P54yzGvA.esm.js +0 -13
- package/dist/flowServices-DTsm-Vf1.esm.js +0 -188
- package/dist/geolocation.d.ts +0 -127
- package/dist/geolocation.esm.js +0 -89
- package/dist/geolocationStateMachine-asasuHY2.esm.js +0 -105
- package/dist/getBrowser-BSXUTWXw.esm.js +0 -41
- package/dist/getDeviceClass-BSntT9_j.esm.js +0 -14
- package/dist/government-validation.d.ts +0 -67
- package/dist/government-validation.esm.js +0 -81
- package/dist/governmentValidationStateMachine-BDDYrJTo.esm.js +0 -271
- package/dist/home.d.ts +0 -99
- package/dist/home.esm.js +0 -61
- package/dist/http.d.ts +0 -68
- package/dist/http.esm.js +0 -3
- package/dist/id-ocr.d.ts +0 -635
- package/dist/id-ocr.esm.js +0 -86
- package/dist/id-verification.d.ts +0 -190
- package/dist/id-verification.esm.js +0 -43
- package/dist/id.d.ts +0 -24
- package/dist/id.esm.js +0 -164
- package/dist/idCaptureManager-B9TGA5dq.d.ts +0 -956
- package/dist/idCaptureManager-DMK0GIt3.esm.js +0 -581
- package/dist/idCaptureStateMachine-Bq0fVZXl.esm.js +0 -2954
- package/dist/idOcrStateMachine-YbjjC_Gg.esm.js +0 -388
- package/dist/idVerificationStateMachine-xbw9HP1Z.esm.js +0 -71
- package/dist/identity-reuse.d.ts +0 -530
- package/dist/identity-reuse.esm.js +0 -274
- package/dist/index-BLKtMA0g.d.ts +0 -1177
- package/dist/index-BcRG8rtJ.d.ts +0 -97
- package/dist/index.d.ts +0 -3
- package/dist/index.esm.js +0 -12
- package/dist/invokeOnCaptureCallback-rc6kBHo5.esm.js +0 -30
- package/dist/lib-BB0B_qQX.esm.js +0 -12499
- package/dist/mandatory-consent.d.ts +0 -412
- package/dist/mandatory-consent.esm.js +0 -78
- package/dist/mandatoryConsentStateMachine-Cnco1jvn.esm.js +0 -126
- package/dist/openviduLazy-Cm0XFh_v.esm.js +0 -3
- package/dist/openviduLazy-Cok70ZSg.esm.js +0 -12
- package/dist/permissionServices-D_i6nzEw.esm.js +0 -50
- package/dist/phone.d.ts +0 -4
- package/dist/phone.esm.js +0 -9
- package/dist/phoneManager-B6M30hKE.d.ts +0 -397
- package/dist/phoneManager-DAJbGhlY.esm.js +0 -256
- package/dist/phoneStateMachine-CuPARRaT.esm.js +0 -351
- package/dist/platform-CfrjKhmi.esm.js +0 -83
- package/dist/qe-signature-DFo_Cc-I.esm.js +0 -12
- package/dist/qe-signature.d.ts +0 -25
- package/dist/qe-signature.esm.js +0 -8
- package/dist/recordingService-Ig2UgbLv.esm.js +0 -1003
- package/dist/redirect-to-mobile.d.ts +0 -107
- package/dist/redirect-to-mobile.esm.js +0 -102
- package/dist/redirectToMobileStateMachine-BOEqe46A.esm.js +0 -249
- package/dist/runChildModule-CqqwqAkW.esm.js +0 -219
- package/dist/selfie.d.ts +0 -26
- package/dist/selfie.esm.js +0 -146
- package/dist/selfieManager-D0lSgd-J.d.ts +0 -68
- package/dist/selfieManager-Duisl7qN.esm.js +0 -60
- package/dist/selfieStateMachine-D76whWEf.esm.js +0 -68
- package/dist/session-BS-d_vuE.esm.js +0 -3206
- package/dist/session.d.ts +0 -217
- package/dist/session.esm.js +0 -9
- package/dist/setup-Buy-hyj4.esm.js +0 -887
- package/dist/setup-C5AITV8m.d.ts +0 -254
- package/dist/signature.d.ts +0 -94
- package/dist/signature.esm.js +0 -66
- package/dist/signatureStateMachine-B5-QVUve.esm.js +0 -132
- package/dist/stats-CIfiPzb1.esm.js +0 -16
- package/dist/stats.d.ts +0 -16
- package/dist/stats.esm.js +0 -4
- package/dist/trust-graph.d.ts +0 -54
- package/dist/trust-graph.esm.js +0 -56
- package/dist/types-B06Ypu2F.d.ts +0 -49
- package/dist/types-BP1m8VRw.d.ts +0 -340
- package/dist/types-CAD4va6a.d.ts +0 -5
- package/dist/types-CFV9G_7j.d.ts +0 -24
- package/dist/warmup-CEcppFiS.d.ts +0 -63
- package/dist/wasm.d.ts +0 -15
- package/dist/wasm.esm.js +0 -12
- package/dist/watchlist-for-business.d.ts +0 -79
- package/dist/watchlist-for-business.esm.js +0 -148
- package/dist/watchlist.d.ts +0 -62
- package/dist/watchlist.esm.js +0 -86
- package/dist/watchlistServices-DMbUhkBX.esm.js +0 -12
- package/dist/workflow.d.ts +0 -907
- package/dist/workflow.esm.js +0 -702
- package/dist/xstate.esm-B70JrNqo.esm.js +0 -3404
|
@@ -1,2954 +0,0 @@
|
|
|
1
|
-
import { l as WasmPipelineType, r as mlWasmJSApi_default, t as BaseWasmProvider, u as IdCaptureModelType } from "./BaseWasmProvider-C_DLEI40.esm.js";
|
|
2
|
-
import { t as BrowserTimerProvider } from "./BrowserTimerProvider-DhNc_x02.esm.js";
|
|
3
|
-
import { r as getToken, t as api } from "./api-CESGtpbH.esm.js";
|
|
4
|
-
import { S as revokeObjectURL } from "./events-D6-e4vok.esm.js";
|
|
5
|
-
import { t as endpoints } from "./endpoints-CnN3SyDa.esm.js";
|
|
6
|
-
import { t as getDisableIpify } from "./session-BS-d_vuE.esm.js";
|
|
7
|
-
import { a as fromPromise, i as fromCallback, n as sendTo, o as and, r as assign, t as setup } from "./xstate.esm-B70JrNqo.esm.js";
|
|
8
|
-
import { n as IncodeCanvas } from "./deepsightService-O74l4Y__.esm.js";
|
|
9
|
-
import { _ as stopRecording$1, a as StreamCanvasCapture, g as startRecording, h as createRecordingSession, i as flagIdManualReview, n as preloadOpenViduProvider, v as StreamCanvasProcessingSession } from "./recordingService-Ig2UgbLv.esm.js";
|
|
10
|
-
import { n as isDesktop } from "./platform-CfrjKhmi.esm.js";
|
|
11
|
-
import { t as getBackCameraStream } from "./backCameraStream-DMdMeGk2.esm.js";
|
|
12
|
-
import { r as getWindowDimensions } from "./getBrowser-BSXUTWXw.esm.js";
|
|
13
|
-
import { t as addDeviceStats } from "./stats-CIfiPzb1.esm.js";
|
|
14
|
-
import { t as getDeviceClass } from "./getDeviceClass-BSntT9_j.esm.js";
|
|
15
|
-
import { n as requestPermission, t as checkPermission } from "./permissionServices-D_i6nzEw.esm.js";
|
|
16
|
-
|
|
17
|
-
//#region src/modules/id/digitalUpload/digitalUploadErrors.ts
|
|
18
|
-
const TERMINAL_FAIL_REASONS = new Set(["DIGITAL_ID_REQUESTED_BUT_OTHER_PROVIDED", "ID_TYPE_UNACCEPTABLE"]);
|
|
19
|
-
function isKnownFailReason(reason) {
|
|
20
|
-
return reason === "DIGITAL_ID_REQUESTED_BUT_OTHER_PROVIDED" || reason === "ID_TYPE_UNACCEPTABLE" || reason === "FILE_CHANGED_ERROR" || reason === "NETWORK_ERROR" || reason === "GENERIC";
|
|
21
|
-
}
|
|
22
|
-
function mapDigitalIdFailReason(response) {
|
|
23
|
-
const failReason = response?.failReason;
|
|
24
|
-
if (typeof failReason !== "string" || failReason.length === 0) return null;
|
|
25
|
-
if (isKnownFailReason(failReason)) return failReason;
|
|
26
|
-
return "GENERIC";
|
|
27
|
-
}
|
|
28
|
-
function isTerminalDigitalIdFailReason(response) {
|
|
29
|
-
return typeof response?.failReason === "string" && TERMINAL_FAIL_REASONS.has(response.failReason);
|
|
30
|
-
}
|
|
31
|
-
function classifyNetworkError(err) {
|
|
32
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
33
|
-
if (message.includes("ERR_UPLOAD_FILE_CHANGED") || message.includes("file changed") || message.includes("FILE_CHANGED")) return "FILE_CHANGED_ERROR";
|
|
34
|
-
return "NETWORK_ERROR";
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
//#endregion
|
|
38
|
-
//#region src/modules/id/digitalUpload/digitalUploadServices.ts
|
|
39
|
-
const DIGITAL_ID_UPLOAD_PATH = "/omni/add/front-id";
|
|
40
|
-
async function uploadDigitalIdFile(params) {
|
|
41
|
-
const { file, signal, onProgress } = params;
|
|
42
|
-
const response = await api.post(DIGITAL_ID_UPLOAD_PATH, file, {
|
|
43
|
-
query: { idType: "DigitalId" },
|
|
44
|
-
headers: { "Content-Type": file.type || "application/pdf" },
|
|
45
|
-
onUploadProgress: onProgress,
|
|
46
|
-
signal
|
|
47
|
-
});
|
|
48
|
-
if (!response.ok) throw new Error(`POST ${DIGITAL_ID_UPLOAD_PATH} failed: ${response.status}`);
|
|
49
|
-
return {
|
|
50
|
-
...response.data,
|
|
51
|
-
uploadDurationMs: 0
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
//#endregion
|
|
56
|
-
//#region src/modules/id/digitalUpload/types.ts
|
|
57
|
-
const DIGITAL_UPLOAD_MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;
|
|
58
|
-
const DIGITAL_UPLOAD_HOLDING_TIMEOUT_MS = 8e3;
|
|
59
|
-
const DIGITAL_UPLOAD_ALLOWED_MIME_TYPES = ["application/pdf"];
|
|
60
|
-
|
|
61
|
-
//#endregion
|
|
62
|
-
//#region src/modules/id/digitalUpload/digitalUploadStateMachine.ts
|
|
63
|
-
const uploadDigitalIdActor = fromPromise(async ({ input, signal }) => {
|
|
64
|
-
return uploadDigitalIdFile({
|
|
65
|
-
file: input.file,
|
|
66
|
-
signal: input.signal ?? signal,
|
|
67
|
-
onProgress: input.onProgress
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
const getUploadResponseFromEvent$1 = (event) => {
|
|
71
|
-
if (!("output" in event)) return;
|
|
72
|
-
return event.output;
|
|
73
|
-
};
|
|
74
|
-
const _digitalUploadMachine = setup({
|
|
75
|
-
types: {
|
|
76
|
-
context: {},
|
|
77
|
-
events: {},
|
|
78
|
-
input: {},
|
|
79
|
-
output: {}
|
|
80
|
-
},
|
|
81
|
-
actors: { uploadDigitalId: uploadDigitalIdActor },
|
|
82
|
-
actions: {
|
|
83
|
-
requestPickerIfPending: assign(({ context }) => {
|
|
84
|
-
if (!context.pendingPickerAutoOpen) return {};
|
|
85
|
-
return {
|
|
86
|
-
pickerRequestId: context.pickerRequestId + 1,
|
|
87
|
-
pendingPickerAutoOpen: false
|
|
88
|
-
};
|
|
89
|
-
}),
|
|
90
|
-
setPendingPickerAutoOpen: assign(() => ({ pendingPickerAutoOpen: true })),
|
|
91
|
-
storeSelectedFile: assign(({ event }) => {
|
|
92
|
-
if (event.type !== "FILE_PICKED") return {};
|
|
93
|
-
return {
|
|
94
|
-
file: event.file,
|
|
95
|
-
failReason: null
|
|
96
|
-
};
|
|
97
|
-
}),
|
|
98
|
-
clearSelectedFile: assign(() => ({
|
|
99
|
-
file: null,
|
|
100
|
-
uploadProgress: 0,
|
|
101
|
-
failReason: null,
|
|
102
|
-
response: void 0,
|
|
103
|
-
uploadDurationMs: void 0
|
|
104
|
-
})),
|
|
105
|
-
setInvalidFileTypeError: assign(() => ({ failReason: "INVALID_FILE_TYPE" })),
|
|
106
|
-
setUploadProgressCapped: assign(({ event }) => {
|
|
107
|
-
if (event.type !== "UPLOAD_PROGRESS") return {};
|
|
108
|
-
return { uploadProgress: Math.min(90, Math.max(0, event.progress)) };
|
|
109
|
-
}),
|
|
110
|
-
setUploadProgressCompleted: assign(() => ({ uploadProgress: 100 })),
|
|
111
|
-
storeUploadResponse: assign(({ event }) => {
|
|
112
|
-
if (!("output" in event)) return {};
|
|
113
|
-
const output = event;
|
|
114
|
-
return {
|
|
115
|
-
response: output.output,
|
|
116
|
-
uploadDurationMs: output.output.uploadDurationMs
|
|
117
|
-
};
|
|
118
|
-
}),
|
|
119
|
-
setFailReasonFromResponse: assign(({ event }) => {
|
|
120
|
-
if (!("output" in event)) return {};
|
|
121
|
-
const response = event.output;
|
|
122
|
-
return { failReason: mapDigitalIdFailReason(response) ?? "GENERIC" };
|
|
123
|
-
}),
|
|
124
|
-
setFailReasonFromNetworkError: assign(({ event }) => {
|
|
125
|
-
if (!("error" in event)) return {};
|
|
126
|
-
return { failReason: classifyNetworkError(event.error) };
|
|
127
|
-
}),
|
|
128
|
-
decrementAttemptOnRetry: assign(({ context }) => {
|
|
129
|
-
if (!(context.failReason !== "INVALID_FILE_TYPE" && context.failReason !== null && context.failReason !== "DIGITAL_ID_REQUESTED_BUT_OTHER_PROVIDED" && context.failReason !== "ID_TYPE_UNACCEPTABLE")) return {};
|
|
130
|
-
return { attemptsRemaining: Math.max(0, context.attemptsRemaining - 1) };
|
|
131
|
-
})
|
|
132
|
-
},
|
|
133
|
-
guards: {
|
|
134
|
-
isSelectedFileTooLarge: ({ event }) => event.type === "FILE_PICKED" && event.file.size > DIGITAL_UPLOAD_MAX_FILE_SIZE_BYTES,
|
|
135
|
-
isSelectedFileMimeInvalid: ({ event }) => event.type === "FILE_PICKED" && !DIGITAL_UPLOAD_ALLOWED_MIME_TYPES.includes(event.file.type),
|
|
136
|
-
hasSelectedFile: ({ context }) => context.file !== null,
|
|
137
|
-
responseHasFailReason: ({ event }) => mapDigitalIdFailReason(getUploadResponseFromEvent$1(event)) !== null,
|
|
138
|
-
hasAttemptsRemaining: ({ context }) => context.attemptsRemaining > 0,
|
|
139
|
-
isTerminalFailReason: ({ event }) => {
|
|
140
|
-
return isTerminalDigitalIdFailReason(getUploadResponseFromEvent$1(event));
|
|
141
|
-
},
|
|
142
|
-
isCurrentFailReasonTerminal: ({ context }) => {
|
|
143
|
-
const terminalReasons = new Set(["DIGITAL_ID_REQUESTED_BUT_OTHER_PROVIDED", "ID_TYPE_UNACCEPTABLE"]);
|
|
144
|
-
return context.failReason !== null && terminalReasons.has(context.failReason);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}).createMachine({
|
|
148
|
-
id: "digitalUpload",
|
|
149
|
-
initial: "decideStart",
|
|
150
|
-
context: ({ input }) => ({
|
|
151
|
-
showTutorial: input.showTutorial,
|
|
152
|
-
file: null,
|
|
153
|
-
uploadProgress: 0,
|
|
154
|
-
attemptsRemaining: input.captureAttempts,
|
|
155
|
-
failReason: null,
|
|
156
|
-
response: void 0,
|
|
157
|
-
uploadDurationMs: void 0,
|
|
158
|
-
pickerRequestId: 0,
|
|
159
|
-
pendingPickerAutoOpen: !input.showTutorial,
|
|
160
|
-
resultType: null
|
|
161
|
-
}),
|
|
162
|
-
output: ({ context }) => ({ result: context.resultType ?? "exhausted" }),
|
|
163
|
-
states: {
|
|
164
|
-
decideStart: { always: [{
|
|
165
|
-
guard: ({ context }) => context.showTutorial,
|
|
166
|
-
target: "tutorial"
|
|
167
|
-
}, { target: "selecting" }] },
|
|
168
|
-
tutorial: { on: { NEXT_STEP: {
|
|
169
|
-
target: "selecting",
|
|
170
|
-
actions: ["setPendingPickerAutoOpen"]
|
|
171
|
-
} } },
|
|
172
|
-
selecting: {
|
|
173
|
-
entry: ["requestPickerIfPending"],
|
|
174
|
-
on: { FILE_PICKED: [
|
|
175
|
-
{
|
|
176
|
-
guard: "isSelectedFileTooLarge",
|
|
177
|
-
target: "fileTooLarge",
|
|
178
|
-
actions: ["clearSelectedFile"]
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
guard: "isSelectedFileMimeInvalid",
|
|
182
|
-
target: "error",
|
|
183
|
-
actions: ["setInvalidFileTypeError"]
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
target: "reviewing",
|
|
187
|
-
actions: ["storeSelectedFile"]
|
|
188
|
-
}
|
|
189
|
-
] }
|
|
190
|
-
},
|
|
191
|
-
fileTooLarge: { on: { CHOOSE_ANOTHER: {
|
|
192
|
-
target: "selecting",
|
|
193
|
-
actions: ["clearSelectedFile", "setPendingPickerAutoOpen"]
|
|
194
|
-
} } },
|
|
195
|
-
reviewing: { on: {
|
|
196
|
-
CONFIRM: {
|
|
197
|
-
target: "uploading",
|
|
198
|
-
guard: "hasSelectedFile"
|
|
199
|
-
},
|
|
200
|
-
REPLACE: {
|
|
201
|
-
target: "selecting",
|
|
202
|
-
actions: ["setPendingPickerAutoOpen"]
|
|
203
|
-
}
|
|
204
|
-
} },
|
|
205
|
-
uploading: {
|
|
206
|
-
invoke: {
|
|
207
|
-
id: "uploadDigitalId",
|
|
208
|
-
src: "uploadDigitalId",
|
|
209
|
-
input: ({ context, self }) => ({
|
|
210
|
-
file: context.file,
|
|
211
|
-
onProgress: (progress) => {
|
|
212
|
-
self.send({
|
|
213
|
-
type: "UPLOAD_PROGRESS",
|
|
214
|
-
progress
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
}),
|
|
218
|
-
onDone: [
|
|
219
|
-
{
|
|
220
|
-
guard: "isTerminalFailReason",
|
|
221
|
-
target: "retriesExhausted",
|
|
222
|
-
actions: ["storeUploadResponse", "setFailReasonFromResponse"]
|
|
223
|
-
},
|
|
224
|
-
{
|
|
225
|
-
guard: "responseHasFailReason",
|
|
226
|
-
target: "checkRetries",
|
|
227
|
-
actions: ["storeUploadResponse", "setFailReasonFromResponse"]
|
|
228
|
-
},
|
|
229
|
-
{
|
|
230
|
-
target: "success",
|
|
231
|
-
actions: ["storeUploadResponse", "setUploadProgressCompleted"]
|
|
232
|
-
}
|
|
233
|
-
],
|
|
234
|
-
onError: {
|
|
235
|
-
target: "checkRetries",
|
|
236
|
-
actions: ["setFailReasonFromNetworkError"]
|
|
237
|
-
}
|
|
238
|
-
},
|
|
239
|
-
initial: "analyzing",
|
|
240
|
-
states: {
|
|
241
|
-
analyzing: { after: { [DIGITAL_UPLOAD_HOLDING_TIMEOUT_MS]: { target: "holding" } } },
|
|
242
|
-
holding: {}
|
|
243
|
-
},
|
|
244
|
-
on: { UPLOAD_PROGRESS: { actions: ["setUploadProgressCapped"] } }
|
|
245
|
-
},
|
|
246
|
-
checkRetries: { always: [
|
|
247
|
-
{
|
|
248
|
-
guard: "isCurrentFailReasonTerminal",
|
|
249
|
-
target: "retriesExhausted"
|
|
250
|
-
},
|
|
251
|
-
{
|
|
252
|
-
guard: "hasAttemptsRemaining",
|
|
253
|
-
target: "error"
|
|
254
|
-
},
|
|
255
|
-
{ target: "retriesExhausted" }
|
|
256
|
-
] },
|
|
257
|
-
error: { on: {
|
|
258
|
-
RETRY: {
|
|
259
|
-
target: "selecting",
|
|
260
|
-
actions: [
|
|
261
|
-
"decrementAttemptOnRetry",
|
|
262
|
-
"setPendingPickerAutoOpen",
|
|
263
|
-
"clearSelectedFile"
|
|
264
|
-
]
|
|
265
|
-
},
|
|
266
|
-
SCAN_INSTEAD: { target: "closed" }
|
|
267
|
-
} },
|
|
268
|
-
retriesExhausted: {
|
|
269
|
-
type: "final",
|
|
270
|
-
entry: assign({ resultType: "exhausted" })
|
|
271
|
-
},
|
|
272
|
-
closed: {
|
|
273
|
-
type: "final",
|
|
274
|
-
entry: assign({ resultType: "closed" })
|
|
275
|
-
},
|
|
276
|
-
success: { on: { NEXT_STEP: { target: "completed" } } },
|
|
277
|
-
completed: {
|
|
278
|
-
type: "final",
|
|
279
|
-
entry: assign({ resultType: "success" })
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
});
|
|
283
|
-
const digitalUploadMachine = _digitalUploadMachine;
|
|
284
|
-
|
|
285
|
-
//#endregion
|
|
286
|
-
//#region src/modules/id/digitalUpload/instrumentation.ts
|
|
287
|
-
const TERMINAL_REASONS = new Set(["DIGITAL_ID_REQUESTED_BUT_OTHER_PROVIDED", "ID_TYPE_UNACCEPTABLE"]);
|
|
288
|
-
function isHoldingState(value) {
|
|
289
|
-
if (value === "holding") return true;
|
|
290
|
-
if (typeof value !== "object" || value === null) return false;
|
|
291
|
-
const uploadingState = value.uploading;
|
|
292
|
-
if (uploadingState === "holding") return true;
|
|
293
|
-
if (typeof uploadingState === "object" && uploadingState !== null) return Object.prototype.hasOwnProperty.call(uploadingState, "holding");
|
|
294
|
-
return false;
|
|
295
|
-
}
|
|
296
|
-
function mapDigitalIdScreenName(value, failReason) {
|
|
297
|
-
if (value === "tutorial") return "uploadDigitalid.tutorial.default";
|
|
298
|
-
if (value === "selecting" || value === "reviewing") return "uploadDigitalid.review.default";
|
|
299
|
-
if (value === "uploading" || isHoldingState(value)) return "uploadDigitalid.analyzing.default";
|
|
300
|
-
if (value === "success") return "uploadDigitalid.success.default";
|
|
301
|
-
if (value === "fileTooLarge") return "uploadDigitalid.error.filetoolarge";
|
|
302
|
-
if (value === "error") {
|
|
303
|
-
if (failReason !== null && TERMINAL_REASONS.has(failReason)) return "uploadDigitalid.error.notaccepted";
|
|
304
|
-
return "uploadDigitalid.error.default";
|
|
305
|
-
}
|
|
306
|
-
return "uploadDigitalid.review.default";
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
//#endregion
|
|
310
|
-
//#region src/modules/id/idCaptureHelpers.ts
|
|
311
|
-
/**
|
|
312
|
-
* Map of config properties received from the backend to adjusted, internal document types.
|
|
313
|
-
*/
|
|
314
|
-
const DOCUMENT_TYPES_CONFIG_TO_ADJUSTED_MAP = [
|
|
315
|
-
["enableId", "id"],
|
|
316
|
-
["enablePassport", "passport"],
|
|
317
|
-
["manualUploadIdCapture", "manualIdUpload"],
|
|
318
|
-
["digitalIdsUpload", "digitalIdUpload"],
|
|
319
|
-
["deviceWallet", "digitalId"]
|
|
320
|
-
];
|
|
321
|
-
/**
|
|
322
|
-
* Returns the list of document types enabled by config for the chooser screen, in display order.
|
|
323
|
-
* Used to populate chooser state so UI and headless consumers can render the correct options.
|
|
324
|
-
*
|
|
325
|
-
* @param config - ID capture configuration (from flow or init)
|
|
326
|
-
* @returns Array of IdDocumentType values that should be shown in the document type chooser
|
|
327
|
-
*/
|
|
328
|
-
function getAvailableDocumentTypes(config) {
|
|
329
|
-
const adjustedDocumentTypes = [];
|
|
330
|
-
for (const [configProperty, adjustedType] of DOCUMENT_TYPES_CONFIG_TO_ADJUSTED_MAP) if (config[configProperty]) adjustedDocumentTypes.push(adjustedType);
|
|
331
|
-
return adjustedDocumentTypes;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
//#endregion
|
|
335
|
-
//#region ../infra/src/providers/wasm/IdCaptureProvider.ts
|
|
336
|
-
var IdCaptureProvider = class extends BaseWasmProvider {
|
|
337
|
-
constructor() {
|
|
338
|
-
super(WasmPipelineType.IdBlurGlarePipeline);
|
|
339
|
-
this.lastProcessResult = null;
|
|
340
|
-
this.capturedCanvas = null;
|
|
341
|
-
this.originalCapturedCanvas = null;
|
|
342
|
-
}
|
|
343
|
-
async initialize(config) {
|
|
344
|
-
await this.initializeBase(config, "idCapture");
|
|
345
|
-
}
|
|
346
|
-
setCallbacks(callbacks) {
|
|
347
|
-
this.ensureInitialized();
|
|
348
|
-
const onCaptureWrapper = () => {
|
|
349
|
-
callbacks.onCapture?.();
|
|
350
|
-
};
|
|
351
|
-
mlWasmJSApi_default.setIdCaptureCallbacks(this.getPipelineType(), callbacks.onFarAway ?? (() => {}), callbacks.onDetectionStarted ?? (() => {}), callbacks.onMaskChange ? (show, mask, top, orientation) => callbacks.onMaskChange?.(show, mask, top, orientation) : () => {}, callbacks.onBlur ?? (() => {}), callbacks.onGlare ?? (() => {}), callbacks.onCapturing ?? (() => {}), callbacks.onCapture ? onCaptureWrapper : () => {}, callbacks.onBestFrame ? (blur, glare, orientation) => callbacks.onBestFrame?.(blur, glare, orientation) : () => {}, callbacks.onIdNotDetected ?? (() => {}), callbacks.onSwitchToManualCapture ?? (() => {}), callbacks.onIdTypeChange ? (idType) => callbacks.onIdTypeChange?.(idType) : () => {}, callbacks.onIdSideChange ? (side) => callbacks.onIdSideChange?.(side) : () => {}, callbacks.onCapturingCounterValueChange ? (value) => callbacks.onCapturingCounterValueChange?.(value) : () => {});
|
|
352
|
-
}
|
|
353
|
-
setThresholds(thresholds) {
|
|
354
|
-
this.ensureInitialized();
|
|
355
|
-
mlWasmJSApi_default.setIdCaptureThresholds(this.getPipelineType(), thresholds.blurThreshold, thresholds.blurChangeThreshold, thresholds.glareThreshold, thresholds.clsThreshold, thresholds.sideThreshold, thresholds.iouThreshold, thresholds.idDetectedTimeout, thresholds.autocaptureTimeout, thresholds.framesAggregationInterval);
|
|
356
|
-
}
|
|
357
|
-
setGeometry(geometry) {
|
|
358
|
-
this.ensureInitialized();
|
|
359
|
-
mlWasmJSApi_default.setIdCaptureGeometryParams(this.getPipelineType(), geometry.areaDown, geometry.areaUp, geometry.areaIOSPassportUp, geometry.areaIOSPassportDown, geometry.widthIOSUp, geometry.widthIOSDown, geometry.widthDown, geometry.widthUp, geometry.windowOuterWidth, geometry.windowOuterHeight, geometry.windowInnerWidth, geometry.windowInnerHeight);
|
|
360
|
-
}
|
|
361
|
-
setSettings(settings) {
|
|
362
|
-
this.ensureInitialized();
|
|
363
|
-
mlWasmJSApi_default.setIdCaptureConfigParams(this.getPipelineType(), settings.isFixedMask, settings.isIPhone14OrHigher, settings.idType, settings.blurCheckEnabled, settings.glareCheckEnabled, settings.faceQualityCheckEnabled, settings.iouCheckEnabled, settings.fpsLimitEnabled);
|
|
364
|
-
}
|
|
365
|
-
setModelType(modelType) {
|
|
366
|
-
this.ensureInitialized();
|
|
367
|
-
let wasmModelType;
|
|
368
|
-
switch (modelType) {
|
|
369
|
-
case "v1":
|
|
370
|
-
wasmModelType = IdCaptureModelType.IdCaptureV1x;
|
|
371
|
-
break;
|
|
372
|
-
case "v2":
|
|
373
|
-
wasmModelType = IdCaptureModelType.IdCaptureV2x;
|
|
374
|
-
break;
|
|
375
|
-
case "v3":
|
|
376
|
-
wasmModelType = IdCaptureModelType.IdCaptureV3x;
|
|
377
|
-
break;
|
|
378
|
-
default: throw new Error(`Unknown model type: ${modelType}`);
|
|
379
|
-
}
|
|
380
|
-
mlWasmJSApi_default.setIdCaptureModelType(this.getPipelineType(), wasmModelType);
|
|
381
|
-
}
|
|
382
|
-
/**
|
|
383
|
-
* Processes a frame through the WASM pipeline and stores the result.
|
|
384
|
-
*/
|
|
385
|
-
async processFrame(image) {
|
|
386
|
-
const result = await this.processFrameWasm(image);
|
|
387
|
-
const pipelineType = this.getPipelineType();
|
|
388
|
-
if (result && pipelineType === WasmPipelineType.IdBlurGlarePipeline) this.lastProcessResult = result;
|
|
389
|
-
else this.lastProcessResult = null;
|
|
390
|
-
}
|
|
391
|
-
/**
|
|
392
|
-
* Gets the last process result from the most recent frame processing.
|
|
393
|
-
* @returns The last process result with quad coordinates, or null if not available
|
|
394
|
-
*/
|
|
395
|
-
getLastProcessResult() {
|
|
396
|
-
return this.lastProcessResult;
|
|
397
|
-
}
|
|
398
|
-
transformPerspective(canvas, frameRect) {
|
|
399
|
-
this.ensureInitialized();
|
|
400
|
-
const originalWidth = canvas.width();
|
|
401
|
-
const originalHeight = canvas.height();
|
|
402
|
-
try {
|
|
403
|
-
const imageData = canvas.getImageData();
|
|
404
|
-
if (!imageData) return canvas;
|
|
405
|
-
const transformedCanvas = mlWasmJSApi_default.IdPerspectiveTransform(imageData, frameRect);
|
|
406
|
-
if (transformedCanvas) {
|
|
407
|
-
const wrappedCanvas = new IncodeCanvas(transformedCanvas);
|
|
408
|
-
const wrappedWidth = wrappedCanvas.width();
|
|
409
|
-
const wrappedHeight = wrappedCanvas.height();
|
|
410
|
-
if (wrappedWidth === originalWidth && wrappedHeight === originalHeight) {
|
|
411
|
-
const croppedCanvas = this.cropCanvasToRect(wrappedCanvas, {
|
|
412
|
-
x: Math.round(frameRect.x),
|
|
413
|
-
y: Math.round(frameRect.y),
|
|
414
|
-
w: Math.round(frameRect.w),
|
|
415
|
-
h: Math.round(frameRect.h)
|
|
416
|
-
});
|
|
417
|
-
if (croppedCanvas) return croppedCanvas;
|
|
418
|
-
}
|
|
419
|
-
return wrappedCanvas;
|
|
420
|
-
}
|
|
421
|
-
return canvas;
|
|
422
|
-
} catch (_error) {
|
|
423
|
-
return canvas;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
/**
|
|
427
|
-
* Crops a canvas to the specified rectangle region.
|
|
428
|
-
* @param canvas - The canvas to crop
|
|
429
|
-
* @param rect - The rectangle to crop to (x, y, w, h)
|
|
430
|
-
* @returns A new IncodeCanvas with the cropped region, or null if cropping fails
|
|
431
|
-
*/
|
|
432
|
-
cropCanvasToRect(canvas, rect) {
|
|
433
|
-
const canvasWidth = canvas.width();
|
|
434
|
-
const canvasHeight = canvas.height();
|
|
435
|
-
if (!canvasWidth || !canvasHeight) return null;
|
|
436
|
-
const x = Math.max(0, Math.min(rect.x, canvasWidth));
|
|
437
|
-
const y = Math.max(0, Math.min(rect.y, canvasHeight));
|
|
438
|
-
const w = Math.max(1, Math.min(rect.w, canvasWidth - x));
|
|
439
|
-
const h = Math.max(1, Math.min(rect.h, canvasHeight - y));
|
|
440
|
-
const croppedCanvasElement = document.createElement("canvas");
|
|
441
|
-
croppedCanvasElement.width = w;
|
|
442
|
-
croppedCanvasElement.height = h;
|
|
443
|
-
const ctx = croppedCanvasElement.getContext("2d");
|
|
444
|
-
if (!ctx) return null;
|
|
445
|
-
ctx.drawImage(canvas.canvas, x, y, w, h, 0, 0, w, h);
|
|
446
|
-
return new IncodeCanvas(croppedCanvasElement);
|
|
447
|
-
}
|
|
448
|
-
/**
|
|
449
|
-
* Gets the captured canvas (transformed for preview).
|
|
450
|
-
* @returns The captured canvas, or null if not available
|
|
451
|
-
*/
|
|
452
|
-
getCapturedCanvas() {
|
|
453
|
-
return this.capturedCanvas;
|
|
454
|
-
}
|
|
455
|
-
/**
|
|
456
|
-
* Gets the original captured canvas (full frame for upload).
|
|
457
|
-
* @returns The original captured canvas, or null if not available
|
|
458
|
-
*/
|
|
459
|
-
getOriginalCapturedCanvas() {
|
|
460
|
-
return this.originalCapturedCanvas;
|
|
461
|
-
}
|
|
462
|
-
/**
|
|
463
|
-
* Sets the captured canvases (original and transformed).
|
|
464
|
-
* @param original - The original full-frame canvas (for upload)
|
|
465
|
-
* @param transformed - The transformed canvas (for preview)
|
|
466
|
-
*/
|
|
467
|
-
setCapturedCanvases(original, transformed) {
|
|
468
|
-
this.originalCapturedCanvas = original;
|
|
469
|
-
this.capturedCanvas = transformed;
|
|
470
|
-
}
|
|
471
|
-
reset() {
|
|
472
|
-
super.reset();
|
|
473
|
-
this.lastProcessResult = null;
|
|
474
|
-
this.capturedCanvas = null;
|
|
475
|
-
this.originalCapturedCanvas = null;
|
|
476
|
-
}
|
|
477
|
-
};
|
|
478
|
-
|
|
479
|
-
//#endregion
|
|
480
|
-
//#region src/internal/analytics/deviceStats.ts
|
|
481
|
-
async function postDeviceStats(stats) {
|
|
482
|
-
try {
|
|
483
|
-
await api.post(endpoints.deviceStats, stats);
|
|
484
|
-
} catch {}
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
//#endregion
|
|
488
|
-
//#region src/modules/id/idCameraStream.ts
|
|
489
|
-
async function getIdCameraStream(deviceId) {
|
|
490
|
-
return getBackCameraStream(deviceId);
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
//#endregion
|
|
494
|
-
//#region src/modules/id/manualUpload/types.ts
|
|
495
|
-
const MANUAL_UPLOAD_MAX_RETRIES = 3;
|
|
496
|
-
const MANUAL_UPLOAD_MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;
|
|
497
|
-
const MANUAL_UPLOAD_EXHAUSTION_FORWARD_MS = 5e3;
|
|
498
|
-
|
|
499
|
-
//#endregion
|
|
500
|
-
//#region src/modules/id/types.ts
|
|
501
|
-
const ID_ERROR_CODES = {
|
|
502
|
-
UPLOAD_ERROR: "UPLOAD_ERROR",
|
|
503
|
-
CLASSIFICATION_FAILED: "CLASSIFICATION_FAILED",
|
|
504
|
-
LOW_SHARPNESS: "LOW_SHARPNESS",
|
|
505
|
-
GLARE_DETECTED: "GLARE_DETECTED",
|
|
506
|
-
WRONG_DOCUMENT_SIDE: "WRONG_DOCUMENT_SIDE",
|
|
507
|
-
ID_TYPE_UNACCEPTABLE: "ID_TYPE_UNACCEPTABLE",
|
|
508
|
-
READABILITY_ISSUE: "READABILITY_ISSUE",
|
|
509
|
-
RETRY_EXHAUSTED_CONTINUE_TO_BACK: "RETRY_EXHAUSTED_CONTINUE_TO_BACK",
|
|
510
|
-
RETRY_EXHAUSTED_SKIP_BACK: "RETRY_EXHAUSTED_SKIP_BACK",
|
|
511
|
-
NO_MORE_TRIES: "NO_MORE_TRIES",
|
|
512
|
-
UNEXPECTED_ERROR: "UNEXPECTED_ERROR",
|
|
513
|
-
NO_TOKEN: "NO_TOKEN",
|
|
514
|
-
PERMISSION_DENIED: "PERMISSION_DENIED",
|
|
515
|
-
USER_CANCELLED: "USER_CANCELLED",
|
|
516
|
-
SERVER: "SERVER_ERROR"
|
|
517
|
-
};
|
|
518
|
-
|
|
519
|
-
//#endregion
|
|
520
|
-
//#region src/modules/id/idCaptureServices.ts
|
|
521
|
-
/**
|
|
522
|
-
* Camera constraints used for PRC warmup before ID capture.
|
|
523
|
-
* Uses environment-facing camera on mobile devices (for back camera ID capture)
|
|
524
|
-
* and user-facing camera on desktop.
|
|
525
|
-
*/
|
|
526
|
-
function getPrcCameraConstraints() {
|
|
527
|
-
if (isDesktop()) return { video: {
|
|
528
|
-
facingMode: "user",
|
|
529
|
-
height: { ideal: 480 },
|
|
530
|
-
width: { ideal: 640 }
|
|
531
|
-
} };
|
|
532
|
-
return { video: {
|
|
533
|
-
facingMode: "environment",
|
|
534
|
-
height: { ideal: 720 }
|
|
535
|
-
} };
|
|
536
|
-
}
|
|
537
|
-
function getUploadEndpoint(type, isSecondId) {
|
|
538
|
-
if (isSecondId) return type === "front" ? endpoints.frontSecondId : endpoints.backSecondId;
|
|
539
|
-
return type === "front" ? endpoints.frontId : endpoints.backId;
|
|
540
|
-
}
|
|
541
|
-
const SHARPNESS_THRESHOLD = 10;
|
|
542
|
-
const GLARE_THRESHOLD = 10;
|
|
543
|
-
const DEFAULT_ID_CAPTURE_THRESHOLDS$1 = {
|
|
544
|
-
blurThreshold: .2,
|
|
545
|
-
blurChangeThreshold: .2,
|
|
546
|
-
glareThreshold: .3,
|
|
547
|
-
clsThreshold: .98,
|
|
548
|
-
sideThreshold: .8,
|
|
549
|
-
iouThreshold: .8,
|
|
550
|
-
framesAggregationInterval: 3e3
|
|
551
|
-
};
|
|
552
|
-
const DEFAULT_ID_CAPTURE_SETTINGS = {
|
|
553
|
-
isFixedMask: false,
|
|
554
|
-
isIPhone14OrHigher: false,
|
|
555
|
-
idType: "",
|
|
556
|
-
blurCheckEnabled: false,
|
|
557
|
-
glareCheckEnabled: false,
|
|
558
|
-
faceQualityCheckEnabled: true,
|
|
559
|
-
iouCheckEnabled: true,
|
|
560
|
-
fpsLimitEnabled: false
|
|
561
|
-
};
|
|
562
|
-
async function initializeIdCapture(params) {
|
|
563
|
-
const { config, deepsightService } = params;
|
|
564
|
-
const provider = new IdCaptureProvider();
|
|
565
|
-
await provider.initialize({});
|
|
566
|
-
provider.setThresholds({
|
|
567
|
-
...DEFAULT_ID_CAPTURE_THRESHOLDS$1,
|
|
568
|
-
...config.thresholds,
|
|
569
|
-
idDetectedTimeout: config.thresholds?.idDetectedTimeout ?? config.deviceIdleTimeout * 1e3,
|
|
570
|
-
autocaptureTimeout: config.thresholds?.autocaptureTimeout ?? config.autoCaptureTimeout * 1e3
|
|
571
|
-
});
|
|
572
|
-
if (config.settings) provider.setSettings({
|
|
573
|
-
...DEFAULT_ID_CAPTURE_SETTINGS,
|
|
574
|
-
...config.settings
|
|
575
|
-
});
|
|
576
|
-
if (deepsightService) try {
|
|
577
|
-
await deepsightService.performPrcCheck({ constraints: getPrcCameraConstraints() });
|
|
578
|
-
} catch {}
|
|
579
|
-
const { stream, fallbackLevel } = await getIdCameraStream();
|
|
580
|
-
const videoTrack = stream.getVideoTracks()[0];
|
|
581
|
-
let captureResolution;
|
|
582
|
-
if (videoTrack) {
|
|
583
|
-
const settings = videoTrack.getSettings();
|
|
584
|
-
if (typeof settings.width === "number" && typeof settings.height === "number") captureResolution = `${settings.width}x${settings.height}`;
|
|
585
|
-
}
|
|
586
|
-
if (deepsightService && videoTrack) deepsightService.metadata.updateCameraInfo(videoTrack);
|
|
587
|
-
return {
|
|
588
|
-
stream,
|
|
589
|
-
provider,
|
|
590
|
-
captureResolution,
|
|
591
|
-
cameraFallbackLevel: fallbackLevel
|
|
592
|
-
};
|
|
593
|
-
}
|
|
594
|
-
function stopStream(stream) {
|
|
595
|
-
for (const track of stream.getTracks()) track.stop();
|
|
596
|
-
}
|
|
597
|
-
function validateUploadResponse(response, sessionState) {
|
|
598
|
-
if (response.failReason === "ID_TYPE_UNACCEPTABLE") return {
|
|
599
|
-
error: true,
|
|
600
|
-
message: "ID type is not acceptable",
|
|
601
|
-
messageDescription: "Please use a valid ID type",
|
|
602
|
-
errorKey: ID_ERROR_CODES.ID_TYPE_UNACCEPTABLE
|
|
603
|
-
};
|
|
604
|
-
if (response.failReason === "WRONG_DOCUMENT_SIDE") return {
|
|
605
|
-
error: true,
|
|
606
|
-
message: "Wrong side of document",
|
|
607
|
-
messageDescription: response.side === "back" ? "Please show the back side of your ID" : "Please show the front side of your ID",
|
|
608
|
-
errorKey: ID_ERROR_CODES.WRONG_DOCUMENT_SIDE
|
|
609
|
-
};
|
|
610
|
-
if (!response.classification) return {
|
|
611
|
-
error: true,
|
|
612
|
-
message: "ID classification failed",
|
|
613
|
-
errorKey: ID_ERROR_CODES.CLASSIFICATION_FAILED
|
|
614
|
-
};
|
|
615
|
-
const sharpnessThreshold = getDeviceClass() === "desktop" ? -1 : SHARPNESS_THRESHOLD;
|
|
616
|
-
if (response.sharpness !== void 0 && sharpnessThreshold >= 0 && response.sharpness < sharpnessThreshold) return {
|
|
617
|
-
error: true,
|
|
618
|
-
message: "Image is not sharp enough",
|
|
619
|
-
messageDescription: "Please ensure the image is clear and well-focused",
|
|
620
|
-
errorKey: ID_ERROR_CODES.LOW_SHARPNESS
|
|
621
|
-
};
|
|
622
|
-
if (response.glare !== void 0 && response.glare < GLARE_THRESHOLD && !sessionState?.skipGlareFront && !sessionState?.skipGlareBack) return {
|
|
623
|
-
error: true,
|
|
624
|
-
message: "Glare detected on ID",
|
|
625
|
-
messageDescription: "Please avoid bright reflections on your ID",
|
|
626
|
-
errorKey: ID_ERROR_CODES.GLARE_DETECTED
|
|
627
|
-
};
|
|
628
|
-
}
|
|
629
|
-
async function getExtraImages(params) {
|
|
630
|
-
const extraImages = params.ageAssurance ? [params.type === "back" ? "croppedBackID" : "croppedFrontID"] : [];
|
|
631
|
-
try {
|
|
632
|
-
const res = await api.post(endpoints.getImages, { images: ["croppedIDFace", ...extraImages] }, { signal: params.signal });
|
|
633
|
-
if (!res.ok) throw new Error(`Failed to get extra images: ${res.status}`);
|
|
634
|
-
return res.data ?? {
|
|
635
|
-
croppedIDFace: "",
|
|
636
|
-
croppedFrontID: "",
|
|
637
|
-
croppedBackID: ""
|
|
638
|
-
};
|
|
639
|
-
} catch {
|
|
640
|
-
return {
|
|
641
|
-
croppedIDFace: "",
|
|
642
|
-
croppedFrontID: "",
|
|
643
|
-
croppedBackID: ""
|
|
644
|
-
};
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
const getRealQualityValue = (value) => (1 - value) * 100;
|
|
648
|
-
async function uploadIdImage(params) {
|
|
649
|
-
const { type, image, onProgress, signal, metadata, ageAssurance, glare, sharpness, shouldSkipGlareBack, analyticsProvider, imageData, isSecondId, onlyFront } = params;
|
|
650
|
-
let finalMetadata = metadata;
|
|
651
|
-
if (analyticsProvider && imageData) try {
|
|
652
|
-
await analyticsProvider.analyzeFrame(imageData);
|
|
653
|
-
analyticsProvider.update();
|
|
654
|
-
const analysisStatus = analyticsProvider.getAnalysisStatus();
|
|
655
|
-
const motionStatus = analyticsProvider.getMotionStatus();
|
|
656
|
-
await postDeviceStats({
|
|
657
|
-
frontIdStatsAnalysisStatus: type === "front" ? analysisStatus : void 0,
|
|
658
|
-
backIdStatsAnalysisStatus: type === "back" ? analysisStatus : void 0,
|
|
659
|
-
motionStatus
|
|
660
|
-
});
|
|
661
|
-
finalMetadata = analyticsProvider.getMetadata();
|
|
662
|
-
} catch (error) {
|
|
663
|
-
console.warn("[IdCapture] Analytics failed:", error);
|
|
664
|
-
}
|
|
665
|
-
const endpoint = getUploadEndpoint(type, isSecondId);
|
|
666
|
-
const body = {
|
|
667
|
-
base64Image: image,
|
|
668
|
-
metadata: finalMetadata
|
|
669
|
-
};
|
|
670
|
-
const queryParams = { imageType: "id" };
|
|
671
|
-
if (onlyFront && type === "front") queryParams.onlyFront = true;
|
|
672
|
-
if (shouldSkipGlareBack && type === "back") queryParams.glare = 0;
|
|
673
|
-
else if (glare !== void 0) queryParams.glare = getRealQualityValue(glare);
|
|
674
|
-
if (sharpness !== void 0) queryParams.sharpness = getRealQualityValue(sharpness);
|
|
675
|
-
try {
|
|
676
|
-
const res = await api.post(endpoint, body, {
|
|
677
|
-
signal,
|
|
678
|
-
query: queryParams,
|
|
679
|
-
onUploadProgress: onProgress
|
|
680
|
-
});
|
|
681
|
-
if (!res.ok) throw new Error(`POST ${endpoint} failed: ${res.status} ${res.statusText}`);
|
|
682
|
-
const response = res.data;
|
|
683
|
-
const extraImages = await getExtraImages({
|
|
684
|
-
type,
|
|
685
|
-
ageAssurance,
|
|
686
|
-
signal
|
|
687
|
-
});
|
|
688
|
-
const fullResponse = {
|
|
689
|
-
...response,
|
|
690
|
-
originalImage: image,
|
|
691
|
-
frontIdImage: type === "front" ? image : void 0,
|
|
692
|
-
backIdImage: extraImages.croppedBackID,
|
|
693
|
-
...extraImages
|
|
694
|
-
};
|
|
695
|
-
onProgress?.(100);
|
|
696
|
-
return fullResponse;
|
|
697
|
-
} catch (error) {
|
|
698
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
699
|
-
throw new Error(`${ID_ERROR_CODES.UPLOAD_ERROR}: ${errorMessage}`);
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
function buildStandardResolution(width, height) {
|
|
703
|
-
return height > width ? {
|
|
704
|
-
width: 1080,
|
|
705
|
-
height: 1920
|
|
706
|
-
} : {
|
|
707
|
-
width: 1920,
|
|
708
|
-
height: 1080
|
|
709
|
-
};
|
|
710
|
-
}
|
|
711
|
-
function buildResolutionFromStream(stream) {
|
|
712
|
-
const track = stream.getVideoTracks()[0];
|
|
713
|
-
if (!track) return "1080x1920";
|
|
714
|
-
const settings = track.getSettings();
|
|
715
|
-
const width = settings.width;
|
|
716
|
-
const height = settings.height;
|
|
717
|
-
if (typeof width === "number" && typeof height === "number") {
|
|
718
|
-
const standard = buildStandardResolution(width, height);
|
|
719
|
-
return `${standard.width}x${standard.height}`;
|
|
720
|
-
}
|
|
721
|
-
return "1080x1920";
|
|
722
|
-
}
|
|
723
|
-
function preloadIdRecordingProvider(config) {
|
|
724
|
-
if (config.enableIdRecording !== true) return;
|
|
725
|
-
preloadOpenViduProvider();
|
|
726
|
-
}
|
|
727
|
-
async function createOpenViduRecordingProvider() {
|
|
728
|
-
const { OpenViduRecordingProvider } = await import("./OpenViduRecordingProvider-CMu6XVdc.esm.js");
|
|
729
|
-
return new OpenViduRecordingProvider();
|
|
730
|
-
}
|
|
731
|
-
async function startRecordingSession(params) {
|
|
732
|
-
if (params.config.enableIdRecording !== true) return;
|
|
733
|
-
if (params.existing) return params.existing;
|
|
734
|
-
const provider = params.config.recording?.capability ?? await createOpenViduRecordingProvider();
|
|
735
|
-
const clonedStream = params.stream.clone();
|
|
736
|
-
const hasAudio = clonedStream.getAudioTracks().length > 0;
|
|
737
|
-
const resolution = buildResolutionFromStream(clonedStream);
|
|
738
|
-
const session = await createRecordingSession(params.type);
|
|
739
|
-
const connection = await provider.connect({
|
|
740
|
-
sessionToken: session.token,
|
|
741
|
-
stream: clonedStream,
|
|
742
|
-
events: {}
|
|
743
|
-
});
|
|
744
|
-
await startRecording({
|
|
745
|
-
videoRecordingId: session.videoRecordingId,
|
|
746
|
-
type: params.type,
|
|
747
|
-
resolution,
|
|
748
|
-
hasAudio
|
|
749
|
-
});
|
|
750
|
-
return {
|
|
751
|
-
token: session.token,
|
|
752
|
-
sessionId: session.sessionId,
|
|
753
|
-
videoRecordingId: session.videoRecordingId,
|
|
754
|
-
connection,
|
|
755
|
-
resolution,
|
|
756
|
-
hasAudio
|
|
757
|
-
};
|
|
758
|
-
}
|
|
759
|
-
function stopRecording(session) {
|
|
760
|
-
(async () => {
|
|
761
|
-
try {
|
|
762
|
-
await stopRecording$1(session.videoRecordingId);
|
|
763
|
-
} finally {
|
|
764
|
-
await session.connection.disconnect();
|
|
765
|
-
}
|
|
766
|
-
})();
|
|
767
|
-
}
|
|
768
|
-
async function processId(isSecondId = false, queueName = "", signal) {
|
|
769
|
-
const endpoint = isSecondId ? endpoints.processSecondId : endpoints.processId;
|
|
770
|
-
const url = queueName ? `${endpoint}?queueName=${queueName}` : endpoint;
|
|
771
|
-
return { isDocumentExpired: (await api.post(url, {}, { signal })).data?.isDocumentExpired ?? false };
|
|
772
|
-
}
|
|
773
|
-
/**
|
|
774
|
-
* Upload a user-selected image as front / back / passport ID.
|
|
775
|
-
*
|
|
776
|
-
* Uses the same request shape as the live-camera path (`uploadIdImage`):
|
|
777
|
-
* JSON body `{ base64Image }` with default application/json Content-Type,
|
|
778
|
-
* `captureType=UPLOAD` query param, `retry=true` when retrying.
|
|
779
|
-
* Back is POSTed to `/omni/add/back-id/v2` (or `/omni/add/back-second-id/v2`
|
|
780
|
-
* when `isSecondId`); front and passport go to `/omni/add/front-id/v2` (or
|
|
781
|
-
* `/omni/add/front-second-id/v2` when `isSecondId`).
|
|
782
|
-
*
|
|
783
|
-
* The v2 endpoints reject raw `image/jpeg` bodies with 415, so the caller
|
|
784
|
-
* must convert the File to base64 before calling this service.
|
|
785
|
-
*/
|
|
786
|
-
async function uploadManualIdFile(params) {
|
|
787
|
-
const { side, base64Image, retry, onlyFront, signal, isSecondId } = params;
|
|
788
|
-
const endpoint = getUploadEndpoint(side === "back" ? "back" : "front", isSecondId);
|
|
789
|
-
const queryParams = { captureType: "UPLOAD" };
|
|
790
|
-
if (retry) queryParams.retry = true;
|
|
791
|
-
if (onlyFront && side === "front") queryParams.onlyFront = true;
|
|
792
|
-
const res = await api.post(endpoint, { base64Image }, {
|
|
793
|
-
signal,
|
|
794
|
-
query: queryParams
|
|
795
|
-
});
|
|
796
|
-
if (!res.ok) throw new Error(`POST ${endpoint} failed: ${res.status} ${res.statusText}`);
|
|
797
|
-
return res.data;
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
//#endregion
|
|
801
|
-
//#region src/modules/id/manualUpload/manualUploadErrors.ts
|
|
802
|
-
/**
|
|
803
|
-
* i18n keys for manual-upload user-facing error copy.
|
|
804
|
-
* Keep in sync with `packages/ui/src/i18n/**.json` under the `manualIdUpload.*` namespace.
|
|
805
|
-
*/
|
|
806
|
-
const MANUAL_UPLOAD_ERROR_KEYS = {
|
|
807
|
-
wrongSide: "manualIdUpload.wrongSide",
|
|
808
|
-
wrongDocument: "manualIdUpload.wrongDocument",
|
|
809
|
-
fileTooBig: "manualIdUpload.fileTooBig",
|
|
810
|
-
generic: "manualIdUpload.generic",
|
|
811
|
-
lowSharpness: "manualIdUpload.lowSharpness",
|
|
812
|
-
glareDetected: "manualIdUpload.glareDetected",
|
|
813
|
-
readabilityIssue: "manualIdUpload.readabilityIssue",
|
|
814
|
-
qualityRejected: "manualIdUpload.qualityRejected"
|
|
815
|
-
};
|
|
816
|
-
/**
|
|
817
|
-
* Map the server's `failReason` (plus client-side passport/ID tab mismatch and
|
|
818
|
-
* per-image quality flags) onto an i18n key. Mirrors v1's `shouldUploadAgain`
|
|
819
|
-
* branch logic in
|
|
820
|
-
* `ms-incodesmile-web/packages/incode-welcome/src/manualIdUpload/manuaIdUpload.tsx`,
|
|
821
|
-
* extended to also reject responses where the backend flagged a per-image
|
|
822
|
-
* quality issue (`correctSharpness`, `correctGlare`, `readability`, or
|
|
823
|
-
* `idQualityAttemptApproved` set to `false`).
|
|
824
|
-
*
|
|
825
|
-
* Quality flags are checked with `=== false` so missing/undefined values
|
|
826
|
-
* (older backends, partial payloads) keep the legacy "trust the server"
|
|
827
|
-
* behaviour and do not produce false positives.
|
|
828
|
-
*
|
|
829
|
-
* Returns `null` when the response represents a successful upload — the caller
|
|
830
|
-
* should treat `null` as "no error, advance to next slot".
|
|
831
|
-
*/
|
|
832
|
-
function mapFailReasonToErrorKey(response, expectedTab) {
|
|
833
|
-
const failReason = response.failReason;
|
|
834
|
-
if (failReason === "WRONG_DOCUMENT_SIDE") return MANUAL_UPLOAD_ERROR_KEYS.wrongSide;
|
|
835
|
-
if (failReason === "WRONG_ONE_SIDED_DOCUMENT" || failReason === "UNKNOWN_DOCUMENT_TYPE") return MANUAL_UPLOAD_ERROR_KEYS.wrongDocument;
|
|
836
|
-
if (failReason === "ID_TYPE_UNACCEPTABLE") return MANUAL_UPLOAD_ERROR_KEYS.wrongDocument;
|
|
837
|
-
if (expectedTab === "passport" && response.typeOfId && response.typeOfId.toLowerCase() !== "passport") return MANUAL_UPLOAD_ERROR_KEYS.wrongDocument;
|
|
838
|
-
if (expectedTab === "id" && response.typeOfId?.toLowerCase() === "passport") return MANUAL_UPLOAD_ERROR_KEYS.wrongDocument;
|
|
839
|
-
if (response.correctSharpness === false) return MANUAL_UPLOAD_ERROR_KEYS.lowSharpness;
|
|
840
|
-
if (response.correctGlare === false) return MANUAL_UPLOAD_ERROR_KEYS.glareDetected;
|
|
841
|
-
if (response.readability === false) return MANUAL_UPLOAD_ERROR_KEYS.readabilityIssue;
|
|
842
|
-
if (response.idQualityAttemptApproved === false) return MANUAL_UPLOAD_ERROR_KEYS.qualityRejected;
|
|
843
|
-
return null;
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
//#endregion
|
|
847
|
-
//#region src/modules/id/manualUpload/manualUploadServices.ts
|
|
848
|
-
/**
|
|
849
|
-
* Read a File's bytes and return the raw base64 payload (the portion after
|
|
850
|
-
* `data:<mime>;base64,`). The backend's `/omni/add/*-id/v2` endpoints reject
|
|
851
|
-
* full data-URLs with `IllegalArgumentException: Illegal base64 character 3a`,
|
|
852
|
-
* so the prefix must be stripped before posting. Mirrors the live-camera
|
|
853
|
-
* path in `packages/infra/src/media/canvas.ts:getBase64Image()`.
|
|
854
|
-
*/
|
|
855
|
-
function fileToBase64Payload(file) {
|
|
856
|
-
return new Promise((resolve, reject) => {
|
|
857
|
-
const reader = new FileReader();
|
|
858
|
-
reader.onload = () => {
|
|
859
|
-
const result = reader.result;
|
|
860
|
-
if (typeof result !== "string") {
|
|
861
|
-
reject(/* @__PURE__ */ new Error("FileReader produced non-string result"));
|
|
862
|
-
return;
|
|
863
|
-
}
|
|
864
|
-
const commaIndex = result.indexOf(",");
|
|
865
|
-
resolve(commaIndex === -1 ? result : result.slice(commaIndex + 1));
|
|
866
|
-
};
|
|
867
|
-
reader.onerror = () => {
|
|
868
|
-
reject(reader.error ?? /* @__PURE__ */ new Error("FileReader failed"));
|
|
869
|
-
};
|
|
870
|
-
reader.readAsDataURL(file);
|
|
871
|
-
});
|
|
872
|
-
}
|
|
873
|
-
|
|
874
|
-
//#endregion
|
|
875
|
-
//#region src/modules/id/manualUpload/manualUploadStateMachine.ts
|
|
876
|
-
const uploadManualFileActor = fromPromise(async ({ input, signal }) => {
|
|
877
|
-
const base64Image = await fileToBase64Payload(input.file);
|
|
878
|
-
return uploadManualIdFile({
|
|
879
|
-
side: input.side,
|
|
880
|
-
base64Image,
|
|
881
|
-
retry: input.retry,
|
|
882
|
-
onlyFront: input.onlyFront,
|
|
883
|
-
isSecondId: input.isSecondId,
|
|
884
|
-
signal
|
|
885
|
-
});
|
|
886
|
-
});
|
|
887
|
-
const getUploadResponseFromEvent = (event) => {
|
|
888
|
-
if ("output" in event) return event.output;
|
|
889
|
-
};
|
|
890
|
-
const _manualUploadMachine = setup({
|
|
891
|
-
types: {
|
|
892
|
-
context: {},
|
|
893
|
-
events: {},
|
|
894
|
-
input: {},
|
|
895
|
-
output: {}
|
|
896
|
-
},
|
|
897
|
-
actors: { uploadManualFile: uploadManualFileActor },
|
|
898
|
-
actions: {
|
|
899
|
-
setManualUploadActiveTab: assign(({ context, event }) => {
|
|
900
|
-
if (event.type !== "MANUAL_UPLOAD_TAB_CHANGED") return {};
|
|
901
|
-
return {
|
|
902
|
-
activeTab: event.tab,
|
|
903
|
-
frontFile: null,
|
|
904
|
-
backFile: null,
|
|
905
|
-
passportFile: null,
|
|
906
|
-
frontUploaded: false,
|
|
907
|
-
backUploaded: false,
|
|
908
|
-
passportUploaded: false,
|
|
909
|
-
skipBackFromServer: false,
|
|
910
|
-
errorMessage: null,
|
|
911
|
-
retriesLeft: context.captureAttempts
|
|
912
|
-
};
|
|
913
|
-
}),
|
|
914
|
-
resetManualUpload: assign(({ context }) => ({
|
|
915
|
-
frontFile: null,
|
|
916
|
-
backFile: null,
|
|
917
|
-
passportFile: null,
|
|
918
|
-
frontUploaded: false,
|
|
919
|
-
backUploaded: false,
|
|
920
|
-
passportUploaded: false,
|
|
921
|
-
skipBackFromServer: false,
|
|
922
|
-
errorMessage: null,
|
|
923
|
-
retriesLeft: context.captureAttempts
|
|
924
|
-
})),
|
|
925
|
-
storeSelectedFile: assign(({ event }) => {
|
|
926
|
-
if (event.type !== "MANUAL_UPLOAD_FILE_SELECTED") return {};
|
|
927
|
-
const updated = { errorMessage: null };
|
|
928
|
-
if (event.side === "front") updated.frontFile = event.file;
|
|
929
|
-
else if (event.side === "back") updated.backFile = event.file;
|
|
930
|
-
else updated.passportFile = event.file;
|
|
931
|
-
return updated;
|
|
932
|
-
}),
|
|
933
|
-
markFrontUploaded: assign(() => ({
|
|
934
|
-
frontUploaded: true,
|
|
935
|
-
errorMessage: null
|
|
936
|
-
})),
|
|
937
|
-
markBackUploaded: assign(() => ({
|
|
938
|
-
backUploaded: true,
|
|
939
|
-
errorMessage: null
|
|
940
|
-
})),
|
|
941
|
-
markPassportUploaded: assign(() => ({
|
|
942
|
-
passportUploaded: true,
|
|
943
|
-
errorMessage: null
|
|
944
|
-
})),
|
|
945
|
-
recordSkipBackFromResponse: assign(({ event }) => {
|
|
946
|
-
if (!("output" in event)) return {};
|
|
947
|
-
if (!event.output.skipBackIdCapture) return {};
|
|
948
|
-
return { skipBackFromServer: true };
|
|
949
|
-
}),
|
|
950
|
-
decrementManualUploadRetries: assign(({ context }) => ({ retriesLeft: Math.max(0, context.retriesLeft - 1) })),
|
|
951
|
-
setManualUploadErrorFromResponse: assign(({ context, event }) => {
|
|
952
|
-
if (!("output" in event)) return {};
|
|
953
|
-
const response = event.output;
|
|
954
|
-
return { errorMessage: mapFailReasonToErrorKey(response, context.activeTab) ?? "manualIdUpload.generic" };
|
|
955
|
-
}),
|
|
956
|
-
setManualUploadGenericError: assign(() => ({ errorMessage: "manualIdUpload.generic" })),
|
|
957
|
-
setManualUploadFileTooLargeError: assign(() => ({ errorMessage: "manualIdUpload.fileTooBig" })),
|
|
958
|
-
clearManualUploadError: assign(() => ({ errorMessage: null }))
|
|
959
|
-
},
|
|
960
|
-
guards: {
|
|
961
|
-
isSelectedFileTooLarge: ({ event }) => {
|
|
962
|
-
if (event.type !== "MANUAL_UPLOAD_FILE_SELECTED") return false;
|
|
963
|
-
return event.file.size > MANUAL_UPLOAD_MAX_FILE_SIZE_BYTES;
|
|
964
|
-
},
|
|
965
|
-
isFrontFileSelection: ({ event }) => event.type === "MANUAL_UPLOAD_FILE_SELECTED" && event.side === "front",
|
|
966
|
-
isBackFileSelection: ({ event }) => event.type === "MANUAL_UPLOAD_FILE_SELECTED" && event.side === "back",
|
|
967
|
-
isPassportFileSelection: ({ event }) => event.type === "MANUAL_UPLOAD_FILE_SELECTED" && event.side === "passport",
|
|
968
|
-
manualUploadRetriesExhausted: ({ context }) => context.retriesLeft <= 0,
|
|
969
|
-
canContinueFromIdTab: ({ context }) => {
|
|
970
|
-
if (context.activeTab !== "id") return false;
|
|
971
|
-
if (!context.frontUploaded) return false;
|
|
972
|
-
if (context.onlyFront) return true;
|
|
973
|
-
if (context.skipBackFromServer) return true;
|
|
974
|
-
return context.backUploaded;
|
|
975
|
-
},
|
|
976
|
-
canContinueFromPassportTab: ({ context }) => context.activeTab === "passport" && context.passportUploaded,
|
|
977
|
-
manualUploadResponseHasError: ({ context, event }) => {
|
|
978
|
-
const response = getUploadResponseFromEvent(event);
|
|
979
|
-
if (!response) return false;
|
|
980
|
-
return mapFailReasonToErrorKey(response, context.activeTab) !== null;
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
}).createMachine({
|
|
984
|
-
id: "manualUpload",
|
|
985
|
-
initial: "selecting",
|
|
986
|
-
context: ({ input }) => ({
|
|
987
|
-
onlyFront: input.onlyFront,
|
|
988
|
-
isSecondId: input.isSecondId,
|
|
989
|
-
captureAttempts: input.captureAttempts,
|
|
990
|
-
frontFile: null,
|
|
991
|
-
backFile: null,
|
|
992
|
-
passportFile: null,
|
|
993
|
-
activeTab: "id",
|
|
994
|
-
retriesLeft: input.captureAttempts,
|
|
995
|
-
errorMessage: null,
|
|
996
|
-
skipBackFromServer: false,
|
|
997
|
-
frontUploaded: false,
|
|
998
|
-
backUploaded: false,
|
|
999
|
-
passportUploaded: false
|
|
1000
|
-
}),
|
|
1001
|
-
on: {
|
|
1002
|
-
MANUAL_UPLOAD_TAB_CHANGED: {
|
|
1003
|
-
target: ".selecting",
|
|
1004
|
-
actions: ["setManualUploadActiveTab"]
|
|
1005
|
-
},
|
|
1006
|
-
MANUAL_UPLOAD_RESET: {
|
|
1007
|
-
target: ".selecting",
|
|
1008
|
-
actions: ["resetManualUpload"]
|
|
1009
|
-
}
|
|
1010
|
-
},
|
|
1011
|
-
states: {
|
|
1012
|
-
selecting: { on: {
|
|
1013
|
-
MANUAL_UPLOAD_FILE_SELECTED: [
|
|
1014
|
-
{
|
|
1015
|
-
guard: "isSelectedFileTooLarge",
|
|
1016
|
-
actions: ["setManualUploadFileTooLargeError"]
|
|
1017
|
-
},
|
|
1018
|
-
{
|
|
1019
|
-
guard: "isFrontFileSelection",
|
|
1020
|
-
target: "uploadingFront",
|
|
1021
|
-
actions: ["storeSelectedFile"]
|
|
1022
|
-
},
|
|
1023
|
-
{
|
|
1024
|
-
guard: "isBackFileSelection",
|
|
1025
|
-
target: "uploadingBack",
|
|
1026
|
-
actions: ["storeSelectedFile"]
|
|
1027
|
-
},
|
|
1028
|
-
{
|
|
1029
|
-
guard: "isPassportFileSelection",
|
|
1030
|
-
target: "uploadingPassport",
|
|
1031
|
-
actions: ["storeSelectedFile"]
|
|
1032
|
-
}
|
|
1033
|
-
],
|
|
1034
|
-
MANUAL_UPLOAD_CONTINUE: [{
|
|
1035
|
-
guard: "canContinueFromIdTab",
|
|
1036
|
-
target: "finished"
|
|
1037
|
-
}, {
|
|
1038
|
-
guard: "canContinueFromPassportTab",
|
|
1039
|
-
target: "finished"
|
|
1040
|
-
}]
|
|
1041
|
-
} },
|
|
1042
|
-
uploadingFront: { invoke: {
|
|
1043
|
-
id: "uploadManualFile",
|
|
1044
|
-
src: "uploadManualFile",
|
|
1045
|
-
input: ({ context }) => ({
|
|
1046
|
-
side: "front",
|
|
1047
|
-
file: context.frontFile,
|
|
1048
|
-
retry: context.retriesLeft < context.captureAttempts,
|
|
1049
|
-
onlyFront: context.onlyFront,
|
|
1050
|
-
isSecondId: context.isSecondId
|
|
1051
|
-
}),
|
|
1052
|
-
onDone: [{
|
|
1053
|
-
guard: "manualUploadResponseHasError",
|
|
1054
|
-
target: "checkRetries",
|
|
1055
|
-
actions: ["decrementManualUploadRetries", "setManualUploadErrorFromResponse"]
|
|
1056
|
-
}, {
|
|
1057
|
-
target: "selecting",
|
|
1058
|
-
actions: [
|
|
1059
|
-
"markFrontUploaded",
|
|
1060
|
-
"recordSkipBackFromResponse",
|
|
1061
|
-
"clearManualUploadError"
|
|
1062
|
-
]
|
|
1063
|
-
}],
|
|
1064
|
-
onError: {
|
|
1065
|
-
target: "checkRetries",
|
|
1066
|
-
actions: ["decrementManualUploadRetries", "setManualUploadGenericError"]
|
|
1067
|
-
}
|
|
1068
|
-
} },
|
|
1069
|
-
uploadingBack: { invoke: {
|
|
1070
|
-
id: "uploadManualFile",
|
|
1071
|
-
src: "uploadManualFile",
|
|
1072
|
-
input: ({ context }) => ({
|
|
1073
|
-
side: "back",
|
|
1074
|
-
file: context.backFile,
|
|
1075
|
-
retry: context.retriesLeft < context.captureAttempts,
|
|
1076
|
-
onlyFront: false,
|
|
1077
|
-
isSecondId: context.isSecondId
|
|
1078
|
-
}),
|
|
1079
|
-
onDone: [{
|
|
1080
|
-
guard: "manualUploadResponseHasError",
|
|
1081
|
-
target: "checkRetries",
|
|
1082
|
-
actions: ["decrementManualUploadRetries", "setManualUploadErrorFromResponse"]
|
|
1083
|
-
}, {
|
|
1084
|
-
target: "selecting",
|
|
1085
|
-
actions: ["markBackUploaded", "clearManualUploadError"]
|
|
1086
|
-
}],
|
|
1087
|
-
onError: {
|
|
1088
|
-
target: "checkRetries",
|
|
1089
|
-
actions: ["decrementManualUploadRetries", "setManualUploadGenericError"]
|
|
1090
|
-
}
|
|
1091
|
-
} },
|
|
1092
|
-
uploadingPassport: { invoke: {
|
|
1093
|
-
id: "uploadManualFile",
|
|
1094
|
-
src: "uploadManualFile",
|
|
1095
|
-
input: ({ context }) => ({
|
|
1096
|
-
side: "passport",
|
|
1097
|
-
file: context.passportFile,
|
|
1098
|
-
retry: context.retriesLeft < context.captureAttempts,
|
|
1099
|
-
onlyFront: false,
|
|
1100
|
-
isSecondId: context.isSecondId
|
|
1101
|
-
}),
|
|
1102
|
-
onDone: [{
|
|
1103
|
-
guard: "manualUploadResponseHasError",
|
|
1104
|
-
target: "checkRetries",
|
|
1105
|
-
actions: ["decrementManualUploadRetries", "setManualUploadErrorFromResponse"]
|
|
1106
|
-
}, {
|
|
1107
|
-
target: "selecting",
|
|
1108
|
-
actions: ["markPassportUploaded", "clearManualUploadError"]
|
|
1109
|
-
}],
|
|
1110
|
-
onError: {
|
|
1111
|
-
target: "checkRetries",
|
|
1112
|
-
actions: ["decrementManualUploadRetries", "setManualUploadGenericError"]
|
|
1113
|
-
}
|
|
1114
|
-
} },
|
|
1115
|
-
checkRetries: { always: [{
|
|
1116
|
-
guard: "manualUploadRetriesExhausted",
|
|
1117
|
-
target: "retriesExhausted"
|
|
1118
|
-
}, { target: "selecting" }] },
|
|
1119
|
-
retriesExhausted: { after: { [MANUAL_UPLOAD_EXHAUSTION_FORWARD_MS]: { target: "exhausted" } } },
|
|
1120
|
-
exhausted: {
|
|
1121
|
-
type: "final",
|
|
1122
|
-
output: { result: "exhausted" }
|
|
1123
|
-
},
|
|
1124
|
-
finished: {
|
|
1125
|
-
type: "final",
|
|
1126
|
-
output: { result: "success" }
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
});
|
|
1130
|
-
const manualUploadMachine = _manualUploadMachine;
|
|
1131
|
-
|
|
1132
|
-
//#endregion
|
|
1133
|
-
//#region ../infra/src/wasm/idCaptureDefaults.ts
|
|
1134
|
-
/**
|
|
1135
|
-
* Default WASM thresholds for ID capture quality checks.
|
|
1136
|
-
* Based on legacy pipelinesConfig.ts values.
|
|
1137
|
-
*/
|
|
1138
|
-
const DEFAULT_ID_CAPTURE_THRESHOLDS = {
|
|
1139
|
-
blurThreshold: .2,
|
|
1140
|
-
blurChangeThreshold: .2,
|
|
1141
|
-
glareThreshold: .3,
|
|
1142
|
-
clsThreshold: .98,
|
|
1143
|
-
sideThreshold: .8,
|
|
1144
|
-
iouThreshold: .8,
|
|
1145
|
-
idDetectedTimeout: 1e4,
|
|
1146
|
-
autocaptureTimeout: 5e3,
|
|
1147
|
-
framesAggregationInterval: 3e3
|
|
1148
|
-
};
|
|
1149
|
-
/**
|
|
1150
|
-
* Default model version for ID capture.
|
|
1151
|
-
*/
|
|
1152
|
-
const DEFAULT_ID_CAPTURE_MODEL_VERSION = "v2";
|
|
1153
|
-
|
|
1154
|
-
//#endregion
|
|
1155
|
-
//#region src/modules/id/idCaptureActors.ts
|
|
1156
|
-
const checkPermissionActor = fromPromise(async () => {
|
|
1157
|
-
return checkPermission();
|
|
1158
|
-
});
|
|
1159
|
-
const requestPermissionActor = fromPromise(async ({ input }) => {
|
|
1160
|
-
return requestPermission({ requestMotion: input.requestMotionPermission });
|
|
1161
|
-
});
|
|
1162
|
-
const initializeCameraActor = fromPromise(async ({ input }) => {
|
|
1163
|
-
return initializeIdCapture(input);
|
|
1164
|
-
});
|
|
1165
|
-
const runDetectionActor = fromCallback(({ input, sendBack }) => {
|
|
1166
|
-
if (!input.frameCapturer || !input.provider) {
|
|
1167
|
-
sendBack({
|
|
1168
|
-
type: "DETECTION_UPDATE",
|
|
1169
|
-
status: "error"
|
|
1170
|
-
});
|
|
1171
|
-
return () => {};
|
|
1172
|
-
}
|
|
1173
|
-
const provider = input.provider;
|
|
1174
|
-
let currentCanvas = null;
|
|
1175
|
-
let bestCanvas = null;
|
|
1176
|
-
let storedQualityElements = {};
|
|
1177
|
-
let isCapturing = false;
|
|
1178
|
-
const timer = BrowserTimerProvider.getInstance();
|
|
1179
|
-
let notificationTimeout = null;
|
|
1180
|
-
let currentNotificationStatus = null;
|
|
1181
|
-
let lastReportedSide = null;
|
|
1182
|
-
const NOTIFICATION_DURATION_MS = 500;
|
|
1183
|
-
const isReportedSideWrong = () => {
|
|
1184
|
-
if (!lastReportedSide) return false;
|
|
1185
|
-
const detectedSide = lastReportedSide.toLowerCase();
|
|
1186
|
-
if (detectedSide === "wrong") return true;
|
|
1187
|
-
const isBackDetected = detectedSide.includes("back") && !detectedSide.includes("front");
|
|
1188
|
-
const isFrontDetected = detectedSide.includes("front") && !detectedSide.includes("back");
|
|
1189
|
-
return input.currentMode === "front" && isBackDetected || input.currentMode === "back" && isFrontDetected;
|
|
1190
|
-
};
|
|
1191
|
-
const clearNotificationTimeout = () => {
|
|
1192
|
-
if (notificationTimeout) {
|
|
1193
|
-
timer.clearTimeout(notificationTimeout);
|
|
1194
|
-
notificationTimeout = null;
|
|
1195
|
-
currentNotificationStatus = null;
|
|
1196
|
-
}
|
|
1197
|
-
};
|
|
1198
|
-
const sendNotification = (status) => {
|
|
1199
|
-
if (isReportedSideWrong()) return;
|
|
1200
|
-
if (notificationTimeout && currentNotificationStatus !== status) return;
|
|
1201
|
-
if (notificationTimeout && currentNotificationStatus === status) timer.clearTimeout(notificationTimeout);
|
|
1202
|
-
currentNotificationStatus = status;
|
|
1203
|
-
sendBack({
|
|
1204
|
-
type: "DETECTION_UPDATE",
|
|
1205
|
-
status
|
|
1206
|
-
});
|
|
1207
|
-
notificationTimeout = timer.setTimeout(() => {
|
|
1208
|
-
notificationTimeout = null;
|
|
1209
|
-
currentNotificationStatus = null;
|
|
1210
|
-
sendBack({
|
|
1211
|
-
type: "DETECTION_UPDATE",
|
|
1212
|
-
status: "detecting"
|
|
1213
|
-
});
|
|
1214
|
-
}, NOTIFICATION_DURATION_MS);
|
|
1215
|
-
};
|
|
1216
|
-
const canvas = input.frameCapturer.getLatestCanvas();
|
|
1217
|
-
const windowDimensions = getWindowDimensions(canvas?.width() ?? 1280, canvas?.height() ?? 720);
|
|
1218
|
-
const DEFAULT_GEOMETRY = {
|
|
1219
|
-
areaDown: 25e3,
|
|
1220
|
-
areaUp: 55e3,
|
|
1221
|
-
areaIOSPassportUp: 3e4,
|
|
1222
|
-
areaIOSPassportDown: 2e4,
|
|
1223
|
-
widthIOSUp: 160,
|
|
1224
|
-
widthIOSDown: 85,
|
|
1225
|
-
widthDown: 110,
|
|
1226
|
-
widthUp: 205
|
|
1227
|
-
};
|
|
1228
|
-
if (input.config.geometry) provider.setGeometry({
|
|
1229
|
-
...input.config.geometry,
|
|
1230
|
-
windowOuterWidth: windowDimensions.outerWidth,
|
|
1231
|
-
windowOuterHeight: windowDimensions.outerHeight,
|
|
1232
|
-
windowInnerWidth: windowDimensions.innerWidth,
|
|
1233
|
-
windowInnerHeight: windowDimensions.innerHeight
|
|
1234
|
-
});
|
|
1235
|
-
else provider.setGeometry({
|
|
1236
|
-
...DEFAULT_GEOMETRY,
|
|
1237
|
-
windowOuterWidth: windowDimensions.outerWidth,
|
|
1238
|
-
windowOuterHeight: windowDimensions.outerHeight,
|
|
1239
|
-
windowInnerWidth: windowDimensions.innerWidth,
|
|
1240
|
-
windowInnerHeight: windowDimensions.innerHeight
|
|
1241
|
-
});
|
|
1242
|
-
const idType = input.currentMode === "back" ? "BackId" : input.currentMode === "passport" ? "Passport" : "FrontId";
|
|
1243
|
-
provider.setSettings({
|
|
1244
|
-
isFixedMask: input.config.settings?.isFixedMask ?? false,
|
|
1245
|
-
isIPhone14OrHigher: input.config.settings?.isIPhone14OrHigher ?? false,
|
|
1246
|
-
idType,
|
|
1247
|
-
blurCheckEnabled: input.config.settings?.blurCheckEnabled ?? false,
|
|
1248
|
-
glareCheckEnabled: input.config.settings?.glareCheckEnabled ?? false,
|
|
1249
|
-
faceQualityCheckEnabled: input.config.settings?.faceQualityCheckEnabled ?? true,
|
|
1250
|
-
iouCheckEnabled: input.config.settings?.iouCheckEnabled ?? true,
|
|
1251
|
-
fpsLimitEnabled: input.config.settings?.fpsLimitEnabled ?? false
|
|
1252
|
-
});
|
|
1253
|
-
const thresholds = {
|
|
1254
|
-
...DEFAULT_ID_CAPTURE_THRESHOLDS,
|
|
1255
|
-
...input.config.thresholds,
|
|
1256
|
-
idDetectedTimeout: (input.config.deviceIdleTimeout ?? 10) * 1e3,
|
|
1257
|
-
autocaptureTimeout: (input.config.autoCaptureTimeout ?? 5) * 1e3
|
|
1258
|
-
};
|
|
1259
|
-
provider.setThresholds(thresholds);
|
|
1260
|
-
const modelType = input.config.modelVersion ?? DEFAULT_ID_CAPTURE_MODEL_VERSION;
|
|
1261
|
-
provider.setModelType(modelType);
|
|
1262
|
-
provider.setCallbacks({
|
|
1263
|
-
onFarAway: () => {
|
|
1264
|
-
if (!isCapturing) sendNotification("farAway");
|
|
1265
|
-
},
|
|
1266
|
-
onDetectionStarted: () => {},
|
|
1267
|
-
onMaskChange: (_show, _mask, _top, orientation) => {
|
|
1268
|
-
sendBack({
|
|
1269
|
-
type: "ORIENTATION_CHANGE",
|
|
1270
|
-
orientation
|
|
1271
|
-
});
|
|
1272
|
-
},
|
|
1273
|
-
onBlur: () => {
|
|
1274
|
-
if (!isCapturing) sendNotification("blur");
|
|
1275
|
-
},
|
|
1276
|
-
onGlare: () => {
|
|
1277
|
-
if (!isCapturing) sendNotification("glare");
|
|
1278
|
-
},
|
|
1279
|
-
onIdNotDetected: () => {
|
|
1280
|
-
if (!isCapturing) sendBack({
|
|
1281
|
-
type: "DETECTION_UPDATE",
|
|
1282
|
-
status: "idNotDetected"
|
|
1283
|
-
});
|
|
1284
|
-
},
|
|
1285
|
-
onSwitchToManualCapture: () => {
|
|
1286
|
-
isCapturing = false;
|
|
1287
|
-
sendBack({ type: "SWITCH_TO_MANUAL_CAPTURE" });
|
|
1288
|
-
},
|
|
1289
|
-
onCapturing: () => {
|
|
1290
|
-
clearNotificationTimeout();
|
|
1291
|
-
lastReportedSide = null;
|
|
1292
|
-
isCapturing = true;
|
|
1293
|
-
sendBack({
|
|
1294
|
-
type: "DETECTION_UPDATE",
|
|
1295
|
-
status: "capturing"
|
|
1296
|
-
});
|
|
1297
|
-
},
|
|
1298
|
-
onBestFrame: (blur, glare, orientation) => {
|
|
1299
|
-
if (currentCanvas) {
|
|
1300
|
-
bestCanvas = currentCanvas.clone();
|
|
1301
|
-
storedQualityElements = {
|
|
1302
|
-
glare,
|
|
1303
|
-
sharpness: blur
|
|
1304
|
-
};
|
|
1305
|
-
}
|
|
1306
|
-
if (orientation === "horizontal" || orientation === "vertical") sendBack({
|
|
1307
|
-
type: "ORIENTATION_CHANGE",
|
|
1308
|
-
orientation
|
|
1309
|
-
});
|
|
1310
|
-
},
|
|
1311
|
-
onCapture: () => {
|
|
1312
|
-
isCapturing = false;
|
|
1313
|
-
if (bestCanvas) sendBack({
|
|
1314
|
-
type: "DETECTION_SUCCESS",
|
|
1315
|
-
canvas: bestCanvas,
|
|
1316
|
-
qualityElements: storedQualityElements
|
|
1317
|
-
});
|
|
1318
|
-
else if (currentCanvas) sendBack({
|
|
1319
|
-
type: "DETECTION_SUCCESS",
|
|
1320
|
-
canvas: currentCanvas.clone(),
|
|
1321
|
-
qualityElements: {}
|
|
1322
|
-
});
|
|
1323
|
-
},
|
|
1324
|
-
onIdTypeChange: (idType$1) => {
|
|
1325
|
-
sendBack({
|
|
1326
|
-
type: "ID_TYPE_CHANGE",
|
|
1327
|
-
idType: idType$1
|
|
1328
|
-
});
|
|
1329
|
-
},
|
|
1330
|
-
onIdSideChange: (side) => {
|
|
1331
|
-
if (isCapturing) return;
|
|
1332
|
-
lastReportedSide = side;
|
|
1333
|
-
if (isReportedSideWrong()) clearNotificationTimeout();
|
|
1334
|
-
sendBack({
|
|
1335
|
-
type: "ID_SIDE_CHANGE",
|
|
1336
|
-
side
|
|
1337
|
-
});
|
|
1338
|
-
},
|
|
1339
|
-
onCapturingCounterValueChange: (value) => {
|
|
1340
|
-
sendBack({
|
|
1341
|
-
type: "COUNTER_VALUE_CHANGE",
|
|
1342
|
-
value
|
|
1343
|
-
});
|
|
1344
|
-
}
|
|
1345
|
-
});
|
|
1346
|
-
sendBack({
|
|
1347
|
-
type: "DETECTION_UPDATE",
|
|
1348
|
-
status: "detecting"
|
|
1349
|
-
});
|
|
1350
|
-
const session = new StreamCanvasProcessingSession({
|
|
1351
|
-
capturer: input.frameCapturer,
|
|
1352
|
-
provider: {
|
|
1353
|
-
processFrame: async (frame) => {
|
|
1354
|
-
currentCanvas = IncodeCanvas.fromImageData(frame);
|
|
1355
|
-
sendBack({
|
|
1356
|
-
type: "DETECTION_FRAME",
|
|
1357
|
-
frame
|
|
1358
|
-
});
|
|
1359
|
-
await provider.processFrame(frame);
|
|
1360
|
-
},
|
|
1361
|
-
reset: () => {
|
|
1362
|
-
if (notificationTimeout) {
|
|
1363
|
-
timer.clearTimeout(notificationTimeout);
|
|
1364
|
-
notificationTimeout = null;
|
|
1365
|
-
currentNotificationStatus = null;
|
|
1366
|
-
}
|
|
1367
|
-
currentCanvas = null;
|
|
1368
|
-
bestCanvas = null;
|
|
1369
|
-
storedQualityElements = {};
|
|
1370
|
-
isCapturing = false;
|
|
1371
|
-
lastReportedSide = null;
|
|
1372
|
-
provider.reset();
|
|
1373
|
-
}
|
|
1374
|
-
},
|
|
1375
|
-
onFrame: (frame) => sendBack({
|
|
1376
|
-
type: "DETECTION_FRAME",
|
|
1377
|
-
frame
|
|
1378
|
-
})
|
|
1379
|
-
});
|
|
1380
|
-
sendBack({
|
|
1381
|
-
type: "DETECTION_RESET_READY",
|
|
1382
|
-
reset: () => {
|
|
1383
|
-
provider.reset();
|
|
1384
|
-
}
|
|
1385
|
-
});
|
|
1386
|
-
return () => {
|
|
1387
|
-
clearNotificationTimeout();
|
|
1388
|
-
session?.dispose();
|
|
1389
|
-
};
|
|
1390
|
-
});
|
|
1391
|
-
const uploadIdImageActor = fromPromise(async ({ input, signal }) => {
|
|
1392
|
-
const image = input.canvas.getBase64Image();
|
|
1393
|
-
if (!image) throw new Error(ID_ERROR_CODES.UPLOAD_ERROR);
|
|
1394
|
-
let metadata;
|
|
1395
|
-
if (input.deepsightService) try {
|
|
1396
|
-
const sessionToken = getToken();
|
|
1397
|
-
const frameSource = input.type === "back" ? "BACK_ID" : "FRONT_ID";
|
|
1398
|
-
await input.deepsightService.performVirtualCameraCheck(sessionToken, frameSource);
|
|
1399
|
-
const imageData$1 = input.canvas.getImageData();
|
|
1400
|
-
if (imageData$1) await input.deepsightService.analyzeFrame(imageData$1);
|
|
1401
|
-
const analysisStatus = input.deepsightService.getAnalysisStatus();
|
|
1402
|
-
const motionStatus = input.deepsightService.getMotionStatus();
|
|
1403
|
-
if (input.type === "front") await addDeviceStats({
|
|
1404
|
-
frontIdStatsAnalysisStatus: analysisStatus,
|
|
1405
|
-
backIdStatsAnalysisStatus: "",
|
|
1406
|
-
selfieStatsAnalysisStatus: "",
|
|
1407
|
-
motionStatus
|
|
1408
|
-
});
|
|
1409
|
-
else await addDeviceStats({
|
|
1410
|
-
frontIdStatsAnalysisStatus: "",
|
|
1411
|
-
backIdStatsAnalysisStatus: analysisStatus,
|
|
1412
|
-
selfieStatsAnalysisStatus: "",
|
|
1413
|
-
motionStatus
|
|
1414
|
-
});
|
|
1415
|
-
metadata = input.deepsightService.getMetadata();
|
|
1416
|
-
} catch {}
|
|
1417
|
-
const imageData = input.canvas?.getImageData() ?? void 0;
|
|
1418
|
-
const logs = input.deepsightService?.getPipelineState() ?? "";
|
|
1419
|
-
input.dependencies?.trackCaptureAttemptFinished?.({
|
|
1420
|
-
logs,
|
|
1421
|
-
resolution: input.captureResolution,
|
|
1422
|
-
fallbackLevel: input.cameraFallbackLevel
|
|
1423
|
-
});
|
|
1424
|
-
return uploadIdImage({
|
|
1425
|
-
image,
|
|
1426
|
-
type: input.type,
|
|
1427
|
-
sendBase64: true,
|
|
1428
|
-
glare: input.qualityElements?.glare,
|
|
1429
|
-
sharpness: input.qualityElements?.sharpness,
|
|
1430
|
-
ageAssurance: input.ageAssurance,
|
|
1431
|
-
signal,
|
|
1432
|
-
onProgress: input.onProgress,
|
|
1433
|
-
metadata,
|
|
1434
|
-
analyticsProvider: input.analyticsProvider,
|
|
1435
|
-
imageData,
|
|
1436
|
-
isSecondId: input.isSecondId,
|
|
1437
|
-
onlyFront: input.onlyFront
|
|
1438
|
-
});
|
|
1439
|
-
});
|
|
1440
|
-
const processIdActor = fromPromise(async ({ input, signal }) => {
|
|
1441
|
-
return processId(input.isSecondId, "", signal);
|
|
1442
|
-
});
|
|
1443
|
-
const startRecordingActor = fromPromise(async ({ input }) => {
|
|
1444
|
-
if (!input.stream) return;
|
|
1445
|
-
const type = input.currentMode === "back" ? "backId" : "frontId";
|
|
1446
|
-
return startRecordingSession({
|
|
1447
|
-
config: input.config,
|
|
1448
|
-
stream: input.stream,
|
|
1449
|
-
existing: input.existing,
|
|
1450
|
-
type
|
|
1451
|
-
});
|
|
1452
|
-
});
|
|
1453
|
-
const checkMotionSensorActor = fromCallback(({ input, sendBack }) => {
|
|
1454
|
-
if (!input.motionProvider) {
|
|
1455
|
-
sendBack({
|
|
1456
|
-
type: "MOTION_STATUS",
|
|
1457
|
-
status: "UNCLEAR"
|
|
1458
|
-
});
|
|
1459
|
-
return () => {};
|
|
1460
|
-
}
|
|
1461
|
-
const timer = BrowserTimerProvider.getInstance();
|
|
1462
|
-
const interval = timer.setInterval(() => {
|
|
1463
|
-
sendBack({
|
|
1464
|
-
type: "MOTION_STATUS",
|
|
1465
|
-
status: input.motionProvider.check()
|
|
1466
|
-
});
|
|
1467
|
-
}, 500);
|
|
1468
|
-
return () => timer.clearInterval(interval);
|
|
1469
|
-
});
|
|
1470
|
-
const initializeDeepsightSessionActor = fromPromise(async ({ input }) => {
|
|
1471
|
-
if (!input.dependencies) return;
|
|
1472
|
-
const { loadDeepsightSession } = await import("./deepsightLoader-Cm4JIT_z.esm.js");
|
|
1473
|
-
return loadDeepsightSession({
|
|
1474
|
-
ds: input.ds,
|
|
1475
|
-
storage: input.dependencies.storage,
|
|
1476
|
-
disableIpify: input.disableIpify
|
|
1477
|
-
});
|
|
1478
|
-
});
|
|
1479
|
-
const checkVirtualCameraActor = fromPromise(async ({ input }) => {
|
|
1480
|
-
if (!input.deepsightService || !input.stream) return false;
|
|
1481
|
-
const videoTrack = input.stream.getVideoTracks()[0];
|
|
1482
|
-
if (!videoTrack) return false;
|
|
1483
|
-
return input.deepsightService.checkVirtualCamera(videoTrack);
|
|
1484
|
-
});
|
|
1485
|
-
|
|
1486
|
-
//#endregion
|
|
1487
|
-
//#region src/modules/id/idCaptureActions.ts
|
|
1488
|
-
function performStopMediaStream(context) {
|
|
1489
|
-
context.frameCapturer?.dispose();
|
|
1490
|
-
if (context.stream) stopStream(context.stream);
|
|
1491
|
-
}
|
|
1492
|
-
function performDisposeProvider(context) {
|
|
1493
|
-
context.provider?.dispose?.();
|
|
1494
|
-
}
|
|
1495
|
-
function performCleanupDeepsight(context) {
|
|
1496
|
-
context.deepsightService?.cleanup();
|
|
1497
|
-
}
|
|
1498
|
-
function performResetForBackCapture(context) {
|
|
1499
|
-
context.frameCapturer?.dispose();
|
|
1500
|
-
if (context.stream) stopStream(context.stream);
|
|
1501
|
-
context.provider?.reset();
|
|
1502
|
-
}
|
|
1503
|
-
function performResetForFrontCapture(context) {
|
|
1504
|
-
context.frameCapturer?.dispose();
|
|
1505
|
-
if (context.stream) stopStream(context.stream);
|
|
1506
|
-
context.provider?.reset();
|
|
1507
|
-
}
|
|
1508
|
-
function performResetDetection(context) {
|
|
1509
|
-
context.resetDetection?.();
|
|
1510
|
-
}
|
|
1511
|
-
function performTrackTutorialId() {}
|
|
1512
|
-
function performTrackContinue() {}
|
|
1513
|
-
function performTrackCameraId(context) {}
|
|
1514
|
-
function performStopMediaRecording(context) {
|
|
1515
|
-
if (context.recordingSession) stopRecording(context.recordingSession);
|
|
1516
|
-
}
|
|
1517
|
-
function getStreamFromEvent(event) {
|
|
1518
|
-
if ("output" in event) return event.output.stream;
|
|
1519
|
-
}
|
|
1520
|
-
function getProviderFromEvent(event) {
|
|
1521
|
-
if ("output" in event) return event.output.provider;
|
|
1522
|
-
}
|
|
1523
|
-
function getCaptureResolutionFromEvent(event) {
|
|
1524
|
-
if ("output" in event) return event.output.captureResolution;
|
|
1525
|
-
}
|
|
1526
|
-
function getCameraFallbackLevelFromEvent(event) {
|
|
1527
|
-
if ("output" in event) return event.output.cameraFallbackLevel;
|
|
1528
|
-
}
|
|
1529
|
-
function getFrameCapturerFromEvent(event) {
|
|
1530
|
-
if ("output" in event) {
|
|
1531
|
-
const output = event.output;
|
|
1532
|
-
if (output.stream) return new StreamCanvasCapture(output.stream);
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
|
-
function getResetContextValues(context) {
|
|
1536
|
-
context.provider?.reset();
|
|
1537
|
-
const currentMode = context.config.onlyBack ? "back" : !context.config.enableId && context.config.enablePassport ? "passport" : context.config.usSmartCapture ? "back" : "front";
|
|
1538
|
-
return {
|
|
1539
|
-
stream: void 0,
|
|
1540
|
-
provider: context.provider,
|
|
1541
|
-
frameCapturer: void 0,
|
|
1542
|
-
error: void 0,
|
|
1543
|
-
detectionStatus: "idle",
|
|
1544
|
-
counterValue: 0,
|
|
1545
|
-
orientation: void 0,
|
|
1546
|
-
capturedImages: {},
|
|
1547
|
-
captureOnlyImages: {},
|
|
1548
|
-
uploadResponse: void 0,
|
|
1549
|
-
recordingSession: void 0,
|
|
1550
|
-
attemptsRemaining: context.config.captureAttempts,
|
|
1551
|
-
expiredAttempts: 0,
|
|
1552
|
-
skipProcessId: false,
|
|
1553
|
-
expiredFromUpload: false,
|
|
1554
|
-
isDigitalUpload: false,
|
|
1555
|
-
exhaustedFromUpload: false,
|
|
1556
|
-
forceFinishAfterProcessing: false,
|
|
1557
|
-
uploadError: void 0,
|
|
1558
|
-
permissionResult: void 0,
|
|
1559
|
-
resetDetection: void 0,
|
|
1560
|
-
idType: void 0,
|
|
1561
|
-
qualityElements: void 0,
|
|
1562
|
-
previewImageUrl: void 0,
|
|
1563
|
-
uploadProgress: void 0,
|
|
1564
|
-
currentMode,
|
|
1565
|
-
selectedDocumentType: void 0,
|
|
1566
|
-
manualCaptureTriggered: false,
|
|
1567
|
-
captureResolution: void 0,
|
|
1568
|
-
cameraFallbackLevel: void 0
|
|
1569
|
-
};
|
|
1570
|
-
}
|
|
1571
|
-
function getClearUploadFailureValues(context) {
|
|
1572
|
-
if (context.previewImageUrl) revokeObjectURL(context.previewImageUrl);
|
|
1573
|
-
return {
|
|
1574
|
-
uploadError: void 0,
|
|
1575
|
-
detectionStatus: "idle",
|
|
1576
|
-
previewImageUrl: void 0,
|
|
1577
|
-
uploadProgress: void 0
|
|
1578
|
-
};
|
|
1579
|
-
}
|
|
1580
|
-
function getUploadValidationError(context) {
|
|
1581
|
-
if (!context.uploadResponse) return ID_ERROR_CODES.SERVER;
|
|
1582
|
-
return validateUploadResponse(context.uploadResponse, {
|
|
1583
|
-
skipGlareFront: context.uploadResponse.skipGlareFront,
|
|
1584
|
-
skipGlareBack: context.uploadResponse.skipGlareBack
|
|
1585
|
-
})?.errorKey ?? ID_ERROR_CODES.SERVER;
|
|
1586
|
-
}
|
|
1587
|
-
function storeCapturedCanvasInProviderLogic(context, event) {
|
|
1588
|
-
let canvas = null;
|
|
1589
|
-
if ("canvas" in event && event.canvas) canvas = event.canvas;
|
|
1590
|
-
else canvas = context.frameCapturer?.getLatestCanvas() ?? null;
|
|
1591
|
-
if (!canvas || !context.provider) return;
|
|
1592
|
-
const canvasWidth = canvas.width();
|
|
1593
|
-
const canvasHeight = canvas.height();
|
|
1594
|
-
if (!canvasWidth || !canvasHeight) return;
|
|
1595
|
-
const originalCanvas = canvas;
|
|
1596
|
-
let frameRect;
|
|
1597
|
-
const { innerWidth: viewportWidth, innerHeight: viewportHeight } = getWindowDimensions();
|
|
1598
|
-
if (context.detectionArea) {
|
|
1599
|
-
const scaleX = viewportWidth / canvasWidth;
|
|
1600
|
-
const scaleY = viewportHeight / canvasHeight;
|
|
1601
|
-
const scale = Math.max(scaleX, scaleY);
|
|
1602
|
-
const displayedWidth = canvasWidth * scale;
|
|
1603
|
-
const displayedHeight = canvasHeight * scale;
|
|
1604
|
-
const offsetX = (viewportWidth - displayedWidth) / 2;
|
|
1605
|
-
const offsetY = (viewportHeight - displayedHeight) / 2;
|
|
1606
|
-
frameRect = {
|
|
1607
|
-
x: (context.detectionArea.x - offsetX) / scale,
|
|
1608
|
-
y: (context.detectionArea.y - offsetY) / scale,
|
|
1609
|
-
w: context.detectionArea.width / scale,
|
|
1610
|
-
h: context.detectionArea.height / scale
|
|
1611
|
-
};
|
|
1612
|
-
} else if (context.frameRect) {
|
|
1613
|
-
const scaleX = viewportWidth / canvasWidth;
|
|
1614
|
-
const scaleY = viewportHeight / canvasHeight;
|
|
1615
|
-
const scale = Math.max(scaleX, scaleY);
|
|
1616
|
-
const displayedWidth = canvasWidth * scale;
|
|
1617
|
-
const displayedHeight = canvasHeight * scale;
|
|
1618
|
-
const offsetX = (viewportWidth - displayedWidth) / 2;
|
|
1619
|
-
const offsetY = (viewportHeight - displayedHeight) / 2;
|
|
1620
|
-
frameRect = {
|
|
1621
|
-
x: (context.frameRect.x - offsetX) / scale,
|
|
1622
|
-
y: (context.frameRect.y - offsetY) / scale,
|
|
1623
|
-
w: context.frameRect.w / scale,
|
|
1624
|
-
h: context.frameRect.h / scale
|
|
1625
|
-
};
|
|
1626
|
-
} else {
|
|
1627
|
-
const quadValue = (context.provider.getLastProcessResult?.())?.quad;
|
|
1628
|
-
const hasQuad = !!quadValue;
|
|
1629
|
-
const quadSize = quadValue?.size ? quadValue.size() : quadValue?.length ?? 0;
|
|
1630
|
-
if (hasQuad && quadSize >= 4 && quadValue.get) {
|
|
1631
|
-
const p0 = quadValue.get(0);
|
|
1632
|
-
const p1 = quadValue.get(1);
|
|
1633
|
-
const p2 = quadValue.get(2);
|
|
1634
|
-
const p3 = quadValue.get(3);
|
|
1635
|
-
const minX = Math.min(p0.x, p1.x, p2.x, p3.x);
|
|
1636
|
-
const maxX = Math.max(p0.x, p1.x, p2.x, p3.x);
|
|
1637
|
-
const minY = Math.min(p0.y, p1.y, p2.y, p3.y);
|
|
1638
|
-
const maxY = Math.max(p0.y, p1.y, p2.y, p3.y);
|
|
1639
|
-
frameRect = {
|
|
1640
|
-
x: minX,
|
|
1641
|
-
y: minY,
|
|
1642
|
-
w: maxX - minX,
|
|
1643
|
-
h: maxY - minY
|
|
1644
|
-
};
|
|
1645
|
-
} else {
|
|
1646
|
-
const frameViewportWidth = Math.min(387, viewportWidth * .9);
|
|
1647
|
-
const frameViewportHeight = frameViewportWidth / (35 / 22);
|
|
1648
|
-
const frameViewportX = (viewportWidth - frameViewportWidth) / 2;
|
|
1649
|
-
const frameViewportY = (viewportHeight - frameViewportHeight) / 2;
|
|
1650
|
-
frameRect = {
|
|
1651
|
-
x: canvasWidth * frameViewportX / viewportWidth,
|
|
1652
|
-
y: canvasHeight * frameViewportY / viewportHeight,
|
|
1653
|
-
w: canvasWidth * frameViewportWidth / viewportWidth,
|
|
1654
|
-
h: canvasHeight * frameViewportHeight / viewportHeight
|
|
1655
|
-
};
|
|
1656
|
-
}
|
|
1657
|
-
}
|
|
1658
|
-
const transformedCanvas = context.provider.transformPerspective(originalCanvas, frameRect);
|
|
1659
|
-
context.provider.setCapturedCanvases(originalCanvas, transformedCanvas);
|
|
1660
|
-
}
|
|
1661
|
-
function getStoreCapturedImageValues(context, event) {
|
|
1662
|
-
if (!context.currentMode) return {
|
|
1663
|
-
capturedImages: context.capturedImages,
|
|
1664
|
-
previewImageUrl: context.previewImageUrl
|
|
1665
|
-
};
|
|
1666
|
-
const transformedCanvas = context.provider?.getCapturedCanvas();
|
|
1667
|
-
const transformedImage = transformedCanvas?.getBase64Image(1, true);
|
|
1668
|
-
let fallbackImage = "";
|
|
1669
|
-
if ("output" in event) fallbackImage = event.output.originalImage ?? "";
|
|
1670
|
-
const imageData = { imageBase64: transformedImage ?? fallbackImage };
|
|
1671
|
-
let capturedImages = context.capturedImages;
|
|
1672
|
-
if (context.currentMode === "front" || context.currentMode === "passport") capturedImages = {
|
|
1673
|
-
...context.capturedImages,
|
|
1674
|
-
front: imageData
|
|
1675
|
-
};
|
|
1676
|
-
else capturedImages = {
|
|
1677
|
-
...context.capturedImages,
|
|
1678
|
-
back: imageData
|
|
1679
|
-
};
|
|
1680
|
-
let previewImageUrl = context.previewImageUrl;
|
|
1681
|
-
if (transformedCanvas) {
|
|
1682
|
-
transformedCanvas.updateBlob();
|
|
1683
|
-
const blobData = transformedCanvas.getBlobData();
|
|
1684
|
-
if (blobData?.url) previewImageUrl = blobData.url;
|
|
1685
|
-
} else if ("canvas" in event && event.canvas) {
|
|
1686
|
-
const canvas = event.canvas;
|
|
1687
|
-
canvas.updateBlob();
|
|
1688
|
-
const blobData = canvas.getBlobData();
|
|
1689
|
-
if (blobData?.url) previewImageUrl = blobData.url;
|
|
1690
|
-
}
|
|
1691
|
-
return {
|
|
1692
|
-
capturedImages,
|
|
1693
|
-
previewImageUrl
|
|
1694
|
-
};
|
|
1695
|
-
}
|
|
1696
|
-
function getDetectionStatusFromUpdate(context, event) {
|
|
1697
|
-
if (event.type === "DETECTION_UPDATE") {
|
|
1698
|
-
const newStatus = event.status;
|
|
1699
|
-
const currentStatus = context.detectionStatus;
|
|
1700
|
-
if (currentStatus === "wrongSide") {
|
|
1701
|
-
if (!(newStatus === "capturing" || newStatus === "manualCapture" || newStatus === "offline")) return currentStatus;
|
|
1702
|
-
return newStatus;
|
|
1703
|
-
}
|
|
1704
|
-
if ((newStatus === "blur" || newStatus === "glare") && currentStatus === "farAway") return currentStatus;
|
|
1705
|
-
if ((newStatus === "wrongSide" || newStatus === "farAway") && (currentStatus === "blur" || currentStatus === "glare")) return newStatus;
|
|
1706
|
-
return newStatus;
|
|
1707
|
-
}
|
|
1708
|
-
return "idle";
|
|
1709
|
-
}
|
|
1710
|
-
function getDetectionStatusFromSideChange(context, side) {
|
|
1711
|
-
const detectedSide = side?.toLowerCase() || "";
|
|
1712
|
-
const currentMode = context.currentMode;
|
|
1713
|
-
if (detectedSide === "wrong") return "wrongSide";
|
|
1714
|
-
const isBackDetected = detectedSide.includes("back") && !detectedSide.includes("front");
|
|
1715
|
-
const isFrontDetected = detectedSide.includes("front") && !detectedSide.includes("back");
|
|
1716
|
-
if (currentMode === "front" && isBackDetected || currentMode === "back" && isFrontDetected) return "wrongSide";
|
|
1717
|
-
if (currentMode === "front" && isFrontDetected || currentMode === "back" && isBackDetected || currentMode === "passport") return "detecting";
|
|
1718
|
-
return "detecting";
|
|
1719
|
-
}
|
|
1720
|
-
function getCurrentModeFromEvent(context, event) {
|
|
1721
|
-
if ("documentType" in event) {
|
|
1722
|
-
if (event.documentType === "passport") return "passport";
|
|
1723
|
-
return context.config.usSmartCapture ? "back" : "front";
|
|
1724
|
-
}
|
|
1725
|
-
if (event.type === "FRONT_COMPLETE") return "back";
|
|
1726
|
-
return context.currentMode;
|
|
1727
|
-
}
|
|
1728
|
-
|
|
1729
|
-
//#endregion
|
|
1730
|
-
//#region src/modules/id/idCaptureGuards.ts
|
|
1731
|
-
const hasShowTutorialGuard = ({ context }) => context.config.showTutorial;
|
|
1732
|
-
const hasAgeAssuranceGuard = ({ context }) => context.config.ageAssurance === true;
|
|
1733
|
-
const hasShowDocumentChooserGuard = ({ context }) => !context.config.onlyBack && (context.config.showDocumentChooserScreen ?? false);
|
|
1734
|
-
const isPermissionGrantedGuard = ({ event }) => {
|
|
1735
|
-
if ("output" in event) return event.output === "granted";
|
|
1736
|
-
return false;
|
|
1737
|
-
};
|
|
1738
|
-
const isPermissionDeniedErrorGuard = ({ event }) => {
|
|
1739
|
-
if ("error" in event) {
|
|
1740
|
-
const error = event.error;
|
|
1741
|
-
return error?.name === "NotAllowedError" || error?.name === "PermissionDeniedError";
|
|
1742
|
-
}
|
|
1743
|
-
return false;
|
|
1744
|
-
};
|
|
1745
|
-
const hasStreamGuard = ({ context }) => context.stream !== void 0;
|
|
1746
|
-
const hasAttemptsRemainingGuard = ({ context }) => context.attemptsRemaining > 0;
|
|
1747
|
-
const hasCapturedImageGuard = ({ context }) => {
|
|
1748
|
-
return context.provider?.getCapturedCanvas() !== null;
|
|
1749
|
-
};
|
|
1750
|
-
const hasUploadValidationErrorGuard = ({ context }) => {
|
|
1751
|
-
if (!context.uploadResponse) return false;
|
|
1752
|
-
return validateUploadResponse(context.uploadResponse, {
|
|
1753
|
-
skipGlareFront: context.uploadResponse.skipGlareFront,
|
|
1754
|
-
skipGlareBack: context.uploadResponse.skipGlareBack
|
|
1755
|
-
}) !== void 0;
|
|
1756
|
-
};
|
|
1757
|
-
const isFrontModeGuard = ({ context }) => context.currentMode === "front" || context.currentMode === "passport";
|
|
1758
|
-
/**
|
|
1759
|
-
* `config.onlyFront` from the orchestrated flow JSON is intentionally not
|
|
1760
|
-
* read here: the flow value cannot account for per-document overrides, so the
|
|
1761
|
-
* backend resolves the real policy per document at upload time
|
|
1762
|
-
* (via `skipBackIdCapture` on the upload response). Standalone
|
|
1763
|
-
* `idCaptureManager` consumers that pass `onlyFront: true` directly will
|
|
1764
|
-
* therefore also be ignored — re-wire this guard if that capability is needed
|
|
1765
|
-
* again.
|
|
1766
|
-
*/
|
|
1767
|
-
const isOnlyFrontGuard = (_args) => false;
|
|
1768
|
-
const shouldContinueToBackGuard = ({ context }) => {
|
|
1769
|
-
if (context.currentMode !== "front" && context.currentMode !== "passport") return false;
|
|
1770
|
-
if (context.config.onlyBack) return false;
|
|
1771
|
-
if (context.config.usSmartCapture) return false;
|
|
1772
|
-
if (context.uploadResponse?.skipBackIdCapture) {
|
|
1773
|
-
if (!(context.config.alwaysCaptureBackOfId === true && context.currentMode !== "passport")) return false;
|
|
1774
|
-
}
|
|
1775
|
-
return true;
|
|
1776
|
-
};
|
|
1777
|
-
const shouldContinueToFrontGuard = ({ context }) => context.config.usSmartCapture === true && context.currentMode === "back" && context.uploadResponse?.forceFrontIdCapture === true;
|
|
1778
|
-
const hasMandatoryConsentGuard = ({ context }) => context.uploadResponse?.showMandatoryConsent === true;
|
|
1779
|
-
const isDeepsightEnabledGuard = ({ context }) => context.dependencies !== void 0;
|
|
1780
|
-
const isDeepsightReadyGuard = ({ context }) => context.deepsightService !== void 0;
|
|
1781
|
-
const needsDeepsightInitGuard = ({ context }) => context.dependencies !== void 0 && context.deepsightService === void 0 && !context.deepsightInitAttempted;
|
|
1782
|
-
const hasOnlyManualUploadAvailableGuard = ({ context }) => context.availableDocumentTypes.length === 1 && context.availableDocumentTypes[0] === "manualIdUpload";
|
|
1783
|
-
const isManualIdUploadSelectedGuard = ({ event }) => event.type === "SELECT_DOCUMENT" && event.documentType === "manualIdUpload";
|
|
1784
|
-
const isDigitalIdUploadSelectedGuard = ({ event }) => event.type === "SELECT_DOCUMENT" && event.documentType === "digitalIdUpload";
|
|
1785
|
-
const isUploadExpiredGuard = ({ context }) => context.uploadResponse?.isDocumentExpired === true;
|
|
1786
|
-
/**
|
|
1787
|
-
* True when *this* expired upload will exhaust the budget. Compares the
|
|
1788
|
-
* post-increment count, so the exhaustion branch can be picked in the same
|
|
1789
|
-
* tick that runs `incrementExpiredAttempts`. With `captureAttempts=3`:
|
|
1790
|
-
* - attempt 1 → 0+1=1 (not exhausted)
|
|
1791
|
-
* - attempt 2 → 1+1=2 (not exhausted)
|
|
1792
|
-
* - attempt 3 → 2+1=3 (exhausted, force-back / finish)
|
|
1793
|
-
*/
|
|
1794
|
-
const isExpiredAttemptsExhaustedGuard = ({ context }) => context.expiredAttempts + 1 >= context.config.captureAttempts;
|
|
1795
|
-
const isNotPassportModeGuard = ({ context }) => context.currentMode !== "passport";
|
|
1796
|
-
/**
|
|
1797
|
-
* V1 parity for `shouldApplyAlwaysCaptureBackOverride` — force-redirects to
|
|
1798
|
-
* back capture after expired-front-attempts exhaust, but only when:
|
|
1799
|
-
* - we're on the front side
|
|
1800
|
-
* - `alwaysCaptureBackOfId` is set
|
|
1801
|
-
* - the flow isn't single-side (onlyBack / usSmartCapture)
|
|
1802
|
-
* - the session isn't a Digital ID upload (digital IDs are PDFs — no back
|
|
1803
|
-
* side exists, so the override never applies regardless of config)
|
|
1804
|
-
*/
|
|
1805
|
-
const shouldForceBackOnExpiredGuard = ({ context }) => context.currentMode === "front" && context.config.alwaysCaptureBackOfId === true && !context.config.onlyBack && !context.config.usSmartCapture && !context.isDigitalUpload;
|
|
1806
|
-
const wasExpiredFromUploadGuard = ({ context }) => context.expiredFromUpload === true;
|
|
1807
|
-
const shouldSkipProcessIdGuard = ({ context }) => context.skipProcessId === true;
|
|
1808
|
-
/**
|
|
1809
|
-
* Bug 4 fix: when `expiredExhausted` is reached via the per-upload-expired
|
|
1810
|
-
* exhaustion path with a back side captured (or the entire single-side back
|
|
1811
|
-
* flow), we want `processId` to run once on Continue so the backend
|
|
1812
|
-
* processes whatever sides were uploaded. Front-only exhaustion (no back to
|
|
1813
|
-
* process) and the force-back V1 path keep using `setSkipProcessId` instead.
|
|
1814
|
-
*/
|
|
1815
|
-
const shouldProcessAfterExhaustionGuard = ({ context }) => context.exhaustedFromUpload === true && context.currentMode === "back";
|
|
1816
|
-
/**
|
|
1817
|
-
* `processing.onDone` reads this to short-circuit straight to `finished`
|
|
1818
|
-
* after the post-exhaustion `processId` call returns — without it, an
|
|
1819
|
-
* `isDocumentExpired:true` response would loop back to the Expired screen
|
|
1820
|
-
* we just terminated.
|
|
1821
|
-
*/
|
|
1822
|
-
const forceFinishAfterProcessingGuard = ({ context }) => context.forceFinishAfterProcessing === true;
|
|
1823
|
-
/**
|
|
1824
|
-
* Cap on the end-of-flow expired path. All capture types (camera, digital,
|
|
1825
|
-
* manual) share `config.captureAttempts` for consistency — the user-visible
|
|
1826
|
-
* "X attempts remaining" counter is the same regardless of how the document
|
|
1827
|
-
* was submitted.
|
|
1828
|
-
*/
|
|
1829
|
-
const isProcessingExpiredExhaustedGuard = ({ context }) => context.processingExpiredAttempts + 1 >= context.config.captureAttempts;
|
|
1830
|
-
|
|
1831
|
-
//#endregion
|
|
1832
|
-
//#region src/modules/id/idCaptureStateMachine.ts
|
|
1833
|
-
function getIdErrorCodeFromUnknown(error) {
|
|
1834
|
-
if (error instanceof Error) {
|
|
1835
|
-
const message = error.message;
|
|
1836
|
-
return Object.values(ID_ERROR_CODES).find((value) => message.includes(value));
|
|
1837
|
-
}
|
|
1838
|
-
}
|
|
1839
|
-
const _idCaptureMachine = setup({
|
|
1840
|
-
types: {
|
|
1841
|
-
context: {},
|
|
1842
|
-
events: {},
|
|
1843
|
-
input: {}
|
|
1844
|
-
},
|
|
1845
|
-
actors: {
|
|
1846
|
-
checkPermission: checkPermissionActor,
|
|
1847
|
-
requestPermission: requestPermissionActor,
|
|
1848
|
-
initializeCamera: initializeCameraActor,
|
|
1849
|
-
runDetection: runDetectionActor,
|
|
1850
|
-
uploadIdImage: uploadIdImageActor,
|
|
1851
|
-
processId: processIdActor,
|
|
1852
|
-
startRecording: startRecordingActor,
|
|
1853
|
-
checkMotionSensor: checkMotionSensorActor,
|
|
1854
|
-
initializeDeepsightSession: initializeDeepsightSessionActor,
|
|
1855
|
-
checkVirtualCamera: checkVirtualCameraActor,
|
|
1856
|
-
manualUploadMachine,
|
|
1857
|
-
digitalUploadMachine
|
|
1858
|
-
},
|
|
1859
|
-
actions: {
|
|
1860
|
-
stopMediaStream: assign(({ context }) => {
|
|
1861
|
-
performStopMediaStream(context);
|
|
1862
|
-
return {
|
|
1863
|
-
stream: void 0,
|
|
1864
|
-
frameCapturer: void 0
|
|
1865
|
-
};
|
|
1866
|
-
}),
|
|
1867
|
-
disposeProvider: ({ context }) => {
|
|
1868
|
-
performDisposeProvider(context);
|
|
1869
|
-
},
|
|
1870
|
-
cleanupDeepsight: ({ context }) => {
|
|
1871
|
-
performCleanupDeepsight(context);
|
|
1872
|
-
},
|
|
1873
|
-
flagIdManualReview: () => {
|
|
1874
|
-
flagIdManualReview();
|
|
1875
|
-
},
|
|
1876
|
-
resetForBackCapture: assign(({ context }) => {
|
|
1877
|
-
performResetForBackCapture(context);
|
|
1878
|
-
return {
|
|
1879
|
-
stream: void 0,
|
|
1880
|
-
frameCapturer: void 0,
|
|
1881
|
-
detectionStatus: "idle",
|
|
1882
|
-
counterValue: 0,
|
|
1883
|
-
orientation: void 0,
|
|
1884
|
-
resetDetection: void 0,
|
|
1885
|
-
idType: void 0,
|
|
1886
|
-
qualityElements: void 0,
|
|
1887
|
-
debugFrame: void 0,
|
|
1888
|
-
frameRect: void 0,
|
|
1889
|
-
previewImageUrl: void 0,
|
|
1890
|
-
uploadProgress: void 0,
|
|
1891
|
-
manualCaptureTriggered: false,
|
|
1892
|
-
attemptsRemaining: context.config.captureAttempts,
|
|
1893
|
-
expiredAttempts: 0,
|
|
1894
|
-
expiredFromUpload: false,
|
|
1895
|
-
exhaustedFromUpload: false,
|
|
1896
|
-
forceFinishAfterProcessing: false,
|
|
1897
|
-
captureResolution: void 0,
|
|
1898
|
-
cameraFallbackLevel: void 0
|
|
1899
|
-
};
|
|
1900
|
-
}),
|
|
1901
|
-
resetForFrontCapture: assign(({ context }) => {
|
|
1902
|
-
performResetForFrontCapture(context);
|
|
1903
|
-
return {
|
|
1904
|
-
stream: void 0,
|
|
1905
|
-
frameCapturer: void 0,
|
|
1906
|
-
detectionStatus: "idle",
|
|
1907
|
-
counterValue: 0,
|
|
1908
|
-
orientation: void 0,
|
|
1909
|
-
resetDetection: void 0,
|
|
1910
|
-
idType: void 0,
|
|
1911
|
-
qualityElements: void 0,
|
|
1912
|
-
debugFrame: void 0,
|
|
1913
|
-
frameRect: void 0,
|
|
1914
|
-
previewImageUrl: void 0,
|
|
1915
|
-
uploadProgress: void 0,
|
|
1916
|
-
manualCaptureTriggered: false,
|
|
1917
|
-
attemptsRemaining: context.config.captureAttempts,
|
|
1918
|
-
expiredAttempts: 0,
|
|
1919
|
-
expiredFromUpload: false,
|
|
1920
|
-
exhaustedFromUpload: false,
|
|
1921
|
-
forceFinishAfterProcessing: false,
|
|
1922
|
-
captureResolution: void 0,
|
|
1923
|
-
cameraFallbackLevel: void 0
|
|
1924
|
-
};
|
|
1925
|
-
}),
|
|
1926
|
-
prepareForBackCapture: assign(({ context }) => {
|
|
1927
|
-
context.provider?.reset();
|
|
1928
|
-
return {
|
|
1929
|
-
detectionStatus: "idle",
|
|
1930
|
-
counterValue: 0,
|
|
1931
|
-
orientation: void 0,
|
|
1932
|
-
resetDetection: void 0,
|
|
1933
|
-
idType: void 0,
|
|
1934
|
-
qualityElements: void 0,
|
|
1935
|
-
debugFrame: void 0,
|
|
1936
|
-
frameRect: void 0,
|
|
1937
|
-
previewImageUrl: void 0,
|
|
1938
|
-
uploadProgress: void 0,
|
|
1939
|
-
manualCaptureTriggered: false,
|
|
1940
|
-
attemptsRemaining: context.config.captureAttempts
|
|
1941
|
-
};
|
|
1942
|
-
}),
|
|
1943
|
-
setStreamAndCapturer: assign({
|
|
1944
|
-
stream: ({ event }) => getStreamFromEvent(event),
|
|
1945
|
-
provider: ({ event }) => getProviderFromEvent(event),
|
|
1946
|
-
frameCapturer: ({ event }) => getFrameCapturerFromEvent(event),
|
|
1947
|
-
captureResolution: ({ event }) => getCaptureResolutionFromEvent(event),
|
|
1948
|
-
cameraFallbackLevel: ({ event }) => getCameraFallbackLevelFromEvent(event)
|
|
1949
|
-
}),
|
|
1950
|
-
trackTutorialId: () => {
|
|
1951
|
-
/* @__PURE__ */ performTrackTutorialId();
|
|
1952
|
-
},
|
|
1953
|
-
trackContinue: () => {
|
|
1954
|
-
/* @__PURE__ */ performTrackContinue();
|
|
1955
|
-
},
|
|
1956
|
-
trackCameraId: ({ context }) => {
|
|
1957
|
-
/* @__PURE__ */ performTrackCameraId(context);
|
|
1958
|
-
},
|
|
1959
|
-
preloadRecordingProvider: ({ context }) => {
|
|
1960
|
-
preloadIdRecordingProvider(context.config);
|
|
1961
|
-
},
|
|
1962
|
-
resetContext: assign(({ context }) => getResetContextValues(context)),
|
|
1963
|
-
resetDetection: ({ context }) => {
|
|
1964
|
-
performResetDetection(context);
|
|
1965
|
-
},
|
|
1966
|
-
captureImage: assign({ qualityElements: ({ event }) => {
|
|
1967
|
-
if ("qualityElements" in event) return event.qualityElements;
|
|
1968
|
-
} }),
|
|
1969
|
-
storeCapturedCanvasInProvider: ({ context, event }) => {
|
|
1970
|
-
storeCapturedCanvasInProviderLogic(context, event);
|
|
1971
|
-
},
|
|
1972
|
-
captureLatestFrame: ({ context }) => {
|
|
1973
|
-
context.frameCapturer?.getLatestCanvas();
|
|
1974
|
-
},
|
|
1975
|
-
clearUploadFailure: assign(({ context }) => getClearUploadFailureValues(context)),
|
|
1976
|
-
clearStreamForRetry: assign(({ context }) => {
|
|
1977
|
-
performStopMediaStream(context);
|
|
1978
|
-
performDisposeProvider(context);
|
|
1979
|
-
return {
|
|
1980
|
-
stream: void 0,
|
|
1981
|
-
provider: void 0,
|
|
1982
|
-
frameCapturer: void 0,
|
|
1983
|
-
captureResolution: void 0,
|
|
1984
|
-
cameraFallbackLevel: void 0
|
|
1985
|
-
};
|
|
1986
|
-
}),
|
|
1987
|
-
decrementAttemptsRemaining: assign(({ context }) => ({ attemptsRemaining: context.attemptsRemaining - 1 })),
|
|
1988
|
-
setUploadErrorFromUploadValidation: assign({ uploadError: ({ context }) => getUploadValidationError(context) }),
|
|
1989
|
-
stopMediaRecording: ({ context }) => {
|
|
1990
|
-
performStopMediaRecording(context);
|
|
1991
|
-
},
|
|
1992
|
-
clearRecordingSession: assign({ recordingSession: () => void 0 }),
|
|
1993
|
-
setSelectedDocument: assign({ selectedDocumentType: ({ event }) => {
|
|
1994
|
-
if ("documentType" in event) return event.documentType;
|
|
1995
|
-
} }),
|
|
1996
|
-
setCurrentMode: assign({ currentMode: ({ event, context }) => getCurrentModeFromEvent(context, event) }),
|
|
1997
|
-
storeCapturedImage: assign(({ context, event }) => getStoreCapturedImageValues(context, event)),
|
|
1998
|
-
setDetectionStatus: assign({ detectionStatus: ({ event, context }) => getDetectionStatusFromUpdate(context, event) }),
|
|
1999
|
-
setCounterValue: assign({ counterValue: ({ event }) => {
|
|
2000
|
-
if ("value" in event) return event.value;
|
|
2001
|
-
return 0;
|
|
2002
|
-
} }),
|
|
2003
|
-
setIdType: assign({ idType: ({ event }) => {
|
|
2004
|
-
if ("idType" in event) return event.idType;
|
|
2005
|
-
} }),
|
|
2006
|
-
setOrientation: assign({ orientation: ({ event }) => {
|
|
2007
|
-
if ("orientation" in event) return event.orientation;
|
|
2008
|
-
} }),
|
|
2009
|
-
setFrameRect: assign({ frameRect: ({ event }) => {
|
|
2010
|
-
if ("frameRect" in event) return event.frameRect;
|
|
2011
|
-
} }),
|
|
2012
|
-
setDetectionArea: assign({ detectionArea: ({ event }) => {
|
|
2013
|
-
if ("detectionArea" in event) return event.detectionArea;
|
|
2014
|
-
} }),
|
|
2015
|
-
setMotionStatus: assign({ motionStatus: ({ event }) => {
|
|
2016
|
-
if ("status" in event && event.type === "MOTION_STATUS") return event.status;
|
|
2017
|
-
} }),
|
|
2018
|
-
incrementExpiredAttempts: assign(({ context }) => ({ expiredAttempts: context.expiredAttempts + 1 })),
|
|
2019
|
-
storeDigitalUploadResponse: assign(({ self }) => {
|
|
2020
|
-
const response = ((self.getSnapshot().children?.["digitalIdUpload"]?.getSnapshot())?.context)?.response;
|
|
2021
|
-
if (!response) return { isDigitalUpload: true };
|
|
2022
|
-
return {
|
|
2023
|
-
uploadResponse: response,
|
|
2024
|
-
isDigitalUpload: true
|
|
2025
|
-
};
|
|
2026
|
-
}),
|
|
2027
|
-
incrementProcessingExpiredAttempts: assign(({ context }) => ({ processingExpiredAttempts: context.processingExpiredAttempts + 1 })),
|
|
2028
|
-
setSkipProcessId: assign({ skipProcessId: () => true }),
|
|
2029
|
-
setExpiredFromUpload: assign({ expiredFromUpload: () => true }),
|
|
2030
|
-
setExhaustedFromUpload: assign({ exhaustedFromUpload: () => true }),
|
|
2031
|
-
setForceFinishAfterProcessing: assign({ forceFinishAfterProcessing: () => true }),
|
|
2032
|
-
clearExpiredFromUpload: assign({ expiredFromUpload: () => false })
|
|
2033
|
-
},
|
|
2034
|
-
guards: {
|
|
2035
|
-
hasShowTutorial: hasShowTutorialGuard,
|
|
2036
|
-
hasAgeAssurance: hasAgeAssuranceGuard,
|
|
2037
|
-
hasShowDocumentChooser: hasShowDocumentChooserGuard,
|
|
2038
|
-
isPermissionGranted: isPermissionGrantedGuard,
|
|
2039
|
-
isPermissionDeniedError: isPermissionDeniedErrorGuard,
|
|
2040
|
-
hasStream: hasStreamGuard,
|
|
2041
|
-
hasAttemptsRemaining: hasAttemptsRemainingGuard,
|
|
2042
|
-
hasCapturedImage: hasCapturedImageGuard,
|
|
2043
|
-
hasUploadValidationError: hasUploadValidationErrorGuard,
|
|
2044
|
-
isFrontMode: isFrontModeGuard,
|
|
2045
|
-
isOnlyFront: isOnlyFrontGuard,
|
|
2046
|
-
shouldContinueToBack: shouldContinueToBackGuard,
|
|
2047
|
-
shouldContinueToFront: shouldContinueToFrontGuard,
|
|
2048
|
-
hasMandatoryConsent: hasMandatoryConsentGuard,
|
|
2049
|
-
isDeepsightEnabled: isDeepsightEnabledGuard,
|
|
2050
|
-
isDeepsightReady: isDeepsightReadyGuard,
|
|
2051
|
-
needsDeepsightInit: needsDeepsightInitGuard,
|
|
2052
|
-
hasOnlyManualUploadAvailable: hasOnlyManualUploadAvailableGuard,
|
|
2053
|
-
isManualIdUploadSelected: isManualIdUploadSelectedGuard,
|
|
2054
|
-
isDigitalIdUploadSelected: isDigitalIdUploadSelectedGuard,
|
|
2055
|
-
isUploadExpired: isUploadExpiredGuard,
|
|
2056
|
-
isExpiredAttemptsExhausted: isExpiredAttemptsExhaustedGuard,
|
|
2057
|
-
isNotPassportMode: isNotPassportModeGuard,
|
|
2058
|
-
shouldForceBackOnExpired: shouldForceBackOnExpiredGuard,
|
|
2059
|
-
wasExpiredFromUpload: wasExpiredFromUploadGuard,
|
|
2060
|
-
shouldSkipProcessId: shouldSkipProcessIdGuard,
|
|
2061
|
-
isProcessingExpiredExhausted: isProcessingExpiredExhaustedGuard,
|
|
2062
|
-
shouldProcessAfterExhaustion: shouldProcessAfterExhaustionGuard,
|
|
2063
|
-
forceFinishAfterProcessing: forceFinishAfterProcessingGuard,
|
|
2064
|
-
isManualUploadExhausted: ({ event }) => event.output?.result === "exhausted",
|
|
2065
|
-
isDigitalUploadExhausted: ({ event }) => event.output?.result === "exhausted",
|
|
2066
|
-
isDigitalUploadClosed: ({ event }) => event.output?.result === "closed",
|
|
2067
|
-
isDigitalUploadSuccessful: ({ event }) => event.output?.result === "success"
|
|
2068
|
-
}
|
|
2069
|
-
}).createMachine({
|
|
2070
|
-
id: "idCapture",
|
|
2071
|
-
initial: "idle",
|
|
2072
|
-
context: ({ input }) => {
|
|
2073
|
-
const currentMode = input.config.onlyBack ? "back" : !input.config.enableId && input.config.enablePassport ? "passport" : input.config.usSmartCapture ? "back" : "front";
|
|
2074
|
-
return {
|
|
2075
|
-
config: input.config,
|
|
2076
|
-
currentMode,
|
|
2077
|
-
selectedDocumentType: void 0,
|
|
2078
|
-
stream: void 0,
|
|
2079
|
-
provider: void 0,
|
|
2080
|
-
frameCapturer: void 0,
|
|
2081
|
-
error: void 0,
|
|
2082
|
-
detectionStatus: "idle",
|
|
2083
|
-
counterValue: 0,
|
|
2084
|
-
orientation: void 0,
|
|
2085
|
-
capturedImages: {},
|
|
2086
|
-
captureOnlyImages: {},
|
|
2087
|
-
uploadResponse: void 0,
|
|
2088
|
-
recordingSession: void 0,
|
|
2089
|
-
attemptsRemaining: input.config.captureAttempts,
|
|
2090
|
-
expiredAttempts: 0,
|
|
2091
|
-
processingExpiredAttempts: 0,
|
|
2092
|
-
skipProcessId: input.config.skipProcessId === true,
|
|
2093
|
-
expiredFromUpload: false,
|
|
2094
|
-
isDigitalUpload: false,
|
|
2095
|
-
exhaustedFromUpload: false,
|
|
2096
|
-
forceFinishAfterProcessing: false,
|
|
2097
|
-
uploadError: void 0,
|
|
2098
|
-
permissionResult: void 0,
|
|
2099
|
-
resetDetection: void 0,
|
|
2100
|
-
idType: void 0,
|
|
2101
|
-
qualityElements: void 0,
|
|
2102
|
-
debugFrame: void 0,
|
|
2103
|
-
frameRect: void 0,
|
|
2104
|
-
detectionArea: void 0,
|
|
2105
|
-
previewImageUrl: void 0,
|
|
2106
|
-
uploadProgress: void 0,
|
|
2107
|
-
motionStatus: void 0,
|
|
2108
|
-
manualCaptureTriggered: false,
|
|
2109
|
-
deepsightService: void 0,
|
|
2110
|
-
analyticsProvider: input.analyticsProvider,
|
|
2111
|
-
dependencies: input.dependencies,
|
|
2112
|
-
disableIpify: getDisableIpify(),
|
|
2113
|
-
deepsightInitAttempted: false,
|
|
2114
|
-
availableDocumentTypes: getAvailableDocumentTypes(input.config),
|
|
2115
|
-
captureResolution: void 0,
|
|
2116
|
-
cameraFallbackLevel: void 0
|
|
2117
|
-
};
|
|
2118
|
-
},
|
|
2119
|
-
on: {
|
|
2120
|
-
QUIT: { target: "#idCapture.closed" },
|
|
2121
|
-
UPDATE_DETECTION_AREA: { actions: "setDetectionArea" }
|
|
2122
|
-
},
|
|
2123
|
-
states: {
|
|
2124
|
-
idle: { on: { LOAD: [
|
|
2125
|
-
{
|
|
2126
|
-
target: "manualIdUpload",
|
|
2127
|
-
guard: "hasOnlyManualUploadAvailable"
|
|
2128
|
-
},
|
|
2129
|
-
{
|
|
2130
|
-
target: "chooser",
|
|
2131
|
-
guard: "hasShowDocumentChooser"
|
|
2132
|
-
},
|
|
2133
|
-
{
|
|
2134
|
-
target: "ageVerification",
|
|
2135
|
-
guard: "hasAgeAssurance"
|
|
2136
|
-
},
|
|
2137
|
-
{
|
|
2138
|
-
target: "tutorial",
|
|
2139
|
-
guard: "hasShowTutorial"
|
|
2140
|
-
},
|
|
2141
|
-
{ target: "loading" }
|
|
2142
|
-
] } },
|
|
2143
|
-
chooser: { on: { SELECT_DOCUMENT: [
|
|
2144
|
-
{
|
|
2145
|
-
target: "digitalIdUpload",
|
|
2146
|
-
guard: "isDigitalIdUploadSelected",
|
|
2147
|
-
actions: ["setSelectedDocument"]
|
|
2148
|
-
},
|
|
2149
|
-
{
|
|
2150
|
-
target: "manualIdUpload",
|
|
2151
|
-
guard: "isManualIdUploadSelected",
|
|
2152
|
-
actions: ["setSelectedDocument"]
|
|
2153
|
-
},
|
|
2154
|
-
{
|
|
2155
|
-
target: "ageVerification",
|
|
2156
|
-
guard: "hasAgeAssurance",
|
|
2157
|
-
actions: ["setSelectedDocument", "setCurrentMode"]
|
|
2158
|
-
},
|
|
2159
|
-
{
|
|
2160
|
-
target: "tutorial",
|
|
2161
|
-
guard: "hasShowTutorial",
|
|
2162
|
-
actions: ["setSelectedDocument", "setCurrentMode"]
|
|
2163
|
-
},
|
|
2164
|
-
{
|
|
2165
|
-
target: "loading",
|
|
2166
|
-
actions: ["setSelectedDocument", "setCurrentMode"]
|
|
2167
|
-
}
|
|
2168
|
-
] } },
|
|
2169
|
-
ageVerification: { on: { NEXT_STEP: [{
|
|
2170
|
-
target: "tutorial",
|
|
2171
|
-
guard: "hasShowTutorial",
|
|
2172
|
-
actions: "trackContinue"
|
|
2173
|
-
}, {
|
|
2174
|
-
target: "loading",
|
|
2175
|
-
actions: "trackContinue"
|
|
2176
|
-
}] } },
|
|
2177
|
-
loading: {
|
|
2178
|
-
entry: "preloadRecordingProvider",
|
|
2179
|
-
type: "parallel",
|
|
2180
|
-
states: {
|
|
2181
|
-
permissionCheck: {
|
|
2182
|
-
initial: "checking",
|
|
2183
|
-
states: {
|
|
2184
|
-
checking: { invoke: {
|
|
2185
|
-
id: "checkPermissionLoading",
|
|
2186
|
-
src: "checkPermission",
|
|
2187
|
-
onDone: {
|
|
2188
|
-
target: "done",
|
|
2189
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2190
|
-
},
|
|
2191
|
-
onError: {
|
|
2192
|
-
target: "done",
|
|
2193
|
-
actions: assign({ permissionResult: () => "prompt" })
|
|
2194
|
-
}
|
|
2195
|
-
} },
|
|
2196
|
-
done: { type: "final" }
|
|
2197
|
-
}
|
|
2198
|
-
},
|
|
2199
|
-
deepsightInit: {
|
|
2200
|
-
initial: "initializing",
|
|
2201
|
-
states: {
|
|
2202
|
-
initializing: { invoke: {
|
|
2203
|
-
id: "initDeepsightLoading",
|
|
2204
|
-
src: "initializeDeepsightSession",
|
|
2205
|
-
input: ({ context }) => ({
|
|
2206
|
-
ds: context.config.ds,
|
|
2207
|
-
dependencies: context.dependencies,
|
|
2208
|
-
disableIpify: context.disableIpify
|
|
2209
|
-
}),
|
|
2210
|
-
onDone: {
|
|
2211
|
-
target: "done",
|
|
2212
|
-
actions: assign({
|
|
2213
|
-
deepsightService: ({ event }) => event.output,
|
|
2214
|
-
deepsightInitAttempted: () => true
|
|
2215
|
-
})
|
|
2216
|
-
},
|
|
2217
|
-
onError: {
|
|
2218
|
-
target: "done",
|
|
2219
|
-
actions: [assign({ deepsightInitAttempted: () => true }), () => console.warn("Deepsight initialization failed")]
|
|
2220
|
-
}
|
|
2221
|
-
} },
|
|
2222
|
-
done: { type: "final" }
|
|
2223
|
-
}
|
|
2224
|
-
}
|
|
2225
|
-
},
|
|
2226
|
-
onDone: [{
|
|
2227
|
-
target: "capture",
|
|
2228
|
-
guard: "isPermissionGranted"
|
|
2229
|
-
}, { target: "permissions" }]
|
|
2230
|
-
},
|
|
2231
|
-
tutorial: {
|
|
2232
|
-
initial: "checkingPermission",
|
|
2233
|
-
entry: ["trackTutorialId", "preloadRecordingProvider"],
|
|
2234
|
-
states: {
|
|
2235
|
-
checkingPermission: {
|
|
2236
|
-
invoke: {
|
|
2237
|
-
id: "checkPermissionTutorial",
|
|
2238
|
-
src: "checkPermission",
|
|
2239
|
-
onDone: [{
|
|
2240
|
-
target: "initializingCamera",
|
|
2241
|
-
guard: "isPermissionGranted",
|
|
2242
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2243
|
-
}, {
|
|
2244
|
-
target: "ready",
|
|
2245
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2246
|
-
}]
|
|
2247
|
-
},
|
|
2248
|
-
on: { NEXT_STEP: {
|
|
2249
|
-
target: "#idCapture.capture",
|
|
2250
|
-
actions: "trackContinue"
|
|
2251
|
-
} }
|
|
2252
|
-
},
|
|
2253
|
-
initializingCamera: {
|
|
2254
|
-
type: "parallel",
|
|
2255
|
-
states: {
|
|
2256
|
-
cameraInit: {
|
|
2257
|
-
initial: "initializingDeepsight",
|
|
2258
|
-
states: {
|
|
2259
|
-
initializingDeepsight: { invoke: {
|
|
2260
|
-
id: "tutorialInitDeepsight",
|
|
2261
|
-
src: "initializeDeepsightSession",
|
|
2262
|
-
input: ({ context }) => ({
|
|
2263
|
-
ds: context.config.ds,
|
|
2264
|
-
dependencies: context.dependencies,
|
|
2265
|
-
disableIpify: context.disableIpify
|
|
2266
|
-
}),
|
|
2267
|
-
onDone: {
|
|
2268
|
-
target: "initializingStream",
|
|
2269
|
-
actions: assign({
|
|
2270
|
-
deepsightService: ({ event }) => event.output,
|
|
2271
|
-
deepsightInitAttempted: () => true
|
|
2272
|
-
})
|
|
2273
|
-
},
|
|
2274
|
-
onError: {
|
|
2275
|
-
target: "initializingStream",
|
|
2276
|
-
actions: [assign({ deepsightInitAttempted: () => true }), () => console.warn("Deepsight initialization failed in tutorial")]
|
|
2277
|
-
}
|
|
2278
|
-
} },
|
|
2279
|
-
initializingStream: { invoke: {
|
|
2280
|
-
id: "tutorialInitCamera",
|
|
2281
|
-
src: "initializeCamera",
|
|
2282
|
-
input: ({ context }) => ({
|
|
2283
|
-
config: context.config,
|
|
2284
|
-
deepsightService: context.deepsightService
|
|
2285
|
-
}),
|
|
2286
|
-
onDone: {
|
|
2287
|
-
target: "ready",
|
|
2288
|
-
actions: "setStreamAndCapturer"
|
|
2289
|
-
},
|
|
2290
|
-
onError: [{
|
|
2291
|
-
target: "#idCapture.tutorial.ready",
|
|
2292
|
-
guard: "isPermissionDeniedError",
|
|
2293
|
-
actions: assign({ permissionResult: () => {
|
|
2294
|
-
return "denied";
|
|
2295
|
-
} })
|
|
2296
|
-
}, {
|
|
2297
|
-
target: "#idCapture.tutorial.ready",
|
|
2298
|
-
actions: assign({ error: ({ event }) => String(event.error) })
|
|
2299
|
-
}]
|
|
2300
|
-
} },
|
|
2301
|
-
ready: { type: "final" }
|
|
2302
|
-
}
|
|
2303
|
-
},
|
|
2304
|
-
userIntent: {
|
|
2305
|
-
initial: "booting",
|
|
2306
|
-
states: {
|
|
2307
|
-
booting: { on: { NEXT_STEP: {
|
|
2308
|
-
target: "clicked",
|
|
2309
|
-
actions: "trackContinue"
|
|
2310
|
-
} } },
|
|
2311
|
-
clicked: { type: "final" }
|
|
2312
|
-
}
|
|
2313
|
-
}
|
|
2314
|
-
},
|
|
2315
|
-
onDone: { target: "#idCapture.capture" }
|
|
2316
|
-
},
|
|
2317
|
-
ready: { on: { NEXT_STEP: {
|
|
2318
|
-
target: "waitingForPermission",
|
|
2319
|
-
actions: "trackContinue"
|
|
2320
|
-
} } },
|
|
2321
|
-
waitingForPermission: { invoke: {
|
|
2322
|
-
id: "checkPermissionWaiting",
|
|
2323
|
-
src: "checkPermission",
|
|
2324
|
-
onDone: [{
|
|
2325
|
-
target: "#idCapture.capture",
|
|
2326
|
-
guard: "isPermissionGranted",
|
|
2327
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2328
|
-
}, {
|
|
2329
|
-
target: "#idCapture.permissions",
|
|
2330
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2331
|
-
}]
|
|
2332
|
-
} }
|
|
2333
|
-
}
|
|
2334
|
-
},
|
|
2335
|
-
permissions: {
|
|
2336
|
-
entry: "preloadRecordingProvider",
|
|
2337
|
-
initial: "idle",
|
|
2338
|
-
states: {
|
|
2339
|
-
idle: {
|
|
2340
|
-
invoke: {
|
|
2341
|
-
id: "checkPermissionIdle",
|
|
2342
|
-
src: "checkPermission",
|
|
2343
|
-
onDone: [
|
|
2344
|
-
{
|
|
2345
|
-
target: "#idCapture.capture",
|
|
2346
|
-
guard: "isPermissionGranted",
|
|
2347
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2348
|
-
},
|
|
2349
|
-
{
|
|
2350
|
-
target: "denied",
|
|
2351
|
-
guard: ({ event }) => event.output === "denied",
|
|
2352
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2353
|
-
},
|
|
2354
|
-
{
|
|
2355
|
-
target: "waitingForUser",
|
|
2356
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2357
|
-
}
|
|
2358
|
-
],
|
|
2359
|
-
onError: {
|
|
2360
|
-
target: "waitingForUser",
|
|
2361
|
-
actions: assign({ permissionResult: () => "prompt" })
|
|
2362
|
-
}
|
|
2363
|
-
},
|
|
2364
|
-
on: {
|
|
2365
|
-
REQUEST_PERMISSION: "requesting",
|
|
2366
|
-
GO_TO_LEARN_MORE: "learnMore"
|
|
2367
|
-
}
|
|
2368
|
-
},
|
|
2369
|
-
waitingForUser: { on: {
|
|
2370
|
-
REQUEST_PERMISSION: "requesting",
|
|
2371
|
-
GO_TO_LEARN_MORE: "learnMore"
|
|
2372
|
-
} },
|
|
2373
|
-
learnMore: { on: {
|
|
2374
|
-
BACK: "idle",
|
|
2375
|
-
REQUEST_PERMISSION: "requesting"
|
|
2376
|
-
} },
|
|
2377
|
-
requesting: { invoke: {
|
|
2378
|
-
id: "requestPermission",
|
|
2379
|
-
src: "requestPermission",
|
|
2380
|
-
input: ({ context }) => ({ requestMotionPermission: context.config.ds === true }),
|
|
2381
|
-
onDone: [
|
|
2382
|
-
{
|
|
2383
|
-
target: "#idCapture.capture",
|
|
2384
|
-
guard: "isPermissionGranted",
|
|
2385
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2386
|
-
},
|
|
2387
|
-
{
|
|
2388
|
-
target: "denied",
|
|
2389
|
-
guard: ({ event }) => event.output === "denied",
|
|
2390
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2391
|
-
},
|
|
2392
|
-
{
|
|
2393
|
-
target: "idle",
|
|
2394
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2395
|
-
}
|
|
2396
|
-
],
|
|
2397
|
-
onError: { target: "denied" }
|
|
2398
|
-
} },
|
|
2399
|
-
denied: { entry: assign({ permissionResult: () => "refresh" }) }
|
|
2400
|
-
}
|
|
2401
|
-
},
|
|
2402
|
-
capture: {
|
|
2403
|
-
initial: "checkingStream",
|
|
2404
|
-
entry: ["trackCameraId", "preloadRecordingProvider"],
|
|
2405
|
-
exit: ["stopMediaRecording", "clearRecordingSession"],
|
|
2406
|
-
on: { SET_FRAME_RECT: { actions: "setFrameRect" } },
|
|
2407
|
-
states: {
|
|
2408
|
-
checkingStream: { always: [
|
|
2409
|
-
{
|
|
2410
|
-
target: "initializingDeepsight",
|
|
2411
|
-
guard: "needsDeepsightInit"
|
|
2412
|
-
},
|
|
2413
|
-
{
|
|
2414
|
-
target: "detecting",
|
|
2415
|
-
guard: "hasStream"
|
|
2416
|
-
},
|
|
2417
|
-
{ target: "initializing" }
|
|
2418
|
-
] },
|
|
2419
|
-
initializingDeepsight: { invoke: {
|
|
2420
|
-
id: "initDeepsightCapture",
|
|
2421
|
-
src: "initializeDeepsightSession",
|
|
2422
|
-
input: ({ context }) => ({
|
|
2423
|
-
ds: context.config.ds,
|
|
2424
|
-
dependencies: context.dependencies,
|
|
2425
|
-
disableIpify: context.disableIpify
|
|
2426
|
-
}),
|
|
2427
|
-
onDone: {
|
|
2428
|
-
target: "checkingStream",
|
|
2429
|
-
actions: assign({
|
|
2430
|
-
deepsightService: ({ event }) => event.output,
|
|
2431
|
-
deepsightInitAttempted: () => true
|
|
2432
|
-
})
|
|
2433
|
-
},
|
|
2434
|
-
onError: {
|
|
2435
|
-
target: "checkingStream",
|
|
2436
|
-
actions: [assign({ deepsightInitAttempted: () => true }), () => console.warn("Deepsight initialization failed in capture")]
|
|
2437
|
-
}
|
|
2438
|
-
} },
|
|
2439
|
-
initializing: { invoke: {
|
|
2440
|
-
id: "initializeCamera",
|
|
2441
|
-
src: "initializeCamera",
|
|
2442
|
-
input: ({ context }) => ({
|
|
2443
|
-
config: context.config,
|
|
2444
|
-
deepsightService: context.deepsightService
|
|
2445
|
-
}),
|
|
2446
|
-
onDone: {
|
|
2447
|
-
target: "detecting",
|
|
2448
|
-
actions: "setStreamAndCapturer"
|
|
2449
|
-
},
|
|
2450
|
-
onError: [{
|
|
2451
|
-
target: "#idCapture.permissions",
|
|
2452
|
-
guard: "isPermissionDeniedError",
|
|
2453
|
-
actions: assign({ permissionResult: () => "denied" })
|
|
2454
|
-
}, {
|
|
2455
|
-
target: "#idCapture.error",
|
|
2456
|
-
actions: assign({ error: ({ event }) => String(event.error) })
|
|
2457
|
-
}]
|
|
2458
|
-
} },
|
|
2459
|
-
detecting: {
|
|
2460
|
-
always: [{
|
|
2461
|
-
target: "manualCaptureWaiting",
|
|
2462
|
-
guard: ({ context }) => context.manualCaptureTriggered,
|
|
2463
|
-
actions: assign({ detectionStatus: () => "manualCapture" })
|
|
2464
|
-
}],
|
|
2465
|
-
entry: [assign({ detectionStatus: () => "detecting" })],
|
|
2466
|
-
invoke: [{
|
|
2467
|
-
id: "startRecording",
|
|
2468
|
-
src: "startRecording",
|
|
2469
|
-
input: ({ context }) => ({
|
|
2470
|
-
config: context.config,
|
|
2471
|
-
stream: context.stream,
|
|
2472
|
-
existing: context.recordingSession,
|
|
2473
|
-
currentMode: context.currentMode
|
|
2474
|
-
}),
|
|
2475
|
-
onDone: { actions: assign({ recordingSession: ({ context, event }) => {
|
|
2476
|
-
return event.output ?? context.recordingSession;
|
|
2477
|
-
} }) },
|
|
2478
|
-
onError: { actions: () => void 0 }
|
|
2479
|
-
}, {
|
|
2480
|
-
id: "runDetection",
|
|
2481
|
-
src: "runDetection",
|
|
2482
|
-
input: ({ context }) => ({
|
|
2483
|
-
frameCapturer: context.frameCapturer,
|
|
2484
|
-
provider: context.provider,
|
|
2485
|
-
config: context.config,
|
|
2486
|
-
currentMode: context.currentMode,
|
|
2487
|
-
detectionArea: context.detectionArea ?? context.config.detectionArea
|
|
2488
|
-
})
|
|
2489
|
-
}],
|
|
2490
|
-
on: {
|
|
2491
|
-
DETECTION_UPDATE: { actions: "setDetectionStatus" },
|
|
2492
|
-
DETECTION_FRAME: { actions: assign({ debugFrame: ({ event }) => event.frame }) },
|
|
2493
|
-
DETECTION_RESET_READY: { actions: assign({ resetDetection: ({ event }) => event.reset }) },
|
|
2494
|
-
DETECTION_SUCCESS: {
|
|
2495
|
-
target: "capturing",
|
|
2496
|
-
actions: assign({ qualityElements: ({ event }) => event.qualityElements })
|
|
2497
|
-
},
|
|
2498
|
-
MANUAL_CAPTURE: { target: "capturingManual" },
|
|
2499
|
-
SWITCH_TO_MANUAL_CAPTURE: {
|
|
2500
|
-
target: "manualCaptureWaiting",
|
|
2501
|
-
actions: assign({
|
|
2502
|
-
detectionStatus: () => "manualCapture",
|
|
2503
|
-
manualCaptureTriggered: () => true
|
|
2504
|
-
})
|
|
2505
|
-
},
|
|
2506
|
-
COUNTER_VALUE_CHANGE: { actions: "setCounterValue" },
|
|
2507
|
-
ID_TYPE_CHANGE: { actions: "setIdType" },
|
|
2508
|
-
ID_SIDE_CHANGE: { actions: assign({ detectionStatus: ({ event, context }) => getDetectionStatusFromSideChange(context, event.side) }) },
|
|
2509
|
-
ORIENTATION_CHANGE: { actions: "setOrientation" }
|
|
2510
|
-
}
|
|
2511
|
-
},
|
|
2512
|
-
manualCaptureWaiting: { on: { MANUAL_CAPTURE: { target: "capturingManual" } } },
|
|
2513
|
-
capturing: {
|
|
2514
|
-
entry: [
|
|
2515
|
-
"captureImage",
|
|
2516
|
-
"storeCapturedCanvasInProvider",
|
|
2517
|
-
"storeCapturedImage"
|
|
2518
|
-
],
|
|
2519
|
-
always: [{
|
|
2520
|
-
target: "uploading",
|
|
2521
|
-
guard: "hasCapturedImage"
|
|
2522
|
-
}, {
|
|
2523
|
-
target: "uploadError",
|
|
2524
|
-
actions: assign(({ context }) => ({
|
|
2525
|
-
uploadError: ID_ERROR_CODES.UPLOAD_ERROR,
|
|
2526
|
-
attemptsRemaining: context.attemptsRemaining - 1
|
|
2527
|
-
}))
|
|
2528
|
-
}]
|
|
2529
|
-
},
|
|
2530
|
-
capturingManual: {
|
|
2531
|
-
entry: [
|
|
2532
|
-
"captureLatestFrame",
|
|
2533
|
-
"storeCapturedCanvasInProvider",
|
|
2534
|
-
"storeCapturedImage"
|
|
2535
|
-
],
|
|
2536
|
-
always: [{
|
|
2537
|
-
target: "uploading",
|
|
2538
|
-
guard: "hasCapturedImage"
|
|
2539
|
-
}, {
|
|
2540
|
-
target: "uploadError",
|
|
2541
|
-
actions: assign(({ context }) => ({
|
|
2542
|
-
uploadError: ID_ERROR_CODES.UPLOAD_ERROR,
|
|
2543
|
-
attemptsRemaining: context.attemptsRemaining - 1
|
|
2544
|
-
}))
|
|
2545
|
-
}]
|
|
2546
|
-
},
|
|
2547
|
-
uploading: {
|
|
2548
|
-
entry: assign({ uploadProgress: () => 0 }),
|
|
2549
|
-
invoke: {
|
|
2550
|
-
id: "uploadIdImage",
|
|
2551
|
-
src: "uploadIdImage",
|
|
2552
|
-
input: ({ context, self }) => {
|
|
2553
|
-
const canvas = context.provider?.getOriginalCapturedCanvas();
|
|
2554
|
-
if (!canvas) throw new Error(ID_ERROR_CODES.UPLOAD_ERROR);
|
|
2555
|
-
return {
|
|
2556
|
-
canvas,
|
|
2557
|
-
type: context.currentMode === "back" ? "back" : "front",
|
|
2558
|
-
qualityElements: context.qualityElements,
|
|
2559
|
-
onProgress: (progress) => {
|
|
2560
|
-
self.send({
|
|
2561
|
-
type: "UPLOAD_PROGRESS",
|
|
2562
|
-
progress
|
|
2563
|
-
});
|
|
2564
|
-
},
|
|
2565
|
-
deepsightService: context.deepsightService,
|
|
2566
|
-
stream: context.stream,
|
|
2567
|
-
isSecondId: context.config.isSecondId ?? false,
|
|
2568
|
-
onlyFront: false,
|
|
2569
|
-
ageAssurance: context.config.ageAssurance,
|
|
2570
|
-
dependencies: context.dependencies,
|
|
2571
|
-
captureResolution: context.captureResolution,
|
|
2572
|
-
cameraFallbackLevel: context.cameraFallbackLevel,
|
|
2573
|
-
croppedCanvas: context.provider?.getCapturedCanvas() ?? null
|
|
2574
|
-
};
|
|
2575
|
-
},
|
|
2576
|
-
onDone: {
|
|
2577
|
-
target: "validatingUpload",
|
|
2578
|
-
actions: [assign({
|
|
2579
|
-
uploadResponse: ({ event }) => event.output,
|
|
2580
|
-
uploadProgress: () => 100
|
|
2581
|
-
}), "storeCapturedImage"]
|
|
2582
|
-
},
|
|
2583
|
-
onError: {
|
|
2584
|
-
target: "uploadError",
|
|
2585
|
-
actions: assign(({ context, event }) => ({
|
|
2586
|
-
uploadError: getIdErrorCodeFromUnknown(event.error) ?? ID_ERROR_CODES.UPLOAD_ERROR,
|
|
2587
|
-
attemptsRemaining: context.attemptsRemaining - 1
|
|
2588
|
-
}))
|
|
2589
|
-
}
|
|
2590
|
-
},
|
|
2591
|
-
on: { UPLOAD_PROGRESS: { actions: assign({ uploadProgress: ({ event }) => event.progress }) } }
|
|
2592
|
-
},
|
|
2593
|
-
validatingUpload: { always: [
|
|
2594
|
-
{
|
|
2595
|
-
target: "uploadError",
|
|
2596
|
-
guard: "hasUploadValidationError",
|
|
2597
|
-
actions: ["setUploadErrorFromUploadValidation", "decrementAttemptsRemaining"]
|
|
2598
|
-
},
|
|
2599
|
-
{
|
|
2600
|
-
target: "#idCapture.finished",
|
|
2601
|
-
guard: and(["shouldSkipProcessId", "isUploadExpired"])
|
|
2602
|
-
},
|
|
2603
|
-
{
|
|
2604
|
-
target: "#idCapture.expiredExhausted",
|
|
2605
|
-
guard: and([
|
|
2606
|
-
"isNotPassportMode",
|
|
2607
|
-
"isUploadExpired",
|
|
2608
|
-
"isExpiredAttemptsExhausted"
|
|
2609
|
-
]),
|
|
2610
|
-
actions: ["incrementExpiredAttempts", "setExhaustedFromUpload"]
|
|
2611
|
-
},
|
|
2612
|
-
{
|
|
2613
|
-
target: "#idCapture.expired",
|
|
2614
|
-
guard: and(["isNotPassportMode", "isUploadExpired"]),
|
|
2615
|
-
actions: ["incrementExpiredAttempts", "setExpiredFromUpload"]
|
|
2616
|
-
},
|
|
2617
|
-
{ target: "success" }
|
|
2618
|
-
] },
|
|
2619
|
-
uploadError: { on: { CONTINUE_FROM_ERROR: [
|
|
2620
|
-
{
|
|
2621
|
-
target: "checkingStream",
|
|
2622
|
-
guard: "hasAttemptsRemaining",
|
|
2623
|
-
actions: [
|
|
2624
|
-
"resetDetection",
|
|
2625
|
-
"clearUploadFailure",
|
|
2626
|
-
"clearStreamForRetry"
|
|
2627
|
-
]
|
|
2628
|
-
},
|
|
2629
|
-
{
|
|
2630
|
-
target: "#idCapture.frontFinished",
|
|
2631
|
-
guard: "shouldContinueToBack",
|
|
2632
|
-
actions: ["flagIdManualReview"]
|
|
2633
|
-
},
|
|
2634
|
-
{
|
|
2635
|
-
target: "#idCapture.backFinished",
|
|
2636
|
-
guard: "shouldContinueToFront",
|
|
2637
|
-
actions: ["flagIdManualReview"]
|
|
2638
|
-
},
|
|
2639
|
-
{
|
|
2640
|
-
target: "#idCapture.processing",
|
|
2641
|
-
actions: ["flagIdManualReview"]
|
|
2642
|
-
}
|
|
2643
|
-
] } },
|
|
2644
|
-
success: { on: { NEXT_STEP: [
|
|
2645
|
-
{
|
|
2646
|
-
target: "#idCapture.mandatoryConsent",
|
|
2647
|
-
guard: "hasMandatoryConsent"
|
|
2648
|
-
},
|
|
2649
|
-
{
|
|
2650
|
-
target: "#idCapture.frontFinished",
|
|
2651
|
-
guard: "shouldContinueToBack"
|
|
2652
|
-
},
|
|
2653
|
-
{
|
|
2654
|
-
target: "#idCapture.backFinished",
|
|
2655
|
-
guard: "shouldContinueToFront"
|
|
2656
|
-
},
|
|
2657
|
-
{ target: "#idCapture.processing" }
|
|
2658
|
-
] } }
|
|
2659
|
-
}
|
|
2660
|
-
},
|
|
2661
|
-
mandatoryConsent: { on: {
|
|
2662
|
-
CONSENT_ACCEPT: [
|
|
2663
|
-
{
|
|
2664
|
-
target: "frontFinished",
|
|
2665
|
-
guard: "shouldContinueToBack"
|
|
2666
|
-
},
|
|
2667
|
-
{
|
|
2668
|
-
target: "backFinished",
|
|
2669
|
-
guard: "shouldContinueToFront"
|
|
2670
|
-
},
|
|
2671
|
-
{ target: "processing" }
|
|
2672
|
-
],
|
|
2673
|
-
CONSENT_CANCEL: { target: "closed" }
|
|
2674
|
-
} },
|
|
2675
|
-
frontFinished: {
|
|
2676
|
-
entry: ["stopMediaRecording", "resetForBackCapture"],
|
|
2677
|
-
type: "parallel",
|
|
2678
|
-
states: {
|
|
2679
|
-
cameraInit: {
|
|
2680
|
-
initial: "checking",
|
|
2681
|
-
states: {
|
|
2682
|
-
checking: { always: [{
|
|
2683
|
-
target: "ready",
|
|
2684
|
-
guard: "hasStream"
|
|
2685
|
-
}, { target: "initializingStream" }] },
|
|
2686
|
-
initializingStream: { invoke: {
|
|
2687
|
-
id: "frontFinishedInitCamera",
|
|
2688
|
-
src: "initializeCamera",
|
|
2689
|
-
input: ({ context }) => ({
|
|
2690
|
-
config: context.config,
|
|
2691
|
-
deepsightService: context.deepsightService
|
|
2692
|
-
}),
|
|
2693
|
-
onDone: {
|
|
2694
|
-
target: "ready",
|
|
2695
|
-
actions: "setStreamAndCapturer"
|
|
2696
|
-
},
|
|
2697
|
-
onError: {
|
|
2698
|
-
target: "ready",
|
|
2699
|
-
actions: () => {
|
|
2700
|
-
console.warn("Camera initialization failed during flip transition");
|
|
2701
|
-
}
|
|
2702
|
-
}
|
|
2703
|
-
} },
|
|
2704
|
-
ready: { type: "final" }
|
|
2705
|
-
}
|
|
2706
|
-
},
|
|
2707
|
-
userIntent: {
|
|
2708
|
-
initial: "waiting",
|
|
2709
|
-
states: {
|
|
2710
|
-
waiting: { on: { CONTINUE_TO_BACK: {
|
|
2711
|
-
target: "clicked",
|
|
2712
|
-
actions: assign({ currentMode: () => "back" })
|
|
2713
|
-
} } },
|
|
2714
|
-
clicked: { type: "final" }
|
|
2715
|
-
}
|
|
2716
|
-
}
|
|
2717
|
-
},
|
|
2718
|
-
onDone: [{
|
|
2719
|
-
target: "#idCapture.capture.detecting",
|
|
2720
|
-
guard: "hasStream"
|
|
2721
|
-
}, { target: "#idCapture.capture" }]
|
|
2722
|
-
},
|
|
2723
|
-
backFinished: {
|
|
2724
|
-
entry: ["stopMediaRecording", "resetForFrontCapture"],
|
|
2725
|
-
type: "parallel",
|
|
2726
|
-
states: {
|
|
2727
|
-
cameraInit: {
|
|
2728
|
-
initial: "checking",
|
|
2729
|
-
states: {
|
|
2730
|
-
checking: { always: [{
|
|
2731
|
-
target: "ready",
|
|
2732
|
-
guard: "hasStream"
|
|
2733
|
-
}, { target: "initializingStream" }] },
|
|
2734
|
-
initializingStream: { invoke: {
|
|
2735
|
-
id: "backFinishedInitCamera",
|
|
2736
|
-
src: "initializeCamera",
|
|
2737
|
-
input: ({ context }) => ({
|
|
2738
|
-
config: context.config,
|
|
2739
|
-
deepsightService: context.deepsightService
|
|
2740
|
-
}),
|
|
2741
|
-
onDone: {
|
|
2742
|
-
target: "ready",
|
|
2743
|
-
actions: "setStreamAndCapturer"
|
|
2744
|
-
},
|
|
2745
|
-
onError: {
|
|
2746
|
-
target: "ready",
|
|
2747
|
-
actions: () => {
|
|
2748
|
-
console.warn("Camera initialization failed during flip transition");
|
|
2749
|
-
}
|
|
2750
|
-
}
|
|
2751
|
-
} },
|
|
2752
|
-
ready: { type: "final" }
|
|
2753
|
-
}
|
|
2754
|
-
},
|
|
2755
|
-
userIntent: {
|
|
2756
|
-
initial: "waiting",
|
|
2757
|
-
states: {
|
|
2758
|
-
waiting: { on: { CONTINUE_TO_FRONT: {
|
|
2759
|
-
target: "clicked",
|
|
2760
|
-
actions: assign({ currentMode: () => "front" })
|
|
2761
|
-
} } },
|
|
2762
|
-
clicked: { type: "final" }
|
|
2763
|
-
}
|
|
2764
|
-
}
|
|
2765
|
-
},
|
|
2766
|
-
onDone: [{
|
|
2767
|
-
target: "#idCapture.capture.detecting",
|
|
2768
|
-
guard: "hasStream"
|
|
2769
|
-
}, { target: "#idCapture.capture" }]
|
|
2770
|
-
},
|
|
2771
|
-
processing: {
|
|
2772
|
-
entry: "stopMediaStream",
|
|
2773
|
-
always: [{
|
|
2774
|
-
target: "finished",
|
|
2775
|
-
guard: "shouldSkipProcessId"
|
|
2776
|
-
}],
|
|
2777
|
-
invoke: {
|
|
2778
|
-
id: "processId",
|
|
2779
|
-
src: "processId",
|
|
2780
|
-
input: ({ context }) => ({ isSecondId: context.config.isSecondId ?? false }),
|
|
2781
|
-
onDone: [
|
|
2782
|
-
{
|
|
2783
|
-
target: "finished",
|
|
2784
|
-
guard: "forceFinishAfterProcessing"
|
|
2785
|
-
},
|
|
2786
|
-
{
|
|
2787
|
-
target: "expiredExhausted",
|
|
2788
|
-
guard: and([({ event }) => event.output.isDocumentExpired, "isProcessingExpiredExhausted"]),
|
|
2789
|
-
actions: ["incrementProcessingExpiredAttempts"]
|
|
2790
|
-
},
|
|
2791
|
-
{
|
|
2792
|
-
target: "expired",
|
|
2793
|
-
guard: ({ event }) => event.output.isDocumentExpired,
|
|
2794
|
-
actions: ["incrementProcessingExpiredAttempts", "clearExpiredFromUpload"]
|
|
2795
|
-
},
|
|
2796
|
-
{ target: "finished" }
|
|
2797
|
-
],
|
|
2798
|
-
onError: { target: "finished" }
|
|
2799
|
-
}
|
|
2800
|
-
},
|
|
2801
|
-
expired: { on: { RETRY_CAPTURE: [
|
|
2802
|
-
{
|
|
2803
|
-
target: "#idCapture.capture",
|
|
2804
|
-
guard: "wasExpiredFromUpload",
|
|
2805
|
-
actions: [
|
|
2806
|
-
"resetDetection",
|
|
2807
|
-
"clearExpiredFromUpload",
|
|
2808
|
-
"clearUploadFailure"
|
|
2809
|
-
]
|
|
2810
|
-
},
|
|
2811
|
-
{
|
|
2812
|
-
target: "chooser",
|
|
2813
|
-
guard: "hasShowDocumentChooser",
|
|
2814
|
-
actions: ["resetContext"]
|
|
2815
|
-
},
|
|
2816
|
-
{
|
|
2817
|
-
target: "ageVerification",
|
|
2818
|
-
guard: "hasAgeAssurance",
|
|
2819
|
-
actions: "resetContext"
|
|
2820
|
-
},
|
|
2821
|
-
{
|
|
2822
|
-
target: "tutorial",
|
|
2823
|
-
guard: "hasShowTutorial",
|
|
2824
|
-
actions: "resetContext"
|
|
2825
|
-
},
|
|
2826
|
-
{
|
|
2827
|
-
target: "loading",
|
|
2828
|
-
actions: "resetContext"
|
|
2829
|
-
}
|
|
2830
|
-
] } },
|
|
2831
|
-
expiredExhausted: { on: { CONTINUE_EXHAUSTED: [
|
|
2832
|
-
{
|
|
2833
|
-
target: "#idCapture.frontFinished",
|
|
2834
|
-
guard: "shouldForceBackOnExpired",
|
|
2835
|
-
actions: ["setSkipProcessId"]
|
|
2836
|
-
},
|
|
2837
|
-
{
|
|
2838
|
-
target: "#idCapture.processing",
|
|
2839
|
-
guard: "shouldProcessAfterExhaustion",
|
|
2840
|
-
actions: ["setForceFinishAfterProcessing"]
|
|
2841
|
-
},
|
|
2842
|
-
{
|
|
2843
|
-
target: "#idCapture.finished",
|
|
2844
|
-
actions: ["setSkipProcessId"]
|
|
2845
|
-
}
|
|
2846
|
-
] } },
|
|
2847
|
-
finished: {
|
|
2848
|
-
entry: [
|
|
2849
|
-
"stopMediaRecording",
|
|
2850
|
-
"stopMediaStream",
|
|
2851
|
-
"disposeProvider",
|
|
2852
|
-
"cleanupDeepsight"
|
|
2853
|
-
],
|
|
2854
|
-
type: "final"
|
|
2855
|
-
},
|
|
2856
|
-
closed: {
|
|
2857
|
-
entry: [
|
|
2858
|
-
"stopMediaStream",
|
|
2859
|
-
"disposeProvider",
|
|
2860
|
-
"cleanupDeepsight"
|
|
2861
|
-
],
|
|
2862
|
-
type: "final"
|
|
2863
|
-
},
|
|
2864
|
-
error: {
|
|
2865
|
-
entry: [
|
|
2866
|
-
"stopMediaStream",
|
|
2867
|
-
"disposeProvider",
|
|
2868
|
-
"cleanupDeepsight"
|
|
2869
|
-
],
|
|
2870
|
-
on: { RESET: {
|
|
2871
|
-
target: "idle",
|
|
2872
|
-
actions: "resetContext"
|
|
2873
|
-
} }
|
|
2874
|
-
},
|
|
2875
|
-
manualIdUpload: {
|
|
2876
|
-
invoke: {
|
|
2877
|
-
id: "manualIdUpload",
|
|
2878
|
-
src: "manualUploadMachine",
|
|
2879
|
-
input: ({ context }) => ({
|
|
2880
|
-
isSecondId: context.config.isSecondId ?? false,
|
|
2881
|
-
onlyFront: false,
|
|
2882
|
-
captureAttempts: context.config.captureAttempts
|
|
2883
|
-
}),
|
|
2884
|
-
onSnapshot: { actions: () => {} },
|
|
2885
|
-
onDone: [{
|
|
2886
|
-
guard: "isManualUploadExhausted",
|
|
2887
|
-
target: "#idCapture.finished"
|
|
2888
|
-
}, { target: "#idCapture.processing" }],
|
|
2889
|
-
onError: {
|
|
2890
|
-
target: "#idCapture.error",
|
|
2891
|
-
actions: assign({ error: ({ event }) => String(event.error) })
|
|
2892
|
-
}
|
|
2893
|
-
},
|
|
2894
|
-
on: {
|
|
2895
|
-
QUIT: { target: "closed" },
|
|
2896
|
-
MANUAL_UPLOAD_TAB_CHANGED: { actions: sendTo("manualIdUpload", ({ event }) => event) },
|
|
2897
|
-
MANUAL_UPLOAD_FILE_SELECTED: { actions: sendTo("manualIdUpload", ({ event }) => event) },
|
|
2898
|
-
MANUAL_UPLOAD_CONTINUE: { actions: sendTo("manualIdUpload", ({ event }) => event) },
|
|
2899
|
-
MANUAL_UPLOAD_RESET: { actions: sendTo("manualIdUpload", ({ event }) => event) }
|
|
2900
|
-
}
|
|
2901
|
-
},
|
|
2902
|
-
digitalIdUpload: {
|
|
2903
|
-
invoke: {
|
|
2904
|
-
id: "digitalIdUpload",
|
|
2905
|
-
src: "digitalUploadMachine",
|
|
2906
|
-
input: ({ context }) => ({
|
|
2907
|
-
showTutorial: context.config.showTutorial,
|
|
2908
|
-
captureAttempts: context.config.captureAttempts
|
|
2909
|
-
}),
|
|
2910
|
-
onSnapshot: { actions: () => {} },
|
|
2911
|
-
onDone: [
|
|
2912
|
-
{
|
|
2913
|
-
guard: "isDigitalUploadExhausted",
|
|
2914
|
-
target: "#idCapture.finished"
|
|
2915
|
-
},
|
|
2916
|
-
{
|
|
2917
|
-
guard: "isDigitalUploadClosed",
|
|
2918
|
-
target: "#idCapture.chooser"
|
|
2919
|
-
},
|
|
2920
|
-
{
|
|
2921
|
-
guard: "isDigitalUploadSuccessful",
|
|
2922
|
-
target: "#idCapture.processing",
|
|
2923
|
-
actions: ["storeDigitalUploadResponse"]
|
|
2924
|
-
},
|
|
2925
|
-
{
|
|
2926
|
-
target: "#idCapture.error",
|
|
2927
|
-
actions: assign({ error: () => "Digital upload finished without output" })
|
|
2928
|
-
}
|
|
2929
|
-
],
|
|
2930
|
-
onError: {
|
|
2931
|
-
target: "#idCapture.error",
|
|
2932
|
-
actions: assign({ error: ({ event }) => String(event.error) })
|
|
2933
|
-
}
|
|
2934
|
-
},
|
|
2935
|
-
on: {
|
|
2936
|
-
QUIT: { target: "closed" },
|
|
2937
|
-
DIGITAL_UPLOAD_NEXT_STEP: { actions: sendTo("digitalIdUpload", { type: "NEXT_STEP" }) },
|
|
2938
|
-
DIGITAL_UPLOAD_FILE_PICKED: { actions: sendTo("digitalIdUpload", ({ event }) => ({
|
|
2939
|
-
type: "FILE_PICKED",
|
|
2940
|
-
file: event.file
|
|
2941
|
-
})) },
|
|
2942
|
-
DIGITAL_UPLOAD_CONFIRM: { actions: sendTo("digitalIdUpload", { type: "CONFIRM" }) },
|
|
2943
|
-
DIGITAL_UPLOAD_REPLACE: { actions: sendTo("digitalIdUpload", { type: "REPLACE" }) },
|
|
2944
|
-
DIGITAL_UPLOAD_RETRY: { actions: sendTo("digitalIdUpload", { type: "RETRY" }) },
|
|
2945
|
-
DIGITAL_UPLOAD_SCAN_INSTEAD: { actions: sendTo("digitalIdUpload", { type: "SCAN_INSTEAD" }) },
|
|
2946
|
-
DIGITAL_UPLOAD_CHOOSE_ANOTHER: { actions: sendTo("digitalIdUpload", { type: "CHOOSE_ANOTHER" }) }
|
|
2947
|
-
}
|
|
2948
|
-
}
|
|
2949
|
-
}
|
|
2950
|
-
});
|
|
2951
|
-
const idCaptureMachine = _idCaptureMachine;
|
|
2952
|
-
|
|
2953
|
-
//#endregion
|
|
2954
|
-
export { startRecordingSession as a, uploadIdImage as c, ID_ERROR_CODES as d, MANUAL_UPLOAD_EXHAUSTION_FORWARD_MS as f, mapDigitalIdScreenName as h, processId as i, uploadManualIdFile as l, MANUAL_UPLOAD_MAX_RETRIES as m, initializeIdCapture as n, stopRecording as o, MANUAL_UPLOAD_MAX_FILE_SIZE_BYTES as p, preloadIdRecordingProvider as r, stopStream as s, idCaptureMachine as t, validateUploadResponse as u };
|