@incodetech/core 0.0.0-dev-20260911-aec162f0 → 0.0.0-dev-20260914-8aef7789
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/dist/{FaceDetectionProvider-Cn1wS-sA.d.ts → BaseWasmProvider-CO0GfaHM.d.ts} +7 -37
- package/dist/{BrowserDiagnosticsCryptoProvider-8sT0QLgq.esm.js → BrowserDiagnosticsCryptoProvider-BoYzmYY5.esm.js} +1 -1
- package/dist/{onDeviceFaceResults-hle2Ci9l.esm.js → FaceDetectionProvider-0bWjPgW5.esm.js} +219 -340
- package/dist/FaceDetectionProvider-CyLxkzRP.d.ts +36 -0
- package/dist/{IIdCaptureCapability-DDWlQzhi.d.ts → IIdCaptureCapability-nfpic2z2.d.ts} +7 -3
- package/dist/{IWasmUtilCapability-SNPhmIwB.d.ts → IWasmUtilCapability-DaP6pfHq.d.ts} +10 -4
- package/dist/{MotionSensorProvider-Vlyhbcty.esm.js → MotionSensorProvider-BnZ8_1Sk.esm.js} +1 -1
- package/dist/{StreamCanvasCapture-D2XcXCZ4.esm.js → StreamCanvasCapture-C9jtgBdT.esm.js} +2 -2
- package/dist/{deepsightService-MZOpj7Vp.d.ts → StreamCanvasCapture-D9Dz8kqB.d.ts} +54 -41
- package/dist/ae-signature.esm.js +1 -1
- package/dist/{apiError-XdhqSAmg.esm.js → apiError-CixFeCyt.esm.js} +1 -1
- package/dist/authentication.d.ts +3 -3
- package/dist/authentication.esm.js +2 -2
- package/dist/{authenticationManager-DqBOkMzk.esm.js → authenticationManager-CN26fkJa.esm.js} +4 -4
- package/dist/{authenticationManager-BCkV6CSG.d.ts → authenticationManager-D7UUqgnN.d.ts} +1 -1
- package/dist/{authenticationStateMachine-Cto_G5bN.esm.js → authenticationStateMachine-CUXpIxAD.esm.js} +6 -62
- package/dist/avatar.d.ts +1 -1
- package/dist/avatar.esm.js +1 -1
- package/dist/{backCameraStream-DE_5qY04.esm.js → backCameraStream-BOtyQowf.esm.js} +75 -18
- package/dist/{camera-_2sXMXiF.esm.js → camera-sIa9ceW2.esm.js} +19 -1
- package/dist/camera.esm.js +1 -1
- package/dist/{canvas-E1zGkel4.esm.js → canvas-BxFzWTt-.esm.js} +19 -0
- package/dist/createCameraCycleOwnership-DQ5-F2oW.esm.js +826 -0
- package/dist/{createFaceAvatar-DQKaRise.esm.js → createFaceAvatar-BNHdeFj8.esm.js} +2 -2
- package/dist/{createFaceAvatar-pUEkdk4X.d.ts → createFaceAvatar-CTM9aj9Q.d.ts} +12 -6
- package/dist/curp-validation.d.ts +1 -1
- package/dist/{curpValidationManager-cSd2MrOQ.d.ts → curpValidationManager-CTJB2RsD.d.ts} +1 -1
- package/dist/{deepsightLoader-Dwr1zKFa.esm.js → deepsightLoader-Dhz9T_KJ.esm.js} +19 -53
- package/dist/document-capture.esm.js +2 -2
- package/dist/{documentCaptureManager-BTpHZMgW.esm.js → documentCaptureManager-BwcbMwo5.esm.js} +1 -1
- package/dist/{documentCaptureStateMachine-CPizkpcg.esm.js → documentCaptureStateMachine-F8SCOtL_.esm.js} +4 -4
- package/dist/dynamic-forms.esm.js +2 -2
- package/dist/{dynamicFormsManager-Cmh84Nz4.esm.js → dynamicFormsManager-CNBrBOR3.esm.js} +1 -1
- package/dist/{dynamicFormsStateMachine-DZr7Ugvy.esm.js → dynamicFormsStateMachine-Bo2qrjHB.esm.js} +1 -1
- package/dist/ekyb.d.ts +1 -1
- package/dist/ekyb.esm.js +3 -3
- package/dist/{ekybManager-Dc2tT9fu.esm.js → ekybManager-D8DdfRAD.esm.js} +1 -1
- package/dist/{ekybStateMachine-GSEMOiHn.esm.js → ekybStateMachine-oPCbEFob.esm.js} +1 -1
- package/dist/electronic-signature.esm.js +1 -1
- package/dist/{electronicSignatureManager-CpLuqw7T.esm.js → electronicSignatureManager-DkKQ07vx.esm.js} +1 -1
- package/dist/extensibility.d.ts +11 -58
- package/dist/extensibility.esm.js +13 -13
- package/dist/{faceCaptureManagerFactory-kDmbL0I7.esm.js → faceCaptureManagerFactory-D_EjQnnE.esm.js} +19 -4
- package/dist/{faceCaptureManagerFactory-CzUr_ZPq.d.ts → faceCaptureManagerFactory-DqrYpjA5.d.ts} +24 -12
- package/dist/{faceCaptureSetup-CAGBnLVx.esm.js → faceCaptureSetup-WeO8-TfR.esm.js} +999 -382
- package/dist/{feature-management-B6CtmH1O.esm.js → feature-management-BEqf3Sr3.esm.js} +1 -1
- package/dist/feature-management.esm.js +1 -1
- package/dist/fiscal-qr.esm.js +1 -1
- package/dist/{fiscalQrManager-DI6uOffY.esm.js → fiscalQrManager-Bp_-3LJr.esm.js} +3 -3
- package/dist/flow-events.d.ts +1 -1
- package/dist/flow.d.ts +6 -6
- package/dist/flow.esm.js +3 -3
- package/dist/{flowCompletionService-BpoZDpAn.esm.js → flowCompletionService-DELbVeL5.esm.js} +1 -1
- package/dist/{flowServices-BVnSStkh.esm.js → flowServices-Brr2fh_c.esm.js} +5 -5
- package/dist/geolocation.esm.js +2 -2
- package/dist/{geolocationManager-CLm86P8G.esm.js → geolocationManager-CtVZDjng.esm.js} +1 -1
- package/dist/{geolocationStateMachine-Bi3vy7Wl.esm.js → geolocationStateMachine-tjsYcMhr.esm.js} +1 -1
- package/dist/home.d.ts +1 -1
- package/dist/id-selfie-flow.d.ts +3 -3
- package/dist/id-selfie-flow.esm.js +10 -10
- package/dist/id.d.ts +4 -4
- package/dist/id.esm.js +35 -44
- package/dist/{idCaptureDefaults-BLsd7shz.esm.js → idCaptureDefaults-C66YvkgN.esm.js} +19 -14
- package/dist/{idCaptureManager-DW1GeEUk.d.ts → idCaptureManager-DE_jyr5X.d.ts} +98 -37
- package/dist/{idCaptureManager-BUTdcmaD.esm.js → idCaptureManager-zjul9YdZ.esm.js} +27 -17
- package/dist/{idCaptureServices-fzIhBqAK.esm.js → idCaptureServices-UXYCBZPK.esm.js} +80 -20
- package/dist/{idCaptureStateMachine-Cp2_revF.esm.js → idCaptureStateMachine-D3pqfK2Z.esm.js} +1954 -1082
- package/dist/{index-1PoJuUJ-.d.ts → index-BGxFwnld.d.ts} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/mandatory-consent.d.ts +2 -2
- package/dist/{mandatoryConsentManager-BJnylLZO.d.ts → mandatoryConsentManager-CZwhsUlO.d.ts} +1 -1
- package/dist/{permissionGuards-DxbvOoZJ.esm.js → permissionGuards-o1JLtewE.esm.js} +1 -1
- package/dist/{permissionServices-f7nBnW5P.esm.js → permissionServices-7lzEiOsO.esm.js} +3 -3
- package/dist/personhood.d.ts +5 -5
- package/dist/personhood.esm.js +8 -8
- package/dist/qe-signature.esm.js +1 -1
- package/dist/{runChildModule-BPlX2IDO.esm.js → runChildModule-BDlvNMrA.esm.js} +1 -1
- package/dist/{safeStorage-Dp9m6aOh.esm.js → safeStorage-1O9k0ulP.esm.js} +8 -8
- package/dist/{sdkVersion-Dr9_E3d9.esm.js → sdkVersion-CS_0s_Lc.esm.js} +1 -1
- package/dist/selfie.d.ts +4 -4
- package/dist/selfie.esm.js +12 -74
- package/dist/{selfieManager-BdP-RgH4.esm.js → selfieManager-BouB9yUQ.esm.js} +4 -4
- package/dist/{selfieManager-Bg_Xwe4p.d.ts → selfieManager-DZ3u_WN9.d.ts} +1 -1
- package/dist/{selfieStateMachine-B8vFeT39.esm.js → selfieStateMachine-TGfI9hNp.esm.js} +22 -31
- package/dist/{session-C2THUsQZ.esm.js → session-m9j27bHm.esm.js} +3 -3
- package/dist/session.d.ts +1 -1
- package/dist/session.esm.js +4 -4
- package/dist/{sessionInitializer-CEycxhm4.esm.js → sessionInitializer-CUpgbHzs.esm.js} +4 -4
- package/dist/{setup-D6yz9se2.d.ts → setup-CEX95gJ1.d.ts} +11 -6
- package/dist/{setup-BHJ3-fhX.esm.js → setup-CfNAVG-d.esm.js} +12 -11
- package/dist/{trueSightService-DLzYznkh.esm.js → trueSightService-TqmmYye3.esm.js} +4 -4
- package/dist/types-BhHF-CuL.d.ts +6 -0
- package/dist/{types-DJ2OM9rw.d.ts → types-BzuUebkB.d.ts} +1 -1
- package/dist/{types-DzmqFoCH.d.ts → types-CBctcPeF.d.ts} +1 -1
- package/dist/{types-BBI4-s9u2.d.ts → types-CoOlCUp82.d.ts} +5 -5
- package/dist/{types-hSqUyXyw.d.ts → types-DL0CXuWv.d.ts} +3 -3
- package/dist/types-Ds928RiU.d.ts +1 -0
- package/dist/{types-_pWNFY1F.d.ts → types-eLtVBhon.d.ts} +1 -1
- package/dist/video-selfie.d.ts +3 -3
- package/dist/video-selfie.esm.js +5 -5
- package/dist/{videoSelfieCameraWarmer-D5E12WjL.esm.js → videoSelfieCameraWarmer-C-cESczy.esm.js} +9 -9
- package/dist/{videoSelfieStepDetector-B8TvFDNK.d.ts → videoSelfieStepDetector-CdXIFh9s.d.ts} +4 -4
- package/dist/virtualCameraCheck-WOloJ-do.esm.js +48 -0
- package/dist/{warmup-BOM-sD-6.esm.js → warmup-CUUnwYxe.esm.js} +282 -90
- package/dist/{warmup-CXHBgvFC.d.ts → warmup-Cis2p6O0.d.ts} +13 -2
- package/dist/wasm.d.ts +9 -3
- package/dist/wasm.esm.js +10 -4
- package/dist/{wasmDsFlagSync-C3k_VK9o.esm.js → wasmDsFlagSync-BJtLh2XK.esm.js} +1 -1
- package/dist/{wasmWebClient-BJCaFeBL.esm.js → wasmWebClient-B7baE-Wf.esm.js} +223 -2
- package/dist/workflow.d.ts +1 -1
- package/dist/workflow.esm.js +15 -15
- package/package.json +1 -1
- package/dist/imageFile-CLaua6xO.esm.js +0 -69
- package/dist/types-m4t_cT5J.d.ts +0 -6
- package/dist/{Face2DProvider-UUQt_vRC.esm.js → Face2DProvider-BF48sz5c.esm.js} +1 -1
- package/dist/{PrivacyLensProvider-D8PS7AJa.esm.js → PrivacyLensProvider-EwnC_C5n.esm.js} +1 -1
- package/dist/{selfieErrorUtils-C6gC06J7.esm.js → selfieErrorUtils-C77GXJH6.esm.js} +1 -1
package/dist/{idCaptureStateMachine-Cp2_revF.esm.js → idCaptureStateMachine-D3pqfK2Z.esm.js}
RENAMED
|
@@ -1,28 +1,32 @@
|
|
|
1
|
-
import { l as BrowserStorageProvider } from "./setup-
|
|
1
|
+
import { l as BrowserStorageProvider } from "./setup-CfNAVG-d.esm.js";
|
|
2
|
+
import { r as WasmUtilProvider } from "./safeStorage-1O9k0ulP.esm.js";
|
|
2
3
|
import { t as BrowserTimerProvider } from "./BrowserTimerProvider-BXhgNxLt.esm.js";
|
|
3
|
-
import { s as exposeExperimentOnce } from "./feature-management-
|
|
4
|
-
import { n as revokeObjectURL } from "./IBrowserEnvironmentCapability-DEaRRk-R.esm.js";
|
|
4
|
+
import { s as exposeExperimentOnce } from "./feature-management-BEqf3Sr3.esm.js";
|
|
5
|
+
import { n as revokeObjectURL, t as getTimestamp } from "./IBrowserEnvironmentCapability-DEaRRk-R.esm.js";
|
|
5
6
|
import { r as getToken, t as api } from "./api-Bx3gKW_y.esm.js";
|
|
6
|
-
import { c as trueSightHintTransition, l as trueSightLog, r as noteTrueSightCaptureActivity } from "./trueSightService-
|
|
7
|
+
import { c as trueSightHintTransition, l as trueSightLog, m as isTrueSightTesting, r as noteTrueSightCaptureActivity } from "./trueSightService-TqmmYye3.esm.js";
|
|
7
8
|
import { n as eventModuleNames, s as recordExperimentAssignmentOnce } from "./events-ijlbX_Wx.esm.js";
|
|
8
|
-
import { t as getDisableIpify } from "./sessionInitializer-
|
|
9
|
+
import { t as getDisableIpify } from "./sessionInitializer-CUpgbHzs.esm.js";
|
|
9
10
|
import { t as endpoints } from "./endpoints-D3B9mUHh.esm.js";
|
|
10
11
|
import { t as addDeviceStats } from "./stats-DkK-f8JT.esm.js";
|
|
11
12
|
import { a as isIOS, s as isIPad, t as isAndroid, u as isMacOsSafari } from "./platform-DkcRc9JV.esm.js";
|
|
12
|
-
import "./session-
|
|
13
|
+
import "./session-m9j27bHm.esm.js";
|
|
13
14
|
import { c as not, i as assign, l as raise, n as enqueueActions, o as and, r as sendTo, t as setup } from "./xstate.esm-BuFLFuzz.esm.js";
|
|
14
15
|
import { n as fromPromise, t as fromCallback } from "./xstate-actors.esm-BXeQ-Ucz.esm.js";
|
|
15
16
|
import { n as getUrlSearchParam, t as buildUrlWithSearchParams } from "./urlUtils-D6phjq1-.esm.js";
|
|
16
|
-
import {
|
|
17
|
-
import { t as
|
|
18
|
-
import { t as
|
|
17
|
+
import { r as getCameraReacquisitionConstraints } from "./camera-sIa9ceW2.esm.js";
|
|
18
|
+
import { n as invokeRequestPermissionActor, t as checkPermission } from "./permissionServices-7lzEiOsO.esm.js";
|
|
19
|
+
import { i as imageFileToDataUrl, n as runProtectedAttempt, o as flagIdManualReview, r as cameraCycleProvider, s as PROTECTED_CAPTURE_TARGET, t as createCameraCycleOwnership } from "./createCameraCycleOwnership-DQ5-F2oW.esm.js";
|
|
20
|
+
import { t as IncodeCanvas } from "./canvas-BxFzWTt-.esm.js";
|
|
21
|
+
import { n as needsMotionPrimeOnlyFromPermission, r as resolveStoredPermissionResult, t as isReadyForCaptureFromPermission } from "./permissionGuards-o1JLtewE.esm.js";
|
|
19
22
|
import { a as StreamCanvasProcessingSession } from "./recordingsRepository-CCWy13M-.esm.js";
|
|
23
|
+
import { t as sleep } from "./ITimerCapability-DgdDzp8G.esm.js";
|
|
20
24
|
import { t as getBrowser } from "./getBrowser-Cbe1C4Tn.esm.js";
|
|
21
25
|
import { n as getWindowDimensions } from "./getDeviceClass-CeBiEayS.esm.js";
|
|
22
|
-
import { t as
|
|
23
|
-
import { n as
|
|
24
|
-
import { r as
|
|
25
|
-
import {
|
|
26
|
+
import { n as runVirtualCameraCheck, t as frameSources } from "./virtualCameraCheck-WOloJ-do.esm.js";
|
|
27
|
+
import { n as DEFAULT_ID_CAPTURE_THRESHOLDS, r as IdCaptureProvider } from "./idCaptureDefaults-C66YvkgN.esm.js";
|
|
28
|
+
import { S as getIdCameraStream, _ as ID_ERROR_CODES, a as getRealQualityValue, b as CAPTURE_OPTIMIZING, d as startRecordingSession, f as stopRecording, g as validateUploadResponse, h as uploadManualIdFile, i as finalizeRecordingSession, l as prepareRecordingForCameraRetry, m as uploadIdImage, o as initializeIdCapture, p as stopStream, r as disposeRecordingSession, t as addBarcode, u as processId, x as OPTIMIZING_WATCHDOG_MARGIN_MS, y as resolveIdCaptureThresholds } from "./idCaptureServices-UXYCBZPK.esm.js";
|
|
29
|
+
import { t as StreamCanvasCapture } from "./StreamCanvasCapture-C9jtgBdT.esm.js";
|
|
26
30
|
//#region src/modules/id/digitalUpload/digitalUploadErrors.ts
|
|
27
31
|
const TERMINAL_FAIL_REASONS = /* @__PURE__ */ new Set(["DIGITAL_ID_REQUESTED_BUT_OTHER_PROVIDED", "ID_TYPE_UNACCEPTABLE"]);
|
|
28
32
|
function isKnownFailReason(reason) {
|
|
@@ -955,8 +959,6 @@ const isPermissionDeniedErrorGuard = ({ event }) => {
|
|
|
955
959
|
return false;
|
|
956
960
|
};
|
|
957
961
|
const isPermissionBlockedGuard = ({ context }) => context.permissionResult === "denied" || context.permissionResult === "refresh";
|
|
958
|
-
const hasStreamGuard = ({ context }) => context.stream !== void 0;
|
|
959
|
-
const hasInitializedCameraGuard = ({ context }) => context.stream !== void 0 && context.provider !== void 0;
|
|
960
962
|
const hasAttemptsRemainingGuard = ({ context }) => context.attemptsRemaining > 0;
|
|
961
963
|
const hasCapturedImageGuard = ({ context }) => {
|
|
962
964
|
return context.provider?.getCapturedCanvas() !== null;
|
|
@@ -964,17 +966,6 @@ const hasCapturedImageGuard = ({ context }) => {
|
|
|
964
966
|
const hasCandidateFrameGuard = ({ event }) => {
|
|
965
967
|
return event.type === "DETECTION_OPTIMIZING" && Boolean(event.candidateCanvas);
|
|
966
968
|
};
|
|
967
|
-
/**
|
|
968
|
-
* IDC-05: whether WASM's commit arrived while the optimizing phase was still
|
|
969
|
-
* spending its dwell, and is therefore parked in `optimizing.holding` waiting
|
|
970
|
-
* for the release.
|
|
971
|
-
*
|
|
972
|
-
* Gates the phase's own `SWITCH_TO_MANUAL_CAPTURE` / `MANUAL_CAPTURE` handlers:
|
|
973
|
-
* while a commit is parked those escapes end the dwell early instead of leaving
|
|
974
|
-
* the phase, so WASM's committed frame is honored rather than dropped on the way
|
|
975
|
-
* out. False leaves both events to the arm parent, the documented escape hatch.
|
|
976
|
-
*/
|
|
977
|
-
const hasStashedCommitGuard = ({ context }) => context.stashedCommit !== void 0;
|
|
978
969
|
const hasUploadValidationErrorGuard = ({ context }) => {
|
|
979
970
|
if (!context.uploadResponse) return false;
|
|
980
971
|
return validateUploadResponse(context.uploadResponse, {
|
|
@@ -1353,412 +1344,133 @@ function computeIdCaptureOutput(context) {
|
|
|
1353
1344
|
};
|
|
1354
1345
|
}
|
|
1355
1346
|
//#endregion
|
|
1356
|
-
//#region src/modules/
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
if (
|
|
1362
|
-
const
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
/** GET the provider catalog. Ordering is applied FE-side by the module. */
|
|
1366
|
-
async function listProviders(params, signal) {
|
|
1367
|
-
const url = withQuery(endpoints.digitalIdProviders, params);
|
|
1368
|
-
const res = await api.get(url, { signal });
|
|
1369
|
-
if (!res.ok) throw new Error(`GET ${url} failed: ${res.status} ${res.statusText}`);
|
|
1370
|
-
return res.data ?? [];
|
|
1371
|
-
}
|
|
1372
|
-
/**
|
|
1373
|
-
* Append the onboarding `uuid` to `returnUrl` when absent, so the return leg can
|
|
1374
|
-
* re-attach the (onboarding-scoped) verification. Idempotent (skips when a `uuid`
|
|
1375
|
-
* is already present) and non-fatal (returns the URL unchanged on any failure).
|
|
1376
|
-
* Exported for unit testing.
|
|
1377
|
-
*/
|
|
1378
|
-
async function ensureReturnUrlUuid(returnUrl, signal) {
|
|
1379
|
-
try {
|
|
1380
|
-
if (getUrlSearchParam(returnUrl, "uuid")) return returnUrl;
|
|
1381
|
-
const res = await api.get(endpoints.onboardingUrl, { signal });
|
|
1382
|
-
const onboardingUrl = res.ok ? res.data?.url : void 0;
|
|
1383
|
-
const uuid = onboardingUrl ? getUrlSearchParam(onboardingUrl, "uuid") : null;
|
|
1384
|
-
if (!uuid) return returnUrl;
|
|
1385
|
-
return buildUrlWithSearchParams(returnUrl, { uuid });
|
|
1386
|
-
} catch (error) {
|
|
1387
|
-
console.warn("[DigitalIdRedirect] ensureReturnUrlUuid failed, proceeding without uuid:", error);
|
|
1388
|
-
return returnUrl;
|
|
1389
|
-
}
|
|
1390
|
-
}
|
|
1391
|
-
/**
|
|
1392
|
-
* Create a verification. On success the caller must full-page-redirect to
|
|
1393
|
-
* `flowData.launchUrl`. NOTE: this is the billable moment for iDIN/FTN — each
|
|
1394
|
-
* call (incl. every retry) is a new session and a new billing event.
|
|
1395
|
-
*
|
|
1396
|
-
* The `redirectUrl` is first passed through `ensureReturnUrlUuid` so a bare
|
|
1397
|
-
* launch gets a resumable `uuid` before the bank round-trip. This reuses the
|
|
1398
|
-
* current session token (no extra `/omni/start`) and only fetches when the URL
|
|
1399
|
-
* lacks a `uuid`.
|
|
1400
|
-
*/
|
|
1401
|
-
async function createVerification(params, signal) {
|
|
1402
|
-
const redirectUrl = await ensureReturnUrlUuid(params.redirectUrl, signal);
|
|
1403
|
-
const res = await api.post(endpoints.digitalIdVerifications, {
|
|
1404
|
-
...params,
|
|
1405
|
-
redirectUrl
|
|
1406
|
-
}, { signal });
|
|
1407
|
-
if (!res.ok) throw new Error(`POST ${endpoints.digitalIdVerifications} failed: ${res.status} ${res.statusText}`);
|
|
1408
|
-
return res.data;
|
|
1409
|
-
}
|
|
1410
|
-
/**
|
|
1411
|
-
* Submit the provider's return params. The contract wants them wrapped as a
|
|
1412
|
-
* JSON *string* under `walletResponse` (success serialized as "true"/"false").
|
|
1413
|
-
*/
|
|
1414
|
-
async function submitWalletResponse(verificationId, params, signal) {
|
|
1415
|
-
const url = `${endpoints.digitalIdVerifications}/${verificationId}/response`;
|
|
1416
|
-
const body = { walletResponse: JSON.stringify({
|
|
1417
|
-
sessionId: params.sessionId,
|
|
1418
|
-
resultsAccessKey: params.resultsAccessKey,
|
|
1419
|
-
success: String(params.success)
|
|
1420
|
-
}) };
|
|
1421
|
-
const res = await api.post(url, body, { signal });
|
|
1422
|
-
if (!res.ok) throw new Error(`POST ${url} failed: ${res.status} ${res.statusText}`);
|
|
1423
|
-
return res.data;
|
|
1424
|
-
}
|
|
1425
|
-
/** Poll fallback — used when the user does not return or results are delayed. */
|
|
1426
|
-
async function getVerificationStatus(verificationId, signal) {
|
|
1427
|
-
const url = `${endpoints.digitalIdVerifications}/${verificationId}/status`;
|
|
1428
|
-
const res = await api.get(url, { signal });
|
|
1429
|
-
if (!res.ok) throw new Error(`GET ${url} failed: ${res.status} ${res.statusText}`);
|
|
1430
|
-
return res.data;
|
|
1347
|
+
//#region src/modules/id/idDetectionNotificationController.ts
|
|
1348
|
+
const NOTIFICATION_DURATION_MS = 500;
|
|
1349
|
+
function isReportedIdSideWrong(currentMode, reportedSide) {
|
|
1350
|
+
if (!reportedSide) return false;
|
|
1351
|
+
const detectedSide = reportedSide.toLowerCase();
|
|
1352
|
+
if (detectedSide === "wrong") return true;
|
|
1353
|
+
const isBackDetected = detectedSide.includes("back") && !detectedSide.includes("front");
|
|
1354
|
+
const isFrontDetected = detectedSide.includes("front") && !detectedSide.includes("back");
|
|
1355
|
+
return currentMode === "front" && isBackDetected || currentMode === "back" && isFrontDetected;
|
|
1431
1356
|
}
|
|
1432
1357
|
/**
|
|
1433
|
-
*
|
|
1434
|
-
*
|
|
1358
|
+
* Coalesces noisy per-frame quality callbacks into stable presentation state.
|
|
1359
|
+
* Repeating the current status extends its display window without re-emitting
|
|
1360
|
+
* it, while a different status waits until that window closes.
|
|
1435
1361
|
*/
|
|
1436
|
-
|
|
1437
|
-
const
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1362
|
+
function createIdDetectionNotificationController(input) {
|
|
1363
|
+
const timer = BrowserTimerProvider.getInstance();
|
|
1364
|
+
let timeout = null;
|
|
1365
|
+
let currentStatus = null;
|
|
1366
|
+
const scheduleReset = () => {
|
|
1367
|
+
timeout = timer.setTimeout(() => {
|
|
1368
|
+
timeout = null;
|
|
1369
|
+
currentStatus = null;
|
|
1370
|
+
input.send("detecting");
|
|
1371
|
+
}, NOTIFICATION_DURATION_MS);
|
|
1372
|
+
};
|
|
1373
|
+
const clear = () => {
|
|
1374
|
+
if (timeout) timer.clearTimeout(timeout);
|
|
1375
|
+
timeout = null;
|
|
1376
|
+
currentStatus = null;
|
|
1377
|
+
};
|
|
1378
|
+
const show = (status) => {
|
|
1379
|
+
if (input.isSuppressed()) return;
|
|
1380
|
+
if (timeout) {
|
|
1381
|
+
if (currentStatus !== status) return;
|
|
1382
|
+
timer.clearTimeout(timeout);
|
|
1383
|
+
scheduleReset();
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
currentStatus = status;
|
|
1387
|
+
input.onStatusShown?.(status);
|
|
1388
|
+
input.send(status);
|
|
1389
|
+
scheduleReset();
|
|
1390
|
+
};
|
|
1391
|
+
return {
|
|
1392
|
+
show,
|
|
1393
|
+
clear
|
|
1394
|
+
};
|
|
1441
1395
|
}
|
|
1442
1396
|
//#endregion
|
|
1443
|
-
//#region src/modules/
|
|
1397
|
+
//#region src/modules/id/idCaptureActors.ts
|
|
1398
|
+
const checkPermissionActor = fromPromise(async () => {
|
|
1399
|
+
return checkPermission();
|
|
1400
|
+
});
|
|
1401
|
+
async function requestIdCapturePermission(input) {
|
|
1402
|
+
if (!isAndroid() || getBrowser() !== "firefox") return invokeRequestPermissionActor(input);
|
|
1403
|
+
if (input.requestMotionPermission) {
|
|
1404
|
+
const motionResult = await invokeRequestPermissionActor({
|
|
1405
|
+
...input,
|
|
1406
|
+
permissionResult: "granted"
|
|
1407
|
+
});
|
|
1408
|
+
if (motionResult !== "granted") return motionResult;
|
|
1409
|
+
}
|
|
1410
|
+
const { stream, constraints, fallbackLevel } = await getIdCameraStream();
|
|
1411
|
+
if (!input.acceptStream?.({
|
|
1412
|
+
stream,
|
|
1413
|
+
constraints,
|
|
1414
|
+
fallbackLevel
|
|
1415
|
+
})) stopStream(stream);
|
|
1416
|
+
return {
|
|
1417
|
+
permissionResult: "granted",
|
|
1418
|
+
cameraFallbackLevel: fallbackLevel
|
|
1419
|
+
};
|
|
1420
|
+
}
|
|
1421
|
+
const requestPermissionActor = fromPromise(async ({ input }) => {
|
|
1422
|
+
return requestIdCapturePermission(input);
|
|
1423
|
+
});
|
|
1424
|
+
fromPromise(async ({ input }) => {
|
|
1425
|
+
return initializeIdCapture(input);
|
|
1426
|
+
});
|
|
1427
|
+
const DEFAULT_ID_CAPTURE_GEOMETRY = {
|
|
1428
|
+
areaDown: 25e3,
|
|
1429
|
+
areaUp: 55e3,
|
|
1430
|
+
areaIOSPassportUp: 3e4,
|
|
1431
|
+
areaIOSPassportDown: 2e4,
|
|
1432
|
+
widthIOSUp: 160,
|
|
1433
|
+
widthIOSDown: 85,
|
|
1434
|
+
widthDown: 110,
|
|
1435
|
+
widthUp: 205
|
|
1436
|
+
};
|
|
1444
1437
|
/**
|
|
1445
|
-
*
|
|
1446
|
-
*
|
|
1447
|
-
* read back on the return leg. Only the non-sensitive `verificationId` +
|
|
1448
|
-
* `providerId` live here — the session credential is the host's concern
|
|
1449
|
-
* (re-bootstrapped from `url_uuid`) and is NEVER persisted by this module.
|
|
1438
|
+
* Applies the canonical ID workflow configuration to either the legacy
|
|
1439
|
+
* host-fed pipeline or the protected camera-cycle workflow.
|
|
1450
1440
|
*
|
|
1451
|
-
*
|
|
1452
|
-
*
|
|
1453
|
-
*
|
|
1454
|
-
* is used, so a stale record from an abandoned redirect is overwritten by the
|
|
1455
|
-
* next one and is only ever read on the host's return route.
|
|
1456
|
-
*
|
|
1457
|
-
* TODO(follow-up): add a staleness TTL once an injected time capability lands
|
|
1458
|
-
* (Core forbids `Date.now()` directly — `no-browser-api-in-core`).
|
|
1441
|
+
* Keeping geometry, thresholds, settings, model selection, callbacks, and
|
|
1442
|
+
* barcode setup here prevents the two frame-transport architectures from
|
|
1443
|
+
* drifting while the protected path is rolled out.
|
|
1459
1444
|
*/
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1445
|
+
function configureIdCaptureProvider(input) {
|
|
1446
|
+
const windowDimensions = getWindowDimensions(input.frameSize.width, input.frameSize.height);
|
|
1447
|
+
input.provider.setGeometry({
|
|
1448
|
+
...input.config.geometry ?? DEFAULT_ID_CAPTURE_GEOMETRY,
|
|
1449
|
+
windowOuterWidth: windowDimensions.outerWidth,
|
|
1450
|
+
windowOuterHeight: windowDimensions.outerHeight,
|
|
1451
|
+
windowInnerWidth: windowDimensions.innerWidth,
|
|
1452
|
+
windowInnerHeight: windowDimensions.innerHeight
|
|
1465
1453
|
});
|
|
1454
|
+
const idType = input.currentMode === "back" ? "BackId" : input.currentMode === "passport" ? "Passport" : "FrontId";
|
|
1455
|
+
input.provider.setSettings({
|
|
1456
|
+
isFixedMask: input.config.settings?.isFixedMask ?? false,
|
|
1457
|
+
isIPhone14OrHigher: input.config.settings?.isIPhone14OrHigher ?? false,
|
|
1458
|
+
idType,
|
|
1459
|
+
blurCheckEnabled: input.config.settings?.blurCheckEnabled ?? false,
|
|
1460
|
+
glareCheckEnabled: input.config.settings?.glareCheckEnabled ?? false,
|
|
1461
|
+
faceQualityCheckEnabled: input.config.settings?.faceQualityCheckEnabled ?? true,
|
|
1462
|
+
iouCheckEnabled: input.config.settings?.iouCheckEnabled ?? true,
|
|
1463
|
+
fpsLimitEnabled: input.config.settings?.fpsLimitEnabled ?? false
|
|
1464
|
+
});
|
|
1465
|
+
input.provider.setThresholds(resolveIdCaptureThresholds(input.config));
|
|
1466
|
+
input.provider.setModelType(input.config.modelVersion ?? "v2");
|
|
1467
|
+
input.provider.setCallbacks(input.callbacks);
|
|
1468
|
+
const barcodeCaptureEnabled = input.config.usSmartCapture === true && input.currentMode === "back";
|
|
1469
|
+
input.provider.setBarcodeCaptureEnabled(barcodeCaptureEnabled);
|
|
1470
|
+
input.provider.setBarcodeAutoCaptureOnDecode(false);
|
|
1471
|
+
if (barcodeCaptureEnabled) input.provider.setBarcodeEnhancementModel().catch(() => {});
|
|
1466
1472
|
}
|
|
1467
|
-
|
|
1468
|
-
const pending = await storage.get(PENDING_KEY);
|
|
1469
|
-
return pending?.verificationId && pending?.providerId ? pending : null;
|
|
1470
|
-
}
|
|
1471
|
-
async function clearPendingRedirect(storage) {
|
|
1472
|
-
await storage.remove(PENDING_KEY);
|
|
1473
|
-
}
|
|
1474
|
-
//#endregion
|
|
1475
|
-
//#region src/modules/digital-id-redirect/digitalIdRedirectStateMachine.ts
|
|
1476
|
-
const POLL_INTERVAL_MS = 1500;
|
|
1477
|
-
const MAX_POLL_ATTEMPTS = 20;
|
|
1478
|
-
const TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
1479
|
-
"COMPLETED",
|
|
1480
|
-
"FAILED",
|
|
1481
|
-
"EXPIRED",
|
|
1482
|
-
"CANCELLED"
|
|
1483
|
-
]);
|
|
1484
|
-
function isTerminal(status) {
|
|
1485
|
-
return TERMINAL_STATUSES.has(status);
|
|
1486
|
-
}
|
|
1487
|
-
const digitalIdRedirectMachine = setup({
|
|
1488
|
-
types: {
|
|
1489
|
-
context: {},
|
|
1490
|
-
events: {},
|
|
1491
|
-
input: {},
|
|
1492
|
-
output: {}
|
|
1493
|
-
},
|
|
1494
|
-
actors: {
|
|
1495
|
-
listProviders: fromPromise(async ({ input, signal }) => listProviders(input ? { country: input.country } : void 0, signal)),
|
|
1496
|
-
createVerification: fromPromise(async ({ input, signal }) => createVerification(input, signal)),
|
|
1497
|
-
submitWalletResponse: fromPromise(async ({ input, signal }) => submitWalletResponse(input.verificationId, input.params, signal)),
|
|
1498
|
-
refreshVerification: fromPromise(async ({ input, signal }) => refreshVerification(input.verificationId, signal)),
|
|
1499
|
-
pollStatus: fromCallback(({ sendBack, input }) => {
|
|
1500
|
-
const timer = BrowserTimerProvider.getInstance();
|
|
1501
|
-
const interval = timer.setInterval(async () => {
|
|
1502
|
-
try {
|
|
1503
|
-
const v = await getVerificationStatus(input.verificationId);
|
|
1504
|
-
if (isTerminal(v.status)) sendBack({
|
|
1505
|
-
type: "POLL_RESULT",
|
|
1506
|
-
verification: v
|
|
1507
|
-
});
|
|
1508
|
-
} catch (error) {
|
|
1509
|
-
console.warn("[DigitalIdRedirect] status poll failed:", error);
|
|
1510
|
-
}
|
|
1511
|
-
}, POLL_INTERVAL_MS);
|
|
1512
|
-
return () => timer.clearInterval(interval);
|
|
1513
|
-
}),
|
|
1514
|
-
persistPending: fromPromise(async ({ input }) => {
|
|
1515
|
-
await persistPendingRedirect(input.storage, {
|
|
1516
|
-
verificationId: input.verificationId,
|
|
1517
|
-
providerId: input.providerId
|
|
1518
|
-
});
|
|
1519
|
-
})
|
|
1520
|
-
},
|
|
1521
|
-
actions: {
|
|
1522
|
-
setProviders: assign(({ event }) => ({ providers: event.output })),
|
|
1523
|
-
setSelectedProvider: assign(({ event }) => ({ selectedProvider: event.providerId })),
|
|
1524
|
-
setVerification: assign(({ event }) => {
|
|
1525
|
-
const v = event.output;
|
|
1526
|
-
return {
|
|
1527
|
-
verificationId: v.verificationId,
|
|
1528
|
-
launchUrl: v.flowData?.launchUrl ?? void 0,
|
|
1529
|
-
expiresAt: v.flowData?.expiresAt ?? void 0,
|
|
1530
|
-
status: v.status,
|
|
1531
|
-
failureReason: v.failureReason ?? void 0,
|
|
1532
|
-
portraitPresent: v.portraitPresent ?? false
|
|
1533
|
-
};
|
|
1534
|
-
}),
|
|
1535
|
-
setVerificationFromEvent: assign(({ event }) => {
|
|
1536
|
-
const v = event.verification;
|
|
1537
|
-
return {
|
|
1538
|
-
status: v.status,
|
|
1539
|
-
failureReason: v.failureReason ?? void 0,
|
|
1540
|
-
portraitPresent: v.portraitPresent ?? false
|
|
1541
|
-
};
|
|
1542
|
-
}),
|
|
1543
|
-
setError: assign(({ event }) => ({ error: String(event.error ?? "Unknown error") })),
|
|
1544
|
-
clearResume: assign(() => ({
|
|
1545
|
-
returnParams: void 0,
|
|
1546
|
-
verificationId: void 0,
|
|
1547
|
-
failureReason: void 0,
|
|
1548
|
-
status: void 0,
|
|
1549
|
-
error: void 0
|
|
1550
|
-
}))
|
|
1551
|
-
},
|
|
1552
|
-
guards: {
|
|
1553
|
-
hasPresetProvider: ({ context }) => Boolean(context.config.provider),
|
|
1554
|
-
autoStartPreset: ({ context }) => context.autoStart && Boolean(context.config.provider),
|
|
1555
|
-
autoStartCatalog: ({ context }) => context.autoStart && !context.config.provider,
|
|
1556
|
-
isResuming: ({ context }) => Boolean(context.returnParams),
|
|
1557
|
-
returnSucceeded: ({ context }) => context.returnParams?.success === true,
|
|
1558
|
-
submittedTerminalOk: ({ event }) => event.output.status === "COMPLETED",
|
|
1559
|
-
submittedFailed: ({ event }) => {
|
|
1560
|
-
const s = event.output.status;
|
|
1561
|
-
return s === "FAILED" || s === "EXPIRED" || s === "CANCELLED";
|
|
1562
|
-
},
|
|
1563
|
-
polledOk: ({ event }) => event.verification.status === "COMPLETED"
|
|
1564
|
-
}
|
|
1565
|
-
}).createMachine({
|
|
1566
|
-
id: "digitalIdRedirect",
|
|
1567
|
-
initial: "idle",
|
|
1568
|
-
context: ({ input }) => ({
|
|
1569
|
-
config: input.config,
|
|
1570
|
-
storage: input.storage,
|
|
1571
|
-
returnUrl: input.config.returnUrl ?? "",
|
|
1572
|
-
providers: [],
|
|
1573
|
-
selectedProvider: input.config.provider,
|
|
1574
|
-
verificationId: input.resume?.verificationId,
|
|
1575
|
-
launchUrl: void 0,
|
|
1576
|
-
expiresAt: void 0,
|
|
1577
|
-
status: void 0,
|
|
1578
|
-
failureReason: void 0,
|
|
1579
|
-
portraitPresent: false,
|
|
1580
|
-
returnParams: input.resume?.returnParams,
|
|
1581
|
-
error: void 0,
|
|
1582
|
-
autoStart: input.autoStart ?? false
|
|
1583
|
-
}),
|
|
1584
|
-
output: ({ context }) => context.status === "COMPLETED" ? {
|
|
1585
|
-
status: "COMPLETED",
|
|
1586
|
-
providerId: context.selectedProvider ?? context.config.provider ?? "",
|
|
1587
|
-
portraitPresent: context.portraitPresent
|
|
1588
|
-
} : { status: "DISMISSED" },
|
|
1589
|
-
states: {
|
|
1590
|
-
idle: {
|
|
1591
|
-
always: [
|
|
1592
|
-
{
|
|
1593
|
-
guard: "isResuming",
|
|
1594
|
-
target: "submitting"
|
|
1595
|
-
},
|
|
1596
|
-
{
|
|
1597
|
-
guard: "autoStartPreset",
|
|
1598
|
-
target: "creating"
|
|
1599
|
-
},
|
|
1600
|
-
{
|
|
1601
|
-
guard: "autoStartCatalog",
|
|
1602
|
-
target: "loadingProviders"
|
|
1603
|
-
}
|
|
1604
|
-
],
|
|
1605
|
-
on: { LOAD: [{
|
|
1606
|
-
guard: "hasPresetProvider",
|
|
1607
|
-
target: "creating"
|
|
1608
|
-
}, { target: "loadingProviders" }] }
|
|
1609
|
-
},
|
|
1610
|
-
loadingProviders: { invoke: {
|
|
1611
|
-
src: "listProviders",
|
|
1612
|
-
input: ({ context }) => ({ country: context.config.country }),
|
|
1613
|
-
onDone: {
|
|
1614
|
-
target: "choosingProvider",
|
|
1615
|
-
actions: "setProviders"
|
|
1616
|
-
},
|
|
1617
|
-
onError: {
|
|
1618
|
-
target: "error",
|
|
1619
|
-
actions: "setError"
|
|
1620
|
-
}
|
|
1621
|
-
} },
|
|
1622
|
-
choosingProvider: { on: { SELECT_PROVIDER: {
|
|
1623
|
-
target: "creating",
|
|
1624
|
-
actions: "setSelectedProvider"
|
|
1625
|
-
} } },
|
|
1626
|
-
creating: { invoke: {
|
|
1627
|
-
src: "createVerification",
|
|
1628
|
-
input: ({ context }) => ({
|
|
1629
|
-
providerId: context.selectedProvider ?? "",
|
|
1630
|
-
redirectUrl: context.returnUrl
|
|
1631
|
-
}),
|
|
1632
|
-
onDone: {
|
|
1633
|
-
target: "persisting",
|
|
1634
|
-
actions: "setVerification"
|
|
1635
|
-
},
|
|
1636
|
-
onError: {
|
|
1637
|
-
target: "error",
|
|
1638
|
-
actions: "setError"
|
|
1639
|
-
}
|
|
1640
|
-
} },
|
|
1641
|
-
persisting: { invoke: {
|
|
1642
|
-
src: "persistPending",
|
|
1643
|
-
input: ({ context }) => ({
|
|
1644
|
-
storage: context.storage,
|
|
1645
|
-
verificationId: context.verificationId ?? "",
|
|
1646
|
-
providerId: context.selectedProvider ?? ""
|
|
1647
|
-
}),
|
|
1648
|
-
onDone: { target: "readyToRedirect" },
|
|
1649
|
-
onError: { target: "readyToRedirect" }
|
|
1650
|
-
} },
|
|
1651
|
-
readyToRedirect: { on: { REFRESH: { target: "refreshing" } } },
|
|
1652
|
-
refreshing: { invoke: {
|
|
1653
|
-
src: "refreshVerification",
|
|
1654
|
-
input: ({ context }) => ({ verificationId: context.verificationId ?? "" }),
|
|
1655
|
-
onDone: {
|
|
1656
|
-
target: "readyToRedirect",
|
|
1657
|
-
actions: "setVerification"
|
|
1658
|
-
},
|
|
1659
|
-
onError: {
|
|
1660
|
-
target: "error",
|
|
1661
|
-
actions: "setError"
|
|
1662
|
-
}
|
|
1663
|
-
} },
|
|
1664
|
-
submitting: { invoke: {
|
|
1665
|
-
src: "submitWalletResponse",
|
|
1666
|
-
input: ({ context }) => ({
|
|
1667
|
-
verificationId: context.verificationId ?? "",
|
|
1668
|
-
params: context.returnParams
|
|
1669
|
-
}),
|
|
1670
|
-
onDone: [
|
|
1671
|
-
{
|
|
1672
|
-
guard: "submittedTerminalOk",
|
|
1673
|
-
target: "succeeded",
|
|
1674
|
-
actions: "setVerification"
|
|
1675
|
-
},
|
|
1676
|
-
{
|
|
1677
|
-
guard: "submittedFailed",
|
|
1678
|
-
target: "failed",
|
|
1679
|
-
actions: "setVerification"
|
|
1680
|
-
},
|
|
1681
|
-
{
|
|
1682
|
-
target: "polling",
|
|
1683
|
-
actions: "setVerification"
|
|
1684
|
-
}
|
|
1685
|
-
],
|
|
1686
|
-
onError: {
|
|
1687
|
-
target: "error",
|
|
1688
|
-
actions: "setError"
|
|
1689
|
-
}
|
|
1690
|
-
} },
|
|
1691
|
-
polling: {
|
|
1692
|
-
invoke: {
|
|
1693
|
-
src: "pollStatus",
|
|
1694
|
-
input: ({ context }) => ({ verificationId: context.verificationId ?? "" })
|
|
1695
|
-
},
|
|
1696
|
-
on: { POLL_RESULT: [{
|
|
1697
|
-
guard: "polledOk",
|
|
1698
|
-
target: "succeeded",
|
|
1699
|
-
actions: "setVerificationFromEvent"
|
|
1700
|
-
}, {
|
|
1701
|
-
target: "failed",
|
|
1702
|
-
actions: "setVerificationFromEvent"
|
|
1703
|
-
}] },
|
|
1704
|
-
after: { [POLL_INTERVAL_MS * MAX_POLL_ATTEMPTS]: {
|
|
1705
|
-
target: "failed",
|
|
1706
|
-
actions: assign({ failureReason: () => "SESSION_EXPIRED" })
|
|
1707
|
-
} }
|
|
1708
|
-
},
|
|
1709
|
-
succeeded: { on: { CONTINUE: { target: "finished" } } },
|
|
1710
|
-
finished: { type: "final" },
|
|
1711
|
-
failed: { on: {
|
|
1712
|
-
RETRY: [{
|
|
1713
|
-
guard: "hasPresetProvider",
|
|
1714
|
-
target: "creating"
|
|
1715
|
-
}, { target: "choosingProvider" }],
|
|
1716
|
-
USE_ANOTHER_METHOD: { target: "closed" },
|
|
1717
|
-
CLOSE: { target: "closed" }
|
|
1718
|
-
} },
|
|
1719
|
-
error: { on: {
|
|
1720
|
-
RETRY: [{
|
|
1721
|
-
guard: "hasPresetProvider",
|
|
1722
|
-
target: "creating",
|
|
1723
|
-
actions: "clearResume"
|
|
1724
|
-
}, {
|
|
1725
|
-
target: "choosingProvider",
|
|
1726
|
-
actions: "clearResume"
|
|
1727
|
-
}],
|
|
1728
|
-
USE_ANOTHER_METHOD: { target: "closed" },
|
|
1729
|
-
CLOSE: { target: "closed" }
|
|
1730
|
-
} },
|
|
1731
|
-
closed: { type: "final" }
|
|
1732
|
-
}
|
|
1733
|
-
});
|
|
1734
|
-
//#endregion
|
|
1735
|
-
//#region src/modules/id/idCaptureActors.ts
|
|
1736
|
-
const checkPermissionActor = fromPromise(async () => {
|
|
1737
|
-
return checkPermission();
|
|
1738
|
-
});
|
|
1739
|
-
async function requestIdCapturePermission(input) {
|
|
1740
|
-
if (!isAndroid() || getBrowser() !== "firefox") return invokeRequestPermissionActor(input);
|
|
1741
|
-
if (input.requestMotionPermission) {
|
|
1742
|
-
const motionResult = await invokeRequestPermissionActor({
|
|
1743
|
-
...input,
|
|
1744
|
-
permissionResult: "granted"
|
|
1745
|
-
});
|
|
1746
|
-
if (motionResult !== "granted") return motionResult;
|
|
1747
|
-
}
|
|
1748
|
-
const { stream, fallbackLevel } = await getIdCameraStream();
|
|
1749
|
-
return {
|
|
1750
|
-
permissionResult: "granted",
|
|
1751
|
-
stream,
|
|
1752
|
-
cameraFallbackLevel: fallbackLevel
|
|
1753
|
-
};
|
|
1754
|
-
}
|
|
1755
|
-
const requestPermissionActor = fromPromise(async ({ input }) => {
|
|
1756
|
-
return requestIdCapturePermission(input);
|
|
1757
|
-
});
|
|
1758
|
-
const initializeCameraActor = fromPromise(async ({ input }) => {
|
|
1759
|
-
return initializeIdCapture(input);
|
|
1760
|
-
});
|
|
1761
|
-
const runDetectionActor = fromCallback(({ input, sendBack }) => {
|
|
1473
|
+
fromCallback(({ input, sendBack }) => {
|
|
1762
1474
|
if (!input.frameCapturer || !input.provider) {
|
|
1763
1475
|
sendBack({
|
|
1764
1476
|
type: "DETECTION_UPDATE",
|
|
@@ -1772,7 +1484,6 @@ const runDetectionActor = fromCallback(({ input, sendBack }) => {
|
|
|
1772
1484
|
let storedQualityElements = {};
|
|
1773
1485
|
let isCapturing = false;
|
|
1774
1486
|
const timer = BrowserTimerProvider.getInstance();
|
|
1775
|
-
let notificationTimeout = null;
|
|
1776
1487
|
let optimizingBoundaryTimeout = null;
|
|
1777
1488
|
/**
|
|
1778
1489
|
* IDC-05 latch for the boundary clock: whether a boundary is currently
|
|
@@ -1780,24 +1491,8 @@ const runDetectionActor = fromCallback(({ input, sendBack }) => {
|
|
|
1780
1491
|
* the clock's only T0; nothing in WASM enforces that it fires once per window.
|
|
1781
1492
|
*/
|
|
1782
1493
|
let isOptimizingBoundaryArmed = false;
|
|
1783
|
-
let currentNotificationStatus = null;
|
|
1784
1494
|
let lastReportedSide = null;
|
|
1785
|
-
const
|
|
1786
|
-
const isReportedSideWrong = () => {
|
|
1787
|
-
if (!lastReportedSide) return false;
|
|
1788
|
-
const detectedSide = lastReportedSide.toLowerCase();
|
|
1789
|
-
if (detectedSide === "wrong") return true;
|
|
1790
|
-
const isBackDetected = detectedSide.includes("back") && !detectedSide.includes("front");
|
|
1791
|
-
const isFrontDetected = detectedSide.includes("front") && !detectedSide.includes("back");
|
|
1792
|
-
return input.currentMode === "front" && isBackDetected || input.currentMode === "back" && isFrontDetected;
|
|
1793
|
-
};
|
|
1794
|
-
const clearNotificationTimeout = () => {
|
|
1795
|
-
if (notificationTimeout) {
|
|
1796
|
-
timer.clearTimeout(notificationTimeout);
|
|
1797
|
-
notificationTimeout = null;
|
|
1798
|
-
currentNotificationStatus = null;
|
|
1799
|
-
}
|
|
1800
|
-
};
|
|
1495
|
+
const isReportedSideWrong = () => isReportedIdSideWrong(input.currentMode, lastReportedSide);
|
|
1801
1496
|
const clearOptimizingBoundary = () => {
|
|
1802
1497
|
if (optimizingBoundaryTimeout) {
|
|
1803
1498
|
timer.clearTimeout(optimizingBoundaryTimeout);
|
|
@@ -1842,173 +1537,130 @@ const runDetectionActor = fromCallback(({ input, sendBack }) => {
|
|
|
1842
1537
|
candidateCanvas
|
|
1843
1538
|
});
|
|
1844
1539
|
};
|
|
1845
|
-
const
|
|
1846
|
-
|
|
1847
|
-
if (notificationTimeout && currentNotificationStatus !== status) return;
|
|
1848
|
-
if (notificationTimeout && currentNotificationStatus === status) timer.clearTimeout(notificationTimeout);
|
|
1849
|
-
currentNotificationStatus = status;
|
|
1850
|
-
trueSightHintTransition("module.id-capture", "idScan", status);
|
|
1851
|
-
sendBack({
|
|
1540
|
+
const notifications = createIdDetectionNotificationController({
|
|
1541
|
+
send: (status) => sendBack({
|
|
1852
1542
|
type: "DETECTION_UPDATE",
|
|
1853
1543
|
status
|
|
1854
|
-
})
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
currentNotificationStatus = null;
|
|
1858
|
-
sendBack({
|
|
1859
|
-
type: "DETECTION_UPDATE",
|
|
1860
|
-
status: "detecting"
|
|
1861
|
-
});
|
|
1862
|
-
}, NOTIFICATION_DURATION_MS);
|
|
1863
|
-
};
|
|
1864
|
-
const canvas = input.frameCapturer.getLatestCanvas();
|
|
1865
|
-
const windowDimensions = getWindowDimensions(canvas?.width() ?? 1280, canvas?.height() ?? 720);
|
|
1866
|
-
const DEFAULT_GEOMETRY = {
|
|
1867
|
-
areaDown: 25e3,
|
|
1868
|
-
areaUp: 55e3,
|
|
1869
|
-
areaIOSPassportUp: 3e4,
|
|
1870
|
-
areaIOSPassportDown: 2e4,
|
|
1871
|
-
widthIOSUp: 160,
|
|
1872
|
-
widthIOSDown: 85,
|
|
1873
|
-
widthDown: 110,
|
|
1874
|
-
widthUp: 205
|
|
1875
|
-
};
|
|
1876
|
-
if (input.config.geometry) provider.setGeometry({
|
|
1877
|
-
...input.config.geometry,
|
|
1878
|
-
windowOuterWidth: windowDimensions.outerWidth,
|
|
1879
|
-
windowOuterHeight: windowDimensions.outerHeight,
|
|
1880
|
-
windowInnerWidth: windowDimensions.innerWidth,
|
|
1881
|
-
windowInnerHeight: windowDimensions.innerHeight
|
|
1882
|
-
});
|
|
1883
|
-
else provider.setGeometry({
|
|
1884
|
-
...DEFAULT_GEOMETRY,
|
|
1885
|
-
windowOuterWidth: windowDimensions.outerWidth,
|
|
1886
|
-
windowOuterHeight: windowDimensions.outerHeight,
|
|
1887
|
-
windowInnerWidth: windowDimensions.innerWidth,
|
|
1888
|
-
windowInnerHeight: windowDimensions.innerHeight
|
|
1889
|
-
});
|
|
1890
|
-
const idType = input.currentMode === "back" ? "BackId" : input.currentMode === "passport" ? "Passport" : "FrontId";
|
|
1891
|
-
provider.setSettings({
|
|
1892
|
-
isFixedMask: input.config.settings?.isFixedMask ?? false,
|
|
1893
|
-
isIPhone14OrHigher: input.config.settings?.isIPhone14OrHigher ?? false,
|
|
1894
|
-
idType,
|
|
1895
|
-
blurCheckEnabled: input.config.settings?.blurCheckEnabled ?? false,
|
|
1896
|
-
glareCheckEnabled: input.config.settings?.glareCheckEnabled ?? false,
|
|
1897
|
-
faceQualityCheckEnabled: input.config.settings?.faceQualityCheckEnabled ?? true,
|
|
1898
|
-
iouCheckEnabled: input.config.settings?.iouCheckEnabled ?? true,
|
|
1899
|
-
fpsLimitEnabled: input.config.settings?.fpsLimitEnabled ?? false
|
|
1544
|
+
}),
|
|
1545
|
+
isSuppressed: isReportedSideWrong,
|
|
1546
|
+
onStatusShown: (status) => trueSightHintTransition("module.id-capture", "idScan", status)
|
|
1900
1547
|
});
|
|
1901
|
-
|
|
1902
|
-
const
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
type: "ORIENTATION_CHANGE",
|
|
1912
|
-
orientation
|
|
1913
|
-
});
|
|
1914
|
-
},
|
|
1915
|
-
onBlur: () => {
|
|
1916
|
-
if (!isCapturing) sendNotification("blur");
|
|
1917
|
-
},
|
|
1918
|
-
onGlare: () => {
|
|
1919
|
-
if (!isCapturing) sendNotification("glare");
|
|
1548
|
+
const canvas = input.frameCapturer.getLatestCanvas();
|
|
1549
|
+
const canvasWidth = canvas?.width() ?? 1280;
|
|
1550
|
+
const canvasHeight = canvas?.height() ?? 720;
|
|
1551
|
+
configureIdCaptureProvider({
|
|
1552
|
+
provider,
|
|
1553
|
+
config: input.config,
|
|
1554
|
+
currentMode: input.currentMode,
|
|
1555
|
+
frameSize: {
|
|
1556
|
+
width: canvasWidth,
|
|
1557
|
+
height: canvasHeight
|
|
1920
1558
|
},
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1559
|
+
callbacks: {
|
|
1560
|
+
onFarAway: () => {
|
|
1561
|
+
if (!isCapturing) notifications.show("farAway");
|
|
1562
|
+
},
|
|
1563
|
+
onDetectionStarted: () => {},
|
|
1564
|
+
onMaskChange: (_show, _mask, _top, orientation) => {
|
|
1924
1565
|
sendBack({
|
|
1925
|
-
type: "
|
|
1926
|
-
|
|
1566
|
+
type: "ORIENTATION_CHANGE",
|
|
1567
|
+
orientation
|
|
1927
1568
|
});
|
|
1928
|
-
}
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
}
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
onBestFrame: (blur, glare, orientation) => {
|
|
1947
|
-
if (currentCanvas) {
|
|
1948
|
-
bestCanvas = currentCanvas.clone();
|
|
1949
|
-
storedQualityElements = {
|
|
1950
|
-
glare,
|
|
1951
|
-
sharpness: blur
|
|
1952
|
-
};
|
|
1953
|
-
}
|
|
1954
|
-
if (orientation === "horizontal" || orientation === "vertical") sendBack({
|
|
1955
|
-
type: "ORIENTATION_CHANGE",
|
|
1956
|
-
orientation
|
|
1957
|
-
});
|
|
1958
|
-
},
|
|
1959
|
-
onCapture: () => {
|
|
1960
|
-
isCapturing = false;
|
|
1961
|
-
if (isOptimizingBoundaryArmed) {
|
|
1569
|
+
},
|
|
1570
|
+
onBlur: () => {
|
|
1571
|
+
if (!isCapturing) notifications.show("blur");
|
|
1572
|
+
},
|
|
1573
|
+
onGlare: () => {
|
|
1574
|
+
if (!isCapturing) notifications.show("glare");
|
|
1575
|
+
},
|
|
1576
|
+
onIdNotDetected: () => {
|
|
1577
|
+
if (!isCapturing) {
|
|
1578
|
+
trueSightHintTransition("module.id-capture", "idScan", "idNotDetected");
|
|
1579
|
+
sendBack({
|
|
1580
|
+
type: "DETECTION_UPDATE",
|
|
1581
|
+
status: "idNotDetected"
|
|
1582
|
+
});
|
|
1583
|
+
}
|
|
1584
|
+
},
|
|
1585
|
+
onSwitchToManualCapture: () => {
|
|
1586
|
+
isCapturing = false;
|
|
1962
1587
|
clearOptimizingBoundary();
|
|
1963
|
-
|
|
1964
|
-
}
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1588
|
+
sendBack({ type: "SWITCH_TO_MANUAL_CAPTURE" });
|
|
1589
|
+
},
|
|
1590
|
+
onCapturing: () => {
|
|
1591
|
+
notifications.clear();
|
|
1592
|
+
lastReportedSide = null;
|
|
1593
|
+
isCapturing = true;
|
|
1594
|
+
trueSightHintTransition("module.id-capture", "idScan", "capturing");
|
|
1595
|
+
sendBack({
|
|
1596
|
+
type: "DETECTION_UPDATE",
|
|
1597
|
+
status: "capturing"
|
|
1598
|
+
});
|
|
1599
|
+
scheduleOptimizingBoundary();
|
|
1600
|
+
},
|
|
1601
|
+
onBestFrame: (blur, glare, orientation) => {
|
|
1602
|
+
if (currentCanvas) {
|
|
1603
|
+
bestCanvas = currentCanvas.clone();
|
|
1604
|
+
storedQualityElements = {
|
|
1605
|
+
glare,
|
|
1606
|
+
sharpness: blur
|
|
1607
|
+
};
|
|
1608
|
+
}
|
|
1609
|
+
if (orientation === "horizontal" || orientation === "vertical") sendBack({
|
|
1610
|
+
type: "ORIENTATION_CHANGE",
|
|
1611
|
+
orientation
|
|
1612
|
+
});
|
|
1613
|
+
},
|
|
1614
|
+
onCapture: () => {
|
|
1615
|
+
isCapturing = false;
|
|
1616
|
+
if (isOptimizingBoundaryArmed) {
|
|
1617
|
+
clearOptimizingBoundary();
|
|
1618
|
+
enterOptimizing();
|
|
1619
|
+
}
|
|
1620
|
+
if (!bestCanvas) {
|
|
1621
|
+
const clonedCanvas = currentCanvas?.clone();
|
|
1622
|
+
if (clonedCanvas) sendBack({
|
|
1623
|
+
type: "DETECTION_SUCCESS",
|
|
1624
|
+
canvas: clonedCanvas,
|
|
1625
|
+
qualityElements: {}
|
|
1626
|
+
});
|
|
1627
|
+
return;
|
|
1628
|
+
}
|
|
1629
|
+
sendBack({
|
|
1630
|
+
type: "DETECTION_SUCCESS",
|
|
1631
|
+
canvas: bestCanvas,
|
|
1632
|
+
qualityElements: storedQualityElements
|
|
1633
|
+
});
|
|
1634
|
+
},
|
|
1635
|
+
onIdTypeChange: (idType) => {
|
|
1636
|
+
sendBack({
|
|
1637
|
+
type: "ID_TYPE_CHANGE",
|
|
1638
|
+
idType
|
|
1639
|
+
});
|
|
1640
|
+
},
|
|
1641
|
+
onIdSideChange: (side) => {
|
|
1642
|
+
if (isCapturing) return;
|
|
1643
|
+
lastReportedSide = side;
|
|
1644
|
+
if (isReportedSideWrong()) notifications.clear();
|
|
1645
|
+
sendBack({
|
|
1646
|
+
type: "ID_SIDE_CHANGE",
|
|
1647
|
+
side
|
|
1648
|
+
});
|
|
1649
|
+
},
|
|
1650
|
+
onCapturingCounterValueChange: (value) => {
|
|
1651
|
+
sendBack({
|
|
1652
|
+
type: "COUNTER_VALUE_CHANGE",
|
|
1653
|
+
value
|
|
1654
|
+
});
|
|
1655
|
+
},
|
|
1656
|
+
onBarcodeDecoded: (decoded) => {
|
|
1657
|
+
sendBack({
|
|
1658
|
+
type: "BARCODE_DECODED",
|
|
1659
|
+
decoded
|
|
1971
1660
|
});
|
|
1972
|
-
return;
|
|
1973
1661
|
}
|
|
1974
|
-
sendBack({
|
|
1975
|
-
type: "DETECTION_SUCCESS",
|
|
1976
|
-
canvas: bestCanvas,
|
|
1977
|
-
qualityElements: storedQualityElements
|
|
1978
|
-
});
|
|
1979
|
-
},
|
|
1980
|
-
onIdTypeChange: (idType) => {
|
|
1981
|
-
sendBack({
|
|
1982
|
-
type: "ID_TYPE_CHANGE",
|
|
1983
|
-
idType
|
|
1984
|
-
});
|
|
1985
|
-
},
|
|
1986
|
-
onIdSideChange: (side) => {
|
|
1987
|
-
if (isCapturing) return;
|
|
1988
|
-
lastReportedSide = side;
|
|
1989
|
-
if (isReportedSideWrong()) clearNotificationTimeout();
|
|
1990
|
-
sendBack({
|
|
1991
|
-
type: "ID_SIDE_CHANGE",
|
|
1992
|
-
side
|
|
1993
|
-
});
|
|
1994
|
-
},
|
|
1995
|
-
onCapturingCounterValueChange: (value) => {
|
|
1996
|
-
sendBack({
|
|
1997
|
-
type: "COUNTER_VALUE_CHANGE",
|
|
1998
|
-
value
|
|
1999
|
-
});
|
|
2000
|
-
},
|
|
2001
|
-
onBarcodeDecoded: (decoded) => {
|
|
2002
|
-
sendBack({
|
|
2003
|
-
type: "BARCODE_DECODED",
|
|
2004
|
-
decoded
|
|
2005
|
-
});
|
|
2006
1662
|
}
|
|
2007
1663
|
});
|
|
2008
|
-
const barcodeCaptureEnabled = input.config.usSmartCapture === true && input.currentMode === "back";
|
|
2009
|
-
provider.setBarcodeCaptureEnabled(barcodeCaptureEnabled);
|
|
2010
|
-
provider.setBarcodeAutoCaptureOnDecode(false);
|
|
2011
|
-
if (barcodeCaptureEnabled) provider.setBarcodeEnhancementModel().catch(() => {});
|
|
2012
1664
|
sendBack({
|
|
2013
1665
|
type: "DETECTION_UPDATE",
|
|
2014
1666
|
status: "detecting"
|
|
@@ -2021,11 +1673,7 @@ const runDetectionActor = fromCallback(({ input, sendBack }) => {
|
|
|
2021
1673
|
await provider.processFrame(frame);
|
|
2022
1674
|
},
|
|
2023
1675
|
reset: () => {
|
|
2024
|
-
|
|
2025
|
-
timer.clearTimeout(notificationTimeout);
|
|
2026
|
-
notificationTimeout = null;
|
|
2027
|
-
currentNotificationStatus = null;
|
|
2028
|
-
}
|
|
1676
|
+
notifications.clear();
|
|
2029
1677
|
clearOptimizingBoundary();
|
|
2030
1678
|
currentCanvas = null;
|
|
2031
1679
|
bestCanvas = null;
|
|
@@ -2044,7 +1692,7 @@ const runDetectionActor = fromCallback(({ input, sendBack }) => {
|
|
|
2044
1692
|
}
|
|
2045
1693
|
});
|
|
2046
1694
|
return () => {
|
|
2047
|
-
|
|
1695
|
+
notifications.clear();
|
|
2048
1696
|
clearOptimizingBoundary();
|
|
2049
1697
|
session?.dispose();
|
|
2050
1698
|
noteTrueSightCaptureActivity(false);
|
|
@@ -2057,7 +1705,7 @@ const uploadProgressTickerActor = fromCallback(({ sendBack }) => {
|
|
|
2057
1705
|
}, 400);
|
|
2058
1706
|
return () => timer.clearInterval(interval);
|
|
2059
1707
|
});
|
|
2060
|
-
|
|
1708
|
+
fromPromise(async ({ input, signal }) => {
|
|
2061
1709
|
const image = input.canvas.getBase64Image();
|
|
2062
1710
|
if (!image) throw new Error(ID_ERROR_CODES.UPLOAD_ERROR);
|
|
2063
1711
|
let metadata;
|
|
@@ -2121,7 +1769,7 @@ const submitBarcodeActor = fromPromise(async ({ input, signal }) => {
|
|
|
2121
1769
|
}), input.minDurationMs ? sleep(input.minDurationMs) : Promise.resolve()]);
|
|
2122
1770
|
return response;
|
|
2123
1771
|
});
|
|
2124
|
-
|
|
1772
|
+
fromPromise(async ({ input }) => {
|
|
2125
1773
|
if (!input.stream) return;
|
|
2126
1774
|
const type = input.currentMode === "back" ? "backId" : "frontId";
|
|
2127
1775
|
return startRecordingSession({
|
|
@@ -2131,16 +1779,16 @@ const startRecordingActor = fromPromise(async ({ input }) => {
|
|
|
2131
1779
|
type
|
|
2132
1780
|
});
|
|
2133
1781
|
});
|
|
2134
|
-
|
|
1782
|
+
fromPromise(async ({ input }) => {
|
|
2135
1783
|
if (!input.dependencies) return;
|
|
2136
|
-
const { loadDeepsightSession } = await import("./deepsightLoader-
|
|
1784
|
+
const { loadDeepsightSession } = await import("./deepsightLoader-Dhz9T_KJ.esm.js");
|
|
2137
1785
|
return loadDeepsightSession({
|
|
2138
1786
|
ds: input.ds,
|
|
2139
1787
|
storage: input.dependencies.storage,
|
|
2140
1788
|
disableIpify: input.disableIpify
|
|
2141
1789
|
});
|
|
2142
1790
|
});
|
|
2143
|
-
|
|
1791
|
+
fromPromise(async ({ input }) => {
|
|
2144
1792
|
if (!input.deepsightService || !input.stream) return false;
|
|
2145
1793
|
const videoTrack = input.stream.getVideoTracks()[0];
|
|
2146
1794
|
if (!videoTrack) return false;
|
|
@@ -2155,9 +1803,6 @@ function performStopMediaStream(context) {
|
|
|
2155
1803
|
function performDisposeProvider(context) {
|
|
2156
1804
|
context.provider?.dispose?.();
|
|
2157
1805
|
}
|
|
2158
|
-
function performCleanupDeepsight(context) {
|
|
2159
|
-
context.deepsightService?.cleanup();
|
|
2160
|
-
}
|
|
2161
1806
|
function performResetForBackCapture(context) {
|
|
2162
1807
|
context.frameCapturer?.dispose();
|
|
2163
1808
|
if (context.stream) stopStream(context.stream);
|
|
@@ -2168,9 +1813,6 @@ function performResetForFrontCapture(context) {
|
|
|
2168
1813
|
if (context.stream) stopStream(context.stream);
|
|
2169
1814
|
context.provider?.reset();
|
|
2170
1815
|
}
|
|
2171
|
-
function performResetDetection(context) {
|
|
2172
|
-
context.resetDetection?.();
|
|
2173
|
-
}
|
|
2174
1816
|
function performReportCaptureOptimizingAssignment(context) {
|
|
2175
1817
|
if (context.config.supportsOptimizingStatus !== true) return;
|
|
2176
1818
|
const assignment = exposeExperimentOnce(CAPTURE_OPTIMIZING);
|
|
@@ -2180,15 +1822,9 @@ function performReportCaptureOptimizingAssignment(context) {
|
|
|
2180
1822
|
function performStopMediaRecording(context) {
|
|
2181
1823
|
if (context.recordingSession) stopRecording(context.recordingSession);
|
|
2182
1824
|
}
|
|
2183
|
-
function performPauseRecordingForAttempt(context) {
|
|
2184
|
-
if (context.recordingSession) pauseRecordingForAttempt(context.recordingSession);
|
|
2185
|
-
}
|
|
2186
1825
|
function performPrepareRecordingForCameraRetry(context) {
|
|
2187
1826
|
if (context.recordingSession) prepareRecordingForCameraRetry(context.recordingSession);
|
|
2188
1827
|
}
|
|
2189
|
-
function getStreamFromEvent(event) {
|
|
2190
|
-
if ("output" in event) return event.output.stream;
|
|
2191
|
-
}
|
|
2192
1828
|
function getPermissionResultFromEvent(event) {
|
|
2193
1829
|
if (!("output" in event)) return;
|
|
2194
1830
|
const { output } = event;
|
|
@@ -2198,24 +1834,9 @@ function getPermissionResultFromEvent(event) {
|
|
|
2198
1834
|
if (result === "granted" || result === "denied" || result === "prompt") return result;
|
|
2199
1835
|
}
|
|
2200
1836
|
}
|
|
2201
|
-
function getProviderFromEvent(event) {
|
|
2202
|
-
if ("output" in event) return event.output.provider;
|
|
2203
|
-
}
|
|
2204
|
-
function getCaptureResolutionFromEvent(event) {
|
|
2205
|
-
if ("output" in event) return event.output.captureResolution;
|
|
2206
|
-
}
|
|
2207
1837
|
function getCameraFallbackLevelFromEvent(event) {
|
|
2208
1838
|
if ("output" in event) return event.output.cameraFallbackLevel;
|
|
2209
1839
|
}
|
|
2210
|
-
function getUsingBackCameraFromEvent(event) {
|
|
2211
|
-
if ("output" in event) return event.output.usingBackCamera;
|
|
2212
|
-
}
|
|
2213
|
-
function getFrameCapturerFromEvent(event) {
|
|
2214
|
-
if ("output" in event) {
|
|
2215
|
-
const output = event.output;
|
|
2216
|
-
if (output.stream) return new StreamCanvasCapture(output.stream);
|
|
2217
|
-
}
|
|
2218
|
-
}
|
|
2219
1840
|
function getResetContextValues(context) {
|
|
2220
1841
|
context.provider?.reset();
|
|
2221
1842
|
const currentMode = context.config.onlyBack ? "back" : !context.config.enableId && context.config.enablePassport ? "passport" : context.config.usSmartCapture ? "back" : "front";
|
|
@@ -2274,19 +1895,6 @@ function getUploadValidationError(context) {
|
|
|
2274
1895
|
skipGlareBack: context.uploadResponse.skipGlareBack
|
|
2275
1896
|
})?.errorKey ?? ID_ERROR_CODES.SERVER;
|
|
2276
1897
|
}
|
|
2277
|
-
function storeCapturedCanvasInProviderLogic(context, event) {
|
|
2278
|
-
let canvas = null;
|
|
2279
|
-
if ("canvas" in event && event.canvas) canvas = event.canvas;
|
|
2280
|
-
else canvas = context.frameCapturer?.getLatestCanvas() ?? null;
|
|
2281
|
-
if (!canvas || !context.provider) return;
|
|
2282
|
-
const canvasWidth = canvas.width();
|
|
2283
|
-
const canvasHeight = canvas.height();
|
|
2284
|
-
if (!canvasWidth || !canvasHeight) return;
|
|
2285
|
-
const originalCanvas = canvas;
|
|
2286
|
-
const frameRect = resolveCaptureFrameRect(context, canvasWidth, canvasHeight);
|
|
2287
|
-
const transformedCanvas = context.provider.transformPerspective(originalCanvas, frameRect);
|
|
2288
|
-
context.provider.setCapturedCanvases(originalCanvas, transformedCanvas);
|
|
2289
|
-
}
|
|
2290
1898
|
/**
|
|
2291
1899
|
* JPEG quality for the IDC-05 optimizing phase's display-only still.
|
|
2292
1900
|
*
|
|
@@ -2426,10 +2034,10 @@ function getStoreCapturedImageValues(context, event) {
|
|
|
2426
2034
|
*
|
|
2427
2035
|
* Revokes any previous URL rather than leaking one per retry.
|
|
2428
2036
|
*/
|
|
2429
|
-
function getCandidateFrameValues(context, event) {
|
|
2037
|
+
function getCandidateFrameValues(context, event, provider = context.provider) {
|
|
2430
2038
|
if (event.type !== "DETECTION_OPTIMIZING" || !event.candidateCanvas) return { candidateImageUrl: context.candidateImageUrl };
|
|
2431
2039
|
const candidateCanvas = event.candidateCanvas;
|
|
2432
|
-
const canvas = cropCanvasForPreview(context, candidateCanvas);
|
|
2040
|
+
const canvas = cropCanvasForPreview(context, candidateCanvas, provider);
|
|
2433
2041
|
canvas.updateBlob(CANDIDATE_FRAME_JPEG_QUALITY);
|
|
2434
2042
|
const url = canvas.getBlobData()?.url;
|
|
2435
2043
|
if (!url) {
|
|
@@ -2464,12 +2072,12 @@ function releasePreviewCanvases(source, preview, { shouldReleasePreview }) {
|
|
|
2464
2072
|
if (shouldReleasePreview) preview.release();
|
|
2465
2073
|
source.release();
|
|
2466
2074
|
}
|
|
2467
|
-
function cropCanvasForPreview(context, canvas) {
|
|
2075
|
+
function cropCanvasForPreview(context, canvas, provider = context.provider) {
|
|
2468
2076
|
const canvasWidth = canvas.width();
|
|
2469
2077
|
const canvasHeight = canvas.height();
|
|
2470
|
-
if (!
|
|
2078
|
+
if (!provider || !canvasWidth || !canvasHeight) return canvas;
|
|
2471
2079
|
const frameRect = resolveCaptureFrameRect(context, canvasWidth, canvasHeight);
|
|
2472
|
-
return
|
|
2080
|
+
return provider.transformPerspective(canvas, frameRect);
|
|
2473
2081
|
}
|
|
2474
2082
|
/**
|
|
2475
2083
|
* Drops the IDC-05 best-so-far still at every attempt/side boundary. Unlike
|
|
@@ -2491,6 +2099,7 @@ function getDetectionStatusFromUpdate(context, event) {
|
|
|
2491
2099
|
if (event.type === "DETECTION_UPDATE") {
|
|
2492
2100
|
const newStatus = event.status;
|
|
2493
2101
|
const currentStatus = context.detectionStatus;
|
|
2102
|
+
if (currentStatus === "capturing" && newStatus !== "offline") return currentStatus;
|
|
2494
2103
|
if (currentStatus === "wrongSide") {
|
|
2495
2104
|
if (!(newStatus === "capturing" || newStatus === "manualCapture" || newStatus === "offline")) return currentStatus;
|
|
2496
2105
|
return newStatus;
|
|
@@ -2550,8 +2159,1353 @@ function getBarcodeResponseValues(context, event) {
|
|
|
2550
2159
|
isDocumentExpired: output?.isDocumentExpired,
|
|
2551
2160
|
success: output?.success
|
|
2552
2161
|
},
|
|
2553
|
-
skipProcessId: output?.idValidationCompleted === true || context.skipProcessId
|
|
2554
|
-
};
|
|
2162
|
+
skipProcessId: output?.idValidationCompleted === true || context.skipProcessId
|
|
2163
|
+
};
|
|
2164
|
+
}
|
|
2165
|
+
//#endregion
|
|
2166
|
+
//#region src/modules/id/idCaptureDiagnostics.ts
|
|
2167
|
+
const ID_CAMERA_DIAGNOSTIC_PREFIX = "[Incode ID camera]";
|
|
2168
|
+
function finiteNumber(value) {
|
|
2169
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
2170
|
+
}
|
|
2171
|
+
function stringValue(value) {
|
|
2172
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
2173
|
+
}
|
|
2174
|
+
function readFocusRequest(constraints) {
|
|
2175
|
+
const sets = [constraints, ...constraints.advanced ?? []];
|
|
2176
|
+
const requestedFocusMode = sets.map((set) => stringValue(set.focusMode)).find((value) => value !== void 0);
|
|
2177
|
+
const requestedFocusDistance = sets.map((set) => finiteNumber(set.focusDistance)).find((value) => value !== void 0);
|
|
2178
|
+
return {
|
|
2179
|
+
focusRequested: requestedFocusMode !== void 0 || requestedFocusDistance !== void 0,
|
|
2180
|
+
requestedFocusMode,
|
|
2181
|
+
requestedFocusDistance
|
|
2182
|
+
};
|
|
2183
|
+
}
|
|
2184
|
+
/**
|
|
2185
|
+
* Returns an intentionally narrow, non-identifying camera diagnostic view.
|
|
2186
|
+
* Device IDs and labels must never be added here.
|
|
2187
|
+
*/
|
|
2188
|
+
function getIdCameraTrackDiagnosticFields(track) {
|
|
2189
|
+
if (!track) return {};
|
|
2190
|
+
let settings = {};
|
|
2191
|
+
let constraints = {};
|
|
2192
|
+
try {
|
|
2193
|
+
settings = track.getSettings();
|
|
2194
|
+
} catch {}
|
|
2195
|
+
try {
|
|
2196
|
+
constraints = track.getConstraints();
|
|
2197
|
+
} catch {}
|
|
2198
|
+
return {
|
|
2199
|
+
width: finiteNumber(settings.width),
|
|
2200
|
+
height: finiteNumber(settings.height),
|
|
2201
|
+
frameRate: finiteNumber(settings.frameRate),
|
|
2202
|
+
facingMode: stringValue(settings.facingMode),
|
|
2203
|
+
readyState: track.readyState,
|
|
2204
|
+
muted: track.muted,
|
|
2205
|
+
devicePinned: settings.deviceId !== void 0,
|
|
2206
|
+
...readFocusRequest(constraints),
|
|
2207
|
+
appliedFocusMode: stringValue(settings.focusMode),
|
|
2208
|
+
appliedFocusDistance: finiteNumber(settings.focusDistance)
|
|
2209
|
+
};
|
|
2210
|
+
}
|
|
2211
|
+
/**
|
|
2212
|
+
* Emits a bounded diagnostic line only in SDK testing mode (devMode or a
|
|
2213
|
+
* recognized non-production API host). The payload is primitive-only so the
|
|
2214
|
+
* browser console cannot retain live media or native-backed objects.
|
|
2215
|
+
*/
|
|
2216
|
+
function logIdCameraDiagnostic(event, fields) {
|
|
2217
|
+
if (!isTrueSightTesting()) return;
|
|
2218
|
+
console.debug(`${ID_CAMERA_DIAGNOSTIC_PREFIX} ${event} ${JSON.stringify(fields)}`);
|
|
2219
|
+
}
|
|
2220
|
+
//#endregion
|
|
2221
|
+
//#region src/modules/id/idMetadataPreparationCoordinator.ts
|
|
2222
|
+
function cleanup(service) {
|
|
2223
|
+
try {
|
|
2224
|
+
service.cleanup();
|
|
2225
|
+
} catch {}
|
|
2226
|
+
}
|
|
2227
|
+
function createIdMetadataPreparationCoordinator(load = async (input) => (await import("./deepsightLoader-Dhz9T_KJ.esm.js")).loadDeepsightSession(input)) {
|
|
2228
|
+
let disposed = false;
|
|
2229
|
+
let preparation;
|
|
2230
|
+
let service;
|
|
2231
|
+
const prepare = (input) => {
|
|
2232
|
+
if (disposed) return Promise.reject(/* @__PURE__ */ new Error("ID metadata coordinator is disposed"));
|
|
2233
|
+
preparation ??= (async () => {
|
|
2234
|
+
const prepared = await load(input);
|
|
2235
|
+
if (disposed) {
|
|
2236
|
+
cleanup(prepared);
|
|
2237
|
+
throw new Error("ID metadata coordinator is disposed");
|
|
2238
|
+
}
|
|
2239
|
+
service = prepared;
|
|
2240
|
+
return prepared;
|
|
2241
|
+
})();
|
|
2242
|
+
return preparation;
|
|
2243
|
+
};
|
|
2244
|
+
return {
|
|
2245
|
+
start(input) {
|
|
2246
|
+
prepare(input).catch(() => void 0);
|
|
2247
|
+
},
|
|
2248
|
+
prepare,
|
|
2249
|
+
dispose() {
|
|
2250
|
+
if (disposed) return;
|
|
2251
|
+
disposed = true;
|
|
2252
|
+
preparation = void 0;
|
|
2253
|
+
const prepared = service;
|
|
2254
|
+
service = void 0;
|
|
2255
|
+
if (prepared) cleanup(prepared);
|
|
2256
|
+
}
|
|
2257
|
+
};
|
|
2258
|
+
}
|
|
2259
|
+
//#endregion
|
|
2260
|
+
//#region src/modules/id/idProtectedCapture.ts
|
|
2261
|
+
const ID_PROTECTED_CAPTURE_CONTROLLER = Symbol("idProtectedCaptureController");
|
|
2262
|
+
function attachIdProtectedCaptureController(owner, controller) {
|
|
2263
|
+
const target = owner;
|
|
2264
|
+
const existing = target[ID_PROTECTED_CAPTURE_CONTROLLER];
|
|
2265
|
+
if (existing) {
|
|
2266
|
+
if (existing !== controller) {
|
|
2267
|
+
existing.dispose();
|
|
2268
|
+
target[ID_PROTECTED_CAPTURE_CONTROLLER] = controller;
|
|
2269
|
+
}
|
|
2270
|
+
return controller;
|
|
2271
|
+
}
|
|
2272
|
+
Object.defineProperty(target, ID_PROTECTED_CAPTURE_CONTROLLER, {
|
|
2273
|
+
configurable: false,
|
|
2274
|
+
enumerable: false,
|
|
2275
|
+
value: controller,
|
|
2276
|
+
writable: true
|
|
2277
|
+
});
|
|
2278
|
+
return controller;
|
|
2279
|
+
}
|
|
2280
|
+
function getIdProtectedCaptureController(owner) {
|
|
2281
|
+
const controller = findIdProtectedCaptureController(owner);
|
|
2282
|
+
if (!controller) throw new Error("ID protected capture controller is unavailable");
|
|
2283
|
+
return controller;
|
|
2284
|
+
}
|
|
2285
|
+
function findIdProtectedCaptureController(owner) {
|
|
2286
|
+
return owner[ID_PROTECTED_CAPTURE_CONTROLLER];
|
|
2287
|
+
}
|
|
2288
|
+
function streamResolution(stream) {
|
|
2289
|
+
const track = stream.getVideoTracks()[0];
|
|
2290
|
+
const settings = track && typeof track.getSettings === "function" ? track.getSettings() : void 0;
|
|
2291
|
+
return typeof settings?.width === "number" && typeof settings.height === "number" ? `${settings.width}x${settings.height}` : void 0;
|
|
2292
|
+
}
|
|
2293
|
+
function streamUsesBackCamera(stream) {
|
|
2294
|
+
const track = stream.getVideoTracks()[0];
|
|
2295
|
+
if (!track) return;
|
|
2296
|
+
const settings = typeof track.getSettings === "function" ? track.getSettings() : {};
|
|
2297
|
+
const constrainedFacingMode = typeof track.getConstraints === "function" ? track.getConstraints().facingMode : void 0;
|
|
2298
|
+
const facingMode = settings.facingMode ?? (typeof constrainedFacingMode === "string" ? constrainedFacingMode : void 0);
|
|
2299
|
+
if (facingMode === "environment") return true;
|
|
2300
|
+
if (facingMode === "user") return false;
|
|
2301
|
+
const label = typeof track.label === "string" ? track.label.toLowerCase() : "";
|
|
2302
|
+
if (label.includes("back") || label.includes("rear")) return true;
|
|
2303
|
+
if (label.includes("front") || label.includes("user")) return false;
|
|
2304
|
+
}
|
|
2305
|
+
function createIdProtectedCaptureController(dependencies = {}) {
|
|
2306
|
+
const metadataCoordinator = createIdMetadataPreparationCoordinator(dependencies.loadMetadata);
|
|
2307
|
+
let disposed = false;
|
|
2308
|
+
let visible = true;
|
|
2309
|
+
let preAcquired;
|
|
2310
|
+
let preAcquirePromise;
|
|
2311
|
+
let preAcquireGeneration = 0;
|
|
2312
|
+
let provider;
|
|
2313
|
+
let displayStream;
|
|
2314
|
+
let frameCapturer;
|
|
2315
|
+
let captureResolution;
|
|
2316
|
+
let cameraFallbackLevel;
|
|
2317
|
+
let usingBackCamera;
|
|
2318
|
+
let previewImageUrl;
|
|
2319
|
+
let pendingPreviewCanvas;
|
|
2320
|
+
let attemptGeneration = 0;
|
|
2321
|
+
let autoCaptureFrame;
|
|
2322
|
+
let committed = false;
|
|
2323
|
+
let uploadResponse;
|
|
2324
|
+
let cycleOwnership;
|
|
2325
|
+
let attemptContext;
|
|
2326
|
+
let attemptSend;
|
|
2327
|
+
let diagnosticAttempt;
|
|
2328
|
+
const logDiagnostic = (event, fields = {}) => {
|
|
2329
|
+
if (!diagnosticAttempt) return;
|
|
2330
|
+
logIdCameraDiagnostic(event, {
|
|
2331
|
+
attempt: diagnosticAttempt.attempt,
|
|
2332
|
+
side: diagnosticAttempt.side,
|
|
2333
|
+
elapsedMs: Math.round(getTimestamp() - diagnosticAttempt.startedAt),
|
|
2334
|
+
...fields
|
|
2335
|
+
});
|
|
2336
|
+
};
|
|
2337
|
+
const releasePresentationFrame = (frame) => {
|
|
2338
|
+
frame.width = 1;
|
|
2339
|
+
frame.height = 1;
|
|
2340
|
+
};
|
|
2341
|
+
const releasePreAcquired = () => {
|
|
2342
|
+
if (preAcquired) {
|
|
2343
|
+
stopStream(preAcquired.stream);
|
|
2344
|
+
preAcquired = void 0;
|
|
2345
|
+
}
|
|
2346
|
+
};
|
|
2347
|
+
const acceptPreAcquired = (value) => {
|
|
2348
|
+
if (disposed) {
|
|
2349
|
+
stopStream(value.stream);
|
|
2350
|
+
return false;
|
|
2351
|
+
}
|
|
2352
|
+
releasePreAcquired();
|
|
2353
|
+
preAcquired = value;
|
|
2354
|
+
captureResolution = streamResolution(value.stream);
|
|
2355
|
+
cameraFallbackLevel = value.fallbackLevel;
|
|
2356
|
+
usingBackCamera = streamUsesBackCamera(value.stream);
|
|
2357
|
+
return true;
|
|
2358
|
+
};
|
|
2359
|
+
const preAcquire = () => {
|
|
2360
|
+
if (disposed) return Promise.reject(/* @__PURE__ */ new Error("ID protected capture controller is disposed"));
|
|
2361
|
+
if (preAcquired) return Promise.resolve();
|
|
2362
|
+
if (preAcquirePromise) return preAcquirePromise;
|
|
2363
|
+
const generation = preAcquireGeneration;
|
|
2364
|
+
const pending = (async () => {
|
|
2365
|
+
const value = await (dependencies.acquireCamera ?? getIdCameraStream)();
|
|
2366
|
+
if (disposed || generation !== preAcquireGeneration) {
|
|
2367
|
+
stopStream(value.stream);
|
|
2368
|
+
if (disposed) throw new Error("ID protected capture controller is disposed");
|
|
2369
|
+
return;
|
|
2370
|
+
}
|
|
2371
|
+
acceptPreAcquired(value);
|
|
2372
|
+
})();
|
|
2373
|
+
preAcquirePromise = pending;
|
|
2374
|
+
pending.then(() => {
|
|
2375
|
+
if (preAcquirePromise === pending) preAcquirePromise = void 0;
|
|
2376
|
+
}, () => {
|
|
2377
|
+
if (preAcquirePromise === pending) preAcquirePromise = void 0;
|
|
2378
|
+
});
|
|
2379
|
+
return pending;
|
|
2380
|
+
};
|
|
2381
|
+
const replaceDisplayStream = (stream) => {
|
|
2382
|
+
frameCapturer?.dispose();
|
|
2383
|
+
frameCapturer = void 0;
|
|
2384
|
+
if (displayStream && displayStream !== stream) stopStream(displayStream);
|
|
2385
|
+
displayStream = stream;
|
|
2386
|
+
frameCapturer = new StreamCanvasCapture(stream, { continuous: false });
|
|
2387
|
+
captureResolution = streamResolution(stream);
|
|
2388
|
+
usingBackCamera = streamUsesBackCamera(stream) ?? usingBackCamera;
|
|
2389
|
+
};
|
|
2390
|
+
const clearAttempt = () => {
|
|
2391
|
+
if (diagnosticAttempt) logDiagnostic("attempt-release", { committed });
|
|
2392
|
+
attemptGeneration += 1;
|
|
2393
|
+
frameCapturer?.dispose();
|
|
2394
|
+
frameCapturer = void 0;
|
|
2395
|
+
if (displayStream) stopStream(displayStream);
|
|
2396
|
+
displayStream = void 0;
|
|
2397
|
+
provider?.dispose?.();
|
|
2398
|
+
provider = void 0;
|
|
2399
|
+
captureResolution = void 0;
|
|
2400
|
+
usingBackCamera = void 0;
|
|
2401
|
+
previewImageUrl = void 0;
|
|
2402
|
+
pendingPreviewCanvas?.dispose();
|
|
2403
|
+
pendingPreviewCanvas = void 0;
|
|
2404
|
+
if (autoCaptureFrame) {
|
|
2405
|
+
releasePresentationFrame(autoCaptureFrame);
|
|
2406
|
+
autoCaptureFrame = void 0;
|
|
2407
|
+
}
|
|
2408
|
+
committed = false;
|
|
2409
|
+
uploadResponse = void 0;
|
|
2410
|
+
attemptContext = void 0;
|
|
2411
|
+
attemptSend = void 0;
|
|
2412
|
+
diagnosticAttempt = void 0;
|
|
2413
|
+
cycleOwnership?.releaseByController();
|
|
2414
|
+
cycleOwnership = void 0;
|
|
2415
|
+
};
|
|
2416
|
+
const storeCommit = (previewElement) => {
|
|
2417
|
+
previewImageUrl = void 0;
|
|
2418
|
+
pendingPreviewCanvas?.dispose();
|
|
2419
|
+
pendingPreviewCanvas = void 0;
|
|
2420
|
+
const generation = attemptGeneration;
|
|
2421
|
+
try {
|
|
2422
|
+
const original = new IncodeCanvas(previewElement);
|
|
2423
|
+
let presentation = original;
|
|
2424
|
+
if (attemptContext) try {
|
|
2425
|
+
presentation = cropCanvasForPreview(attemptContext, original, provider);
|
|
2426
|
+
} catch {}
|
|
2427
|
+
try {
|
|
2428
|
+
provider?.setCapturedCanvases(original, presentation);
|
|
2429
|
+
} catch {}
|
|
2430
|
+
pendingPreviewCanvas = presentation;
|
|
2431
|
+
presentation.updateBlobAsync(1).then((blobData) => {
|
|
2432
|
+
if (disposed || attemptGeneration !== generation || pendingPreviewCanvas !== presentation) {
|
|
2433
|
+
presentation.dispose();
|
|
2434
|
+
return;
|
|
2435
|
+
}
|
|
2436
|
+
if (!blobData) {
|
|
2437
|
+
pendingPreviewCanvas = void 0;
|
|
2438
|
+
return;
|
|
2439
|
+
}
|
|
2440
|
+
previewImageUrl = blobData.url;
|
|
2441
|
+
attemptSend?.({ type: "PROTECTED_PREVIEW_READY" });
|
|
2442
|
+
}).catch(() => {
|
|
2443
|
+
if (pendingPreviewCanvas === presentation) pendingPreviewCanvas = void 0;
|
|
2444
|
+
presentation.dispose();
|
|
2445
|
+
});
|
|
2446
|
+
} finally {
|
|
2447
|
+
releasePresentationFrame(previewElement);
|
|
2448
|
+
committed = true;
|
|
2449
|
+
}
|
|
2450
|
+
};
|
|
2451
|
+
const controller = {
|
|
2452
|
+
get disposed() {
|
|
2453
|
+
return disposed;
|
|
2454
|
+
},
|
|
2455
|
+
beginAttempt(context, send) {
|
|
2456
|
+
if (disposed) throw new Error("ID protected capture controller is disposed");
|
|
2457
|
+
clearAttempt();
|
|
2458
|
+
diagnosticAttempt = {
|
|
2459
|
+
attempt: ++protectedIdAttemptSequence,
|
|
2460
|
+
side: context.currentMode === "back" ? "back" : "front",
|
|
2461
|
+
startedAt: getTimestamp()
|
|
2462
|
+
};
|
|
2463
|
+
attemptContext = context;
|
|
2464
|
+
attemptSend = send;
|
|
2465
|
+
provider = (dependencies.createProvider ?? createProtectedIdProvider)(context.config);
|
|
2466
|
+
cycleOwnership = createCameraCycleOwnership(cameraCycleProvider);
|
|
2467
|
+
logDiagnostic("attempt-start", { aggregationMs: context.config?.thresholds?.framesAggregationInterval ?? DEFAULT_ID_CAPTURE_THRESHOLDS.framesAggregationInterval });
|
|
2468
|
+
},
|
|
2469
|
+
startMetadataPreparation(context) {
|
|
2470
|
+
const storage = context.dependencies?.storage;
|
|
2471
|
+
if (!storage) return;
|
|
2472
|
+
metadataCoordinator.start({
|
|
2473
|
+
ds: context.config.ds,
|
|
2474
|
+
storage,
|
|
2475
|
+
disableIpify: context.disableIpify
|
|
2476
|
+
});
|
|
2477
|
+
},
|
|
2478
|
+
prepareMetadata(context) {
|
|
2479
|
+
const storage = context.dependencies?.storage;
|
|
2480
|
+
if (!storage) return Promise.reject(/* @__PURE__ */ new Error("ID metadata storage is unavailable"));
|
|
2481
|
+
return metadataCoordinator.prepare({
|
|
2482
|
+
ds: context.config.ds,
|
|
2483
|
+
storage,
|
|
2484
|
+
disableIpify: context.disableIpify
|
|
2485
|
+
});
|
|
2486
|
+
},
|
|
2487
|
+
clearAttempt,
|
|
2488
|
+
dispose() {
|
|
2489
|
+
if (disposed) return;
|
|
2490
|
+
disposed = true;
|
|
2491
|
+
preAcquireGeneration += 1;
|
|
2492
|
+
metadataCoordinator.dispose();
|
|
2493
|
+
releasePreAcquired();
|
|
2494
|
+
clearAttempt();
|
|
2495
|
+
},
|
|
2496
|
+
preAcquire,
|
|
2497
|
+
setVisible(nextVisible) {
|
|
2498
|
+
visible = nextVisible;
|
|
2499
|
+
},
|
|
2500
|
+
isVisible() {
|
|
2501
|
+
return visible;
|
|
2502
|
+
},
|
|
2503
|
+
storePreAcquiredStream(value) {
|
|
2504
|
+
preAcquireGeneration += 1;
|
|
2505
|
+
return acceptPreAcquired(value);
|
|
2506
|
+
},
|
|
2507
|
+
takePreAcquiredStream() {
|
|
2508
|
+
const value = preAcquired;
|
|
2509
|
+
preAcquired = void 0;
|
|
2510
|
+
if (value) cameraFallbackLevel = value.fallbackLevel;
|
|
2511
|
+
return value;
|
|
2512
|
+
},
|
|
2513
|
+
getProvider() {
|
|
2514
|
+
return provider;
|
|
2515
|
+
},
|
|
2516
|
+
getCycleOwnership() {
|
|
2517
|
+
if (!cycleOwnership) throw new Error("Protected ID cycle ownership is unavailable");
|
|
2518
|
+
return cycleOwnership;
|
|
2519
|
+
},
|
|
2520
|
+
getProjection() {
|
|
2521
|
+
return {
|
|
2522
|
+
stream: displayStream,
|
|
2523
|
+
captureResolution,
|
|
2524
|
+
cameraFallbackLevel,
|
|
2525
|
+
usingBackCamera
|
|
2526
|
+
};
|
|
2527
|
+
},
|
|
2528
|
+
getDiagnosticAttempt() {
|
|
2529
|
+
return diagnosticAttempt;
|
|
2530
|
+
},
|
|
2531
|
+
getPresentationCanvas() {
|
|
2532
|
+
return frameCapturer?.getLatestCanvas() ?? null;
|
|
2533
|
+
},
|
|
2534
|
+
storeAutoCaptureFrame(canvas) {
|
|
2535
|
+
if (disposed) {
|
|
2536
|
+
if (canvas) releasePresentationFrame(canvas);
|
|
2537
|
+
return;
|
|
2538
|
+
}
|
|
2539
|
+
if (autoCaptureFrame && autoCaptureFrame !== canvas) releasePresentationFrame(autoCaptureFrame);
|
|
2540
|
+
autoCaptureFrame = canvas ?? void 0;
|
|
2541
|
+
},
|
|
2542
|
+
hasAutoCaptureFrame() {
|
|
2543
|
+
return autoCaptureFrame !== void 0;
|
|
2544
|
+
},
|
|
2545
|
+
takeAutoCaptureFrame() {
|
|
2546
|
+
const frame = autoCaptureFrame;
|
|
2547
|
+
autoCaptureFrame = void 0;
|
|
2548
|
+
return frame ?? null;
|
|
2549
|
+
},
|
|
2550
|
+
takeCommitPreviewImageUrl() {
|
|
2551
|
+
const value = previewImageUrl;
|
|
2552
|
+
previewImageUrl = void 0;
|
|
2553
|
+
pendingPreviewCanvas = void 0;
|
|
2554
|
+
return value;
|
|
2555
|
+
},
|
|
2556
|
+
hasCommit() {
|
|
2557
|
+
return committed;
|
|
2558
|
+
},
|
|
2559
|
+
takeUploadResponse() {
|
|
2560
|
+
const value = uploadResponse;
|
|
2561
|
+
uploadResponse = void 0;
|
|
2562
|
+
return value;
|
|
2563
|
+
},
|
|
2564
|
+
buildCaptureOnlyUpload(context, onProgress) {
|
|
2565
|
+
const canvas = provider?.getOriginalCapturedCanvas();
|
|
2566
|
+
if (!canvas) throw new Error(ID_ERROR_CODES.UPLOAD_ERROR);
|
|
2567
|
+
const type = context.currentMode === "back" ? "back" : "front";
|
|
2568
|
+
return {
|
|
2569
|
+
canvas,
|
|
2570
|
+
type,
|
|
2571
|
+
qualityElements: context.qualityElements,
|
|
2572
|
+
onProgress,
|
|
2573
|
+
deepsightService: void 0,
|
|
2574
|
+
stream: displayStream,
|
|
2575
|
+
isSecondId: context.config.isSecondId ?? false,
|
|
2576
|
+
onlyFront: type === "front" && (context.config.onlyFront ?? false),
|
|
2577
|
+
ageAssurance: context.config.ageAssurance,
|
|
2578
|
+
dependencies: context.dependencies,
|
|
2579
|
+
captureResolution,
|
|
2580
|
+
cameraFallbackLevel,
|
|
2581
|
+
extractIdFace: context.config.extractIdFace,
|
|
2582
|
+
croppedCanvas: provider?.getCapturedCanvas() ?? null
|
|
2583
|
+
};
|
|
2584
|
+
},
|
|
2585
|
+
runAttempt(sendBack, receive) {
|
|
2586
|
+
if (!attemptContext || !attemptSend) throw new Error("Protected ID attempt is unavailable");
|
|
2587
|
+
return (dependencies.runAttempt ?? runProtectedAttempt)({
|
|
2588
|
+
input: createProtectedIdAttemptInput({
|
|
2589
|
+
context: attemptContext,
|
|
2590
|
+
controller,
|
|
2591
|
+
send: attemptSend
|
|
2592
|
+
}),
|
|
2593
|
+
sendBack,
|
|
2594
|
+
receive
|
|
2595
|
+
});
|
|
2596
|
+
},
|
|
2597
|
+
async deliverCaptureOnly(signal) {
|
|
2598
|
+
if (!dependencies.finalizeCaptureOnly || !attemptContext || !attemptSend) throw new Error(ID_ERROR_CODES.UPLOAD_ERROR);
|
|
2599
|
+
return dependencies.finalizeCaptureOnly(controller.buildCaptureOnlyUpload(attemptContext, (progress) => {
|
|
2600
|
+
attemptSend?.({
|
|
2601
|
+
type: "UPLOAD_PROGRESS",
|
|
2602
|
+
progress
|
|
2603
|
+
});
|
|
2604
|
+
}), signal);
|
|
2605
|
+
},
|
|
2606
|
+
resourceSink: {
|
|
2607
|
+
ready(stream) {
|
|
2608
|
+
if (disposed) {
|
|
2609
|
+
stopStream(stream);
|
|
2610
|
+
return;
|
|
2611
|
+
}
|
|
2612
|
+
replaceDisplayStream(stream);
|
|
2613
|
+
logDiagnostic("protected-camera-ready", {
|
|
2614
|
+
...getIdCameraTrackDiagnosticFields(stream.getVideoTracks()[0]),
|
|
2615
|
+
fallbackLevel: cameraFallbackLevel
|
|
2616
|
+
});
|
|
2617
|
+
},
|
|
2618
|
+
autoCommitted: storeCommit,
|
|
2619
|
+
manualCommitted: storeCommit,
|
|
2620
|
+
finalized(_recording, stream) {
|
|
2621
|
+
if (!stream || disposed) {
|
|
2622
|
+
logDiagnostic("attempt-finalized");
|
|
2623
|
+
return;
|
|
2624
|
+
}
|
|
2625
|
+
replaceDisplayStream(stream);
|
|
2626
|
+
logDiagnostic("attempt-finalized");
|
|
2627
|
+
},
|
|
2628
|
+
uploadDone(result) {
|
|
2629
|
+
if (result.kind === "id") {
|
|
2630
|
+
uploadResponse = protectedIdResultToCaptureResponse(result);
|
|
2631
|
+
logDiagnostic("upload-complete", {
|
|
2632
|
+
classification: result.classification,
|
|
2633
|
+
readability: result.readability
|
|
2634
|
+
});
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
};
|
|
2639
|
+
return controller;
|
|
2640
|
+
}
|
|
2641
|
+
function createProtectedIdAttemptActor(ownedController) {
|
|
2642
|
+
return fromCallback(({ sendBack, receive }) => {
|
|
2643
|
+
let controller = ownedController;
|
|
2644
|
+
let attemptReceiver;
|
|
2645
|
+
let cleanup;
|
|
2646
|
+
receive((command) => {
|
|
2647
|
+
if (command.type === "BIND_PROTECTED_ID_CONTROLLER") {
|
|
2648
|
+
controller ??= command.controller;
|
|
2649
|
+
return;
|
|
2650
|
+
}
|
|
2651
|
+
if (command.type === "START_PROTECTED_ID_ATTEMPT") {
|
|
2652
|
+
if (!controller || cleanup) return;
|
|
2653
|
+
cleanup = controller.runAttempt(sendBack, (listener) => {
|
|
2654
|
+
attemptReceiver = listener;
|
|
2655
|
+
});
|
|
2656
|
+
return;
|
|
2657
|
+
}
|
|
2658
|
+
attemptReceiver?.(command);
|
|
2659
|
+
});
|
|
2660
|
+
return () => cleanup?.();
|
|
2661
|
+
});
|
|
2662
|
+
}
|
|
2663
|
+
function createProtectedIdControllerLifetimeActor(ownedController) {
|
|
2664
|
+
return fromCallback(({ receive, sendBack }) => {
|
|
2665
|
+
let active = true;
|
|
2666
|
+
let controller = ownedController;
|
|
2667
|
+
let preAcquireOwner;
|
|
2668
|
+
let preAcquirePending = false;
|
|
2669
|
+
receive((command) => {
|
|
2670
|
+
if (command.type === "BIND_PROTECTED_ID_CONTROLLER") {
|
|
2671
|
+
controller ??= command.controller;
|
|
2672
|
+
return;
|
|
2673
|
+
}
|
|
2674
|
+
const owner = controller;
|
|
2675
|
+
if (!owner || preAcquirePending && preAcquireOwner === owner) return;
|
|
2676
|
+
preAcquireOwner = owner;
|
|
2677
|
+
preAcquirePending = true;
|
|
2678
|
+
owner.preAcquire().then(() => {
|
|
2679
|
+
if (active && controller === owner) sendBack({ type: "PROTECTED_PRE_ACQUIRE_DONE" });
|
|
2680
|
+
if (preAcquireOwner === owner) preAcquirePending = false;
|
|
2681
|
+
}, (error) => {
|
|
2682
|
+
if (active && controller === owner) sendBack({
|
|
2683
|
+
type: "PROTECTED_PRE_ACQUIRE_FAILED",
|
|
2684
|
+
error
|
|
2685
|
+
});
|
|
2686
|
+
if (preAcquireOwner === owner) preAcquirePending = false;
|
|
2687
|
+
});
|
|
2688
|
+
});
|
|
2689
|
+
return () => {
|
|
2690
|
+
active = false;
|
|
2691
|
+
controller?.dispose();
|
|
2692
|
+
};
|
|
2693
|
+
});
|
|
2694
|
+
}
|
|
2695
|
+
function createIdCaptureOnlyDeliveryActor(ownedController) {
|
|
2696
|
+
return fromCallback(({ input, sendBack, receive }) => {
|
|
2697
|
+
if (input.mode !== "captureOnly") return;
|
|
2698
|
+
const abortController = new AbortController();
|
|
2699
|
+
let controller = ownedController;
|
|
2700
|
+
let started = false;
|
|
2701
|
+
const start = () => {
|
|
2702
|
+
if (!controller || started) return;
|
|
2703
|
+
started = true;
|
|
2704
|
+
controller.deliverCaptureOnly(abortController.signal).then((output) => {
|
|
2705
|
+
if (!abortController.signal.aborted) sendBack({
|
|
2706
|
+
type: "CAPTURE_ONLY_DELIVERY_DONE",
|
|
2707
|
+
output
|
|
2708
|
+
});
|
|
2709
|
+
}, (error) => {
|
|
2710
|
+
if (!abortController.signal.aborted) sendBack({
|
|
2711
|
+
type: "CAPTURE_ONLY_DELIVERY_FAILED",
|
|
2712
|
+
error
|
|
2713
|
+
});
|
|
2714
|
+
});
|
|
2715
|
+
};
|
|
2716
|
+
receive((command) => {
|
|
2717
|
+
controller ??= command.controller;
|
|
2718
|
+
start();
|
|
2719
|
+
});
|
|
2720
|
+
start();
|
|
2721
|
+
return () => abortController.abort();
|
|
2722
|
+
});
|
|
2723
|
+
}
|
|
2724
|
+
let protectedIdAttemptSequence = 0;
|
|
2725
|
+
function resolveProtectedIdWorkflow(config) {
|
|
2726
|
+
if (config.modelVersion === "v3" || config.usSmartCapture === true) return 7;
|
|
2727
|
+
if (config.settings?.faceQualityCheckEnabled === true) return 8;
|
|
2728
|
+
if (config.settings?.faceQualityCheckEnabled === false) return 6;
|
|
2729
|
+
if (config.modelVersion === "v1") return 6;
|
|
2730
|
+
return 0;
|
|
2731
|
+
}
|
|
2732
|
+
function resolveProtectedIdTarget(config, currentMode) {
|
|
2733
|
+
const back = currentMode === "back";
|
|
2734
|
+
if (config.isSecondId === true) return back ? PROTECTED_CAPTURE_TARGET.backSecondId : PROTECTED_CAPTURE_TARGET.frontSecondId;
|
|
2735
|
+
return back ? PROTECTED_CAPTURE_TARGET.backId : PROTECTED_CAPTURE_TARGET.frontId;
|
|
2736
|
+
}
|
|
2737
|
+
function createProtectedIdProvider(config) {
|
|
2738
|
+
const workflow = resolveProtectedIdWorkflow(config);
|
|
2739
|
+
return workflow === 0 ? new IdCaptureProvider() : new IdCaptureProvider(workflow);
|
|
2740
|
+
}
|
|
2741
|
+
function createProtectedIdRecorderHooks(input) {
|
|
2742
|
+
let session;
|
|
2743
|
+
const enabled = input.enabled !== false && input.config.enableIdRecording === true;
|
|
2744
|
+
return {
|
|
2745
|
+
mode: enabled ? "finalizeBeforePoc" : "none",
|
|
2746
|
+
async start(stream) {
|
|
2747
|
+
if (!enabled) return;
|
|
2748
|
+
session = await startRecordingSession({
|
|
2749
|
+
config: input.config,
|
|
2750
|
+
stream,
|
|
2751
|
+
type: input.currentMode === "back" ? "backId" : "frontId"
|
|
2752
|
+
});
|
|
2753
|
+
},
|
|
2754
|
+
async prepareForPoc() {
|
|
2755
|
+
if (!session) return {};
|
|
2756
|
+
const currentSession = session;
|
|
2757
|
+
session = void 0;
|
|
2758
|
+
return finalizeRecordingSession(currentSession);
|
|
2759
|
+
},
|
|
2760
|
+
async resumeAfterPoc() {},
|
|
2761
|
+
pauseForBackground() {},
|
|
2762
|
+
async resumeFromBackground() {},
|
|
2763
|
+
dispose() {
|
|
2764
|
+
input.disposeCaptureCallbacks();
|
|
2765
|
+
if (!session) return;
|
|
2766
|
+
disposeRecordingSession(session);
|
|
2767
|
+
session = void 0;
|
|
2768
|
+
}
|
|
2769
|
+
};
|
|
2770
|
+
}
|
|
2771
|
+
function createProtectedIdCallbackSession(input) {
|
|
2772
|
+
const timer = BrowserTimerProvider.getInstance();
|
|
2773
|
+
let optimizingBoundary = null;
|
|
2774
|
+
let countdownTimers = [];
|
|
2775
|
+
let qualityElements;
|
|
2776
|
+
let isCapturing = false;
|
|
2777
|
+
let lastReportedSide = null;
|
|
2778
|
+
let blurSignals = 0;
|
|
2779
|
+
let bestFrameSignals = 0;
|
|
2780
|
+
let bestBlur;
|
|
2781
|
+
const logDiagnostic = (event, fields = {}) => {
|
|
2782
|
+
const attempt = input.controller.getDiagnosticAttempt();
|
|
2783
|
+
if (!attempt) return;
|
|
2784
|
+
logIdCameraDiagnostic(event, {
|
|
2785
|
+
attempt: attempt.attempt,
|
|
2786
|
+
side: attempt.side,
|
|
2787
|
+
elapsedMs: Math.round(getTimestamp() - attempt.startedAt),
|
|
2788
|
+
...fields
|
|
2789
|
+
});
|
|
2790
|
+
};
|
|
2791
|
+
const clearOptimizingBoundary = () => {
|
|
2792
|
+
if (optimizingBoundary) {
|
|
2793
|
+
timer.clearTimeout(optimizingBoundary);
|
|
2794
|
+
optimizingBoundary = null;
|
|
2795
|
+
}
|
|
2796
|
+
};
|
|
2797
|
+
const clearCountdown = () => {
|
|
2798
|
+
for (const countdownTimer of countdownTimers) timer.clearTimeout(countdownTimer);
|
|
2799
|
+
countdownTimers = [];
|
|
2800
|
+
};
|
|
2801
|
+
const startCountdown = () => {
|
|
2802
|
+
clearCountdown();
|
|
2803
|
+
const stepMs = (input.context.config.thresholds?.framesAggregationInterval ?? DEFAULT_ID_CAPTURE_THRESHOLDS.framesAggregationInterval) / 3;
|
|
2804
|
+
input.send({
|
|
2805
|
+
type: "COUNTER_VALUE_CHANGE",
|
|
2806
|
+
value: 3
|
|
2807
|
+
});
|
|
2808
|
+
countdownTimers = [
|
|
2809
|
+
2,
|
|
2810
|
+
1,
|
|
2811
|
+
0
|
|
2812
|
+
].map((value, index) => timer.setTimeout(() => input.send({
|
|
2813
|
+
type: "COUNTER_VALUE_CHANGE",
|
|
2814
|
+
value
|
|
2815
|
+
}), stepMs * (index + 1)));
|
|
2816
|
+
};
|
|
2817
|
+
const setDetectionStatus = (status) => {
|
|
2818
|
+
input.send({
|
|
2819
|
+
type: "DETECTION_UPDATE",
|
|
2820
|
+
status
|
|
2821
|
+
});
|
|
2822
|
+
};
|
|
2823
|
+
const notifications = createIdDetectionNotificationController({
|
|
2824
|
+
send: setDetectionStatus,
|
|
2825
|
+
isSuppressed: () => isReportedIdSideWrong(input.context.currentMode, lastReportedSide)
|
|
2826
|
+
});
|
|
2827
|
+
return {
|
|
2828
|
+
callbacks: {
|
|
2829
|
+
onFarAway: () => {
|
|
2830
|
+
if (!isCapturing) notifications.show("farAway");
|
|
2831
|
+
},
|
|
2832
|
+
onDetectionStarted: () => {},
|
|
2833
|
+
onMaskChange: (_show, _mask, _top, orientation) => {
|
|
2834
|
+
input.send({
|
|
2835
|
+
type: "ORIENTATION_CHANGE",
|
|
2836
|
+
orientation
|
|
2837
|
+
});
|
|
2838
|
+
},
|
|
2839
|
+
onBlur: () => {
|
|
2840
|
+
blurSignals += 1;
|
|
2841
|
+
if (!isCapturing) notifications.show("blur");
|
|
2842
|
+
},
|
|
2843
|
+
onGlare: () => {
|
|
2844
|
+
if (!isCapturing) notifications.show("glare");
|
|
2845
|
+
},
|
|
2846
|
+
onIdNotDetected: () => {
|
|
2847
|
+
if (!isCapturing) setDetectionStatus("idNotDetected");
|
|
2848
|
+
},
|
|
2849
|
+
onSwitchToManualCapture: () => {
|
|
2850
|
+
isCapturing = false;
|
|
2851
|
+
notifications.clear();
|
|
2852
|
+
clearOptimizingBoundary();
|
|
2853
|
+
clearCountdown();
|
|
2854
|
+
input.send({ type: input.controller.hasCommit() ? "PROTECTED_RELEASE_STASHED_COMMIT" : "SWITCH_TO_MANUAL_CAPTURE" });
|
|
2855
|
+
},
|
|
2856
|
+
onCapturing: () => {
|
|
2857
|
+
const wasCapturing = isCapturing;
|
|
2858
|
+
notifications.clear();
|
|
2859
|
+
lastReportedSide = null;
|
|
2860
|
+
isCapturing = true;
|
|
2861
|
+
setDetectionStatus("capturing");
|
|
2862
|
+
if (!wasCapturing) logDiagnostic("capture-window", {
|
|
2863
|
+
aggregationMs: input.context.config.thresholds?.framesAggregationInterval ?? DEFAULT_ID_CAPTURE_THRESHOLDS.framesAggregationInterval,
|
|
2864
|
+
blurSignals
|
|
2865
|
+
});
|
|
2866
|
+
if (!wasCapturing && input.context.captureFeedbackMode === "countdown") startCountdown();
|
|
2867
|
+
if (input.context.captureFeedbackMode === "optimizing" && input.context.config.supportsOptimizingStatus === true && input.context.captureWindowMs != null) {
|
|
2868
|
+
clearOptimizingBoundary();
|
|
2869
|
+
optimizingBoundary = timer.setTimeout(() => {
|
|
2870
|
+
optimizingBoundary = null;
|
|
2871
|
+
const presentation = input.controller.getPresentationCanvas();
|
|
2872
|
+
if (presentation) {
|
|
2873
|
+
presentation.release();
|
|
2874
|
+
input.send({ type: "PROTECTED_OPTIMIZING" });
|
|
2875
|
+
}
|
|
2876
|
+
}, input.context.captureWindowMs);
|
|
2877
|
+
}
|
|
2878
|
+
},
|
|
2879
|
+
onBestFrame: (blur, glare, orientation) => {
|
|
2880
|
+
bestFrameSignals += 1;
|
|
2881
|
+
bestBlur = bestBlur === void 0 ? blur : Math.min(bestBlur, blur);
|
|
2882
|
+
qualityElements = {
|
|
2883
|
+
glare,
|
|
2884
|
+
sharpness: blur
|
|
2885
|
+
};
|
|
2886
|
+
if (orientation === "horizontal" || orientation === "vertical") input.send({
|
|
2887
|
+
type: "ORIENTATION_CHANGE",
|
|
2888
|
+
orientation
|
|
2889
|
+
});
|
|
2890
|
+
},
|
|
2891
|
+
onCapture: (canvas) => {
|
|
2892
|
+
isCapturing = false;
|
|
2893
|
+
clearOptimizingBoundary();
|
|
2894
|
+
clearCountdown();
|
|
2895
|
+
logDiagnostic("capture-selected", {
|
|
2896
|
+
blurSignals,
|
|
2897
|
+
bestFrameSignals,
|
|
2898
|
+
bestBlur,
|
|
2899
|
+
selectedBlur: qualityElements?.sharpness,
|
|
2900
|
+
selectedGlare: qualityElements?.glare
|
|
2901
|
+
});
|
|
2902
|
+
input.controller.storeAutoCaptureFrame(canvas);
|
|
2903
|
+
input.send({
|
|
2904
|
+
type: "PROTECTED_AUTO_CAPTURE",
|
|
2905
|
+
qualityElements
|
|
2906
|
+
});
|
|
2907
|
+
},
|
|
2908
|
+
onIdTypeChange: (idType) => {
|
|
2909
|
+
input.send({
|
|
2910
|
+
type: "ID_TYPE_CHANGE",
|
|
2911
|
+
idType
|
|
2912
|
+
});
|
|
2913
|
+
},
|
|
2914
|
+
onIdSideChange: (side) => {
|
|
2915
|
+
if (isCapturing) return;
|
|
2916
|
+
lastReportedSide = side;
|
|
2917
|
+
if (isReportedIdSideWrong(input.context.currentMode, lastReportedSide)) notifications.clear();
|
|
2918
|
+
input.send({
|
|
2919
|
+
type: "ID_SIDE_CHANGE",
|
|
2920
|
+
side
|
|
2921
|
+
});
|
|
2922
|
+
},
|
|
2923
|
+
onCapturingCounterValueChange: () => {},
|
|
2924
|
+
onBarcodeDecoded: (decoded) => {
|
|
2925
|
+
input.send({
|
|
2926
|
+
type: "BARCODE_DECODED",
|
|
2927
|
+
decoded
|
|
2928
|
+
});
|
|
2929
|
+
}
|
|
2930
|
+
},
|
|
2931
|
+
dispose: () => {
|
|
2932
|
+
notifications.clear();
|
|
2933
|
+
clearOptimizingBoundary();
|
|
2934
|
+
clearCountdown();
|
|
2935
|
+
}
|
|
2936
|
+
};
|
|
2937
|
+
}
|
|
2938
|
+
function createProtectedIdAttemptInput(input) {
|
|
2939
|
+
const { context, controller } = input;
|
|
2940
|
+
const provider = controller.getProvider();
|
|
2941
|
+
if (!provider) throw new Error("Protected ID provider is unavailable");
|
|
2942
|
+
const workflow = resolveProtectedIdWorkflow(context.config);
|
|
2943
|
+
const target = resolveProtectedIdTarget(context.config, context.currentMode);
|
|
2944
|
+
const callbackSession = createProtectedIdCallbackSession(input);
|
|
2945
|
+
let wasmUtil;
|
|
2946
|
+
const preAcquired = controller.takePreAcquiredStream();
|
|
2947
|
+
let selectedVideoTrack = preAcquired?.stream.getVideoTracks()[0];
|
|
2948
|
+
const constraints = getCameraReacquisitionConstraints(selectedVideoTrack, preAcquired?.constraints);
|
|
2949
|
+
const captureOnly = "onCapture" in context.config && typeof context.config.onCapture === "function";
|
|
2950
|
+
const diagnosticAttempt = controller.getDiagnosticAttempt();
|
|
2951
|
+
const isAttemptActive = () => !controller.disposed && controller.getProvider() === provider && controller.getDiagnosticAttempt() === diagnosticAttempt;
|
|
2952
|
+
const logSelectedCamera = (stream, fallbackLevel, reacquisitionConstraints, preAcquiredStream) => {
|
|
2953
|
+
if (!diagnosticAttempt) return;
|
|
2954
|
+
logIdCameraDiagnostic("selected-camera", {
|
|
2955
|
+
attempt: diagnosticAttempt.attempt,
|
|
2956
|
+
side: diagnosticAttempt.side,
|
|
2957
|
+
elapsedMs: Math.round(getTimestamp() - diagnosticAttempt.startedAt),
|
|
2958
|
+
...getIdCameraTrackDiagnosticFields(stream.getVideoTracks()[0]),
|
|
2959
|
+
preAcquired: preAcquiredStream,
|
|
2960
|
+
fallbackLevel,
|
|
2961
|
+
workflow: String(workflow),
|
|
2962
|
+
devicePinned: reacquisitionConstraints?.deviceId !== void 0
|
|
2963
|
+
});
|
|
2964
|
+
};
|
|
2965
|
+
if (preAcquired) logSelectedCamera(preAcquired.stream, preAcquired.fallbackLevel, constraints, true);
|
|
2966
|
+
return {
|
|
2967
|
+
attemptId: `protected-id-${diagnosticAttempt?.attempt ?? ++protectedIdAttemptSequence}`,
|
|
2968
|
+
target,
|
|
2969
|
+
workflow,
|
|
2970
|
+
streamSource: preAcquired ? {
|
|
2971
|
+
kind: "preAcquired",
|
|
2972
|
+
stream: preAcquired.stream,
|
|
2973
|
+
constraints
|
|
2974
|
+
} : {
|
|
2975
|
+
kind: "acquire",
|
|
2976
|
+
async acquire() {
|
|
2977
|
+
await controller.preAcquire();
|
|
2978
|
+
const adopted = controller.takePreAcquiredStream();
|
|
2979
|
+
if (!adopted) throw new Error("Protected ID stream acquisition was cancelled");
|
|
2980
|
+
selectedVideoTrack = adopted.stream.getVideoTracks()[0];
|
|
2981
|
+
const reacquisitionConstraints = getCameraReacquisitionConstraints(selectedVideoTrack, adopted.constraints);
|
|
2982
|
+
logSelectedCamera(adopted.stream, adopted.fallbackLevel, reacquisitionConstraints, false);
|
|
2983
|
+
return {
|
|
2984
|
+
stream: adopted.stream,
|
|
2985
|
+
constraints: reacquisitionConstraints
|
|
2986
|
+
};
|
|
2987
|
+
}
|
|
2988
|
+
},
|
|
2989
|
+
initiallyBackgrounded: !controller.isVisible(),
|
|
2990
|
+
resourceSink: controller.resourceSink,
|
|
2991
|
+
capturePresentationFrame: () => controller.takeAutoCaptureFrame(),
|
|
2992
|
+
cycle: cameraCycleProvider,
|
|
2993
|
+
cycleOwnership: controller.getCycleOwnership(),
|
|
2994
|
+
recorder: createProtectedIdRecorderHooks({
|
|
2995
|
+
config: context.config,
|
|
2996
|
+
currentMode: context.currentMode,
|
|
2997
|
+
disposeCaptureCallbacks: callbackSession.dispose,
|
|
2998
|
+
enabled: !captureOnly
|
|
2999
|
+
}),
|
|
3000
|
+
releaseUnadoptedStream: stopStream,
|
|
3001
|
+
beforeAdopt: captureOnly ? void 0 : async (stream) => {
|
|
3002
|
+
const track = stream.getVideoTracks()[0];
|
|
3003
|
+
if (!track) throw new Error("Protected ID camera has no selected video track");
|
|
3004
|
+
const metadata = await controller.prepareMetadata(context);
|
|
3005
|
+
if (!isAttemptActive()) return;
|
|
3006
|
+
await metadata.checkVirtualCamera(track);
|
|
3007
|
+
},
|
|
3008
|
+
onStartupTiming(timing) {
|
|
3009
|
+
if (!diagnosticAttempt) return;
|
|
3010
|
+
logIdCameraDiagnostic("camera-startup", {
|
|
3011
|
+
attempt: diagnosticAttempt.attempt,
|
|
3012
|
+
side: diagnosticAttempt.side,
|
|
3013
|
+
elapsedMs: Math.round(getTimestamp() - diagnosticAttempt.startedAt),
|
|
3014
|
+
...timing
|
|
3015
|
+
});
|
|
3016
|
+
},
|
|
3017
|
+
async configureWorkflow() {
|
|
3018
|
+
await provider.initialize({});
|
|
3019
|
+
configureIdCaptureProvider({
|
|
3020
|
+
provider,
|
|
3021
|
+
config: context.config,
|
|
3022
|
+
currentMode: context.currentMode,
|
|
3023
|
+
frameSize: cameraCycleProvider.getCaptureSize(),
|
|
3024
|
+
callbacks: callbackSession.callbacks
|
|
3025
|
+
});
|
|
3026
|
+
},
|
|
3027
|
+
async runPrc() {
|
|
3028
|
+
if (!isAttemptActive()) return;
|
|
3029
|
+
wasmUtil = await (input.getWasmUtil ?? WasmUtilProvider.getInstance)();
|
|
3030
|
+
if (!isAttemptActive()) return;
|
|
3031
|
+
await wasmUtil.prc();
|
|
3032
|
+
},
|
|
3033
|
+
async runPoc() {
|
|
3034
|
+
if (captureOnly) return;
|
|
3035
|
+
if (!isAttemptActive()) return;
|
|
3036
|
+
if (!wasmUtil) wasmUtil = await (input.getWasmUtil ?? WasmUtilProvider.getInstance)();
|
|
3037
|
+
if (!isAttemptActive()) return;
|
|
3038
|
+
await (input.runPocCheck ?? runVirtualCameraCheck)({
|
|
3039
|
+
wasmUtil,
|
|
3040
|
+
source: context.currentMode === "back" ? frameSources.back : frameSources.front,
|
|
3041
|
+
token: (input.getSessionToken ?? getToken)()
|
|
3042
|
+
});
|
|
3043
|
+
if (!isAttemptActive()) return;
|
|
3044
|
+
const metadata = await controller.prepareMetadata(context);
|
|
3045
|
+
if (isAttemptActive()) {
|
|
3046
|
+
try {
|
|
3047
|
+
await metadata.finalizeProtectedCaptureMetadata();
|
|
3048
|
+
} catch {
|
|
3049
|
+
if (isAttemptActive()) trueSightLog("warning", "deepsight", "idScan", "protected capture metadata finalization failed");
|
|
3050
|
+
}
|
|
3051
|
+
if (!isAttemptActive()) return;
|
|
3052
|
+
try {
|
|
3053
|
+
const analysisStatus = metadata.getAnalysisStatus();
|
|
3054
|
+
const motionStatus = metadata.getMotionStatus();
|
|
3055
|
+
const isBack = context.currentMode === "back";
|
|
3056
|
+
addDeviceStats({
|
|
3057
|
+
frontIdStatsAnalysisStatus: isBack ? "" : analysisStatus,
|
|
3058
|
+
backIdStatsAnalysisStatus: isBack ? analysisStatus : "",
|
|
3059
|
+
selfieStatsAnalysisStatus: "",
|
|
3060
|
+
motionStatus
|
|
3061
|
+
});
|
|
3062
|
+
} catch {}
|
|
3063
|
+
try {
|
|
3064
|
+
const logs = metadata.getPipelineState();
|
|
3065
|
+
if (!isAttemptActive()) return;
|
|
3066
|
+
const projection = controller.getProjection();
|
|
3067
|
+
context.dependencies?.trackCaptureAttemptFinished?.({
|
|
3068
|
+
logs,
|
|
3069
|
+
resolution: projection.captureResolution,
|
|
3070
|
+
fallbackLevel: projection.cameraFallbackLevel
|
|
3071
|
+
});
|
|
3072
|
+
} catch {
|
|
3073
|
+
if (isAttemptActive()) trueSightLog("warning", "deepsight", "idScan", "protected capture diagnostics failed");
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
3076
|
+
}
|
|
3077
|
+
};
|
|
3078
|
+
}
|
|
3079
|
+
function protectedIdResultToCaptureResponse(result) {
|
|
3080
|
+
const regulationType = result.regulationType === "US" || result.regulationType === "Worldwide" || result.regulationType === "Other" || result.regulationType === "US_Illinois" || result.regulationType === "US_Texas" || result.regulationType === "US_California" || result.regulationType === "US_Washington" ? result.regulationType : void 0;
|
|
3081
|
+
return {
|
|
3082
|
+
sharpness: result.sharpness ?? 0,
|
|
3083
|
+
correctSharpness: result.sharpness != null && result.sharpness >= 10,
|
|
3084
|
+
glare: result.glare ?? 0,
|
|
3085
|
+
correctGlare: result.glare != null && result.glare >= 10,
|
|
3086
|
+
horizontalResolution: 0,
|
|
3087
|
+
classification: result.classification === true,
|
|
3088
|
+
readability: result.readability === true,
|
|
3089
|
+
typeOfId: result.typeOfId ?? "",
|
|
3090
|
+
issueYear: 0,
|
|
3091
|
+
issueName: "",
|
|
3092
|
+
sessionStatus: result.sessionStatus ?? "",
|
|
3093
|
+
countryCode: result.countryCode ?? "",
|
|
3094
|
+
skipBackIdCapture: result.skipBackIdCapture,
|
|
3095
|
+
skipGlareFront: result.skipGlareFront,
|
|
3096
|
+
skipGlareBack: result.skipGlareBack,
|
|
3097
|
+
acceptedDocuments: result.acceptedDocuments ? [...result.acceptedDocuments] : void 0,
|
|
3098
|
+
forceFrontIdCapture: result.forceFrontIdCapture,
|
|
3099
|
+
idValidationCompleted: result.idValidationCompleted,
|
|
3100
|
+
showMandatoryConsent: result.showMandatoryConsent,
|
|
3101
|
+
regulationType,
|
|
3102
|
+
failReason: result.failReason,
|
|
3103
|
+
side: result.side,
|
|
3104
|
+
idQualityAttemptApproved: result.idQualityAttemptApproved,
|
|
3105
|
+
isDocumentExpired: result.isDocumentExpired,
|
|
3106
|
+
success: result.success
|
|
3107
|
+
};
|
|
3108
|
+
}
|
|
3109
|
+
function getProtectedIdUploadRequest(context, sessionToken = getToken()) {
|
|
3110
|
+
const target = resolveProtectedIdTarget(context.config, context.currentMode);
|
|
3111
|
+
const front = context.currentMode !== "back";
|
|
3112
|
+
const params = {};
|
|
3113
|
+
if (front && context.config.onlyFront === true) params.onlyFront = true;
|
|
3114
|
+
if (front && context.config.extractIdFace === false) params.extractIdFace = false;
|
|
3115
|
+
const sharpness = context.qualityElements?.sharpness;
|
|
3116
|
+
if (sharpness !== void 0 && sharpness !== 0 && Number.isFinite(sharpness)) params.sharpness = getRealQualityValue(sharpness);
|
|
3117
|
+
const config = {
|
|
3118
|
+
...sessionToken ? { headers: { "X-Incode-Hardware-Id": sessionToken } } : {},
|
|
3119
|
+
...Object.keys(params).length > 0 ? { params } : {}
|
|
3120
|
+
};
|
|
3121
|
+
return Object.keys(config).length > 0 ? {
|
|
3122
|
+
target,
|
|
3123
|
+
config
|
|
3124
|
+
} : { target };
|
|
3125
|
+
}
|
|
3126
|
+
//#endregion
|
|
3127
|
+
//#region src/modules/digital-id-redirect/digitalIdRedirectServices.ts
|
|
3128
|
+
function withQuery(path, params) {
|
|
3129
|
+
if (!params) return path;
|
|
3130
|
+
const search = new URLSearchParams();
|
|
3131
|
+
if (params.country) search.set("country", params.country);
|
|
3132
|
+
if (params.region) search.set("region", params.region);
|
|
3133
|
+
const qs = search.toString();
|
|
3134
|
+
return qs ? `${path}?${qs}` : path;
|
|
3135
|
+
}
|
|
3136
|
+
/** GET the provider catalog. Ordering is applied FE-side by the module. */
|
|
3137
|
+
async function listProviders(params, signal) {
|
|
3138
|
+
const url = withQuery(endpoints.digitalIdProviders, params);
|
|
3139
|
+
const res = await api.get(url, { signal });
|
|
3140
|
+
if (!res.ok) throw new Error(`GET ${url} failed: ${res.status} ${res.statusText}`);
|
|
3141
|
+
return res.data ?? [];
|
|
3142
|
+
}
|
|
3143
|
+
/**
|
|
3144
|
+
* Append the onboarding `uuid` to `returnUrl` when absent, so the return leg can
|
|
3145
|
+
* re-attach the (onboarding-scoped) verification. Idempotent (skips when a `uuid`
|
|
3146
|
+
* is already present) and non-fatal (returns the URL unchanged on any failure).
|
|
3147
|
+
* Exported for unit testing.
|
|
3148
|
+
*/
|
|
3149
|
+
async function ensureReturnUrlUuid(returnUrl, signal) {
|
|
3150
|
+
try {
|
|
3151
|
+
if (getUrlSearchParam(returnUrl, "uuid")) return returnUrl;
|
|
3152
|
+
const res = await api.get(endpoints.onboardingUrl, { signal });
|
|
3153
|
+
const onboardingUrl = res.ok ? res.data?.url : void 0;
|
|
3154
|
+
const uuid = onboardingUrl ? getUrlSearchParam(onboardingUrl, "uuid") : null;
|
|
3155
|
+
if (!uuid) return returnUrl;
|
|
3156
|
+
return buildUrlWithSearchParams(returnUrl, { uuid });
|
|
3157
|
+
} catch (error) {
|
|
3158
|
+
console.warn("[DigitalIdRedirect] ensureReturnUrlUuid failed, proceeding without uuid:", error);
|
|
3159
|
+
return returnUrl;
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
/**
|
|
3163
|
+
* Create a verification. On success the caller must full-page-redirect to
|
|
3164
|
+
* `flowData.launchUrl`. NOTE: this is the billable moment for iDIN/FTN — each
|
|
3165
|
+
* call (incl. every retry) is a new session and a new billing event.
|
|
3166
|
+
*
|
|
3167
|
+
* The `redirectUrl` is first passed through `ensureReturnUrlUuid` so a bare
|
|
3168
|
+
* launch gets a resumable `uuid` before the bank round-trip. This reuses the
|
|
3169
|
+
* current session token (no extra `/omni/start`) and only fetches when the URL
|
|
3170
|
+
* lacks a `uuid`.
|
|
3171
|
+
*/
|
|
3172
|
+
async function createVerification(params, signal) {
|
|
3173
|
+
const redirectUrl = await ensureReturnUrlUuid(params.redirectUrl, signal);
|
|
3174
|
+
const res = await api.post(endpoints.digitalIdVerifications, {
|
|
3175
|
+
...params,
|
|
3176
|
+
redirectUrl
|
|
3177
|
+
}, { signal });
|
|
3178
|
+
if (!res.ok) throw new Error(`POST ${endpoints.digitalIdVerifications} failed: ${res.status} ${res.statusText}`);
|
|
3179
|
+
return res.data;
|
|
3180
|
+
}
|
|
3181
|
+
/**
|
|
3182
|
+
* Submit the provider's return params. The contract wants them wrapped as a
|
|
3183
|
+
* JSON *string* under `walletResponse` (success serialized as "true"/"false").
|
|
3184
|
+
*/
|
|
3185
|
+
async function submitWalletResponse(verificationId, params, signal) {
|
|
3186
|
+
const url = `${endpoints.digitalIdVerifications}/${verificationId}/response`;
|
|
3187
|
+
const body = { walletResponse: JSON.stringify({
|
|
3188
|
+
sessionId: params.sessionId,
|
|
3189
|
+
resultsAccessKey: params.resultsAccessKey,
|
|
3190
|
+
success: String(params.success)
|
|
3191
|
+
}) };
|
|
3192
|
+
const res = await api.post(url, body, { signal });
|
|
3193
|
+
if (!res.ok) throw new Error(`POST ${url} failed: ${res.status} ${res.statusText}`);
|
|
3194
|
+
return res.data;
|
|
3195
|
+
}
|
|
3196
|
+
/** Poll fallback — used when the user does not return or results are delayed. */
|
|
3197
|
+
async function getVerificationStatus(verificationId, signal) {
|
|
3198
|
+
const url = `${endpoints.digitalIdVerifications}/${verificationId}/status`;
|
|
3199
|
+
const res = await api.get(url, { signal });
|
|
3200
|
+
if (!res.ok) throw new Error(`GET ${url} failed: ${res.status} ${res.statusText}`);
|
|
3201
|
+
return res.data;
|
|
3202
|
+
}
|
|
3203
|
+
/**
|
|
3204
|
+
* Refresh an expiring `launchUrl` (maps to `flowData.expiresAt`). Do NOT create
|
|
3205
|
+
* a new verification for this — that would be a new billing event.
|
|
3206
|
+
*/
|
|
3207
|
+
async function refreshVerification(verificationId, signal) {
|
|
3208
|
+
const url = `${endpoints.digitalIdVerifications}/${verificationId}/refresh`;
|
|
3209
|
+
const res = await api.post(url, {}, { signal });
|
|
3210
|
+
if (!res.ok) throw new Error(`POST ${url} failed: ${res.status} ${res.statusText}`);
|
|
3211
|
+
return res.data;
|
|
3212
|
+
}
|
|
3213
|
+
//#endregion
|
|
3214
|
+
//#region src/modules/digital-id-redirect/digitalIdRedirectStorage.ts
|
|
3215
|
+
/**
|
|
3216
|
+
* Cross-redirect handoff. The full-page redirect out to the provider tears down
|
|
3217
|
+
* the SPA, so the pending verification must be persisted BEFORE navigating and
|
|
3218
|
+
* read back on the return leg. Only the non-sensitive `verificationId` +
|
|
3219
|
+
* `providerId` live here — the session credential is the host's concern
|
|
3220
|
+
* (re-bootstrapped from `url_uuid`) and is NEVER persisted by this module.
|
|
3221
|
+
*
|
|
3222
|
+
* Backed by whatever `IStorageCapability` is injected (default localStorage).
|
|
3223
|
+
* sessionStorage would be preferable (auto-clears on tab close) — swap the
|
|
3224
|
+
* capability when a sessionStorage-backed provider exists. A single fixed key
|
|
3225
|
+
* is used, so a stale record from an abandoned redirect is overwritten by the
|
|
3226
|
+
* next one and is only ever read on the host's return route.
|
|
3227
|
+
*
|
|
3228
|
+
* TODO(follow-up): add a staleness TTL once an injected time capability lands
|
|
3229
|
+
* (Core forbids `Date.now()` directly — `no-browser-api-in-core`).
|
|
3230
|
+
*/
|
|
3231
|
+
const PENDING_KEY = "incode.digitalIdRedirect.pending";
|
|
3232
|
+
async function persistPendingRedirect(storage, entry) {
|
|
3233
|
+
await storage.set(PENDING_KEY, {
|
|
3234
|
+
verificationId: entry.verificationId,
|
|
3235
|
+
providerId: entry.providerId
|
|
3236
|
+
});
|
|
3237
|
+
}
|
|
3238
|
+
async function readPendingRedirect(storage) {
|
|
3239
|
+
const pending = await storage.get(PENDING_KEY);
|
|
3240
|
+
return pending?.verificationId && pending?.providerId ? pending : null;
|
|
3241
|
+
}
|
|
3242
|
+
async function clearPendingRedirect(storage) {
|
|
3243
|
+
await storage.remove(PENDING_KEY);
|
|
3244
|
+
}
|
|
3245
|
+
//#endregion
|
|
3246
|
+
//#region src/modules/digital-id-redirect/digitalIdRedirectStateMachine.ts
|
|
3247
|
+
const POLL_INTERVAL_MS = 1500;
|
|
3248
|
+
const MAX_POLL_ATTEMPTS = 20;
|
|
3249
|
+
const TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
3250
|
+
"COMPLETED",
|
|
3251
|
+
"FAILED",
|
|
3252
|
+
"EXPIRED",
|
|
3253
|
+
"CANCELLED"
|
|
3254
|
+
]);
|
|
3255
|
+
function isTerminal(status) {
|
|
3256
|
+
return TERMINAL_STATUSES.has(status);
|
|
3257
|
+
}
|
|
3258
|
+
const digitalIdRedirectMachine = setup({
|
|
3259
|
+
types: {
|
|
3260
|
+
context: {},
|
|
3261
|
+
events: {},
|
|
3262
|
+
input: {},
|
|
3263
|
+
output: {}
|
|
3264
|
+
},
|
|
3265
|
+
actors: {
|
|
3266
|
+
listProviders: fromPromise(async ({ input, signal }) => listProviders(input ? { country: input.country } : void 0, signal)),
|
|
3267
|
+
createVerification: fromPromise(async ({ input, signal }) => createVerification(input, signal)),
|
|
3268
|
+
submitWalletResponse: fromPromise(async ({ input, signal }) => submitWalletResponse(input.verificationId, input.params, signal)),
|
|
3269
|
+
refreshVerification: fromPromise(async ({ input, signal }) => refreshVerification(input.verificationId, signal)),
|
|
3270
|
+
pollStatus: fromCallback(({ sendBack, input }) => {
|
|
3271
|
+
const timer = BrowserTimerProvider.getInstance();
|
|
3272
|
+
const interval = timer.setInterval(async () => {
|
|
3273
|
+
try {
|
|
3274
|
+
const v = await getVerificationStatus(input.verificationId);
|
|
3275
|
+
if (isTerminal(v.status)) sendBack({
|
|
3276
|
+
type: "POLL_RESULT",
|
|
3277
|
+
verification: v
|
|
3278
|
+
});
|
|
3279
|
+
} catch (error) {
|
|
3280
|
+
console.warn("[DigitalIdRedirect] status poll failed:", error);
|
|
3281
|
+
}
|
|
3282
|
+
}, POLL_INTERVAL_MS);
|
|
3283
|
+
return () => timer.clearInterval(interval);
|
|
3284
|
+
}),
|
|
3285
|
+
persistPending: fromPromise(async ({ input }) => {
|
|
3286
|
+
await persistPendingRedirect(input.storage, {
|
|
3287
|
+
verificationId: input.verificationId,
|
|
3288
|
+
providerId: input.providerId
|
|
3289
|
+
});
|
|
3290
|
+
})
|
|
3291
|
+
},
|
|
3292
|
+
actions: {
|
|
3293
|
+
setProviders: assign(({ event }) => ({ providers: event.output })),
|
|
3294
|
+
setSelectedProvider: assign(({ event }) => ({ selectedProvider: event.providerId })),
|
|
3295
|
+
setVerification: assign(({ event }) => {
|
|
3296
|
+
const v = event.output;
|
|
3297
|
+
return {
|
|
3298
|
+
verificationId: v.verificationId,
|
|
3299
|
+
launchUrl: v.flowData?.launchUrl ?? void 0,
|
|
3300
|
+
expiresAt: v.flowData?.expiresAt ?? void 0,
|
|
3301
|
+
status: v.status,
|
|
3302
|
+
failureReason: v.failureReason ?? void 0,
|
|
3303
|
+
portraitPresent: v.portraitPresent ?? false
|
|
3304
|
+
};
|
|
3305
|
+
}),
|
|
3306
|
+
setVerificationFromEvent: assign(({ event }) => {
|
|
3307
|
+
const v = event.verification;
|
|
3308
|
+
return {
|
|
3309
|
+
status: v.status,
|
|
3310
|
+
failureReason: v.failureReason ?? void 0,
|
|
3311
|
+
portraitPresent: v.portraitPresent ?? false
|
|
3312
|
+
};
|
|
3313
|
+
}),
|
|
3314
|
+
setError: assign(({ event }) => ({ error: String(event.error ?? "Unknown error") })),
|
|
3315
|
+
clearResume: assign(() => ({
|
|
3316
|
+
returnParams: void 0,
|
|
3317
|
+
verificationId: void 0,
|
|
3318
|
+
failureReason: void 0,
|
|
3319
|
+
status: void 0,
|
|
3320
|
+
error: void 0
|
|
3321
|
+
}))
|
|
3322
|
+
},
|
|
3323
|
+
guards: {
|
|
3324
|
+
hasPresetProvider: ({ context }) => Boolean(context.config.provider),
|
|
3325
|
+
autoStartPreset: ({ context }) => context.autoStart && Boolean(context.config.provider),
|
|
3326
|
+
autoStartCatalog: ({ context }) => context.autoStart && !context.config.provider,
|
|
3327
|
+
isResuming: ({ context }) => Boolean(context.returnParams),
|
|
3328
|
+
returnSucceeded: ({ context }) => context.returnParams?.success === true,
|
|
3329
|
+
submittedTerminalOk: ({ event }) => event.output.status === "COMPLETED",
|
|
3330
|
+
submittedFailed: ({ event }) => {
|
|
3331
|
+
const s = event.output.status;
|
|
3332
|
+
return s === "FAILED" || s === "EXPIRED" || s === "CANCELLED";
|
|
3333
|
+
},
|
|
3334
|
+
polledOk: ({ event }) => event.verification.status === "COMPLETED"
|
|
3335
|
+
}
|
|
3336
|
+
}).createMachine({
|
|
3337
|
+
id: "digitalIdRedirect",
|
|
3338
|
+
initial: "idle",
|
|
3339
|
+
context: ({ input }) => ({
|
|
3340
|
+
config: input.config,
|
|
3341
|
+
storage: input.storage,
|
|
3342
|
+
returnUrl: input.config.returnUrl ?? "",
|
|
3343
|
+
providers: [],
|
|
3344
|
+
selectedProvider: input.config.provider,
|
|
3345
|
+
verificationId: input.resume?.verificationId,
|
|
3346
|
+
launchUrl: void 0,
|
|
3347
|
+
expiresAt: void 0,
|
|
3348
|
+
status: void 0,
|
|
3349
|
+
failureReason: void 0,
|
|
3350
|
+
portraitPresent: false,
|
|
3351
|
+
returnParams: input.resume?.returnParams,
|
|
3352
|
+
error: void 0,
|
|
3353
|
+
autoStart: input.autoStart ?? false
|
|
3354
|
+
}),
|
|
3355
|
+
output: ({ context }) => context.status === "COMPLETED" ? {
|
|
3356
|
+
status: "COMPLETED",
|
|
3357
|
+
providerId: context.selectedProvider ?? context.config.provider ?? "",
|
|
3358
|
+
portraitPresent: context.portraitPresent
|
|
3359
|
+
} : { status: "DISMISSED" },
|
|
3360
|
+
states: {
|
|
3361
|
+
idle: {
|
|
3362
|
+
always: [
|
|
3363
|
+
{
|
|
3364
|
+
guard: "isResuming",
|
|
3365
|
+
target: "submitting"
|
|
3366
|
+
},
|
|
3367
|
+
{
|
|
3368
|
+
guard: "autoStartPreset",
|
|
3369
|
+
target: "creating"
|
|
3370
|
+
},
|
|
3371
|
+
{
|
|
3372
|
+
guard: "autoStartCatalog",
|
|
3373
|
+
target: "loadingProviders"
|
|
3374
|
+
}
|
|
3375
|
+
],
|
|
3376
|
+
on: { LOAD: [{
|
|
3377
|
+
guard: "hasPresetProvider",
|
|
3378
|
+
target: "creating"
|
|
3379
|
+
}, { target: "loadingProviders" }] }
|
|
3380
|
+
},
|
|
3381
|
+
loadingProviders: { invoke: {
|
|
3382
|
+
src: "listProviders",
|
|
3383
|
+
input: ({ context }) => ({ country: context.config.country }),
|
|
3384
|
+
onDone: {
|
|
3385
|
+
target: "choosingProvider",
|
|
3386
|
+
actions: "setProviders"
|
|
3387
|
+
},
|
|
3388
|
+
onError: {
|
|
3389
|
+
target: "error",
|
|
3390
|
+
actions: "setError"
|
|
3391
|
+
}
|
|
3392
|
+
} },
|
|
3393
|
+
choosingProvider: { on: { SELECT_PROVIDER: {
|
|
3394
|
+
target: "creating",
|
|
3395
|
+
actions: "setSelectedProvider"
|
|
3396
|
+
} } },
|
|
3397
|
+
creating: { invoke: {
|
|
3398
|
+
src: "createVerification",
|
|
3399
|
+
input: ({ context }) => ({
|
|
3400
|
+
providerId: context.selectedProvider ?? "",
|
|
3401
|
+
redirectUrl: context.returnUrl
|
|
3402
|
+
}),
|
|
3403
|
+
onDone: {
|
|
3404
|
+
target: "persisting",
|
|
3405
|
+
actions: "setVerification"
|
|
3406
|
+
},
|
|
3407
|
+
onError: {
|
|
3408
|
+
target: "error",
|
|
3409
|
+
actions: "setError"
|
|
3410
|
+
}
|
|
3411
|
+
} },
|
|
3412
|
+
persisting: { invoke: {
|
|
3413
|
+
src: "persistPending",
|
|
3414
|
+
input: ({ context }) => ({
|
|
3415
|
+
storage: context.storage,
|
|
3416
|
+
verificationId: context.verificationId ?? "",
|
|
3417
|
+
providerId: context.selectedProvider ?? ""
|
|
3418
|
+
}),
|
|
3419
|
+
onDone: { target: "readyToRedirect" },
|
|
3420
|
+
onError: { target: "readyToRedirect" }
|
|
3421
|
+
} },
|
|
3422
|
+
readyToRedirect: { on: { REFRESH: { target: "refreshing" } } },
|
|
3423
|
+
refreshing: { invoke: {
|
|
3424
|
+
src: "refreshVerification",
|
|
3425
|
+
input: ({ context }) => ({ verificationId: context.verificationId ?? "" }),
|
|
3426
|
+
onDone: {
|
|
3427
|
+
target: "readyToRedirect",
|
|
3428
|
+
actions: "setVerification"
|
|
3429
|
+
},
|
|
3430
|
+
onError: {
|
|
3431
|
+
target: "error",
|
|
3432
|
+
actions: "setError"
|
|
3433
|
+
}
|
|
3434
|
+
} },
|
|
3435
|
+
submitting: { invoke: {
|
|
3436
|
+
src: "submitWalletResponse",
|
|
3437
|
+
input: ({ context }) => ({
|
|
3438
|
+
verificationId: context.verificationId ?? "",
|
|
3439
|
+
params: context.returnParams
|
|
3440
|
+
}),
|
|
3441
|
+
onDone: [
|
|
3442
|
+
{
|
|
3443
|
+
guard: "submittedTerminalOk",
|
|
3444
|
+
target: "succeeded",
|
|
3445
|
+
actions: "setVerification"
|
|
3446
|
+
},
|
|
3447
|
+
{
|
|
3448
|
+
guard: "submittedFailed",
|
|
3449
|
+
target: "failed",
|
|
3450
|
+
actions: "setVerification"
|
|
3451
|
+
},
|
|
3452
|
+
{
|
|
3453
|
+
target: "polling",
|
|
3454
|
+
actions: "setVerification"
|
|
3455
|
+
}
|
|
3456
|
+
],
|
|
3457
|
+
onError: {
|
|
3458
|
+
target: "error",
|
|
3459
|
+
actions: "setError"
|
|
3460
|
+
}
|
|
3461
|
+
} },
|
|
3462
|
+
polling: {
|
|
3463
|
+
invoke: {
|
|
3464
|
+
src: "pollStatus",
|
|
3465
|
+
input: ({ context }) => ({ verificationId: context.verificationId ?? "" })
|
|
3466
|
+
},
|
|
3467
|
+
on: { POLL_RESULT: [{
|
|
3468
|
+
guard: "polledOk",
|
|
3469
|
+
target: "succeeded",
|
|
3470
|
+
actions: "setVerificationFromEvent"
|
|
3471
|
+
}, {
|
|
3472
|
+
target: "failed",
|
|
3473
|
+
actions: "setVerificationFromEvent"
|
|
3474
|
+
}] },
|
|
3475
|
+
after: { [POLL_INTERVAL_MS * MAX_POLL_ATTEMPTS]: {
|
|
3476
|
+
target: "failed",
|
|
3477
|
+
actions: assign({ failureReason: () => "SESSION_EXPIRED" })
|
|
3478
|
+
} }
|
|
3479
|
+
},
|
|
3480
|
+
succeeded: { on: { CONTINUE: { target: "finished" } } },
|
|
3481
|
+
finished: { type: "final" },
|
|
3482
|
+
failed: { on: {
|
|
3483
|
+
RETRY: [{
|
|
3484
|
+
guard: "hasPresetProvider",
|
|
3485
|
+
target: "creating"
|
|
3486
|
+
}, { target: "choosingProvider" }],
|
|
3487
|
+
USE_ANOTHER_METHOD: { target: "closed" },
|
|
3488
|
+
CLOSE: { target: "closed" }
|
|
3489
|
+
} },
|
|
3490
|
+
error: { on: {
|
|
3491
|
+
RETRY: [{
|
|
3492
|
+
guard: "hasPresetProvider",
|
|
3493
|
+
target: "creating",
|
|
3494
|
+
actions: "clearResume"
|
|
3495
|
+
}, {
|
|
3496
|
+
target: "choosingProvider",
|
|
3497
|
+
actions: "clearResume"
|
|
3498
|
+
}],
|
|
3499
|
+
USE_ANOTHER_METHOD: { target: "closed" },
|
|
3500
|
+
CLOSE: { target: "closed" }
|
|
3501
|
+
} },
|
|
3502
|
+
closed: { type: "final" }
|
|
3503
|
+
}
|
|
3504
|
+
});
|
|
3505
|
+
//#endregion
|
|
3506
|
+
//#region src/modules/id/idCaptureDependencies.ts
|
|
3507
|
+
function resolveIdCaptureDependencies(dependencies) {
|
|
3508
|
+
return dependencies ?? { storage: new BrowserStorageProvider() };
|
|
2555
3509
|
}
|
|
2556
3510
|
//#endregion
|
|
2557
3511
|
//#region src/modules/id/idCaptureStateMachine.ts
|
|
@@ -2580,6 +3534,15 @@ function getIdErrorCodeFromUnknown(error) {
|
|
|
2580
3534
|
return Object.values(ID_ERROR_CODES).find((value) => message.includes(value));
|
|
2581
3535
|
}
|
|
2582
3536
|
}
|
|
3537
|
+
function asPublicIdEvent(event) {
|
|
3538
|
+
return event;
|
|
3539
|
+
}
|
|
3540
|
+
function isCaptureOnlyConfig(config) {
|
|
3541
|
+
return "onCapture" in config && typeof config.onCapture === "function";
|
|
3542
|
+
}
|
|
3543
|
+
function protectedFailure(event) {
|
|
3544
|
+
return event.type === "PROTECTED_ATTEMPT_FAILED" ? event : null;
|
|
3545
|
+
}
|
|
2583
3546
|
const idCaptureMachine = setup({
|
|
2584
3547
|
types: {
|
|
2585
3548
|
context: {},
|
|
@@ -2590,15 +3553,12 @@ const idCaptureMachine = setup({
|
|
|
2590
3553
|
actors: {
|
|
2591
3554
|
checkPermission: checkPermissionActor,
|
|
2592
3555
|
requestPermission: requestPermissionActor,
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
3556
|
+
protectedAttempt: createProtectedIdAttemptActor(),
|
|
3557
|
+
protectedControllerLifetime: createProtectedIdControllerLifetimeActor(),
|
|
3558
|
+
captureOnlyDelivery: createIdCaptureOnlyDeliveryActor(),
|
|
2596
3559
|
uploadProgressTicker: uploadProgressTickerActor,
|
|
2597
3560
|
processId: processIdActor,
|
|
2598
3561
|
submitBarcode: submitBarcodeActor,
|
|
2599
|
-
startRecording: startRecordingActor,
|
|
2600
|
-
initializeDeepsightSession: initializeDeepsightSessionActor,
|
|
2601
|
-
checkVirtualCamera: checkVirtualCameraActor,
|
|
2602
3562
|
manualUploadMachine,
|
|
2603
3563
|
digitalUploadMachine,
|
|
2604
3564
|
digitalIdRedirectMachine,
|
|
@@ -2611,6 +3571,108 @@ const idCaptureMachine = setup({
|
|
|
2611
3571
|
})
|
|
2612
3572
|
},
|
|
2613
3573
|
actions: {
|
|
3574
|
+
attachProtectedController: assign(({ self }) => {
|
|
3575
|
+
attachIdProtectedCaptureController(self, createIdProtectedCaptureController());
|
|
3576
|
+
return {};
|
|
3577
|
+
}),
|
|
3578
|
+
startProtectedMetadataPreparation: ({ context, self }) => {
|
|
3579
|
+
if (!isCaptureOnlyConfig(context.config)) getIdProtectedCaptureController(self).startMetadataPreparation(context);
|
|
3580
|
+
},
|
|
3581
|
+
bindProtectedControllerLifetime: sendTo("protectedControllerLifetime", ({ self }) => ({
|
|
3582
|
+
type: "BIND_PROTECTED_ID_CONTROLLER",
|
|
3583
|
+
controller: getIdProtectedCaptureController(self)
|
|
3584
|
+
})),
|
|
3585
|
+
preAcquireProtectedCamera: sendTo("protectedControllerLifetime", { type: "PRE_ACQUIRE" }),
|
|
3586
|
+
initializeProtectedProvider: assign(({ context, self }) => {
|
|
3587
|
+
getIdProtectedCaptureController(self).beginAttempt(context, (event) => self.send(event));
|
|
3588
|
+
return {
|
|
3589
|
+
stream: void 0,
|
|
3590
|
+
provider: void 0,
|
|
3591
|
+
frameCapturer: void 0
|
|
3592
|
+
};
|
|
3593
|
+
}),
|
|
3594
|
+
bindProtectedAttempt: sendTo("protectedAttempt", ({ self }) => ({
|
|
3595
|
+
type: "BIND_PROTECTED_ID_CONTROLLER",
|
|
3596
|
+
controller: getIdProtectedCaptureController(self)
|
|
3597
|
+
})),
|
|
3598
|
+
startProtectedAttempt: sendTo("protectedAttempt", { type: "START_PROTECTED_ID_ATTEMPT" }),
|
|
3599
|
+
setProtectedAttemptReady: assign(({ self, event }) => {
|
|
3600
|
+
if (event.type !== "PROTECTED_ATTEMPT_READY_SIGNAL") return {};
|
|
3601
|
+
const projection = getIdProtectedCaptureController(self).getProjection();
|
|
3602
|
+
return {
|
|
3603
|
+
stream: void 0,
|
|
3604
|
+
frameCapturer: void 0,
|
|
3605
|
+
captureResolution: projection.captureResolution,
|
|
3606
|
+
cameraFallbackLevel: projection.cameraFallbackLevel,
|
|
3607
|
+
usingBackCamera: projection.usingBackCamera
|
|
3608
|
+
};
|
|
3609
|
+
}),
|
|
3610
|
+
requestProtectedAutoCommit: enqueueActions(({ self, enqueue }) => {
|
|
3611
|
+
if (!getIdProtectedCaptureController(self).hasAutoCaptureFrame()) {
|
|
3612
|
+
enqueue(raise({ type: "PROTECTED_PRESENTATION_FAILED" }));
|
|
3613
|
+
return;
|
|
3614
|
+
}
|
|
3615
|
+
enqueue(sendTo("protectedAttempt", { type: "AUTO_CAPTURE" }));
|
|
3616
|
+
}),
|
|
3617
|
+
requestProtectedManualCommit: sendTo("protectedAttempt", { type: "MANUAL_CAPTURE" }),
|
|
3618
|
+
finalizeProtectedAttempt: sendTo("protectedAttempt", { type: "FINALIZE" }),
|
|
3619
|
+
requestProtectedUpload: enqueueActions(({ context, enqueue }) => {
|
|
3620
|
+
if (isCaptureOnlyConfig(context.config)) return;
|
|
3621
|
+
enqueue(sendTo("protectedAttempt", {
|
|
3622
|
+
type: "UPLOAD_PROTECTED",
|
|
3623
|
+
request: getProtectedIdUploadRequest(context)
|
|
3624
|
+
}));
|
|
3625
|
+
}),
|
|
3626
|
+
bindCaptureOnlyDelivery: sendTo("captureOnlyDelivery", ({ self }) => ({
|
|
3627
|
+
type: "BIND_ID_CAPTURE_ONLY_DELIVERY",
|
|
3628
|
+
controller: getIdProtectedCaptureController(self)
|
|
3629
|
+
})),
|
|
3630
|
+
releaseProtectedForClose: sendTo("protectedAttempt", {
|
|
3631
|
+
type: "RELEASE",
|
|
3632
|
+
reason: "close"
|
|
3633
|
+
}),
|
|
3634
|
+
releaseProtectedForRetry: sendTo("protectedAttempt", {
|
|
3635
|
+
type: "RELEASE",
|
|
3636
|
+
reason: "retry"
|
|
3637
|
+
}),
|
|
3638
|
+
forwardProtectedBackground: sendTo("protectedAttempt", { type: "BACKGROUND" }),
|
|
3639
|
+
forwardProtectedForeground: sendTo("protectedAttempt", { type: "FOREGROUND" }),
|
|
3640
|
+
storeProtectedAutoQuality: assign(({ event }) => event.type === "PROTECTED_AUTO_CAPTURE" ? { qualityElements: event.qualityElements } : {}),
|
|
3641
|
+
storeProtectedCommit: assign(({ context, event }) => {
|
|
3642
|
+
if (event.type !== "PROTECTED_AUTO_COMMITTED_SIGNAL" && event.type !== "PROTECTED_MANUAL_COMMITTED_SIGNAL") return {};
|
|
3643
|
+
const side = context.currentMode === "back" ? "back" : "front";
|
|
3644
|
+
return { capturedImages: {
|
|
3645
|
+
...context.capturedImages,
|
|
3646
|
+
[side]: { imageBase64: "" }
|
|
3647
|
+
} };
|
|
3648
|
+
}),
|
|
3649
|
+
storeProtectedPreview: assign(({ context, self, event }) => {
|
|
3650
|
+
if (event.type !== "PROTECTED_PREVIEW_READY") return {};
|
|
3651
|
+
return { previewImageUrl: getIdProtectedCaptureController(self).takeCommitPreviewImageUrl() ?? context.previewImageUrl };
|
|
3652
|
+
}),
|
|
3653
|
+
storeProtectedCandidate: assign(({ context, self }) => {
|
|
3654
|
+
const controller = getIdProtectedCaptureController(self);
|
|
3655
|
+
const candidateCanvas = controller.getPresentationCanvas();
|
|
3656
|
+
return candidateCanvas ? getCandidateFrameValues(context, {
|
|
3657
|
+
type: "DETECTION_OPTIMIZING",
|
|
3658
|
+
candidateCanvas
|
|
3659
|
+
}, controller.getProvider()) : {};
|
|
3660
|
+
}),
|
|
3661
|
+
storeProtectedUploadResponse: assign(({ context, self, event }) => {
|
|
3662
|
+
if (event.type !== "PROTECTED_UPLOAD_DONE_SIGNAL") return {};
|
|
3663
|
+
const uploadResponse = getIdProtectedCaptureController(self).takeUploadResponse();
|
|
3664
|
+
if (!uploadResponse) return {};
|
|
3665
|
+
return {
|
|
3666
|
+
uploadResponse,
|
|
3667
|
+
uploadProgress: 100,
|
|
3668
|
+
skipProcessId: uploadResponse.idValidationCompleted === true || context.skipProcessId
|
|
3669
|
+
};
|
|
3670
|
+
}),
|
|
3671
|
+
setProtectedFailure: assign(({ context, event }) => ({ error: protectedFailure(event)?.failure.code ?? context.error })),
|
|
3672
|
+
setProtectedUploadFailure: assign(({ context }) => ({
|
|
3673
|
+
uploadError: ID_ERROR_CODES.UPLOAD_ERROR,
|
|
3674
|
+
attemptsRemaining: context.attemptsRemaining - 1
|
|
3675
|
+
})),
|
|
2614
3676
|
stopMediaStream: assign(({ context }) => {
|
|
2615
3677
|
performStopMediaStream(context);
|
|
2616
3678
|
return {
|
|
@@ -2618,12 +3680,12 @@ const idCaptureMachine = setup({
|
|
|
2618
3680
|
frameCapturer: void 0
|
|
2619
3681
|
};
|
|
2620
3682
|
}),
|
|
3683
|
+
clearProtectedAttempt: ({ self }) => {
|
|
3684
|
+
getIdProtectedCaptureController(self).clearAttempt();
|
|
3685
|
+
},
|
|
2621
3686
|
disposeProvider: ({ context }) => {
|
|
2622
3687
|
performDisposeProvider(context);
|
|
2623
3688
|
},
|
|
2624
|
-
cleanupDeepsight: ({ context }) => {
|
|
2625
|
-
performCleanupDeepsight(context);
|
|
2626
|
-
},
|
|
2627
3689
|
flagIdManualReview: () => {
|
|
2628
3690
|
flagIdManualReview();
|
|
2629
3691
|
},
|
|
@@ -2707,19 +3769,9 @@ const idCaptureMachine = setup({
|
|
|
2707
3769
|
attemptsRemaining: context.config.captureAttempts
|
|
2708
3770
|
};
|
|
2709
3771
|
}),
|
|
2710
|
-
setStreamAndCapturer: assign({
|
|
2711
|
-
stream: ({ event }) => getStreamFromEvent(event),
|
|
2712
|
-
provider: ({ event }) => getProviderFromEvent(event),
|
|
2713
|
-
frameCapturer: ({ event }) => getFrameCapturerFromEvent(event),
|
|
2714
|
-
captureResolution: ({ event }) => getCaptureResolutionFromEvent(event),
|
|
2715
|
-
cameraFallbackLevel: ({ event }) => getCameraFallbackLevelFromEvent(event),
|
|
2716
|
-
usingBackCamera: ({ event }) => getUsingBackCameraFromEvent(event)
|
|
2717
|
-
}),
|
|
2718
3772
|
setPermissionResultAndStream: assign({
|
|
2719
3773
|
permissionResult: ({ context, event }) => getPermissionResultFromEvent(event) ?? context.permissionResult,
|
|
2720
|
-
|
|
2721
|
-
cameraFallbackLevel: ({ context, event }) => getCameraFallbackLevelFromEvent(event) ?? context.cameraFallbackLevel,
|
|
2722
|
-
usingBackCamera: ({ context, event }) => getUsingBackCameraFromEvent(event) ?? context.usingBackCamera
|
|
3774
|
+
cameraFallbackLevel: ({ context, event }) => getCameraFallbackLevelFromEvent(asPublicIdEvent(event)) ?? context.cameraFallbackLevel
|
|
2723
3775
|
}),
|
|
2724
3776
|
trackTutorialId: () => {},
|
|
2725
3777
|
trackContinue: () => {},
|
|
@@ -2728,21 +3780,14 @@ const idCaptureMachine = setup({
|
|
|
2728
3780
|
performReportCaptureOptimizingAssignment(context);
|
|
2729
3781
|
},
|
|
2730
3782
|
preloadRecordingProvider: ({ context }) => {
|
|
3783
|
+
if (isCaptureOnlyConfig(context.config)) return;
|
|
2731
3784
|
context.config;
|
|
2732
3785
|
},
|
|
2733
3786
|
resetContext: assign(({ context }) => getResetContextValues(context)),
|
|
2734
|
-
resetDetection: (
|
|
2735
|
-
performResetDetection(context);
|
|
2736
|
-
},
|
|
3787
|
+
resetDetection: () => {},
|
|
2737
3788
|
captureImage: assign({ qualityElements: ({ event }) => {
|
|
2738
3789
|
if ("qualityElements" in event) return event.qualityElements;
|
|
2739
3790
|
} }),
|
|
2740
|
-
storeCapturedCanvasInProvider: ({ context, event }) => {
|
|
2741
|
-
storeCapturedCanvasInProviderLogic(context, event);
|
|
2742
|
-
},
|
|
2743
|
-
captureLatestFrame: ({ context }) => {
|
|
2744
|
-
context.frameCapturer?.getLatestCanvas();
|
|
2745
|
-
},
|
|
2746
3791
|
clearUploadFailure: assign(({ context }) => getClearUploadFailureValues(context)),
|
|
2747
3792
|
clearStreamForRetry: assign(({ context }) => {
|
|
2748
3793
|
performPrepareRecordingForCameraRetry(context);
|
|
@@ -2762,33 +3807,19 @@ const idCaptureMachine = setup({
|
|
|
2762
3807
|
stopMediaRecording: ({ context }) => {
|
|
2763
3808
|
performStopMediaRecording(context);
|
|
2764
3809
|
},
|
|
2765
|
-
pauseRecordingForAttempt: ({ context }) => {
|
|
2766
|
-
performPauseRecordingForAttempt(context);
|
|
2767
|
-
},
|
|
2768
|
-
discardFailedRecordingSession: assign(({ context }) => {
|
|
2769
|
-
performStopMediaRecording(context);
|
|
2770
|
-
return { recordingSession: void 0 };
|
|
2771
|
-
}),
|
|
2772
3810
|
clearRecordingSession: assign({ recordingSession: () => void 0 }),
|
|
2773
3811
|
setSelectedDocument: assign({ selectedDocumentType: ({ event }) => {
|
|
2774
3812
|
if ("documentType" in event) return event.documentType;
|
|
2775
3813
|
} }),
|
|
2776
|
-
setCurrentMode: assign({ currentMode: ({ event, context }) => getCurrentModeFromEvent(context, event) }),
|
|
2777
|
-
storeCapturedImage: assign(({ context, event }) => getStoreCapturedImageValues(context, event)),
|
|
2778
|
-
setCandidateFrame: assign(({ context, event }) => getCandidateFrameValues(context, event)),
|
|
3814
|
+
setCurrentMode: assign({ currentMode: ({ event, context }) => getCurrentModeFromEvent(context, asPublicIdEvent(event)) }),
|
|
3815
|
+
storeCapturedImage: assign(({ context, event }) => getStoreCapturedImageValues(context, asPublicIdEvent(event))),
|
|
3816
|
+
setCandidateFrame: assign(({ context, event }) => getCandidateFrameValues(context, asPublicIdEvent(event))),
|
|
2779
3817
|
/**
|
|
2780
3818
|
* IDC-05: parks WASM's commit while the optimizing phase spends the rest of
|
|
2781
3819
|
* its dwell. The frame travels in context only for that stretch —
|
|
2782
3820
|
* `releaseStashedCommit` re-raises it and `getClearOptimizingValues` drops it
|
|
2783
3821
|
* on every other exit from the phase.
|
|
2784
3822
|
*/
|
|
2785
|
-
stashCommittedFrame: assign({ stashedCommit: ({ event }) => {
|
|
2786
|
-
const commit = event;
|
|
2787
|
-
return {
|
|
2788
|
-
canvas: commit.canvas,
|
|
2789
|
-
qualityElements: commit.qualityElements
|
|
2790
|
-
};
|
|
2791
|
-
} }),
|
|
2792
3823
|
/**
|
|
2793
3824
|
* IDC-05: hands a parked commit back to the machine as the very event that
|
|
2794
3825
|
* would have carried it, so `capturing`'s entry actions stay event-driven.
|
|
@@ -2797,15 +3828,16 @@ const idCaptureMachine = setup({
|
|
|
2797
3828
|
* entering event has no canvas — a timer transition into `capturing` would
|
|
2798
3829
|
* stage a live frame for upload instead of the one WASM committed.
|
|
2799
3830
|
*/
|
|
2800
|
-
releaseStashedCommit: enqueueActions(({
|
|
2801
|
-
|
|
2802
|
-
if (!stashed) return;
|
|
3831
|
+
releaseStashedCommit: enqueueActions(({ self, enqueue }) => {
|
|
3832
|
+
if (!getIdProtectedCaptureController(self).hasCommit()) return;
|
|
2803
3833
|
enqueue(raise({
|
|
2804
|
-
type: "
|
|
2805
|
-
|
|
2806
|
-
qualityElements: stashed.qualityElements
|
|
3834
|
+
type: "PROTECTED_AUTO_COMMITTED_SIGNAL",
|
|
3835
|
+
attemptId: "stashed-protected-id-commit"
|
|
2807
3836
|
}));
|
|
2808
3837
|
}),
|
|
3838
|
+
releaseStashedCommitIfPresent: enqueueActions(({ self, enqueue }) => {
|
|
3839
|
+
if (getIdProtectedCaptureController(self).hasCommit()) enqueue(raise({ type: "PROTECTED_RELEASE_STASHED_COMMIT" }));
|
|
3840
|
+
}),
|
|
2809
3841
|
/**
|
|
2810
3842
|
* IDC-05: releases everything the optimizing phase allocated — the parked
|
|
2811
3843
|
* commit AND the frozen still's blob URL. Bound to `optimizing.exit`, so it
|
|
@@ -2822,7 +3854,7 @@ const idCaptureMachine = setup({
|
|
|
2822
3854
|
* resolves to nothing (see `getStoreCapturedImageValues`).
|
|
2823
3855
|
*/
|
|
2824
3856
|
clearOptimizingPhase: assign(({ context }) => getClearOptimizingValues(context)),
|
|
2825
|
-
storeBarcodeResponse: assign(({ context, event }) => getBarcodeResponseValues(context, event)),
|
|
3857
|
+
storeBarcodeResponse: assign(({ context, event }) => getBarcodeResponseValues(context, asPublicIdEvent(event))),
|
|
2826
3858
|
storeDecodedBarcode: assign({ decodedBarcode: ({ event }) => event.decoded }),
|
|
2827
3859
|
setBarcodeFastPathAttempted: assign({ barcodeFastPathAttempted: true }),
|
|
2828
3860
|
markBarcodeFastPathCaptured: assign({
|
|
@@ -2830,7 +3862,7 @@ const idCaptureMachine = setup({
|
|
|
2830
3862
|
previewImageUrl: void 0
|
|
2831
3863
|
}),
|
|
2832
3864
|
clearBarcodeFastPathCaptured: assign({ barcodeFastPathCaptured: false }),
|
|
2833
|
-
setDetectionStatus: assign({ detectionStatus: ({ event, context }) => getDetectionStatusFromUpdate(context, event) }),
|
|
3865
|
+
setDetectionStatus: assign({ detectionStatus: ({ event, context }) => getDetectionStatusFromUpdate(context, asPublicIdEvent(event)) }),
|
|
2834
3866
|
setCounterValue: assign({ counterValue: ({ event }) => {
|
|
2835
3867
|
if ("value" in event) return event.value;
|
|
2836
3868
|
return 0;
|
|
@@ -2928,20 +3960,26 @@ const idCaptureMachine = setup({
|
|
|
2928
3960
|
clearExpiredFromUpload: assign({ expiredFromUpload: () => false })
|
|
2929
3961
|
},
|
|
2930
3962
|
guards: {
|
|
3963
|
+
isCaptureOnlyDelivery: ({ context }) => isCaptureOnlyConfig(context.config),
|
|
3964
|
+
isProtectedUploadFailure: ({ event }) => protectedFailure(event)?.failure.stage === "upload",
|
|
3965
|
+
isProtectedManualRefusal: ({ event }) => protectedFailure(event)?.failure.stage === "manualCommit",
|
|
2931
3966
|
hasShowTutorial: hasShowTutorialGuard,
|
|
2932
3967
|
hasAgeAssurance: hasAgeAssuranceGuard,
|
|
2933
3968
|
hasShowDocumentChooser: hasShowDocumentChooserGuard,
|
|
2934
|
-
isPermissionGranted: isPermissionGrantedGuard,
|
|
2935
|
-
isReadyForCapture: isReadyForCaptureGuard
|
|
2936
|
-
|
|
2937
|
-
|
|
3969
|
+
isPermissionGranted: ({ event }) => isPermissionGrantedGuard({ event: asPublicIdEvent(event) }),
|
|
3970
|
+
isReadyForCapture: ({ context, event }) => isReadyForCaptureGuard({
|
|
3971
|
+
context,
|
|
3972
|
+
event: asPublicIdEvent(event)
|
|
3973
|
+
}),
|
|
3974
|
+
needsMotionPrimeOnly: ({ context, event }) => needsMotionPrimeOnlyGuard({
|
|
3975
|
+
context,
|
|
3976
|
+
event: asPublicIdEvent(event)
|
|
3977
|
+
}),
|
|
3978
|
+
isPermissionDeniedError: ({ event }) => isPermissionDeniedErrorGuard({ event: asPublicIdEvent(event) }),
|
|
2938
3979
|
isPermissionBlocked: isPermissionBlockedGuard,
|
|
2939
|
-
hasStream: hasStreamGuard,
|
|
2940
|
-
hasInitializedCamera: hasInitializedCameraGuard,
|
|
2941
3980
|
hasAttemptsRemaining: hasAttemptsRemainingGuard,
|
|
2942
3981
|
hasCapturedImage: hasCapturedImageGuard,
|
|
2943
|
-
hasCandidateFrame: hasCandidateFrameGuard,
|
|
2944
|
-
hasStashedCommit: hasStashedCommitGuard,
|
|
3982
|
+
hasCandidateFrame: ({ event }) => hasCandidateFrameGuard({ event: asPublicIdEvent(event) }),
|
|
2945
3983
|
hasUploadValidationError: hasUploadValidationErrorGuard,
|
|
2946
3984
|
isFrontMode: isFrontModeGuard,
|
|
2947
3985
|
shouldContinueToBack: shouldContinueToBackGuard,
|
|
@@ -2954,10 +3992,10 @@ const idCaptureMachine = setup({
|
|
|
2954
3992
|
needsDeepsightInit: needsDeepsightInitGuard,
|
|
2955
3993
|
hasOnlyManualUploadAvailable: hasOnlyManualUploadAvailableGuard,
|
|
2956
3994
|
hasNoDocumentTypesAvailable: hasNoDocumentTypesAvailableGuard,
|
|
2957
|
-
isManualIdUploadSelected: isManualIdUploadSelectedGuard,
|
|
2958
|
-
isDigitalIdUploadSelected: isDigitalIdUploadSelectedGuard,
|
|
2959
|
-
isDigitalIdRedirectSelected: isDigitalIdRedirectSelectedGuard,
|
|
2960
|
-
isDigitalIdSelected: isDigitalIdSelectedGuard,
|
|
3995
|
+
isManualIdUploadSelected: ({ event }) => isManualIdUploadSelectedGuard({ event: asPublicIdEvent(event) }),
|
|
3996
|
+
isDigitalIdUploadSelected: ({ event }) => isDigitalIdUploadSelectedGuard({ event: asPublicIdEvent(event) }),
|
|
3997
|
+
isDigitalIdRedirectSelected: ({ event }) => isDigitalIdRedirectSelectedGuard({ event: asPublicIdEvent(event) }),
|
|
3998
|
+
isDigitalIdSelected: ({ event }) => isDigitalIdSelectedGuard({ event: asPublicIdEvent(event) }),
|
|
2961
3999
|
digitalIdRouteIsWallet: digitalIdRouteIsWalletGuard,
|
|
2962
4000
|
digitalIdRouteIsTrinsic: digitalIdRouteIsTrinsicGuard,
|
|
2963
4001
|
isUploadExpired: isUploadExpiredGuard,
|
|
@@ -2967,7 +4005,10 @@ const idCaptureMachine = setup({
|
|
|
2967
4005
|
wasExpiredFromUpload: wasExpiredFromUploadGuard,
|
|
2968
4006
|
shouldSkipProcessId: shouldSkipProcessIdGuard,
|
|
2969
4007
|
shouldSubmitBarcode: shouldSubmitBarcodeGuard,
|
|
2970
|
-
canRunBarcodeFastPath: canRunBarcodeFastPathGuard
|
|
4008
|
+
canRunBarcodeFastPath: ({ context, event }) => canRunBarcodeFastPathGuard({
|
|
4009
|
+
context,
|
|
4010
|
+
event: asPublicIdEvent(event)
|
|
4011
|
+
}),
|
|
2971
4012
|
hasManualCaptureTriggered: hasManualCaptureTriggeredGuard,
|
|
2972
4013
|
isProcessingExpiredExhausted: isProcessingExpiredExhaustedGuard,
|
|
2973
4014
|
shouldProcessAfterExhaustion: shouldProcessAfterExhaustionGuard,
|
|
@@ -3016,7 +4057,13 @@ const idCaptureMachine = setup({
|
|
|
3016
4057
|
id: "idCapture",
|
|
3017
4058
|
initial: "idle",
|
|
3018
4059
|
output: ({ context }) => computeIdCaptureOutput(context),
|
|
3019
|
-
|
|
4060
|
+
entry: ["attachProtectedController", "bindProtectedControllerLifetime"],
|
|
4061
|
+
invoke: {
|
|
4062
|
+
id: "protectedControllerLifetime",
|
|
4063
|
+
src: "protectedControllerLifetime"
|
|
4064
|
+
},
|
|
4065
|
+
context: ({ input, self }) => {
|
|
4066
|
+
attachIdProtectedCaptureController(self, createIdProtectedCaptureController());
|
|
3020
4067
|
const currentMode = input.config.onlyBack ? "back" : !input.config.enableId && input.config.enablePassport ? "passport" : input.config.usSmartCapture ? "back" : "front";
|
|
3021
4068
|
return {
|
|
3022
4069
|
config: input.config,
|
|
@@ -3069,7 +4116,7 @@ const idCaptureMachine = setup({
|
|
|
3069
4116
|
manualCaptureTriggered: false,
|
|
3070
4117
|
deepsightService: void 0,
|
|
3071
4118
|
analyticsProvider: input.analyticsProvider,
|
|
3072
|
-
dependencies: input.dependencies,
|
|
4119
|
+
dependencies: resolveIdCaptureDependencies(input.dependencies),
|
|
3073
4120
|
disableIpify: getDisableIpify(),
|
|
3074
4121
|
deepsightInitAttempted: false,
|
|
3075
4122
|
availableDocumentTypes: getAvailableDocumentTypes(input.config, { credentialsAvailable: input.dependencies?.credentials?.isAvailable() ?? false }),
|
|
@@ -3147,16 +4194,19 @@ const idCaptureMachine = setup({
|
|
|
3147
4194
|
actions: ["setSelectedDocument", "setCurrentMode"]
|
|
3148
4195
|
}
|
|
3149
4196
|
] } },
|
|
3150
|
-
ageVerification: {
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
4197
|
+
ageVerification: {
|
|
4198
|
+
entry: "startProtectedMetadataPreparation",
|
|
4199
|
+
on: { NEXT_STEP: [{
|
|
4200
|
+
target: "tutorial",
|
|
4201
|
+
guard: "hasShowTutorial",
|
|
4202
|
+
actions: "trackContinue"
|
|
4203
|
+
}, {
|
|
4204
|
+
target: "loading",
|
|
4205
|
+
actions: "trackContinue"
|
|
4206
|
+
}] }
|
|
4207
|
+
},
|
|
3158
4208
|
loading: {
|
|
3159
|
-
entry: "preloadRecordingProvider",
|
|
4209
|
+
entry: ["startProtectedMetadataPreparation", "preloadRecordingProvider"],
|
|
3160
4210
|
type: "parallel",
|
|
3161
4211
|
states: {
|
|
3162
4212
|
permissionCheck: {
|
|
@@ -3178,30 +4228,8 @@ const idCaptureMachine = setup({
|
|
|
3178
4228
|
}
|
|
3179
4229
|
},
|
|
3180
4230
|
deepsightInit: {
|
|
3181
|
-
initial: "
|
|
3182
|
-
states: {
|
|
3183
|
-
initializing: { invoke: {
|
|
3184
|
-
id: "initDeepsightLoading",
|
|
3185
|
-
src: "initializeDeepsightSession",
|
|
3186
|
-
input: ({ context }) => ({
|
|
3187
|
-
ds: context.config.ds,
|
|
3188
|
-
dependencies: context.dependencies,
|
|
3189
|
-
disableIpify: context.disableIpify
|
|
3190
|
-
}),
|
|
3191
|
-
onDone: {
|
|
3192
|
-
target: "done",
|
|
3193
|
-
actions: assign({
|
|
3194
|
-
deepsightService: ({ event }) => event.output,
|
|
3195
|
-
deepsightInitAttempted: () => true
|
|
3196
|
-
})
|
|
3197
|
-
},
|
|
3198
|
-
onError: {
|
|
3199
|
-
target: "done",
|
|
3200
|
-
actions: [assign({ deepsightInitAttempted: () => true }), () => console.warn("Deepsight initialization failed")]
|
|
3201
|
-
}
|
|
3202
|
-
} },
|
|
3203
|
-
done: { type: "final" }
|
|
3204
|
-
}
|
|
4231
|
+
initial: "done",
|
|
4232
|
+
states: { done: { type: "final" } }
|
|
3205
4233
|
}
|
|
3206
4234
|
},
|
|
3207
4235
|
onDone: [{
|
|
@@ -3211,7 +4239,11 @@ const idCaptureMachine = setup({
|
|
|
3211
4239
|
},
|
|
3212
4240
|
tutorial: {
|
|
3213
4241
|
initial: "checkingPermission",
|
|
3214
|
-
entry: [
|
|
4242
|
+
entry: [
|
|
4243
|
+
"startProtectedMetadataPreparation",
|
|
4244
|
+
"trackTutorialId",
|
|
4245
|
+
"preloadRecordingProvider"
|
|
4246
|
+
],
|
|
3215
4247
|
states: {
|
|
3216
4248
|
checkingPermission: {
|
|
3217
4249
|
invoke: {
|
|
@@ -3241,50 +4273,22 @@ const idCaptureMachine = setup({
|
|
|
3241
4273
|
type: "parallel",
|
|
3242
4274
|
states: {
|
|
3243
4275
|
cameraInit: {
|
|
3244
|
-
initial: "
|
|
4276
|
+
initial: "initializingStream",
|
|
3245
4277
|
states: {
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
deepsightInitAttempted: () => true
|
|
3259
|
-
})
|
|
3260
|
-
},
|
|
3261
|
-
onError: {
|
|
3262
|
-
target: "initializingStream",
|
|
3263
|
-
actions: [assign({ deepsightInitAttempted: () => true }), () => console.warn("Deepsight initialization failed in tutorial")]
|
|
4278
|
+
initializingStream: {
|
|
4279
|
+
entry: "preAcquireProtectedCamera",
|
|
4280
|
+
on: {
|
|
4281
|
+
PROTECTED_PRE_ACQUIRE_DONE: { target: "ready" },
|
|
4282
|
+
PROTECTED_PRE_ACQUIRE_FAILED: [{
|
|
4283
|
+
target: "#idCapture.tutorial.ready",
|
|
4284
|
+
guard: "isPermissionDeniedError",
|
|
4285
|
+
actions: assign({ permissionResult: () => "denied" })
|
|
4286
|
+
}, {
|
|
4287
|
+
target: "#idCapture.tutorial.ready",
|
|
4288
|
+
actions: assign({ error: ({ event }) => String(event.error) })
|
|
4289
|
+
}]
|
|
3264
4290
|
}
|
|
3265
|
-
}
|
|
3266
|
-
initializingStream: { invoke: {
|
|
3267
|
-
id: "tutorialInitCamera",
|
|
3268
|
-
src: "initializeCamera",
|
|
3269
|
-
input: ({ context }) => ({
|
|
3270
|
-
config: context.config,
|
|
3271
|
-
deepsightService: context.deepsightService
|
|
3272
|
-
}),
|
|
3273
|
-
onDone: {
|
|
3274
|
-
target: "ready",
|
|
3275
|
-
actions: "setStreamAndCapturer"
|
|
3276
|
-
},
|
|
3277
|
-
onError: [{
|
|
3278
|
-
target: "#idCapture.tutorial.ready",
|
|
3279
|
-
guard: "isPermissionDeniedError",
|
|
3280
|
-
actions: assign({ permissionResult: () => {
|
|
3281
|
-
return "denied";
|
|
3282
|
-
} })
|
|
3283
|
-
}, {
|
|
3284
|
-
target: "#idCapture.tutorial.ready",
|
|
3285
|
-
actions: assign({ error: ({ event }) => String(event.error) })
|
|
3286
|
-
}]
|
|
3287
|
-
} },
|
|
4291
|
+
},
|
|
3288
4292
|
ready: { type: "final" }
|
|
3289
4293
|
}
|
|
3290
4294
|
},
|
|
@@ -3416,9 +4420,10 @@ const idCaptureMachine = setup({
|
|
|
3416
4420
|
requesting: { invoke: {
|
|
3417
4421
|
id: "requestPermission",
|
|
3418
4422
|
src: "requestPermission",
|
|
3419
|
-
input: ({ context }) => ({
|
|
4423
|
+
input: ({ context, self }) => ({
|
|
3420
4424
|
permissionResult: context.permissionResult === "refresh" ? void 0 : context.permissionResult,
|
|
3421
|
-
requestMotionPermission: context.config.ds === true
|
|
4425
|
+
requestMotionPermission: context.config.ds === true,
|
|
4426
|
+
acceptStream: (value) => getIdProtectedCaptureController(self).storePreAcquiredStream(value)
|
|
3422
4427
|
}),
|
|
3423
4428
|
onDone: [
|
|
3424
4429
|
{
|
|
@@ -3443,63 +4448,64 @@ const idCaptureMachine = setup({
|
|
|
3443
4448
|
},
|
|
3444
4449
|
capture: {
|
|
3445
4450
|
initial: "checkingStream",
|
|
3446
|
-
entry: [
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
4451
|
+
entry: [
|
|
4452
|
+
"trackCameraId",
|
|
4453
|
+
"preloadRecordingProvider",
|
|
4454
|
+
"initializeProtectedProvider",
|
|
4455
|
+
"bindProtectedAttempt",
|
|
4456
|
+
"startProtectedAttempt"
|
|
4457
|
+
],
|
|
4458
|
+
exit: [
|
|
4459
|
+
"stopMediaRecording",
|
|
4460
|
+
"clearRecordingSession",
|
|
4461
|
+
"clearProtectedAttempt"
|
|
4462
|
+
],
|
|
4463
|
+
invoke: {
|
|
4464
|
+
id: "protectedAttempt",
|
|
4465
|
+
src: "protectedAttempt"
|
|
4466
|
+
},
|
|
4467
|
+
on: {
|
|
4468
|
+
QUIT: { target: ".releasingForClose" },
|
|
4469
|
+
BACKGROUND: { actions: "forwardProtectedBackground" },
|
|
4470
|
+
FOREGROUND: { actions: "forwardProtectedForeground" },
|
|
4471
|
+
PROTECTED_ATTEMPT_READY_SIGNAL: {
|
|
4472
|
+
target: ".choosingDetectionStrategy",
|
|
4473
|
+
actions: "setProtectedAttemptReady"
|
|
4474
|
+
},
|
|
4475
|
+
PROTECTED_ATTEMPT_FAILED: [
|
|
4476
|
+
{ guard: "isProtectedManualRefusal" },
|
|
3451
4477
|
{
|
|
3452
|
-
target: "
|
|
3453
|
-
guard: "
|
|
4478
|
+
target: ".uploadError",
|
|
4479
|
+
guard: "isProtectedUploadFailure",
|
|
4480
|
+
actions: "setProtectedUploadFailure"
|
|
3454
4481
|
},
|
|
3455
4482
|
{
|
|
3456
|
-
target: "choosingDetectionStrategy",
|
|
3457
|
-
guard: "hasInitializedCamera"
|
|
3458
|
-
},
|
|
3459
|
-
{ target: "initializing" }
|
|
3460
|
-
] },
|
|
3461
|
-
initializingDeepsight: { invoke: {
|
|
3462
|
-
id: "initDeepsightCapture",
|
|
3463
|
-
src: "initializeDeepsightSession",
|
|
3464
|
-
input: ({ context }) => ({
|
|
3465
|
-
ds: context.config.ds,
|
|
3466
|
-
dependencies: context.dependencies,
|
|
3467
|
-
disableIpify: context.disableIpify
|
|
3468
|
-
}),
|
|
3469
|
-
onDone: {
|
|
3470
|
-
target: "checkingStream",
|
|
3471
|
-
actions: assign({
|
|
3472
|
-
deepsightService: ({ event }) => event.output,
|
|
3473
|
-
deepsightInitAttempted: () => true
|
|
3474
|
-
})
|
|
3475
|
-
},
|
|
3476
|
-
onError: {
|
|
3477
|
-
target: "checkingStream",
|
|
3478
|
-
actions: [assign({ deepsightInitAttempted: () => true }), () => console.warn("Deepsight initialization failed in capture")]
|
|
3479
|
-
}
|
|
3480
|
-
} },
|
|
3481
|
-
initializing: { invoke: {
|
|
3482
|
-
id: "initializeCamera",
|
|
3483
|
-
src: "initializeCamera",
|
|
3484
|
-
input: ({ context }) => ({
|
|
3485
|
-
config: context.config,
|
|
3486
|
-
deepsightService: context.deepsightService,
|
|
3487
|
-
stream: context.stream,
|
|
3488
|
-
cameraFallbackLevel: context.cameraFallbackLevel
|
|
3489
|
-
}),
|
|
3490
|
-
onDone: {
|
|
3491
|
-
target: "choosingDetectionStrategy",
|
|
3492
|
-
actions: "setStreamAndCapturer"
|
|
3493
|
-
},
|
|
3494
|
-
onError: [{
|
|
3495
|
-
target: "#idCapture.permissions",
|
|
3496
|
-
guard: "isPermissionDeniedError",
|
|
3497
|
-
actions: assign({ permissionResult: () => "denied" })
|
|
3498
|
-
}, {
|
|
3499
4483
|
target: "#idCapture.error",
|
|
3500
|
-
actions:
|
|
3501
|
-
}
|
|
3502
|
-
|
|
4484
|
+
actions: "setProtectedFailure"
|
|
4485
|
+
}
|
|
4486
|
+
],
|
|
4487
|
+
PROTECTED_PRESENTATION_FAILED: {
|
|
4488
|
+
target: ".uploadError",
|
|
4489
|
+
actions: "setProtectedUploadFailure"
|
|
4490
|
+
},
|
|
4491
|
+
PROTECTED_PREVIEW_READY: { actions: "storeProtectedPreview" },
|
|
4492
|
+
SET_FRAME_RECT: { actions: "setFrameRect" }
|
|
4493
|
+
},
|
|
4494
|
+
states: {
|
|
4495
|
+
releasingForClose: {
|
|
4496
|
+
entry: "releaseProtectedForClose",
|
|
4497
|
+
always: "#idCapture.closed"
|
|
4498
|
+
},
|
|
4499
|
+
releasingForRetry: {
|
|
4500
|
+
entry: "releaseProtectedForRetry",
|
|
4501
|
+
always: {
|
|
4502
|
+
target: "#idCapture.capture",
|
|
4503
|
+
reenter: true
|
|
4504
|
+
}
|
|
4505
|
+
},
|
|
4506
|
+
checkingStream: { always: { target: "initializing" } },
|
|
4507
|
+
initializingDeepsight: { always: { target: "initializing" } },
|
|
4508
|
+
initializing: {},
|
|
3503
4509
|
choosingDetectionStrategy: {
|
|
3504
4510
|
entry: ["reportCaptureOptimizingAssignment"],
|
|
3505
4511
|
always: [{
|
|
@@ -3514,43 +4520,19 @@ const idCaptureMachine = setup({
|
|
|
3514
4520
|
actions: assign({ detectionStatus: () => "manualCapture" })
|
|
3515
4521
|
}],
|
|
3516
4522
|
entry: [assign({ detectionStatus: () => "detecting" })],
|
|
3517
|
-
invoke: [{
|
|
3518
|
-
id: "startRecording",
|
|
3519
|
-
src: "startRecording",
|
|
3520
|
-
input: ({ context }) => ({
|
|
3521
|
-
config: context.config,
|
|
3522
|
-
stream: context.stream,
|
|
3523
|
-
existing: context.recordingSession,
|
|
3524
|
-
currentMode: context.currentMode
|
|
3525
|
-
}),
|
|
3526
|
-
onDone: { actions: assign({ recordingSession: ({ context, event }) => {
|
|
3527
|
-
return event.output ?? context.recordingSession;
|
|
3528
|
-
} }) },
|
|
3529
|
-
onError: { actions: "discardFailedRecordingSession" }
|
|
3530
|
-
}, {
|
|
3531
|
-
id: "runDetection",
|
|
3532
|
-
src: "runDetection",
|
|
3533
|
-
input: ({ context }) => ({
|
|
3534
|
-
frameCapturer: context.frameCapturer,
|
|
3535
|
-
provider: context.provider,
|
|
3536
|
-
config: context.config,
|
|
3537
|
-
currentMode: context.currentMode,
|
|
3538
|
-
detectionArea: context.detectionArea ?? context.config.detectionArea
|
|
3539
|
-
})
|
|
3540
|
-
}],
|
|
3541
4523
|
on: {
|
|
3542
4524
|
DETECTION_UPDATE: { actions: "setDetectionStatus" },
|
|
3543
|
-
|
|
3544
|
-
|
|
4525
|
+
PROTECTED_AUTO_CAPTURE: { actions: ["storeProtectedAutoQuality", "requestProtectedAutoCommit"] },
|
|
4526
|
+
PROTECTED_AUTO_COMMITTED_SIGNAL: {
|
|
3545
4527
|
target: "capturing",
|
|
3546
|
-
actions:
|
|
4528
|
+
actions: "storeProtectedCommit"
|
|
3547
4529
|
},
|
|
3548
4530
|
BARCODE_DECODED: [{
|
|
3549
|
-
target: "
|
|
4531
|
+
target: "submittingBarcodePreCapture",
|
|
3550
4532
|
guard: "canRunBarcodeFastPath",
|
|
3551
4533
|
actions: ["storeDecodedBarcode", "setBarcodeFastPathAttempted"]
|
|
3552
4534
|
}, { actions: "storeDecodedBarcode" }],
|
|
3553
|
-
MANUAL_CAPTURE: {
|
|
4535
|
+
MANUAL_CAPTURE: {},
|
|
3554
4536
|
SWITCH_TO_MANUAL_CAPTURE: {
|
|
3555
4537
|
target: "manualCaptureWaiting",
|
|
3556
4538
|
actions: assign({
|
|
@@ -3583,40 +4565,15 @@ const idCaptureMachine = setup({
|
|
|
3583
4565
|
guard: "hasManualCaptureTriggered",
|
|
3584
4566
|
actions: assign({ detectionStatus: () => "manualCapture" })
|
|
3585
4567
|
}],
|
|
3586
|
-
invoke: [{
|
|
3587
|
-
id: "startRecording",
|
|
3588
|
-
src: "startRecording",
|
|
3589
|
-
input: ({ context }) => ({
|
|
3590
|
-
config: context.config,
|
|
3591
|
-
stream: context.stream,
|
|
3592
|
-
existing: context.recordingSession,
|
|
3593
|
-
currentMode: context.currentMode
|
|
3594
|
-
}),
|
|
3595
|
-
onDone: { actions: assign({ recordingSession: ({ context, event }) => {
|
|
3596
|
-
return event.output ?? context.recordingSession;
|
|
3597
|
-
} }) },
|
|
3598
|
-
onError: { actions: "discardFailedRecordingSession" }
|
|
3599
|
-
}, {
|
|
3600
|
-
id: "runDetection",
|
|
3601
|
-
src: "runDetection",
|
|
3602
|
-
input: ({ context }) => ({
|
|
3603
|
-
frameCapturer: context.frameCapturer,
|
|
3604
|
-
provider: context.provider,
|
|
3605
|
-
config: context.config,
|
|
3606
|
-
currentMode: context.currentMode,
|
|
3607
|
-
detectionArea: context.detectionArea ?? context.config.detectionArea,
|
|
3608
|
-
optimizingAfterMs: context.captureWindowMs
|
|
3609
|
-
})
|
|
3610
|
-
}],
|
|
3611
4568
|
on: {
|
|
3612
|
-
|
|
4569
|
+
PROTECTED_AUTO_CAPTURE: { actions: ["storeProtectedAutoQuality", "requestProtectedAutoCommit"] },
|
|
4570
|
+
PROTECTED_AUTO_COMMITTED_SIGNAL: {
|
|
3613
4571
|
target: "capturing",
|
|
3614
|
-
actions:
|
|
4572
|
+
actions: "storeProtectedCommit"
|
|
3615
4573
|
},
|
|
3616
|
-
DETECTION_RESET_READY: { actions: assign({ resetDetection: ({ event }) => event.reset }) },
|
|
3617
4574
|
ID_TYPE_CHANGE: { actions: "setIdType" },
|
|
3618
4575
|
ORIENTATION_CHANGE: { actions: "setOrientation" },
|
|
3619
|
-
MANUAL_CAPTURE: {
|
|
4576
|
+
MANUAL_CAPTURE: {},
|
|
3620
4577
|
SWITCH_TO_MANUAL_CAPTURE: {
|
|
3621
4578
|
target: "#idCapture.capture.manualCaptureWaiting",
|
|
3622
4579
|
actions: assign({
|
|
@@ -3631,34 +4588,28 @@ const idCaptureMachine = setup({
|
|
|
3631
4588
|
DETECTION_UPDATE: { actions: "setDetectionStatus" },
|
|
3632
4589
|
ID_SIDE_CHANGE: { actions: assign({ detectionStatus: ({ context, event }) => getDetectionStatusFromSideChange(context, event.side) }) },
|
|
3633
4590
|
BARCODE_DECODED: [{
|
|
3634
|
-
target: "#idCapture.capture.
|
|
4591
|
+
target: "#idCapture.capture.submittingBarcodePreCapture",
|
|
3635
4592
|
guard: "canRunBarcodeFastPath",
|
|
3636
4593
|
actions: ["storeDecodedBarcode", "setBarcodeFastPathAttempted"]
|
|
3637
4594
|
}, { actions: "storeDecodedBarcode" }],
|
|
3638
|
-
|
|
4595
|
+
PROTECTED_OPTIMIZING: {
|
|
3639
4596
|
target: "optimizing",
|
|
3640
|
-
|
|
3641
|
-
actions: "setCandidateFrame"
|
|
4597
|
+
actions: "storeProtectedCandidate"
|
|
3642
4598
|
}
|
|
3643
4599
|
} },
|
|
3644
4600
|
optimizing: {
|
|
3645
4601
|
exit: "clearOptimizingPhase",
|
|
3646
4602
|
on: {
|
|
3647
4603
|
BARCODE_DECODED: { actions: "storeDecodedBarcode" },
|
|
3648
|
-
SWITCH_TO_MANUAL_CAPTURE: {
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
},
|
|
3652
|
-
MANUAL_CAPTURE: {
|
|
3653
|
-
guard: "hasStashedCommit",
|
|
3654
|
-
target: "#idCapture.capture.detectingWithOptimization.optimizing.released"
|
|
3655
|
-
}
|
|
4604
|
+
SWITCH_TO_MANUAL_CAPTURE: { actions: "releaseStashedCommitIfPresent" },
|
|
4605
|
+
MANUAL_CAPTURE: { actions: "releaseStashedCommitIfPresent" },
|
|
4606
|
+
PROTECTED_RELEASE_STASHED_COMMIT: { target: "#idCapture.capture.detectingWithOptimization.optimizing.released" }
|
|
3656
4607
|
},
|
|
3657
4608
|
initial: "holding",
|
|
3658
4609
|
states: {
|
|
3659
4610
|
holding: {
|
|
3660
4611
|
after: { optimizingDwell: { target: "released" } },
|
|
3661
|
-
on: {
|
|
4612
|
+
on: { PROTECTED_AUTO_COMMITTED_SIGNAL: {} }
|
|
3662
4613
|
},
|
|
3663
4614
|
released: {
|
|
3664
4615
|
entry: "releaseStashedCommit",
|
|
@@ -3671,34 +4622,23 @@ const idCaptureMachine = setup({
|
|
|
3671
4622
|
}
|
|
3672
4623
|
}
|
|
3673
4624
|
},
|
|
3674
|
-
manualCaptureWaiting: {
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
existing: context.recordingSession,
|
|
3682
|
-
currentMode: context.currentMode
|
|
3683
|
-
}),
|
|
3684
|
-
onDone: { actions: assign({ recordingSession: ({ context, event }) => {
|
|
3685
|
-
return event.output ?? context.recordingSession;
|
|
3686
|
-
} }) },
|
|
3687
|
-
onError: { actions: "discardFailedRecordingSession" }
|
|
3688
|
-
},
|
|
3689
|
-
on: { MANUAL_CAPTURE: { target: "capturingManual" } }
|
|
3690
|
-
},
|
|
4625
|
+
manualCaptureWaiting: { on: {
|
|
4626
|
+
MANUAL_CAPTURE: { actions: "requestProtectedManualCommit" },
|
|
4627
|
+
PROTECTED_MANUAL_COMMITTED_SIGNAL: {
|
|
4628
|
+
target: "capturingManual",
|
|
4629
|
+
actions: "storeProtectedCommit"
|
|
4630
|
+
}
|
|
4631
|
+
} },
|
|
3691
4632
|
capturing: {
|
|
3692
|
-
entry:
|
|
3693
|
-
|
|
3694
|
-
"storeCapturedCanvasInProvider",
|
|
3695
|
-
"storeCapturedImage",
|
|
3696
|
-
"pauseRecordingForAttempt"
|
|
3697
|
-
],
|
|
3698
|
-
always: [
|
|
4633
|
+
entry: "finalizeProtectedAttempt",
|
|
4634
|
+
on: { PROTECTED_ATTEMPT_FINALIZED_SIGNAL: [
|
|
3699
4635
|
{
|
|
3700
4636
|
target: "submittingBarcode",
|
|
3701
|
-
guard:
|
|
4637
|
+
guard: "shouldSubmitBarcode"
|
|
4638
|
+
},
|
|
4639
|
+
{
|
|
4640
|
+
target: "uploading",
|
|
4641
|
+
guard: not("isCaptureOnlyDelivery")
|
|
3702
4642
|
},
|
|
3703
4643
|
{
|
|
3704
4644
|
target: "uploading",
|
|
@@ -3706,12 +4646,9 @@ const idCaptureMachine = setup({
|
|
|
3706
4646
|
},
|
|
3707
4647
|
{
|
|
3708
4648
|
target: "uploadError",
|
|
3709
|
-
actions:
|
|
3710
|
-
uploadError: ID_ERROR_CODES.UPLOAD_ERROR,
|
|
3711
|
-
attemptsRemaining: context.attemptsRemaining - 1
|
|
3712
|
-
}))
|
|
4649
|
+
actions: "setProtectedUploadFailure"
|
|
3713
4650
|
}
|
|
3714
|
-
]
|
|
4651
|
+
] }
|
|
3715
4652
|
},
|
|
3716
4653
|
submittingBarcode: { invoke: {
|
|
3717
4654
|
id: "submitBarcode",
|
|
@@ -3727,15 +4664,7 @@ const idCaptureMachine = setup({
|
|
|
3727
4664
|
},
|
|
3728
4665
|
onError: { target: "uploading" }
|
|
3729
4666
|
} },
|
|
3730
|
-
capturingBarcode: {
|
|
3731
|
-
entry: [
|
|
3732
|
-
"captureImage",
|
|
3733
|
-
"storeCapturedCanvasInProvider",
|
|
3734
|
-
"storeCapturedImage",
|
|
3735
|
-
"pauseRecordingForAttempt"
|
|
3736
|
-
],
|
|
3737
|
-
always: [{ target: "submittingBarcodePreCapture" }]
|
|
3738
|
-
},
|
|
4667
|
+
capturingBarcode: { always: [{ target: "submittingBarcodePreCapture" }] },
|
|
3739
4668
|
submittingBarcodePreCapture: { invoke: {
|
|
3740
4669
|
id: "submitBarcode",
|
|
3741
4670
|
src: "submitBarcode",
|
|
@@ -3752,13 +4681,8 @@ const idCaptureMachine = setup({
|
|
|
3752
4681
|
onError: { target: "choosingDetectionStrategy" }
|
|
3753
4682
|
} },
|
|
3754
4683
|
capturingManual: {
|
|
3755
|
-
entry:
|
|
3756
|
-
|
|
3757
|
-
"storeCapturedCanvasInProvider",
|
|
3758
|
-
"storeCapturedImage",
|
|
3759
|
-
"pauseRecordingForAttempt"
|
|
3760
|
-
],
|
|
3761
|
-
always: [
|
|
4684
|
+
entry: "finalizeProtectedAttempt",
|
|
4685
|
+
on: { PROTECTED_ATTEMPT_FINALIZED_SIGNAL: [
|
|
3762
4686
|
{
|
|
3763
4687
|
target: "optimizingHold",
|
|
3764
4688
|
guard: and([
|
|
@@ -3767,6 +4691,10 @@ const idCaptureMachine = setup({
|
|
|
3767
4691
|
"supportsOptimizingStatus"
|
|
3768
4692
|
])
|
|
3769
4693
|
},
|
|
4694
|
+
{
|
|
4695
|
+
target: "uploading",
|
|
4696
|
+
guard: not("isCaptureOnlyDelivery")
|
|
4697
|
+
},
|
|
3770
4698
|
{
|
|
3771
4699
|
target: "uploading",
|
|
3772
4700
|
guard: "hasCapturedImage"
|
|
@@ -3778,44 +4706,35 @@ const idCaptureMachine = setup({
|
|
|
3778
4706
|
attemptsRemaining: context.attemptsRemaining - 1
|
|
3779
4707
|
}))
|
|
3780
4708
|
}
|
|
3781
|
-
]
|
|
4709
|
+
] }
|
|
3782
4710
|
},
|
|
3783
4711
|
optimizingHold: { after: { optimizingDwell: { target: "uploading" } } },
|
|
3784
4712
|
uploading: {
|
|
3785
|
-
entry:
|
|
4713
|
+
entry: [
|
|
4714
|
+
assign({ uploadProgress: () => 1 }),
|
|
4715
|
+
"requestProtectedUpload",
|
|
4716
|
+
"bindCaptureOnlyDelivery"
|
|
4717
|
+
],
|
|
3786
4718
|
invoke: [{
|
|
3787
4719
|
id: "uploadProgressTicker",
|
|
3788
4720
|
src: "uploadProgressTicker"
|
|
3789
4721
|
}, {
|
|
3790
|
-
id: "
|
|
3791
|
-
src: "
|
|
3792
|
-
input: ({ context
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
deepsightService: context.deepsightService,
|
|
3807
|
-
stream: context.stream,
|
|
3808
|
-
isSecondId: context.config.isSecondId ?? false,
|
|
3809
|
-
onlyFront: type === "front" && (context.config.onlyFront ?? false),
|
|
3810
|
-
ageAssurance: context.config.ageAssurance,
|
|
3811
|
-
dependencies: context.dependencies,
|
|
3812
|
-
captureResolution: context.captureResolution,
|
|
3813
|
-
cameraFallbackLevel: context.cameraFallbackLevel,
|
|
3814
|
-
extractIdFace: context.config.extractIdFace,
|
|
3815
|
-
croppedCanvas: context.provider?.getCapturedCanvas() ?? null
|
|
3816
|
-
};
|
|
3817
|
-
},
|
|
3818
|
-
onDone: {
|
|
4722
|
+
id: "captureOnlyDelivery",
|
|
4723
|
+
src: "captureOnlyDelivery",
|
|
4724
|
+
input: ({ context }) => {
|
|
4725
|
+
if (!isCaptureOnlyConfig(context.config)) return { mode: "protected" };
|
|
4726
|
+
return { mode: "captureOnly" };
|
|
4727
|
+
}
|
|
4728
|
+
}],
|
|
4729
|
+
after: { [UPLOAD_TIMEOUT_MS]: {
|
|
4730
|
+
target: "uploadError",
|
|
4731
|
+
actions: assign(({ context }) => ({
|
|
4732
|
+
uploadError: ID_ERROR_CODES.UPLOAD_ERROR,
|
|
4733
|
+
attemptsRemaining: context.attemptsRemaining - 1
|
|
4734
|
+
}))
|
|
4735
|
+
} },
|
|
4736
|
+
on: {
|
|
4737
|
+
CAPTURE_ONLY_DELIVERY_DONE: {
|
|
3819
4738
|
target: "uploadCompleted",
|
|
3820
4739
|
actions: [assign({
|
|
3821
4740
|
uploadResponse: ({ event }) => event.output,
|
|
@@ -3823,22 +4742,17 @@ const idCaptureMachine = setup({
|
|
|
3823
4742
|
skipProcessId: ({ context, event }) => event.output.idValidationCompleted === true || context.skipProcessId
|
|
3824
4743
|
}), "storeCapturedImage"]
|
|
3825
4744
|
},
|
|
3826
|
-
|
|
4745
|
+
CAPTURE_ONLY_DELIVERY_FAILED: {
|
|
3827
4746
|
target: "uploadError",
|
|
3828
4747
|
actions: assign(({ context, event }) => ({
|
|
3829
4748
|
uploadError: getIdErrorCodeFromUnknown(event.error) ?? ID_ERROR_CODES.UPLOAD_ERROR,
|
|
3830
4749
|
attemptsRemaining: context.attemptsRemaining - 1
|
|
3831
4750
|
}))
|
|
3832
|
-
}
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
uploadError: ID_ERROR_CODES.UPLOAD_ERROR,
|
|
3838
|
-
attemptsRemaining: context.attemptsRemaining - 1
|
|
3839
|
-
}))
|
|
3840
|
-
} },
|
|
3841
|
-
on: {
|
|
4751
|
+
},
|
|
4752
|
+
PROTECTED_UPLOAD_DONE_SIGNAL: {
|
|
4753
|
+
target: "uploadCompleted",
|
|
4754
|
+
actions: "storeProtectedUploadResponse"
|
|
4755
|
+
},
|
|
3842
4756
|
UPLOAD_PROGRESS: { actions: assign({ uploadProgress: ({ context, event }) => Math.max(context.uploadProgress ?? 0, Math.round(event.progress / 100 * 80)) }) },
|
|
3843
4757
|
UPLOAD_PROGRESS_TICK: { actions: assign({ uploadProgress: ({ context }) => Math.min(95, (context.uploadProgress ?? 0) + 1) }) }
|
|
3844
4758
|
}
|
|
@@ -3881,7 +4795,7 @@ const idCaptureMachine = setup({
|
|
|
3881
4795
|
] },
|
|
3882
4796
|
uploadError: { on: { CONTINUE_FROM_ERROR: [
|
|
3883
4797
|
{
|
|
3884
|
-
target: "
|
|
4798
|
+
target: "releasingForRetry",
|
|
3885
4799
|
guard: "hasAttemptsRemaining",
|
|
3886
4800
|
actions: [
|
|
3887
4801
|
"resetDetection",
|
|
@@ -3905,7 +4819,6 @@ const idCaptureMachine = setup({
|
|
|
3905
4819
|
}
|
|
3906
4820
|
] } },
|
|
3907
4821
|
success: {
|
|
3908
|
-
entry: ["stopMediaRecording", "clearRecordingSession"],
|
|
3909
4822
|
exit: "clearBarcodeFastPathCaptured",
|
|
3910
4823
|
on: { NEXT_STEP: [
|
|
3911
4824
|
{
|
|
@@ -3946,28 +4859,8 @@ const idCaptureMachine = setup({
|
|
|
3946
4859
|
cameraInit: {
|
|
3947
4860
|
initial: "checking",
|
|
3948
4861
|
states: {
|
|
3949
|
-
checking: { always:
|
|
3950
|
-
|
|
3951
|
-
guard: "hasStream"
|
|
3952
|
-
}, { target: "initializingStream" }] },
|
|
3953
|
-
initializingStream: { invoke: {
|
|
3954
|
-
id: "frontFinishedInitCamera",
|
|
3955
|
-
src: "initializeCamera",
|
|
3956
|
-
input: ({ context }) => ({
|
|
3957
|
-
config: context.config,
|
|
3958
|
-
deepsightService: context.deepsightService
|
|
3959
|
-
}),
|
|
3960
|
-
onDone: {
|
|
3961
|
-
target: "ready",
|
|
3962
|
-
actions: "setStreamAndCapturer"
|
|
3963
|
-
},
|
|
3964
|
-
onError: {
|
|
3965
|
-
target: "ready",
|
|
3966
|
-
actions: () => {
|
|
3967
|
-
console.warn("Camera initialization failed during flip transition");
|
|
3968
|
-
}
|
|
3969
|
-
}
|
|
3970
|
-
} },
|
|
4862
|
+
checking: { always: "ready" },
|
|
4863
|
+
initializingStream: { always: "ready" },
|
|
3971
4864
|
ready: { type: "final" }
|
|
3972
4865
|
}
|
|
3973
4866
|
},
|
|
@@ -3983,10 +4876,6 @@ const idCaptureMachine = setup({
|
|
|
3983
4876
|
}
|
|
3984
4877
|
},
|
|
3985
4878
|
onDone: [{
|
|
3986
|
-
target: "#idCapture.capture.choosingDetectionStrategy",
|
|
3987
|
-
guard: "hasStream",
|
|
3988
|
-
actions: "clearFlipPreview"
|
|
3989
|
-
}, {
|
|
3990
4879
|
target: "#idCapture.capture",
|
|
3991
4880
|
actions: "clearFlipPreview"
|
|
3992
4881
|
}]
|
|
@@ -3998,28 +4887,8 @@ const idCaptureMachine = setup({
|
|
|
3998
4887
|
cameraInit: {
|
|
3999
4888
|
initial: "checking",
|
|
4000
4889
|
states: {
|
|
4001
|
-
checking: { always:
|
|
4002
|
-
|
|
4003
|
-
guard: "hasStream"
|
|
4004
|
-
}, { target: "initializingStream" }] },
|
|
4005
|
-
initializingStream: { invoke: {
|
|
4006
|
-
id: "backFinishedInitCamera",
|
|
4007
|
-
src: "initializeCamera",
|
|
4008
|
-
input: ({ context }) => ({
|
|
4009
|
-
config: context.config,
|
|
4010
|
-
deepsightService: context.deepsightService
|
|
4011
|
-
}),
|
|
4012
|
-
onDone: {
|
|
4013
|
-
target: "ready",
|
|
4014
|
-
actions: "setStreamAndCapturer"
|
|
4015
|
-
},
|
|
4016
|
-
onError: {
|
|
4017
|
-
target: "ready",
|
|
4018
|
-
actions: () => {
|
|
4019
|
-
console.warn("Camera initialization failed during flip transition");
|
|
4020
|
-
}
|
|
4021
|
-
}
|
|
4022
|
-
} },
|
|
4890
|
+
checking: { always: "ready" },
|
|
4891
|
+
initializingStream: { always: "ready" },
|
|
4023
4892
|
ready: { type: "final" }
|
|
4024
4893
|
}
|
|
4025
4894
|
},
|
|
@@ -4035,10 +4904,6 @@ const idCaptureMachine = setup({
|
|
|
4035
4904
|
}
|
|
4036
4905
|
},
|
|
4037
4906
|
onDone: [{
|
|
4038
|
-
target: "#idCapture.capture.choosingDetectionStrategy",
|
|
4039
|
-
guard: "hasStream",
|
|
4040
|
-
actions: "clearFlipPreview"
|
|
4041
|
-
}, {
|
|
4042
4907
|
target: "#idCapture.capture",
|
|
4043
4908
|
actions: "clearFlipPreview"
|
|
4044
4909
|
}]
|
|
@@ -4140,25 +5005,16 @@ const idCaptureMachine = setup({
|
|
|
4140
5005
|
entry: [
|
|
4141
5006
|
"stopMediaRecording",
|
|
4142
5007
|
"stopMediaStream",
|
|
4143
|
-
"disposeProvider"
|
|
4144
|
-
"cleanupDeepsight"
|
|
5008
|
+
"disposeProvider"
|
|
4145
5009
|
],
|
|
4146
5010
|
type: "final"
|
|
4147
5011
|
},
|
|
4148
5012
|
closed: {
|
|
4149
|
-
entry: [
|
|
4150
|
-
"stopMediaStream",
|
|
4151
|
-
"disposeProvider",
|
|
4152
|
-
"cleanupDeepsight"
|
|
4153
|
-
],
|
|
5013
|
+
entry: ["stopMediaStream", "disposeProvider"],
|
|
4154
5014
|
type: "final"
|
|
4155
5015
|
},
|
|
4156
5016
|
error: {
|
|
4157
|
-
entry: [
|
|
4158
|
-
"stopMediaStream",
|
|
4159
|
-
"disposeProvider",
|
|
4160
|
-
"cleanupDeepsight"
|
|
4161
|
-
],
|
|
5017
|
+
entry: ["stopMediaStream", "disposeProvider"],
|
|
4162
5018
|
on: { RESET: {
|
|
4163
5019
|
target: "idle",
|
|
4164
5020
|
actions: "resetContext"
|
|
@@ -4242,7 +5098,7 @@ const idCaptureMachine = setup({
|
|
|
4242
5098
|
invoke: {
|
|
4243
5099
|
id: "readPendingDigitalIdRedirect",
|
|
4244
5100
|
src: "readPendingDigitalIdRedirect",
|
|
4245
|
-
input: ({ context }) => ({ storage: context.dependencies
|
|
5101
|
+
input: ({ context }) => ({ storage: resolveIdCaptureDependencies(context.dependencies).storage }),
|
|
4246
5102
|
onDone: [
|
|
4247
5103
|
{
|
|
4248
5104
|
guard: "hasPendingDigitalIdRedirect",
|
|
@@ -4276,7 +5132,7 @@ const idCaptureMachine = setup({
|
|
|
4276
5132
|
returnUrl: context.config.digitalIdReturnUrl,
|
|
4277
5133
|
country: method?.country
|
|
4278
5134
|
},
|
|
4279
|
-
storage: context.dependencies
|
|
5135
|
+
storage: resolveIdCaptureDependencies(context.dependencies).storage,
|
|
4280
5136
|
autoStart: true,
|
|
4281
5137
|
resume: resuming ? {
|
|
4282
5138
|
verificationId: context.digitalIdResumeVerificationId,
|
|
@@ -4362,5 +5218,21 @@ const idCaptureMachine = setup({
|
|
|
4362
5218
|
}
|
|
4363
5219
|
}
|
|
4364
5220
|
});
|
|
5221
|
+
/**
|
|
5222
|
+
* Composes the protected children around one controller without placing that
|
|
5223
|
+
* authority in any actor input or public machine context.
|
|
5224
|
+
*/
|
|
5225
|
+
function provideIdProtectedCaptureController(machine, controller) {
|
|
5226
|
+
return machine.provide({
|
|
5227
|
+
actors: {
|
|
5228
|
+
protectedAttempt: createProtectedIdAttemptActor(controller),
|
|
5229
|
+
protectedControllerLifetime: createProtectedIdControllerLifetimeActor(controller)
|
|
5230
|
+
},
|
|
5231
|
+
actions: { attachProtectedController: assign(({ self }) => {
|
|
5232
|
+
attachIdProtectedCaptureController(self, controller);
|
|
5233
|
+
return {};
|
|
5234
|
+
}) }
|
|
5235
|
+
});
|
|
5236
|
+
}
|
|
4365
5237
|
//#endregion
|
|
4366
|
-
export {
|
|
5238
|
+
export { createIdProtectedCaptureController as a, DIGITAL_ID_DOCUMENT_TYPES as c, resolveDigitalIdImplementation as d, MANUAL_UPLOAD_EXHAUSTION_FORWARD_MS as f, resolveWalletPlatform as h, createIdCaptureOnlyDeliveryActor as i, DIGITAL_ID_REGISTRY as l, MANUAL_UPLOAD_MAX_RETRIES as m, provideIdProtectedCaptureController as n, findIdProtectedCaptureController as o, MANUAL_UPLOAD_MAX_FILE_SIZE_BYTES as p, attachIdProtectedCaptureController as r, getManualUploadTabs as s, idCaptureMachine as t, isRedirectFlowType as u };
|