@incodetech/core 2.2.0 → 2.3.0-rc.1
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/THIRD_PARTY_NOTICES.txt +281 -0
- package/dist/BaseWasmProvider-Dyi6dKp1.d.ts +65 -0
- package/dist/{BrowserDiagnosticsCryptoProvider-B8vorxN5.esm.js → BrowserDiagnosticsCryptoProvider-CU6kBvqv.esm.js} +1 -1
- package/dist/{BrowserVisibilityObserverProvider-BX1BiLDK.esm.js → BrowserVisibilityObserverProvider-BrJN1B8A.esm.js} +2 -0
- package/dist/FaceDetectionProvider-BfhWkK90.esm.js +431 -0
- package/dist/FaceDetectionProvider-LdZ47bWy.d.ts +36 -0
- package/dist/{IIdCaptureCapability-DHTT3FC2.d.ts → IIdCaptureCapability-RNiFhvXR.d.ts} +7 -33
- package/dist/IWasmUtilCapability-CNWRl7jr.d.ts +117 -0
- package/dist/{MotionSensorProvider-DGiV77J_.esm.js → MotionSensorProvider-BgTYwg9L.esm.js} +1 -1
- package/dist/{StreamCanvasCapture-D2XcXCZ4.esm.js → StreamCanvasCapture-C9jtgBdT.esm.js} +2 -2
- package/dist/{deepsightService-DLVQS_RH.d.ts → StreamCanvasCapture-_8gdW5Lk.d.ts} +54 -41
- package/dist/StreamCanvasProcessingSession-CBnbTnOr.esm.js +42 -0
- package/dist/{addressSearch-D1XpBdUS.esm.js → addressSearch-DyHGgeX8.esm.js} +1 -1
- package/dist/advanceableErrors-CpF2cBy6.esm.js +21 -0
- package/dist/ae-signature.d.ts +4 -2
- package/dist/ae-signature.esm.js +1 -1
- package/dist/antifraud.esm.js +2 -2
- package/dist/{antifraudManager-CQFNgSPt.esm.js → antifraudManager-DNkw66oW.esm.js} +2 -2
- package/dist/{antifraudStateMachine-Bf_JVNwn.esm.js → antifraudStateMachine-DBeq47D2.esm.js} +1 -1
- package/dist/{apiError-BA1d_au0.esm.js → apiError-Budb6m6w.esm.js} +14 -2
- package/dist/authentication.d.ts +3 -3
- package/dist/authentication.esm.js +2 -2
- package/dist/{authenticationManager-BBMGTcwW.d.ts → authenticationManager-CjXBjC-c.d.ts} +7 -1
- package/dist/{authenticationManager-zh9TC62P.esm.js → authenticationManager-cMXhG70r.esm.js} +5 -5
- package/dist/{authenticationStateMachine-xzi-vnvE.esm.js → authenticationStateMachine-MOYz4HCf.esm.js} +6 -62
- package/dist/avatar.d.ts +1 -2
- package/dist/avatar.esm.js +1 -1
- package/dist/{backCameraStream-CUeYm5eu.esm.js → backCameraStream-BOtyQowf.esm.js} +83 -22
- 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/certificate-issuance.d.ts +2 -302
- package/dist/certificate-issuance.esm.js +3 -66
- package/dist/certificateIssuanceManager-C3-CI0_s.esm.js +69 -0
- package/dist/certificateIssuanceManager-DCgEidHz.d.ts +312 -0
- package/dist/{certificateIssuanceStateMachine-D_R92TYu.esm.js → certificateIssuanceStateMachine-CxqS_nD-.esm.js} +1 -1
- package/dist/consent.d.ts +1 -1
- package/dist/consent.esm.js +2 -2
- package/dist/{consentManager-BxjpLZAG.esm.js → consentManager-B6E1XJDw.esm.js} +2 -2
- package/dist/{consentManager-3Pbtj-RV.d.ts → consentManager-BhYFeKiG.d.ts} +4 -4
- package/dist/{consentStateMachine-D9D4ON8Z.esm.js → consentStateMachine-DTSfdGiW.esm.js} +1 -1
- package/dist/createCameraCycleOwnership-CX3hJGKc.esm.js +826 -0
- package/dist/{createFaceAvatar-DQKaRise.esm.js → createFaceAvatar-BNHdeFj8.esm.js} +2 -2
- package/dist/createFaceAvatar-BlcTYgJv.d.ts +497 -0
- package/dist/cross-document-data-match.esm.js +1 -1
- package/dist/{crossDocumentDataMatchManager-CGT0V6RV.esm.js → crossDocumentDataMatchManager-9XhFVZ5S.esm.js} +2 -2
- package/dist/curp-validation.d.ts +1 -1
- package/dist/curp-validation.esm.js +2 -2
- package/dist/{curpValidationManager-6Nmkn5u1.esm.js → curpValidationManager-DbIMYFcJ.esm.js} +2 -2
- package/dist/{curpValidationManager-DVGr7Fq7.d.ts → curpValidationManager-SSKNrm5Z.d.ts} +1 -1
- package/dist/{curpValidationStateMachine-Ds7KMacK.esm.js → curpValidationStateMachine-g5kMfuLj.esm.js} +1 -1
- package/dist/custom-fields.d.ts +2 -114
- package/dist/custom-fields.esm.js +2 -232
- package/dist/custom-watchlist.d.ts +2 -51
- package/dist/custom-watchlist.esm.js +3 -70
- package/dist/customFieldsManager-8-W2KY4n.d.ts +141 -0
- package/dist/customFieldsManager-CzWZTkW-.esm.js +264 -0
- package/dist/customWatchlistManager-DWTED5Ur.esm.js +73 -0
- package/dist/customWatchlistManager-PBWHr_oM.d.ts +64 -0
- package/dist/{customWatchlistStateMachine-YWSgKLbF.esm.js → customWatchlistStateMachine-DOQou6TW.esm.js} +1 -1
- package/dist/{deepsightLoader--wMKWECS.esm.js → deepsightLoader-DDv3vhXU.esm.js} +27 -71
- package/dist/device.d.ts +25 -2
- package/dist/device.esm.js +69 -7
- package/dist/document-capture.d.ts +2 -2
- package/dist/document-capture.esm.js +2 -2
- package/dist/{documentCaptureManager-DsQQhWry.esm.js → documentCaptureManager-CwAiM9WY.esm.js} +2 -2
- package/dist/{documentCaptureManager-B3t0ydtg.d.ts → documentCaptureManager-DensIj5F.d.ts} +83 -83
- package/dist/{documentCaptureStateMachine-BM4Ex_5x.esm.js → documentCaptureStateMachine-DfGOBapD.esm.js} +5 -5
- package/dist/dynamic-forms.d.ts +1 -1
- package/dist/dynamic-forms.esm.js +2 -2
- package/dist/{dynamicFormsManager-fFVIRBNv.esm.js → dynamicFormsManager-BbS-XMFc.esm.js} +16 -5
- package/dist/{dynamicFormsManager-fhK0yINk.d.ts → dynamicFormsManager-D5R_uxLQ.d.ts} +25 -3
- package/dist/{dynamicFormsStateMachine-D6D7oEYk.esm.js → dynamicFormsStateMachine-D8zHBCh4.esm.js} +35 -3
- package/dist/ekyb.d.ts +1 -1
- package/dist/ekyb.esm.js +3 -3
- package/dist/{ekybManager-Y3MkoXpC.esm.js → ekybManager-5aiac8wL.esm.js} +2 -2
- package/dist/{ekybStateMachine-3nlnqdlr.esm.js → ekybStateMachine-Bn2IE9rx.esm.js} +3 -3
- package/dist/ekyc.esm.js +2 -2
- package/dist/{ekycManager-DgT48ky6.esm.js → ekycManager-BlQ-Qj4E.esm.js} +2 -2
- package/dist/{ekycStateMachine-CQwqiR-R.esm.js → ekycStateMachine-CshSNJhh.esm.js} +2 -2
- package/dist/electronic-signature.d.ts +3 -3
- package/dist/electronic-signature.esm.js +2 -2
- package/dist/{electronicSignatureManager-DGbAJ00W.esm.js → electronicSignatureManager-BJJH0Tvi.esm.js} +357 -51
- package/dist/electronicSignatureManager-Ds-KEVTq.d.ts +2786 -0
- package/dist/email.esm.js +2 -2
- package/dist/{emailManager-BY0jeYwR.esm.js → emailManager-bR1N5rV_.esm.js} +2 -2
- package/dist/{emailStateMachine-Crw8QVmc.esm.js → emailStateMachine-Bc_6oIYw.esm.js} +1 -1
- package/dist/{endpoints-CCzL3XD_.esm.js → endpoints-B-3Q-LUw.esm.js} +24 -10
- package/dist/{events-DYiyoSlx.esm.js → events-ijlbX_Wx.esm.js} +2 -2
- package/dist/events.d.ts +1 -1
- package/dist/events.esm.js +1 -1
- package/dist/extensibility.d.ts +24 -64
- package/dist/extensibility.esm.js +35 -29
- package/dist/face-match.esm.js +2 -2
- package/dist/{faceCaptureManagerFactory-CVnZ0fa5.esm.js → faceCaptureManagerFactory-B7Ms6pSs.esm.js} +68 -7
- package/dist/{faceCaptureManagerFactory-BxWPpxyd.d.ts → faceCaptureManagerFactory-BeUl8fl1.d.ts} +86 -54
- package/dist/faceCaptureSetup-bkAlr5d8.esm.js +2067 -0
- package/dist/{faceMatchManager-Ri4UbNz0.esm.js → faceMatchManager-Bmv0HzuY.esm.js} +2 -2
- package/dist/{faceMatchStateMachine-20DdZ3jg.esm.js → faceMatchStateMachine-mRIHQ3dA.esm.js} +1 -1
- package/dist/{feature-management-CPQ4qv3F.esm.js → feature-management-E0mq0pMs.esm.js} +32 -7
- package/dist/feature-management.d.ts +1 -1
- package/dist/feature-management.esm.js +1 -1
- package/dist/field-comparison.esm.js +1 -1
- package/dist/{fieldComparisonManager-Cg6kPQQx.esm.js → fieldComparisonManager-CC-klG0h.esm.js} +2 -2
- package/dist/fiscal-qr.d.ts +2 -56
- package/dist/fiscal-qr.esm.js +2 -308
- package/dist/fiscalQrManager-B1STmT6z.d.ts +71 -0
- package/dist/fiscalQrManager-BunLVFbd.esm.js +34143 -0
- package/dist/flow-events.d.ts +1 -1
- package/dist/flow.d.ts +212 -185
- package/dist/flow.esm.js +119 -30
- package/dist/{flowCompletionService-tfeoGre9.esm.js → flowCompletionService-DJp1odGN.esm.js} +2 -2
- package/dist/{flowServices-f5Ruz7R9.esm.js → flowServices-DjPFGs_D.esm.js} +91 -26
- package/dist/geolocation.esm.js +2 -2
- package/dist/{geolocationManager-CH6RfqFH.esm.js → geolocationManager-D5906YXx.esm.js} +2 -2
- package/dist/{geolocationStateMachine-DmbWFely.esm.js → geolocationStateMachine-BVOduc3y.esm.js} +3 -3
- package/dist/getBrowser-CBiibsL-.esm.js +19 -0
- package/dist/{getBrowser-DNrQeL4T.esm.js → getBrowser-Cbe1C4Tn.esm.js} +2 -1
- package/dist/{getDeviceClass-9y-kbVDw.esm.js → getDeviceClass-5NYZg9s6.esm.js} +2 -2
- package/dist/getParsedUserAgent-B2iFDql1.esm.js +1278 -0
- package/dist/government-validation.d.ts +2 -85
- package/dist/government-validation.esm.js +3 -120
- package/dist/governmentValidationManager-CacFOtKO.esm.js +79 -0
- package/dist/governmentValidationManager-D02vT4yY.d.ts +63 -0
- package/dist/governmentValidationStateMachine-CoaZOSTP.esm.js +54 -0
- package/dist/home.d.ts +1 -1
- package/dist/home.esm.js +1 -1
- package/dist/id-ocr.d.ts +2 -2
- package/dist/id-ocr.esm.js +2 -2
- package/dist/id-selfie-flow.d.ts +3 -2
- package/dist/id-selfie-flow.esm.js +11 -10
- package/dist/id-verification.esm.js +2 -2
- package/dist/id.d.ts +29 -5
- package/dist/id.esm.js +48 -46
- package/dist/idCaptureDefaults-CbPA-Auz.esm.js +727 -0
- package/dist/{idCaptureManager-CqrqSjJV.d.ts → idCaptureManager-DKESug0R.d.ts} +230 -43
- package/dist/{idCaptureManager-BYwTZ2H8.esm.js → idCaptureManager-rfV9dIXy.esm.js} +259 -46
- package/dist/{idCaptureServices-44kwQItl.esm.js → idCaptureServices-i1KxugN7.esm.js} +285 -72
- package/dist/idCaptureStateMachine-Ne_PXth_.esm.js +5333 -0
- package/dist/{idOcrManager-DXc_xRN7.d.ts → idOcrManager-BF_cXZq8.d.ts} +1 -1
- package/dist/{idOcrManager-BIQYQXXj.esm.js → idOcrManager-r46XfZGE.esm.js} +2 -2
- package/dist/{idOcrStateMachine-cSxzHpHt.esm.js → idOcrStateMachine-ClDEP-VI.esm.js} +1 -1
- package/dist/{idVerificationManager-JpV_SAsl.esm.js → idVerificationManager-DT42c77H.esm.js} +2 -2
- package/dist/{idVerificationStateMachine-nPeUNyFq.esm.js → idVerificationStateMachine-DbDVIh9t.esm.js} +1 -1
- package/dist/identity-reuse.esm.js +2 -2
- package/dist/{identityReuseManager-kNCg9AbD.esm.js → identityReuseManager-yG3acUrQ.esm.js} +2 -2
- package/dist/{identityReuseStateMachine-DyulxDjP.esm.js → identityReuseStateMachine-BhAkuIra.esm.js} +1 -1
- package/dist/{index-CLMF0QLQ.d.ts → index-DLcJT5YP.d.ts} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/{invokeOnCaptureCallback-GpvMuz9o.esm.js → invokeOnCaptureCallback-BjzPjJ_p.esm.js} +1 -1
- package/dist/mandatory-consent.d.ts +2 -2
- package/dist/mandatory-consent.esm.js +2 -2
- package/dist/{mandatoryConsentManager-B4Niyg_u.esm.js → mandatoryConsentManager-7dI0D08q.esm.js} +2 -2
- package/dist/{mandatoryConsentManager-DyPzUmsZ.d.ts → mandatoryConsentManager-vhv1co_n.d.ts} +1 -1
- package/dist/{mandatoryConsentStateMachine-B4-1u-L8.esm.js → mandatoryConsentStateMachine-DC5Mo6M1.esm.js} +1 -1
- package/dist/multipartRecordingService-OEgIRvqC.esm.js +605 -0
- package/dist/{permissionGuards-KINpmKtI.esm.js → permissionGuards-uYZYFu4J.esm.js} +1 -1
- package/dist/{permissionServices-UvUcOSRb.esm.js → permissionServices-Bj_fyWtv.esm.js} +5 -5
- package/dist/personhood.d.ts +6 -5
- package/dist/personhood.esm.js +10 -10
- package/dist/phone.esm.js +2 -2
- package/dist/{phoneManager-FsJ0W2Ei.esm.js → phoneManager-IjhSv5XS.esm.js} +2 -2
- package/dist/{phoneStateMachine-Ba0wKHyX.esm.js → phoneStateMachine-CXdXufKg.esm.js} +1 -1
- package/dist/{platform-BJrm5nzZ.esm.js → platform-DkcRc9JV.esm.js} +29 -1
- package/dist/qe-signature.d.ts +5 -3
- package/dist/qe-signature.esm.js +2 -2
- package/dist/redirect-to-mobile.esm.js +2 -2
- package/dist/{redirectToMobileManager-y4VQB11M.esm.js → redirectToMobileManager-FLEWJtv8.esm.js} +2 -2
- package/dist/{redirectToMobileStateMachine-Cyv2x0PP.esm.js → redirectToMobileStateMachine-CSWWgUTO.esm.js} +1 -1
- package/dist/{rolldown-runtime-FZ4Itg2g.esm.js → rolldown-runtime-FDOR9p9I.esm.js} +1 -19
- package/dist/{runChildModule-Dukuw23X.esm.js → runChildModule-CI1gGWN1.esm.js} +3 -21
- package/dist/safeStorage-B-trhxg6.esm.js +423 -0
- package/dist/{sdkVersion-D1Bm59g6.esm.js → sdkVersion-BZh6dj53.esm.js} +1 -1
- package/dist/selfie.d.ts +5 -5
- package/dist/selfie.esm.js +14 -76
- package/dist/{selfieErrorUtils-C2PYBVsp.esm.js → selfieErrorUtils-UiQ46EBa.esm.js} +30 -4
- package/dist/{selfieManager-DwlCppg0.d.ts → selfieManager-4RRLi21P.d.ts} +8 -11
- package/dist/{selfieManager-Bj6B2ZVy.esm.js → selfieManager-B-2c1n_x.esm.js} +5 -5
- package/dist/selfieStateMachine-Bzx41R8d.esm.js +69 -0
- package/dist/{session-BFdLgN4i.esm.js → session-3LmvAU4S.esm.js} +4 -5
- package/dist/session.d.ts +21 -11
- package/dist/session.esm.js +5 -5
- package/dist/{sessionInitializer-dlfDehHk.esm.js → sessionInitializer-BFk33E67.esm.js} +187 -68
- package/dist/{setup-BIAtLa8k.esm.js → setup-BWG-hivt.esm.js} +226 -100
- package/dist/{setup-BgoWtvIS.d.ts → setup-Cv-JM9QC.d.ts} +63 -69
- package/dist/signature.esm.js +2 -2
- package/dist/{signatureManager-Ca43yhwk.esm.js → signatureManager-B72np4ZO.esm.js} +2 -2
- package/dist/{signatureStateMachine-K1LMRrxG.esm.js → signatureStateMachine-ce_XMA3l.esm.js} +1 -1
- package/dist/{src-0Jurt29N.esm.js → src-35ekGRzK.esm.js} +1 -1
- package/dist/{stats-B0nFKawG.esm.js → stats-CZcy2J53.esm.js} +1 -1
- package/dist/stats.esm.js +1 -1
- package/dist/{trueSightService---iW2KKJ.esm.js → trueSightService-BN-Hzw82.esm.js} +7 -7
- package/dist/trust-graph.esm.js +1 -1
- package/dist/{types-BX_XkMsQ2.d.ts → types-9_esGTPj.d.ts} +1 -1
- package/dist/types-BT_Oalip.d.ts +1 -0
- package/dist/{types-DelMqZLe.d.ts → types-BjSly8cp.d.ts} +1 -1
- package/dist/{types-Hmd7U0JA.d.ts → types-Bnl58jUQ.d.ts} +6 -85
- package/dist/types-ChAowIxT.d.ts +6 -0
- package/dist/{types-DVmXIdzW.d.ts → types-D0gekt4U.d.ts} +38 -5
- package/dist/types-DgDvvzg0.d.ts +10 -0
- package/dist/{types-KPvmag_B.d.ts → types-Do5rEXij.d.ts} +7 -4
- package/dist/{types-Bdf8_LYB2.d.ts → types-byBHOzCG2.d.ts} +305 -25
- package/dist/video-selfie.d.ts +59 -35
- package/dist/video-selfie.esm.js +510 -601
- package/dist/{videoSelfieCameraWarmer-NEhFZvWx.esm.js → videoSelfieCameraWarmer-B8PcYqmz.esm.js} +14 -153
- package/dist/videoSelfieFlowModuleMachine-BUe2uACW.esm.js +32 -0
- package/dist/{videoSelfieStepDetector-D3oo2ofo.d.ts → videoSelfieStepDetector-Co0Gu2k2.d.ts} +59 -13
- package/dist/virtualCameraCheck-Cjab7FTI.esm.js +48 -0
- package/dist/warmup-CUUnwYxe.esm.js +714 -0
- package/dist/warmup-Cis2p6O0.d.ts +128 -0
- package/dist/wasm.d.ts +30 -6
- package/dist/wasm.esm.js +36 -4
- package/dist/{wasmDsFlagSync-BqUCwLY8.esm.js → wasmDsFlagSync-B2e8p268.esm.js} +2 -2
- package/dist/{wasmWebClient-DM8lkb0z.esm.js → wasmWebClient-B7baE-Wf.esm.js} +358 -28
- package/dist/watchlist-for-business.d.ts +2 -78
- package/dist/watchlist-for-business.esm.js +3 -102
- package/dist/watchlist.esm.js +2 -2
- package/dist/watchlistForBusinessManager-CIMkpEhu.esm.js +107 -0
- package/dist/watchlistForBusinessManager-CsnJnG-C.d.ts +99 -0
- package/dist/{watchlistForBusinessStateMachine-CxFnlshm.esm.js → watchlistForBusinessStateMachine-CJ-MvUre.esm.js} +13 -6
- package/dist/{watchlistManager-LoNZH9qm.esm.js → watchlistManager-CixcLNDT.esm.js} +2 -2
- package/dist/{watchlistStateMachine-DIKQDoUT.esm.js → watchlistStateMachine-CBqk2w-h.esm.js} +1 -1
- package/dist/workflow.d.ts +12 -8
- package/dist/workflow.esm.js +48 -39
- package/package.json +4 -10
- package/dist/BrowserStorageProvider-k-FDkC4W.esm.js +0 -67
- package/dist/FaceDetectionProvider-Mh6q3EbA.d.ts +0 -349
- package/dist/IFaceAvatarCapability-BrL19G0s.d.ts +0 -23
- package/dist/IStorageCapability-ORkQfK3F.d.ts +0 -242
- package/dist/OpenViduRecordingProvider-Du98qevC.esm.js +0 -85
- package/dist/createFaceAvatar-BEj18KXi.d.ts +0 -50
- package/dist/document-upload.d.ts +0 -325
- package/dist/document-upload.esm.js +0 -197
- package/dist/electronicSignatureManager-CcUXQZS7.d.ts +0 -1300
- package/dist/faceCaptureSetup-Cd-04W_X.esm.js +0 -863
- package/dist/getBrowser-Cb8Zgrgp.esm.js +0 -7
- package/dist/getParsedUserAgent-pJjATANs.esm.js +0 -1622
- package/dist/governmentValidationStateMachine-CK9DrZXX.esm.js +0 -226
- package/dist/idCaptureDefaults-WeHbQM7W.esm.js +0 -225
- package/dist/idCaptureStateMachine-kZ5OpdfM.esm.js +0 -3342
- package/dist/lib-DAyUtOTj.esm.js +0 -12420
- package/dist/manualReviewService-D4IkipnN.esm.js +0 -15
- package/dist/mediaRecorderOptions-dALSV8af.esm.js +0 -40
- package/dist/onDeviceFaceResults-CUHwyZT4.esm.js +0 -646
- package/dist/openviduLazy-CCDpFWg1.esm.js +0 -10
- package/dist/recordingService-3NSENVwp.esm.js +0 -329
- package/dist/safeStorage-Ep56I-f_.esm.js +0 -982
- package/dist/selfieStateMachine-CHV_WNst.esm.js +0 -55
- package/dist/trueSight-B_icM8r2.esm.js +0 -1
- package/dist/types-EELWyWpd.d.ts +0 -6
- package/dist/types-Vb4P9ovf.d.ts +0 -22
- package/dist/warmup-Dv2alr2-.d.ts +0 -82
- package/dist/wasmDefaults-DTUrftxR.esm.js +0 -125
- 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/{types-BfgmV7s72.d.ts → types-BfgmV7s7.d.ts} +0 -0
- /package/dist/{types-CJ7Yl9K-2.d.ts → types-CJ7Yl9K-.d.ts} +0 -0
|
@@ -1,3342 +0,0 @@
|
|
|
1
|
-
import { t as BrowserTimerProvider } from "./BrowserTimerProvider-BXhgNxLt.esm.js";
|
|
2
|
-
import { s as exposeExperimentOnce } from "./feature-management-CPQ4qv3F.esm.js";
|
|
3
|
-
import { n as revokeObjectURL } from "./IBrowserEnvironmentCapability-DEaRRk-R.esm.js";
|
|
4
|
-
import { r as getToken, t as api } from "./api-Bx3gKW_y.esm.js";
|
|
5
|
-
import { c as trueSightHintTransition, l as trueSightLog, r as noteTrueSightCaptureActivity } from "./trueSightService---iW2KKJ.esm.js";
|
|
6
|
-
import { n as eventModuleNames, s as recordExperimentAssignmentOnce } from "./events-DYiyoSlx.esm.js";
|
|
7
|
-
import { t as getDisableIpify } from "./sessionInitializer-dlfDehHk.esm.js";
|
|
8
|
-
import "./trueSight-B_icM8r2.esm.js";
|
|
9
|
-
import { t as addDeviceStats } from "./stats-B0nFKawG.esm.js";
|
|
10
|
-
import { t as isAndroid } from "./platform-BJrm5nzZ.esm.js";
|
|
11
|
-
import "./session-BFdLgN4i.esm.js";
|
|
12
|
-
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";
|
|
13
|
-
import { n as fromPromise, t as fromCallback } from "./xstate-actors.esm-BXeQ-Ucz.esm.js";
|
|
14
|
-
import { n as invokeRequestPermissionActor, t as checkPermission } from "./permissionServices-UvUcOSRb.esm.js";
|
|
15
|
-
import { _ as StreamCanvasProcessingSession } from "./onDeviceFaceResults-CUHwyZT4.esm.js";
|
|
16
|
-
import { t as sleep } from "./ITimerCapability-DgdDzp8G.esm.js";
|
|
17
|
-
import { t as IncodeCanvas } from "./canvas-E1zGkel4.esm.js";
|
|
18
|
-
import { t as getBrowser } from "./getBrowser-DNrQeL4T.esm.js";
|
|
19
|
-
import { n as getWindowDimensions } from "./getDeviceClass-CeBiEayS.esm.js";
|
|
20
|
-
import { t as StreamCanvasCapture } from "./StreamCanvasCapture-D2XcXCZ4.esm.js";
|
|
21
|
-
import { n as needsMotionPrimeOnlyFromPermission, r as resolveStoredPermissionResult, t as isReadyForCaptureFromPermission } from "./permissionGuards-KINpmKtI.esm.js";
|
|
22
|
-
import { n as flagIdManualReview } from "./manualReviewService-D4IkipnN.esm.js";
|
|
23
|
-
import { _ as getIdCameraStream, a as processId, c as stopStream, d as validateUploadResponse, f as ID_ERROR_CODES, g as OPTIMIZING_WATCHDOG_MARGIN_MS, h as CAPTURE_OPTIMIZING, i as preloadIdRecordingProvider, l as uploadIdImage, m as resolveIdCaptureThresholds, o as startRecordingSession, r as initializeIdCapture, s as stopRecording, t as addBarcode, u as uploadManualIdFile } from "./idCaptureServices-44kwQItl.esm.js";
|
|
24
|
-
//#region src/modules/id/digitalUpload/digitalUploadErrors.ts
|
|
25
|
-
const TERMINAL_FAIL_REASONS = /* @__PURE__ */ new Set(["DIGITAL_ID_REQUESTED_BUT_OTHER_PROVIDED", "ID_TYPE_UNACCEPTABLE"]);
|
|
26
|
-
function isKnownFailReason(reason) {
|
|
27
|
-
return reason === "DIGITAL_ID_REQUESTED_BUT_OTHER_PROVIDED" || reason === "ID_TYPE_UNACCEPTABLE" || reason === "FILE_CHANGED_ERROR" || reason === "NETWORK_ERROR" || reason === "GENERIC";
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Maps a digital-upload response to the UI's failure reason, or `null` when
|
|
31
|
-
* the upload is a success.
|
|
32
|
-
*
|
|
33
|
-
* Failure detection is layered so we don't lose backend rejections that V2
|
|
34
|
-
* was previously dropping (V1 parity): explicit `failReason` first, then a
|
|
35
|
-
* "this document isn't accepted" signal (`acceptedDocuments` populated or
|
|
36
|
-
* `classification === false`) which maps to `ID_TYPE_UNACCEPTABLE`, then
|
|
37
|
-
* the bare `success === false` fallback as a generic rejection.
|
|
38
|
-
*/
|
|
39
|
-
function mapDigitalIdFailReason(response) {
|
|
40
|
-
if (!response) return null;
|
|
41
|
-
const { failReason } = response;
|
|
42
|
-
if (typeof failReason === "string" && failReason.length > 0) return isKnownFailReason(failReason) ? failReason : "GENERIC";
|
|
43
|
-
if (response.acceptedDocuments != null && response.acceptedDocuments.length > 0 || response.classification === false) return "ID_TYPE_UNACCEPTABLE";
|
|
44
|
-
if (response.success === false) return "GENERIC";
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
function isTerminalDigitalIdFailReason(response) {
|
|
48
|
-
return typeof response?.failReason === "string" && TERMINAL_FAIL_REASONS.has(response.failReason);
|
|
49
|
-
}
|
|
50
|
-
function classifyNetworkError(err) {
|
|
51
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
52
|
-
if (message.includes("ERR_UPLOAD_FILE_CHANGED") || message.includes("file changed") || message.includes("FILE_CHANGED")) return "FILE_CHANGED_ERROR";
|
|
53
|
-
return "NETWORK_ERROR";
|
|
54
|
-
}
|
|
55
|
-
//#endregion
|
|
56
|
-
//#region src/modules/id/digitalUpload/digitalUploadServices.ts
|
|
57
|
-
const DIGITAL_ID_UPLOAD_PATH = "/omni/add/front-id";
|
|
58
|
-
async function uploadDigitalIdFile(params) {
|
|
59
|
-
const { file, signal, onProgress, extractIdFace } = params;
|
|
60
|
-
const query = { idType: "DigitalId" };
|
|
61
|
-
if (extractIdFace === false) query.extractIdFace = false;
|
|
62
|
-
const response = await api.post(DIGITAL_ID_UPLOAD_PATH, file, {
|
|
63
|
-
query,
|
|
64
|
-
headers: { "Content-Type": file.type || "application/pdf" },
|
|
65
|
-
onUploadProgress: onProgress,
|
|
66
|
-
signal
|
|
67
|
-
});
|
|
68
|
-
if (!response.ok) throw new Error(`POST ${DIGITAL_ID_UPLOAD_PATH} failed: ${response.status}`);
|
|
69
|
-
return {
|
|
70
|
-
...response.data,
|
|
71
|
-
uploadDurationMs: 0
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
const DIGITAL_UPLOAD_HOLDING_TIMEOUT_MS = 8e3;
|
|
75
|
-
const DIGITAL_UPLOAD_ALLOWED_MIME_TYPES = ["application/pdf"];
|
|
76
|
-
//#endregion
|
|
77
|
-
//#region src/modules/id/digitalUpload/digitalUploadStateMachine.ts
|
|
78
|
-
const uploadDigitalIdActor = fromPromise(async ({ input, signal }) => {
|
|
79
|
-
return uploadDigitalIdFile({
|
|
80
|
-
file: input.file,
|
|
81
|
-
signal: input.signal ?? signal,
|
|
82
|
-
onProgress: input.onProgress,
|
|
83
|
-
extractIdFace: input.extractIdFace
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
const getUploadResponseFromEvent$1 = (event) => {
|
|
87
|
-
if (!("output" in event)) return;
|
|
88
|
-
return event.output;
|
|
89
|
-
};
|
|
90
|
-
const digitalUploadMachine = setup({
|
|
91
|
-
types: {
|
|
92
|
-
context: {},
|
|
93
|
-
events: {},
|
|
94
|
-
input: {},
|
|
95
|
-
output: {}
|
|
96
|
-
},
|
|
97
|
-
actors: { uploadDigitalId: uploadDigitalIdActor },
|
|
98
|
-
actions: {
|
|
99
|
-
requestPickerIfPending: assign(({ context }) => {
|
|
100
|
-
if (!context.pendingPickerAutoOpen) return {};
|
|
101
|
-
return {
|
|
102
|
-
pickerRequestId: context.pickerRequestId + 1,
|
|
103
|
-
pendingPickerAutoOpen: false
|
|
104
|
-
};
|
|
105
|
-
}),
|
|
106
|
-
setPendingPickerAutoOpen: assign(() => ({ pendingPickerAutoOpen: true })),
|
|
107
|
-
storeSelectedFile: assign(({ event }) => {
|
|
108
|
-
if (event.type !== "FILE_PICKED") return {};
|
|
109
|
-
return {
|
|
110
|
-
file: event.file,
|
|
111
|
-
failReason: null
|
|
112
|
-
};
|
|
113
|
-
}),
|
|
114
|
-
clearSelectedFile: assign(() => ({
|
|
115
|
-
file: null,
|
|
116
|
-
uploadProgress: 0,
|
|
117
|
-
failReason: null,
|
|
118
|
-
response: void 0,
|
|
119
|
-
uploadDurationMs: void 0
|
|
120
|
-
})),
|
|
121
|
-
setInvalidFileTypeError: assign(() => ({ failReason: "INVALID_FILE_TYPE" })),
|
|
122
|
-
setUploadProgressCapped: assign(({ event }) => {
|
|
123
|
-
if (event.type !== "UPLOAD_PROGRESS") return {};
|
|
124
|
-
return { uploadProgress: Math.min(90, Math.max(0, event.progress)) };
|
|
125
|
-
}),
|
|
126
|
-
setUploadProgressCompleted: assign(() => ({ uploadProgress: 100 })),
|
|
127
|
-
storeUploadResponse: assign(({ event }) => {
|
|
128
|
-
if (!("output" in event)) return {};
|
|
129
|
-
const output = event;
|
|
130
|
-
return {
|
|
131
|
-
response: output.output,
|
|
132
|
-
uploadDurationMs: output.output.uploadDurationMs
|
|
133
|
-
};
|
|
134
|
-
}),
|
|
135
|
-
setFailReasonFromResponse: assign(({ event }) => {
|
|
136
|
-
if (!("output" in event)) return {};
|
|
137
|
-
const response = event.output;
|
|
138
|
-
return { failReason: mapDigitalIdFailReason(response) ?? "GENERIC" };
|
|
139
|
-
}),
|
|
140
|
-
setFailReasonFromNetworkError: assign(({ event }) => {
|
|
141
|
-
if (!("error" in event)) return {};
|
|
142
|
-
return { failReason: classifyNetworkError(event.error) };
|
|
143
|
-
}),
|
|
144
|
-
decrementAttemptOnFailure: assign(({ context }) => ({ attemptsRemaining: Math.max(0, context.attemptsRemaining - 1) }))
|
|
145
|
-
},
|
|
146
|
-
guards: {
|
|
147
|
-
isSelectedFileTooLarge: ({ event }) => event.type === "FILE_PICKED" && event.file.size > 5242880,
|
|
148
|
-
isSelectedFileMimeInvalid: ({ event }) => event.type === "FILE_PICKED" && !DIGITAL_UPLOAD_ALLOWED_MIME_TYPES.includes(event.file.type),
|
|
149
|
-
hasSelectedFile: ({ context }) => context.file !== null,
|
|
150
|
-
responseHasFailReason: ({ event }) => mapDigitalIdFailReason(getUploadResponseFromEvent$1(event)) !== null,
|
|
151
|
-
hasAttemptsRemaining: ({ context }) => context.attemptsRemaining > 0,
|
|
152
|
-
isTerminalFailReason: ({ event }) => {
|
|
153
|
-
return isTerminalDigitalIdFailReason(getUploadResponseFromEvent$1(event));
|
|
154
|
-
},
|
|
155
|
-
isCurrentFailReasonTerminal: ({ context }) => {
|
|
156
|
-
const terminalReasons = /* @__PURE__ */ new Set(["DIGITAL_ID_REQUESTED_BUT_OTHER_PROVIDED", "ID_TYPE_UNACCEPTABLE"]);
|
|
157
|
-
return context.failReason !== null && terminalReasons.has(context.failReason);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}).createMachine({
|
|
161
|
-
id: "digitalUpload",
|
|
162
|
-
initial: "decideStart",
|
|
163
|
-
context: ({ input }) => ({
|
|
164
|
-
showTutorial: input.showTutorial,
|
|
165
|
-
file: null,
|
|
166
|
-
uploadProgress: 0,
|
|
167
|
-
attemptsRemaining: input.attemptsRemaining,
|
|
168
|
-
failReason: null,
|
|
169
|
-
response: void 0,
|
|
170
|
-
uploadDurationMs: void 0,
|
|
171
|
-
pickerRequestId: 0,
|
|
172
|
-
pendingPickerAutoOpen: !input.showTutorial,
|
|
173
|
-
resultType: null,
|
|
174
|
-
extractIdFace: input.extractIdFace
|
|
175
|
-
}),
|
|
176
|
-
output: ({ context }) => ({
|
|
177
|
-
result: context.resultType ?? "exhausted",
|
|
178
|
-
attemptsRemaining: context.attemptsRemaining
|
|
179
|
-
}),
|
|
180
|
-
states: {
|
|
181
|
-
decideStart: { always: [{
|
|
182
|
-
guard: ({ context }) => context.showTutorial,
|
|
183
|
-
target: "tutorial"
|
|
184
|
-
}, { target: "selecting" }] },
|
|
185
|
-
tutorial: { on: { NEXT_STEP: {
|
|
186
|
-
target: "selecting",
|
|
187
|
-
actions: ["setPendingPickerAutoOpen"]
|
|
188
|
-
} } },
|
|
189
|
-
selecting: {
|
|
190
|
-
entry: ["requestPickerIfPending"],
|
|
191
|
-
on: { FILE_PICKED: [
|
|
192
|
-
{
|
|
193
|
-
guard: "isSelectedFileTooLarge",
|
|
194
|
-
target: "fileTooLarge",
|
|
195
|
-
actions: ["clearSelectedFile"]
|
|
196
|
-
},
|
|
197
|
-
{
|
|
198
|
-
guard: "isSelectedFileMimeInvalid",
|
|
199
|
-
target: "error",
|
|
200
|
-
actions: ["setInvalidFileTypeError"]
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
target: "reviewing",
|
|
204
|
-
actions: ["storeSelectedFile"]
|
|
205
|
-
}
|
|
206
|
-
] }
|
|
207
|
-
},
|
|
208
|
-
fileTooLarge: { on: { CHOOSE_ANOTHER: {
|
|
209
|
-
target: "selecting",
|
|
210
|
-
actions: ["clearSelectedFile", "setPendingPickerAutoOpen"]
|
|
211
|
-
} } },
|
|
212
|
-
reviewing: { on: {
|
|
213
|
-
CONFIRM: {
|
|
214
|
-
target: "uploading",
|
|
215
|
-
guard: "hasSelectedFile"
|
|
216
|
-
},
|
|
217
|
-
REPLACE: {
|
|
218
|
-
target: "selecting",
|
|
219
|
-
actions: ["setPendingPickerAutoOpen"]
|
|
220
|
-
}
|
|
221
|
-
} },
|
|
222
|
-
uploading: {
|
|
223
|
-
invoke: {
|
|
224
|
-
id: "uploadDigitalId",
|
|
225
|
-
src: "uploadDigitalId",
|
|
226
|
-
input: ({ context, self }) => ({
|
|
227
|
-
file: context.file,
|
|
228
|
-
onProgress: (progress) => {
|
|
229
|
-
self.send({
|
|
230
|
-
type: "UPLOAD_PROGRESS",
|
|
231
|
-
progress
|
|
232
|
-
});
|
|
233
|
-
},
|
|
234
|
-
extractIdFace: context.extractIdFace
|
|
235
|
-
}),
|
|
236
|
-
onDone: [
|
|
237
|
-
{
|
|
238
|
-
guard: "isTerminalFailReason",
|
|
239
|
-
target: "terminalError",
|
|
240
|
-
actions: [
|
|
241
|
-
"storeUploadResponse",
|
|
242
|
-
"setFailReasonFromResponse",
|
|
243
|
-
"decrementAttemptOnFailure"
|
|
244
|
-
]
|
|
245
|
-
},
|
|
246
|
-
{
|
|
247
|
-
guard: "responseHasFailReason",
|
|
248
|
-
target: "checkRetries",
|
|
249
|
-
actions: [
|
|
250
|
-
"storeUploadResponse",
|
|
251
|
-
"setFailReasonFromResponse",
|
|
252
|
-
"decrementAttemptOnFailure"
|
|
253
|
-
]
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
target: "success",
|
|
257
|
-
actions: ["storeUploadResponse", "setUploadProgressCompleted"]
|
|
258
|
-
}
|
|
259
|
-
],
|
|
260
|
-
onError: {
|
|
261
|
-
target: "checkRetries",
|
|
262
|
-
actions: ["setFailReasonFromNetworkError", "decrementAttemptOnFailure"]
|
|
263
|
-
}
|
|
264
|
-
},
|
|
265
|
-
initial: "analyzing",
|
|
266
|
-
states: {
|
|
267
|
-
analyzing: { after: { [DIGITAL_UPLOAD_HOLDING_TIMEOUT_MS]: { target: "holding" } } },
|
|
268
|
-
holding: {}
|
|
269
|
-
},
|
|
270
|
-
on: { UPLOAD_PROGRESS: { actions: ["setUploadProgressCapped"] } }
|
|
271
|
-
},
|
|
272
|
-
checkRetries: { always: [
|
|
273
|
-
{
|
|
274
|
-
guard: "isCurrentFailReasonTerminal",
|
|
275
|
-
target: "terminalError"
|
|
276
|
-
},
|
|
277
|
-
{
|
|
278
|
-
guard: "hasAttemptsRemaining",
|
|
279
|
-
target: "error"
|
|
280
|
-
},
|
|
281
|
-
{ target: "terminalError" }
|
|
282
|
-
] },
|
|
283
|
-
error: { on: {
|
|
284
|
-
RETRY: {
|
|
285
|
-
target: "selecting",
|
|
286
|
-
actions: ["setPendingPickerAutoOpen", "clearSelectedFile"]
|
|
287
|
-
},
|
|
288
|
-
SCAN_INSTEAD: {
|
|
289
|
-
target: "tutorial",
|
|
290
|
-
actions: ["clearSelectedFile"]
|
|
291
|
-
}
|
|
292
|
-
} },
|
|
293
|
-
terminalError: { on: { SCAN_INSTEAD: [{
|
|
294
|
-
guard: "hasAttemptsRemaining",
|
|
295
|
-
target: "tutorial",
|
|
296
|
-
actions: ["clearSelectedFile"]
|
|
297
|
-
}, { target: "exhausted" }] } },
|
|
298
|
-
exhausted: {
|
|
299
|
-
type: "final",
|
|
300
|
-
entry: assign({ resultType: "exhausted" })
|
|
301
|
-
},
|
|
302
|
-
success: { on: { NEXT_STEP: { target: "completed" } } },
|
|
303
|
-
completed: {
|
|
304
|
-
type: "final",
|
|
305
|
-
entry: assign({ resultType: "success" })
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
});
|
|
309
|
-
//#endregion
|
|
310
|
-
//#region src/modules/id/manualUpload/manualUploadErrors.ts
|
|
311
|
-
/**
|
|
312
|
-
* i18n keys for manual-upload user-facing error copy.
|
|
313
|
-
* Keep in sync with `packages/ui/src/i18n/**.json` under the `manualIdUpload.*` namespace.
|
|
314
|
-
*/
|
|
315
|
-
const MANUAL_UPLOAD_ERROR_KEYS = {
|
|
316
|
-
wrongSide: "manualIdUpload.wrongSide",
|
|
317
|
-
wrongDocument: "manualIdUpload.wrongDocument",
|
|
318
|
-
fileTooBig: "manualIdUpload.fileTooBig",
|
|
319
|
-
generic: "manualIdUpload.generic",
|
|
320
|
-
lowSharpness: "manualIdUpload.lowSharpness",
|
|
321
|
-
glareDetected: "manualIdUpload.glareDetected",
|
|
322
|
-
readabilityIssue: "manualIdUpload.readabilityIssue"
|
|
323
|
-
};
|
|
324
|
-
/**
|
|
325
|
-
* Map the server's `failReason` (plus client-side passport/ID tab mismatch and
|
|
326
|
-
* per-image quality flags) onto an i18n key. Mirrors v1's `shouldUploadAgain`
|
|
327
|
-
* branch logic in
|
|
328
|
-
* `ms-incodesmile-web/packages/incode-welcome/src/manualIdUpload/manuaIdUpload.tsx`,
|
|
329
|
-
* extended to also reject responses where the backend flagged a per-image
|
|
330
|
-
* quality issue (`correctSharpness`, `correctGlare`, or `readability`).
|
|
331
|
-
* `idQualityAttemptApproved` is intentionally ignored — v1 did not treat it
|
|
332
|
-
* as a manual-upload rejection signal.
|
|
333
|
-
*
|
|
334
|
-
* Quality flags are checked with `=== false` so missing/undefined values
|
|
335
|
-
* (older backends, partial payloads) keep the legacy "trust the server"
|
|
336
|
-
* behaviour and do not produce false positives.
|
|
337
|
-
*
|
|
338
|
-
* Returns `null` when the response represents a successful upload — the caller
|
|
339
|
-
* should treat `null` as "no error, advance to next slot".
|
|
340
|
-
*/
|
|
341
|
-
function mapFailReasonToErrorKey(response, expectedTab) {
|
|
342
|
-
const failReason = response.failReason;
|
|
343
|
-
if (failReason === "WRONG_DOCUMENT_SIDE") return MANUAL_UPLOAD_ERROR_KEYS.wrongSide;
|
|
344
|
-
if (failReason === "WRONG_ONE_SIDED_DOCUMENT" || failReason === "UNKNOWN_DOCUMENT_TYPE") return MANUAL_UPLOAD_ERROR_KEYS.wrongDocument;
|
|
345
|
-
if (failReason === "ID_TYPE_UNACCEPTABLE") return MANUAL_UPLOAD_ERROR_KEYS.wrongDocument;
|
|
346
|
-
if (expectedTab === "passport" && response.typeOfId && response.typeOfId.toLowerCase() !== "passport") return MANUAL_UPLOAD_ERROR_KEYS.wrongDocument;
|
|
347
|
-
if (expectedTab === "id" && response.typeOfId?.toLowerCase() === "passport") return MANUAL_UPLOAD_ERROR_KEYS.wrongDocument;
|
|
348
|
-
if (response.correctSharpness === false) return MANUAL_UPLOAD_ERROR_KEYS.lowSharpness;
|
|
349
|
-
if (response.correctGlare === false) return MANUAL_UPLOAD_ERROR_KEYS.glareDetected;
|
|
350
|
-
if (response.readability === false) return MANUAL_UPLOAD_ERROR_KEYS.readabilityIssue;
|
|
351
|
-
return null;
|
|
352
|
-
}
|
|
353
|
-
//#endregion
|
|
354
|
-
//#region ../infra/src/media/imageFile.ts
|
|
355
|
-
const DEFAULT_IMAGE_MIME_TYPE = "image/jpeg";
|
|
356
|
-
const DEFAULT_IMAGE_QUALITY = .92;
|
|
357
|
-
const canNormalizeImageFile = (file) => file.type.startsWith("image/") && typeof document !== "undefined" && typeof Image !== "undefined" && typeof URL !== "undefined" && typeof URL.createObjectURL === "function";
|
|
358
|
-
const readFileAsDataUrl = (file) => new Promise((resolve, reject) => {
|
|
359
|
-
const reader = new FileReader();
|
|
360
|
-
reader.onload = () => {
|
|
361
|
-
const result = reader.result;
|
|
362
|
-
if (typeof result === "string") {
|
|
363
|
-
resolve(result);
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
reject(/* @__PURE__ */ new Error("FileReader produced non-string result"));
|
|
367
|
-
};
|
|
368
|
-
reader.onerror = () => {
|
|
369
|
-
reject(reader.error ?? /* @__PURE__ */ new Error("FileReader failed"));
|
|
370
|
-
};
|
|
371
|
-
reader.readAsDataURL(file);
|
|
372
|
-
});
|
|
373
|
-
const loadImage = (url) => new Promise((resolve, reject) => {
|
|
374
|
-
const image = new Image();
|
|
375
|
-
image.onload = () => resolve(image);
|
|
376
|
-
image.onerror = () => reject(/* @__PURE__ */ new Error("Image decoding failed"));
|
|
377
|
-
image.src = url;
|
|
378
|
-
});
|
|
379
|
-
const fileToCanvasDataUrl = async (file, options) => {
|
|
380
|
-
const objectUrl = URL.createObjectURL(file);
|
|
381
|
-
try {
|
|
382
|
-
const image = await loadImage(objectUrl);
|
|
383
|
-
const width = image.naturalWidth || image.width;
|
|
384
|
-
const height = image.naturalHeight || image.height;
|
|
385
|
-
if (width <= 0 || height <= 0) return readFileAsDataUrl(file);
|
|
386
|
-
const canvas = document.createElement("canvas");
|
|
387
|
-
canvas.width = width;
|
|
388
|
-
canvas.height = height;
|
|
389
|
-
const context = canvas.getContext("2d");
|
|
390
|
-
if (!context) return readFileAsDataUrl(file);
|
|
391
|
-
context.fillStyle = "#fff";
|
|
392
|
-
context.fillRect(0, 0, width, height);
|
|
393
|
-
context.drawImage(image, 0, 0, width, height);
|
|
394
|
-
return canvas.toDataURL(options.mimeType ?? DEFAULT_IMAGE_MIME_TYPE, options.quality ?? DEFAULT_IMAGE_QUALITY);
|
|
395
|
-
} finally {
|
|
396
|
-
URL.revokeObjectURL(objectUrl);
|
|
397
|
-
}
|
|
398
|
-
};
|
|
399
|
-
const imageFileToDataUrl = async (file, options = {}) => {
|
|
400
|
-
if (!canNormalizeImageFile(file)) return readFileAsDataUrl(file);
|
|
401
|
-
try {
|
|
402
|
-
return await fileToCanvasDataUrl(file, options);
|
|
403
|
-
} catch {
|
|
404
|
-
return readFileAsDataUrl(file);
|
|
405
|
-
}
|
|
406
|
-
};
|
|
407
|
-
//#endregion
|
|
408
|
-
//#region src/modules/id/manualUpload/types.ts
|
|
409
|
-
const MANUAL_UPLOAD_MAX_RETRIES = 3;
|
|
410
|
-
const MANUAL_UPLOAD_MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;
|
|
411
|
-
const MANUAL_UPLOAD_EXHAUSTION_FORWARD_MS = 5e3;
|
|
412
|
-
//#endregion
|
|
413
|
-
//#region src/modules/id/manualUpload/manualUploadServices.ts
|
|
414
|
-
const stripDataUrlPrefix = (dataUrl) => {
|
|
415
|
-
const commaIndex = dataUrl.indexOf(",");
|
|
416
|
-
return commaIndex === -1 ? dataUrl : dataUrl.slice(commaIndex + 1);
|
|
417
|
-
};
|
|
418
|
-
const getBase64PayloadByteLength = (payload) => {
|
|
419
|
-
const normalized = payload.replace(/\s/g, "");
|
|
420
|
-
let padding = 0;
|
|
421
|
-
if (normalized.endsWith("==")) padding = 2;
|
|
422
|
-
else if (normalized.endsWith("=")) padding = 1;
|
|
423
|
-
return Math.max(0, Math.floor(normalized.length * 3 / 4) - padding);
|
|
424
|
-
};
|
|
425
|
-
const isBase64PayloadWithinSize = (payload, maxBytes) => getBase64PayloadByteLength(payload) <= maxBytes;
|
|
426
|
-
const fileToBase64Payload = async (file) => {
|
|
427
|
-
const dataUrl = await imageFileToDataUrl(file);
|
|
428
|
-
return stripDataUrlPrefix(dataUrl);
|
|
429
|
-
};
|
|
430
|
-
//#endregion
|
|
431
|
-
//#region src/modules/id/manualUpload/manualUploadStateMachine.ts
|
|
432
|
-
const uploadManualFileActor = fromPromise(async ({ input, signal }) => {
|
|
433
|
-
const base64Image = await fileToBase64Payload(input.file);
|
|
434
|
-
if (!isBase64PayloadWithinSize(base64Image, 5242880)) return { type: "fileTooLarge" };
|
|
435
|
-
return {
|
|
436
|
-
type: "uploaded",
|
|
437
|
-
response: await uploadManualIdFile({
|
|
438
|
-
side: input.side,
|
|
439
|
-
base64Image,
|
|
440
|
-
retry: input.retry,
|
|
441
|
-
onlyFront: input.onlyFront,
|
|
442
|
-
isSecondId: input.isSecondId,
|
|
443
|
-
extractIdFace: input.extractIdFace,
|
|
444
|
-
signal
|
|
445
|
-
})
|
|
446
|
-
};
|
|
447
|
-
});
|
|
448
|
-
const getUploadOutputFromEvent = (event) => {
|
|
449
|
-
if ("output" in event) return event.output;
|
|
450
|
-
};
|
|
451
|
-
const getUploadResponseFromEvent = (event) => {
|
|
452
|
-
const output = getUploadOutputFromEvent(event);
|
|
453
|
-
return output?.type === "uploaded" ? output.response : void 0;
|
|
454
|
-
};
|
|
455
|
-
const manualUploadMachine = setup({
|
|
456
|
-
types: {
|
|
457
|
-
context: {},
|
|
458
|
-
events: {},
|
|
459
|
-
input: {},
|
|
460
|
-
output: {}
|
|
461
|
-
},
|
|
462
|
-
actors: { uploadManualFile: uploadManualFileActor },
|
|
463
|
-
actions: {
|
|
464
|
-
setManualUploadActiveTab: assign(({ context, event }) => {
|
|
465
|
-
if (event.type !== "MANUAL_UPLOAD_TAB_CHANGED") return {};
|
|
466
|
-
return {
|
|
467
|
-
activeTab: event.tab,
|
|
468
|
-
errorMessage: null,
|
|
469
|
-
errorSide: null,
|
|
470
|
-
retriesLeft: context.captureAttempts
|
|
471
|
-
};
|
|
472
|
-
}),
|
|
473
|
-
resetManualUpload: assign(({ context }) => ({
|
|
474
|
-
frontFile: null,
|
|
475
|
-
backFile: null,
|
|
476
|
-
passportFile: null,
|
|
477
|
-
frontUploaded: false,
|
|
478
|
-
backUploaded: false,
|
|
479
|
-
passportUploaded: false,
|
|
480
|
-
skipBackFromServer: false,
|
|
481
|
-
errorMessage: null,
|
|
482
|
-
errorSide: null,
|
|
483
|
-
retriesLeft: context.captureAttempts
|
|
484
|
-
})),
|
|
485
|
-
storeSelectedFile: assign(({ event }) => {
|
|
486
|
-
if (event.type !== "MANUAL_UPLOAD_FILE_SELECTED") return {};
|
|
487
|
-
const updated = {
|
|
488
|
-
errorMessage: null,
|
|
489
|
-
errorSide: null
|
|
490
|
-
};
|
|
491
|
-
if (event.side === "front") updated.frontFile = event.file;
|
|
492
|
-
else if (event.side === "back") updated.backFile = event.file;
|
|
493
|
-
else updated.passportFile = event.file;
|
|
494
|
-
return updated;
|
|
495
|
-
}),
|
|
496
|
-
markFrontUploaded: assign(() => ({
|
|
497
|
-
frontUploaded: true,
|
|
498
|
-
errorMessage: null,
|
|
499
|
-
errorSide: null
|
|
500
|
-
})),
|
|
501
|
-
markBackUploaded: assign(() => ({
|
|
502
|
-
backUploaded: true,
|
|
503
|
-
errorMessage: null,
|
|
504
|
-
errorSide: null
|
|
505
|
-
})),
|
|
506
|
-
markPassportUploaded: assign(() => ({
|
|
507
|
-
passportUploaded: true,
|
|
508
|
-
errorMessage: null,
|
|
509
|
-
errorSide: null
|
|
510
|
-
})),
|
|
511
|
-
recordSkipBackFromResponse: assign(({ event }) => {
|
|
512
|
-
const response = getUploadResponseFromEvent(event);
|
|
513
|
-
if (!response) return {};
|
|
514
|
-
if (!response.skipBackIdCapture) return {};
|
|
515
|
-
return { skipBackFromServer: true };
|
|
516
|
-
}),
|
|
517
|
-
decrementManualUploadRetries: assign(({ context }) => ({ retriesLeft: Math.max(0, context.retriesLeft - 1) })),
|
|
518
|
-
setManualUploadErrorFromResponse: assign(({ context, event }) => {
|
|
519
|
-
const response = getUploadResponseFromEvent(event);
|
|
520
|
-
if (!response) return {};
|
|
521
|
-
return { errorMessage: mapFailReasonToErrorKey(response, context.activeTab) ?? "manualIdUpload.generic" };
|
|
522
|
-
}),
|
|
523
|
-
setManualUploadGenericError: assign(() => ({ errorMessage: "manualIdUpload.generic" })),
|
|
524
|
-
setManualUploadFileTooLargeError: assign(({ event }) => {
|
|
525
|
-
return {
|
|
526
|
-
errorMessage: "manualIdUpload.fileTooBig",
|
|
527
|
-
errorSide: event.type === "MANUAL_UPLOAD_FILE_SELECTED" ? event.side : null
|
|
528
|
-
};
|
|
529
|
-
}),
|
|
530
|
-
markErrorSideFront: assign(() => ({ errorSide: "front" })),
|
|
531
|
-
markErrorSideBack: assign(() => ({ errorSide: "back" })),
|
|
532
|
-
markErrorSidePassport: assign(() => ({ errorSide: "passport" })),
|
|
533
|
-
clearManualUploadError: assign(() => ({
|
|
534
|
-
errorMessage: null,
|
|
535
|
-
errorSide: null
|
|
536
|
-
}))
|
|
537
|
-
},
|
|
538
|
-
guards: {
|
|
539
|
-
isSelectedFileTooLarge: ({ event }) => {
|
|
540
|
-
if (event.type !== "MANUAL_UPLOAD_FILE_SELECTED") return false;
|
|
541
|
-
return event.file.size > MANUAL_UPLOAD_MAX_FILE_SIZE_BYTES;
|
|
542
|
-
},
|
|
543
|
-
isFrontFileSelection: ({ event }) => event.type === "MANUAL_UPLOAD_FILE_SELECTED" && event.side === "front",
|
|
544
|
-
isBackFileSelection: ({ event }) => event.type === "MANUAL_UPLOAD_FILE_SELECTED" && event.side === "back",
|
|
545
|
-
isPassportFileSelection: ({ event }) => event.type === "MANUAL_UPLOAD_FILE_SELECTED" && event.side === "passport",
|
|
546
|
-
manualUploadRetriesExhausted: ({ context }) => context.retriesLeft <= 0,
|
|
547
|
-
canContinueFromIdTab: ({ context }) => {
|
|
548
|
-
if (context.activeTab !== "id") return false;
|
|
549
|
-
if (!context.frontUploaded) return false;
|
|
550
|
-
if (context.onlyFront) return true;
|
|
551
|
-
if (context.skipBackFromServer) return true;
|
|
552
|
-
return context.backUploaded;
|
|
553
|
-
},
|
|
554
|
-
canContinueFromPassportTab: ({ context }) => context.activeTab === "passport" && context.passportUploaded,
|
|
555
|
-
manualUploadResponseHasError: ({ context, event }) => {
|
|
556
|
-
const response = getUploadResponseFromEvent(event);
|
|
557
|
-
if (!response) return false;
|
|
558
|
-
return mapFailReasonToErrorKey(response, context.activeTab) !== null;
|
|
559
|
-
},
|
|
560
|
-
manualUploadPayloadTooLarge: ({ event }) => getUploadOutputFromEvent(event)?.type === "fileTooLarge"
|
|
561
|
-
}
|
|
562
|
-
}).createMachine({
|
|
563
|
-
id: "manualUpload",
|
|
564
|
-
initial: "selecting",
|
|
565
|
-
context: ({ input }) => ({
|
|
566
|
-
onlyFront: input.onlyFront,
|
|
567
|
-
isSecondId: input.isSecondId,
|
|
568
|
-
captureAttempts: input.captureAttempts,
|
|
569
|
-
extractIdFace: input.extractIdFace,
|
|
570
|
-
frontFile: null,
|
|
571
|
-
backFile: null,
|
|
572
|
-
passportFile: null,
|
|
573
|
-
activeTab: "id",
|
|
574
|
-
retriesLeft: input.captureAttempts,
|
|
575
|
-
errorMessage: null,
|
|
576
|
-
errorSide: null,
|
|
577
|
-
skipBackFromServer: false,
|
|
578
|
-
frontUploaded: false,
|
|
579
|
-
backUploaded: false,
|
|
580
|
-
passportUploaded: false
|
|
581
|
-
}),
|
|
582
|
-
on: {
|
|
583
|
-
MANUAL_UPLOAD_TAB_CHANGED: {
|
|
584
|
-
target: ".selecting",
|
|
585
|
-
actions: ["setManualUploadActiveTab"]
|
|
586
|
-
},
|
|
587
|
-
MANUAL_UPLOAD_RESET: {
|
|
588
|
-
target: ".selecting",
|
|
589
|
-
actions: ["resetManualUpload"]
|
|
590
|
-
}
|
|
591
|
-
},
|
|
592
|
-
states: {
|
|
593
|
-
selecting: { on: {
|
|
594
|
-
MANUAL_UPLOAD_FILE_SELECTED: [
|
|
595
|
-
{
|
|
596
|
-
guard: "isSelectedFileTooLarge",
|
|
597
|
-
actions: ["setManualUploadFileTooLargeError"]
|
|
598
|
-
},
|
|
599
|
-
{
|
|
600
|
-
guard: "isFrontFileSelection",
|
|
601
|
-
target: "uploadingFront",
|
|
602
|
-
actions: ["storeSelectedFile"]
|
|
603
|
-
},
|
|
604
|
-
{
|
|
605
|
-
guard: "isBackFileSelection",
|
|
606
|
-
target: "uploadingBack",
|
|
607
|
-
actions: ["storeSelectedFile"]
|
|
608
|
-
},
|
|
609
|
-
{
|
|
610
|
-
guard: "isPassportFileSelection",
|
|
611
|
-
target: "uploadingPassport",
|
|
612
|
-
actions: ["storeSelectedFile"]
|
|
613
|
-
}
|
|
614
|
-
],
|
|
615
|
-
MANUAL_UPLOAD_CONTINUE: [{
|
|
616
|
-
guard: "canContinueFromIdTab",
|
|
617
|
-
target: "finished"
|
|
618
|
-
}, {
|
|
619
|
-
guard: "canContinueFromPassportTab",
|
|
620
|
-
target: "finished"
|
|
621
|
-
}]
|
|
622
|
-
} },
|
|
623
|
-
uploadingFront: { invoke: {
|
|
624
|
-
id: "uploadManualFile",
|
|
625
|
-
src: "uploadManualFile",
|
|
626
|
-
input: ({ context }) => ({
|
|
627
|
-
side: "front",
|
|
628
|
-
file: context.frontFile,
|
|
629
|
-
retry: context.retriesLeft < context.captureAttempts,
|
|
630
|
-
onlyFront: context.onlyFront,
|
|
631
|
-
isSecondId: context.isSecondId,
|
|
632
|
-
extractIdFace: context.extractIdFace
|
|
633
|
-
}),
|
|
634
|
-
onDone: [
|
|
635
|
-
{
|
|
636
|
-
guard: "manualUploadPayloadTooLarge",
|
|
637
|
-
target: "selecting",
|
|
638
|
-
actions: ["setManualUploadFileTooLargeError", "markErrorSideFront"]
|
|
639
|
-
},
|
|
640
|
-
{
|
|
641
|
-
guard: "manualUploadResponseHasError",
|
|
642
|
-
target: "checkRetries",
|
|
643
|
-
actions: [
|
|
644
|
-
"decrementManualUploadRetries",
|
|
645
|
-
"setManualUploadErrorFromResponse",
|
|
646
|
-
"markErrorSideFront"
|
|
647
|
-
]
|
|
648
|
-
},
|
|
649
|
-
{
|
|
650
|
-
target: "selecting",
|
|
651
|
-
actions: [
|
|
652
|
-
"markFrontUploaded",
|
|
653
|
-
"recordSkipBackFromResponse",
|
|
654
|
-
"clearManualUploadError"
|
|
655
|
-
]
|
|
656
|
-
}
|
|
657
|
-
],
|
|
658
|
-
onError: {
|
|
659
|
-
target: "checkRetries",
|
|
660
|
-
actions: [
|
|
661
|
-
"decrementManualUploadRetries",
|
|
662
|
-
"setManualUploadGenericError",
|
|
663
|
-
"markErrorSideFront"
|
|
664
|
-
]
|
|
665
|
-
}
|
|
666
|
-
} },
|
|
667
|
-
uploadingBack: { invoke: {
|
|
668
|
-
id: "uploadManualFile",
|
|
669
|
-
src: "uploadManualFile",
|
|
670
|
-
input: ({ context }) => ({
|
|
671
|
-
side: "back",
|
|
672
|
-
file: context.backFile,
|
|
673
|
-
retry: context.retriesLeft < context.captureAttempts,
|
|
674
|
-
onlyFront: false,
|
|
675
|
-
isSecondId: context.isSecondId
|
|
676
|
-
}),
|
|
677
|
-
onDone: [
|
|
678
|
-
{
|
|
679
|
-
guard: "manualUploadPayloadTooLarge",
|
|
680
|
-
target: "selecting",
|
|
681
|
-
actions: ["setManualUploadFileTooLargeError", "markErrorSideBack"]
|
|
682
|
-
},
|
|
683
|
-
{
|
|
684
|
-
guard: "manualUploadResponseHasError",
|
|
685
|
-
target: "checkRetries",
|
|
686
|
-
actions: [
|
|
687
|
-
"decrementManualUploadRetries",
|
|
688
|
-
"setManualUploadErrorFromResponse",
|
|
689
|
-
"markErrorSideBack"
|
|
690
|
-
]
|
|
691
|
-
},
|
|
692
|
-
{
|
|
693
|
-
target: "selecting",
|
|
694
|
-
actions: ["markBackUploaded", "clearManualUploadError"]
|
|
695
|
-
}
|
|
696
|
-
],
|
|
697
|
-
onError: {
|
|
698
|
-
target: "checkRetries",
|
|
699
|
-
actions: [
|
|
700
|
-
"decrementManualUploadRetries",
|
|
701
|
-
"setManualUploadGenericError",
|
|
702
|
-
"markErrorSideBack"
|
|
703
|
-
]
|
|
704
|
-
}
|
|
705
|
-
} },
|
|
706
|
-
uploadingPassport: { invoke: {
|
|
707
|
-
id: "uploadManualFile",
|
|
708
|
-
src: "uploadManualFile",
|
|
709
|
-
input: ({ context }) => ({
|
|
710
|
-
side: "passport",
|
|
711
|
-
file: context.passportFile,
|
|
712
|
-
retry: context.retriesLeft < context.captureAttempts,
|
|
713
|
-
onlyFront: false,
|
|
714
|
-
isSecondId: context.isSecondId,
|
|
715
|
-
extractIdFace: context.extractIdFace
|
|
716
|
-
}),
|
|
717
|
-
onDone: [
|
|
718
|
-
{
|
|
719
|
-
guard: "manualUploadPayloadTooLarge",
|
|
720
|
-
target: "selecting",
|
|
721
|
-
actions: ["setManualUploadFileTooLargeError", "markErrorSidePassport"]
|
|
722
|
-
},
|
|
723
|
-
{
|
|
724
|
-
guard: "manualUploadResponseHasError",
|
|
725
|
-
target: "checkRetries",
|
|
726
|
-
actions: [
|
|
727
|
-
"decrementManualUploadRetries",
|
|
728
|
-
"setManualUploadErrorFromResponse",
|
|
729
|
-
"markErrorSidePassport"
|
|
730
|
-
]
|
|
731
|
-
},
|
|
732
|
-
{
|
|
733
|
-
target: "selecting",
|
|
734
|
-
actions: ["markPassportUploaded", "clearManualUploadError"]
|
|
735
|
-
}
|
|
736
|
-
],
|
|
737
|
-
onError: {
|
|
738
|
-
target: "checkRetries",
|
|
739
|
-
actions: [
|
|
740
|
-
"decrementManualUploadRetries",
|
|
741
|
-
"setManualUploadGenericError",
|
|
742
|
-
"markErrorSidePassport"
|
|
743
|
-
]
|
|
744
|
-
}
|
|
745
|
-
} },
|
|
746
|
-
checkRetries: { always: [{
|
|
747
|
-
guard: "manualUploadRetriesExhausted",
|
|
748
|
-
target: "retriesExhausted"
|
|
749
|
-
}, { target: "selecting" }] },
|
|
750
|
-
retriesExhausted: { after: { [MANUAL_UPLOAD_EXHAUSTION_FORWARD_MS]: { target: "exhausted" } } },
|
|
751
|
-
exhausted: {
|
|
752
|
-
type: "final",
|
|
753
|
-
output: { result: "exhausted" }
|
|
754
|
-
},
|
|
755
|
-
finished: {
|
|
756
|
-
type: "final",
|
|
757
|
-
output: { result: "success" }
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
});
|
|
761
|
-
//#endregion
|
|
762
|
-
//#region src/modules/id/idCaptureGuards.ts
|
|
763
|
-
function getPermissionOutput(event) {
|
|
764
|
-
if (!("output" in event)) return;
|
|
765
|
-
const { output } = event;
|
|
766
|
-
if (typeof output === "object" && output !== null && "permissionResult" in output) return output.permissionResult;
|
|
767
|
-
return output;
|
|
768
|
-
}
|
|
769
|
-
const hasShowTutorialGuard = ({ context }) => context.config.showTutorial;
|
|
770
|
-
const hasAgeAssuranceGuard = ({ context }) => context.config.ageAssurance === true;
|
|
771
|
-
const hasShowDocumentChooserGuard = ({ context }) => !context.config.onlyBack && (context.config.showDocumentChooserScreen ?? false);
|
|
772
|
-
const isPermissionGrantedGuard = ({ event }) => {
|
|
773
|
-
return getPermissionOutput(event) === "granted";
|
|
774
|
-
};
|
|
775
|
-
const isReadyForCaptureGuard = ({ context, event }) => {
|
|
776
|
-
return isReadyForCaptureFromPermission(resolveStoredPermissionResult(getPermissionOutput(event), context.permissionResult), context.config.ds);
|
|
777
|
-
};
|
|
778
|
-
const needsMotionPrimeOnlyGuard = ({ context, event }) => {
|
|
779
|
-
return needsMotionPrimeOnlyFromPermission(resolveStoredPermissionResult(getPermissionOutput(event), context.permissionResult), context.config.ds);
|
|
780
|
-
};
|
|
781
|
-
const isPermissionDeniedErrorGuard = ({ event }) => {
|
|
782
|
-
if ("error" in event) {
|
|
783
|
-
const error = event.error;
|
|
784
|
-
return error?.name === "NotAllowedError" || error?.name === "PermissionDeniedError";
|
|
785
|
-
}
|
|
786
|
-
return false;
|
|
787
|
-
};
|
|
788
|
-
const hasStreamGuard = ({ context }) => context.stream !== void 0;
|
|
789
|
-
const hasInitializedCameraGuard = ({ context }) => context.stream !== void 0 && context.provider !== void 0;
|
|
790
|
-
const hasAttemptsRemainingGuard = ({ context }) => context.attemptsRemaining > 0;
|
|
791
|
-
const hasCapturedImageGuard = ({ context }) => {
|
|
792
|
-
return context.provider?.getCapturedCanvas() !== null;
|
|
793
|
-
};
|
|
794
|
-
const hasCandidateFrameGuard = ({ event }) => {
|
|
795
|
-
return event.type === "DETECTION_OPTIMIZING" && Boolean(event.candidateCanvas);
|
|
796
|
-
};
|
|
797
|
-
/**
|
|
798
|
-
* IDC-05: whether WASM's commit arrived while the optimizing phase was still
|
|
799
|
-
* spending its dwell, and is therefore parked in `optimizing.holding` waiting
|
|
800
|
-
* for the release.
|
|
801
|
-
*
|
|
802
|
-
* Gates the phase's own `SWITCH_TO_MANUAL_CAPTURE` / `MANUAL_CAPTURE` handlers:
|
|
803
|
-
* while a commit is parked those escapes end the dwell early instead of leaving
|
|
804
|
-
* the phase, so WASM's committed frame is honored rather than dropped on the way
|
|
805
|
-
* out. False leaves both events to the arm parent, the documented escape hatch.
|
|
806
|
-
*/
|
|
807
|
-
const hasStashedCommitGuard = ({ context }) => context.stashedCommit !== void 0;
|
|
808
|
-
const hasUploadValidationErrorGuard = ({ context }) => {
|
|
809
|
-
if (!context.uploadResponse) return false;
|
|
810
|
-
return validateUploadResponse(context.uploadResponse, {
|
|
811
|
-
skipGlareFront: context.uploadResponse.skipGlareFront,
|
|
812
|
-
skipGlareBack: context.uploadResponse.skipGlareBack
|
|
813
|
-
}) !== void 0;
|
|
814
|
-
};
|
|
815
|
-
const isFrontModeGuard = ({ context }) => context.currentMode === "front" || context.currentMode === "passport";
|
|
816
|
-
/**
|
|
817
|
-
* Single client-side authority on whether a back side is needed.
|
|
818
|
-
*
|
|
819
|
-
* `config.onlyFront` is deliberately NOT read here. The flag is forwarded to
|
|
820
|
-
* the backend as `?onlyFront=true` on the front upload
|
|
821
|
-
* (`idCaptureStateMachine` → `uploadIdImage`), and the backend answers with
|
|
822
|
-
* `skipBackIdCapture` after resolving the real per-document policy — which the
|
|
823
|
-
* flow-level flag cannot account for (`perCountryPerDocOverrides`). Honoring
|
|
824
|
-
* `onlyFront` client-side here was the ENG-45236 bug (PR #413): it skipped the
|
|
825
|
-
* back for documents that genuinely need both sides.
|
|
826
|
-
*
|
|
827
|
-
* Note `currentMode === 'passport'` is allowed through: passports are not
|
|
828
|
-
* implicitly single-side and can require a back (PR #269).
|
|
829
|
-
*
|
|
830
|
-
* The rule for when a client-side read IS legitimate (see
|
|
831
|
-
* `docs/features/ID_CAPTURE_FLOWS.md`):
|
|
832
|
-
* 1. read `config.onlyFront` only where the decision must be made before a
|
|
833
|
-
* server answer exists, and
|
|
834
|
-
* 2. where you do, still self-correct once the answer arrives.
|
|
835
|
-
*
|
|
836
|
-
* Two variants qualify under (1): the captureOnly machine
|
|
837
|
-
* (`idCaptureOnlyStateMachine` — no upload, so no answer ever exists) and the
|
|
838
|
-
* manual-upload sub-machine (slot visibility precedes any upload, and it ORs
|
|
839
|
-
* `skipBackFromServer` afterwards to satisfy (2)). This guard is on neither
|
|
840
|
-
* path — the answer is already in hand by the time it runs.
|
|
841
|
-
*/
|
|
842
|
-
const shouldContinueToBackGuard = ({ context }) => {
|
|
843
|
-
if (context.currentMode !== "front" && context.currentMode !== "passport") return false;
|
|
844
|
-
if (context.config.onlyBack) return false;
|
|
845
|
-
if (context.config.usSmartCapture) return false;
|
|
846
|
-
if (context.uploadResponse?.skipBackIdCapture) return false;
|
|
847
|
-
return true;
|
|
848
|
-
};
|
|
849
|
-
const shouldContinueToFrontGuard = ({ context }) => context.config.usSmartCapture === true && context.currentMode === "back" && context.uploadResponse?.forceFrontIdCapture === true;
|
|
850
|
-
const hasMandatoryConsentGuard = ({ context }) => context.uploadResponse?.showMandatoryConsent === true;
|
|
851
|
-
/**
|
|
852
|
-
* IDC-05 arm, as resolved once per session by
|
|
853
|
-
* `resolveCaptureOptimizingTreatment` at actor creation.
|
|
854
|
-
*/
|
|
855
|
-
const isCaptureOptimizingModeGuard = ({ context }) => context.captureFeedbackMode === "optimizing";
|
|
856
|
-
/**
|
|
857
|
-
* IDC-05 rendering-layer capability: whether the consumer opted into rendering
|
|
858
|
-
* `captureStatus === 'optimizing'`. Consumers that omit it retain the direct
|
|
859
|
-
* capture-to-upload path. Nothing is advanced by the host — core owns the phase's
|
|
860
|
-
* timing on both paths (WASM's commit on auto capture, `optimizingDwell` on
|
|
861
|
-
* manual), so there is no acknowledgement call.
|
|
862
|
-
*
|
|
863
|
-
* Paired with `isCaptureOptimizingModeGuard` at both branch sites
|
|
864
|
-
* (`choosingDetectionStrategy`, `capturingManual`). Through
|
|
865
|
-
* `createIdCaptureActor` the two can never disagree — that path derives
|
|
866
|
-
* `captureFeedbackMode` from `resolveCaptureOptimizingTreatment`, which
|
|
867
|
-
* already requires this capability — so the pairing looks redundant, and for
|
|
868
|
-
* SDK-built sessions it is.
|
|
869
|
-
*
|
|
870
|
-
* It is NOT redundant on the public surface: `idCaptureMachine` is exported from
|
|
871
|
-
* `@incodetech/core/id` and its `input.captureFeedbackMode` is settable, so a
|
|
872
|
-
* host wiring the machine up directly could otherwise reach the phase without
|
|
873
|
-
* declaring the capability. This guard is what makes the documented opt-in true
|
|
874
|
-
* for every route into the machine, not just the factory.
|
|
875
|
-
*/
|
|
876
|
-
const supportsOptimizingStatusGuard = ({ context }) => context.config.supportsOptimizingStatus === true;
|
|
877
|
-
const isDeepsightEnabledGuard = ({ context }) => context.dependencies !== void 0;
|
|
878
|
-
const isDeepsightReadyGuard = ({ context }) => context.deepsightService !== void 0;
|
|
879
|
-
const needsDeepsightInitGuard = ({ context }) => context.dependencies !== void 0 && context.deepsightService === void 0 && !context.deepsightInitAttempted;
|
|
880
|
-
const hasOnlyManualUploadAvailableGuard = ({ context }) => context.availableDocumentTypes.length === 1 && context.availableDocumentTypes[0] === "manualIdUpload";
|
|
881
|
-
/** No capture option is enabled — the ID module is misconfigured. */
|
|
882
|
-
const hasNoDocumentTypesAvailableGuard = ({ context }) => context.availableDocumentTypes.length === 0;
|
|
883
|
-
const isManualIdUploadSelectedGuard = ({ event }) => event.type === "SELECT_DOCUMENT" && event.documentType === "manualIdUpload";
|
|
884
|
-
const isDigitalIdUploadSelectedGuard = ({ event }) => event.type === "SELECT_DOCUMENT" && event.documentType === "digitalIdUpload";
|
|
885
|
-
const isUploadExpiredGuard = ({ context }) => context.uploadResponse?.isDocumentExpired === true;
|
|
886
|
-
/**
|
|
887
|
-
* True when *this* expired upload will exhaust the same-side expired budget.
|
|
888
|
-
* Compares the post-increment count, so the exhaustion branch can be picked in
|
|
889
|
-
* the same tick that runs `incrementExpiredAttempts`:
|
|
890
|
-
* - attempt 1 → 0+1=1 (not exhausted)
|
|
891
|
-
* - attempt 2 → 1+1=2 (not exhausted)
|
|
892
|
-
* - attempt 3 → 2+1=3 (exhausted, force-back / finish)
|
|
893
|
-
*/
|
|
894
|
-
const isExpiredAttemptsExhaustedGuard = ({ context }) => context.expiredAttempts + 1 >= 3;
|
|
895
|
-
const isNotPassportModeGuard = ({ context }) => context.currentMode !== "passport";
|
|
896
|
-
/**
|
|
897
|
-
* V1 parity for `shouldApplyAlwaysCaptureBackOverride` — force-redirects to
|
|
898
|
-
* back capture after expired-front-attempts exhaust, but only when:
|
|
899
|
-
* - we're on the front side
|
|
900
|
-
* - `alwaysCaptureBackOfId` is set
|
|
901
|
-
* - the flow isn't single-side (onlyBack / usSmartCapture)
|
|
902
|
-
* - the session isn't a Digital ID upload (digital IDs are PDFs — no back
|
|
903
|
-
* side exists, so the override never applies regardless of config)
|
|
904
|
-
*/
|
|
905
|
-
const shouldForceBackOnExpiredGuard = ({ context }) => context.currentMode === "front" && context.config.alwaysCaptureBackOfId === true && !context.config.onlyBack && !context.config.usSmartCapture && !context.isDigitalUpload;
|
|
906
|
-
const wasExpiredFromUploadGuard = ({ context }) => context.expiredFromUpload === true;
|
|
907
|
-
const shouldSkipProcessIdGuard = ({ context }) => context.skipProcessId === true;
|
|
908
|
-
/**
|
|
909
|
-
* US Smart Capture: after the back best-frame is captured, submit the decoded
|
|
910
|
-
* PDF417 barcode (instead of uploading the full frame) when one was decoded on
|
|
911
|
-
* the back side. Gated exactly as SDK 1 (`usSmartCapture && isBackId`), plus a
|
|
912
|
-
* non-empty decoded payload.
|
|
913
|
-
*/
|
|
914
|
-
const shouldSubmitBarcodeGuard = ({ context }) => context.currentMode === "back" && context.config.usSmartCapture === true && !!context.decodedBarcode?.text;
|
|
915
|
-
/**
|
|
916
|
-
* US Smart Capture pre-capture fast path: submit the decoded PDF417 barcode the
|
|
917
|
-
* instant it is decoded, before the best-frame auto-capture completes. Reads the
|
|
918
|
-
* barcode from the EVENT — the guard runs before the store action, so
|
|
919
|
-
* `context.decodedBarcode` isn't populated yet. One-shot per attempt via
|
|
920
|
-
* `barcodeFastPathAttempted` (a later best-frame decode falls through to the
|
|
921
|
-
* regular `shouldSubmitBarcode` path).
|
|
922
|
-
*/
|
|
923
|
-
const canRunBarcodeFastPathGuard = ({ context, event }) => context.currentMode === "back" && context.config.usSmartCapture === true && !context.barcodeFastPathAttempted && !!event.decoded?.text;
|
|
924
|
-
/**
|
|
925
|
-
* Bug 4 fix: when `expiredExhausted` is reached via the per-upload-expired
|
|
926
|
-
* exhaustion path with a back side captured (or the entire single-side back
|
|
927
|
-
* flow), we want `processId` to run once on Continue so the backend
|
|
928
|
-
* processes whatever sides were uploaded. Front-only exhaustion (no back to
|
|
929
|
-
* process) and the force-back V1 path keep using `setSkipProcessId` instead.
|
|
930
|
-
*/
|
|
931
|
-
const shouldProcessAfterExhaustionGuard = ({ context }) => context.exhaustedFromUpload === true && context.currentMode === "back" && (context.config.onlyBack === true || context.config.usSmartCapture === true);
|
|
932
|
-
/**
|
|
933
|
-
* `processing.onDone` reads this to short-circuit straight to `finished`
|
|
934
|
-
* after the post-exhaustion `processId` call returns — without it, an
|
|
935
|
-
* `isDocumentExpired:true` response would loop back to the Expired screen
|
|
936
|
-
* we just terminated.
|
|
937
|
-
*/
|
|
938
|
-
const forceFinishAfterProcessingGuard = ({ context }) => context.forceFinishAfterProcessing === true;
|
|
939
|
-
/**
|
|
940
|
-
* Cap on the end-of-flow (`processId`) expired path — digital uploads and the
|
|
941
|
-
* multi-side post-capture process step. This path intentionally still keys off
|
|
942
|
-
* the dashboard-configurable `config.captureAttempts`, unlike the per-upload
|
|
943
|
-
* (camera) same-side expired path, which uses the fixed
|
|
944
|
-
* `MAX_EXPIRED_FIRST_SIDE_ATTEMPTS` (decoupled for V1 parity — see ENG-46592).
|
|
945
|
-
* The two expired caps are therefore different by design.
|
|
946
|
-
*/
|
|
947
|
-
const isProcessingExpiredExhaustedGuard = ({ context }) => context.processingExpiredAttempts + 1 >= context.config.captureAttempts;
|
|
948
|
-
/**
|
|
949
|
-
* True when capturing the back side of a two-sided (front+back) ID flow.
|
|
950
|
-
* Used to redirect an expired-back capture to front rather than retrying
|
|
951
|
-
* the same back side (Figma Story #2.1).
|
|
952
|
-
* Excludes onlyBack and usSmartCapture — those are single-side back flows
|
|
953
|
-
* with no front to redirect to.
|
|
954
|
-
*/
|
|
955
|
-
const isBackModeInMultiSideFlowGuard = ({ context }) => context.currentMode === "back" && !context.config.onlyBack && !context.config.usSmartCapture;
|
|
956
|
-
/**
|
|
957
|
-
* True once the user has already been redirected from an expired second-side
|
|
958
|
-
* (back) capture to the first side (front) for their one extra attempt
|
|
959
|
-
* (V1's `expiredRedirected`). Used to make the expired-back→front redirect a
|
|
960
|
-
* one-shot: any subsequent expired upload routes to `expiredExhausted` instead
|
|
961
|
-
* of redirecting again, so total captures stay within the backend's
|
|
962
|
-
* max-attempts/OCR cap (ENG-46592 / re-respects ENG-45666).
|
|
963
|
-
*/
|
|
964
|
-
const wasExpiredRedirectedGuard = ({ context }) => context.expiredRedirected === true;
|
|
965
|
-
const hasManualCaptureTriggeredGuard = ({ context }) => context.manualCaptureTriggered;
|
|
966
|
-
//#endregion
|
|
967
|
-
//#region src/modules/id/idCaptureHelpers.ts
|
|
968
|
-
/**
|
|
969
|
-
* Map of config properties received from the backend to adjusted, internal document types.
|
|
970
|
-
*/
|
|
971
|
-
const DOCUMENT_TYPES_CONFIG_TO_ADJUSTED_MAP = [
|
|
972
|
-
["enableId", "id"],
|
|
973
|
-
["enablePassport", "passport"],
|
|
974
|
-
["manualUploadIdCapture", "manualIdUpload"],
|
|
975
|
-
["digitalIdsUpload", "digitalIdUpload"],
|
|
976
|
-
["deviceWallet", "digitalId"]
|
|
977
|
-
];
|
|
978
|
-
/**
|
|
979
|
-
* Returns the list of document types enabled by config for the chooser screen, in display order.
|
|
980
|
-
* Used to populate chooser state so UI and headless consumers can render the correct options.
|
|
981
|
-
*
|
|
982
|
-
* @param config - ID capture configuration (from flow or init)
|
|
983
|
-
* @returns Array of IdDocumentType values that should be shown in the document type chooser
|
|
984
|
-
*/
|
|
985
|
-
function getAvailableDocumentTypes(config) {
|
|
986
|
-
const adjustedDocumentTypes = [];
|
|
987
|
-
for (const [configProperty, adjustedType] of DOCUMENT_TYPES_CONFIG_TO_ADJUSTED_MAP) if (config[configProperty]) adjustedDocumentTypes.push(adjustedType);
|
|
988
|
-
return adjustedDocumentTypes;
|
|
989
|
-
}
|
|
990
|
-
/**
|
|
991
|
-
* Which manual-upload tabs to show. Falls back to both tabs when neither
|
|
992
|
-
* `enableId` nor `enablePassport` is set (no accepted documents).
|
|
993
|
-
*/
|
|
994
|
-
function getManualUploadTabs(config) {
|
|
995
|
-
const showIdTab = !!config.enableId;
|
|
996
|
-
const showPassportTab = !!config.enablePassport;
|
|
997
|
-
if (!showIdTab && !showPassportTab) return {
|
|
998
|
-
showIdTab: true,
|
|
999
|
-
showPassportTab: true
|
|
1000
|
-
};
|
|
1001
|
-
return {
|
|
1002
|
-
showIdTab,
|
|
1003
|
-
showPassportTab
|
|
1004
|
-
};
|
|
1005
|
-
}
|
|
1006
|
-
/**
|
|
1007
|
-
* Computes `idCaptureMachine`'s terminal output — the downstream module-skip
|
|
1008
|
-
* signal read by the Flow orchestrator (via `runChildModule`'s `MODULE_COMPLETE`).
|
|
1009
|
-
*
|
|
1010
|
-
* `skipFaceMatch` is set ONLY for the US Smart Capture *camera back-only* path:
|
|
1011
|
-
* a back image was captured on-device (`capturedImages.back`) and no front was
|
|
1012
|
-
* (`!capturedImages.front`) — "no front, no ID face, no match".
|
|
1013
|
-
*
|
|
1014
|
-
* Requiring a captured back is deliberate and load-bearing: the manual-upload
|
|
1015
|
-
* and digital-ID-upload paths submit a full ID (front face present) but do NOT
|
|
1016
|
-
* populate `capturedImages` (only the camera path does). Gating on a captured
|
|
1017
|
-
* back excludes those upload paths so a real ID-vs-selfie match is never
|
|
1018
|
-
* silently skipped. `capturedImages.front`/`forceFrontIdCapture` alone are not
|
|
1019
|
-
* enough (a later front upload clears the request; uploads set neither field).
|
|
1020
|
-
*
|
|
1021
|
-
* Always `false` outside US Smart Capture. The selfie/face capture itself is
|
|
1022
|
-
* unaffected — only the ID-vs-selfie match is skipped.
|
|
1023
|
-
*/
|
|
1024
|
-
function computeIdCaptureOutput(context) {
|
|
1025
|
-
const frontIdCaptured = Boolean(context.capturedImages.front);
|
|
1026
|
-
const backIdCaptured = Boolean(context.capturedImages.back);
|
|
1027
|
-
return {
|
|
1028
|
-
frontIdCaptured,
|
|
1029
|
-
skipFaceMatch: context.config.usSmartCapture === true && backIdCaptured && !frontIdCaptured
|
|
1030
|
-
};
|
|
1031
|
-
}
|
|
1032
|
-
//#endregion
|
|
1033
|
-
//#region src/modules/id/idCaptureActors.ts
|
|
1034
|
-
const checkPermissionActor = fromPromise(async () => {
|
|
1035
|
-
return checkPermission();
|
|
1036
|
-
});
|
|
1037
|
-
async function requestIdCapturePermission(input) {
|
|
1038
|
-
if (!isAndroid() || getBrowser() !== "firefox") return invokeRequestPermissionActor(input);
|
|
1039
|
-
if (input.requestMotionPermission) {
|
|
1040
|
-
const motionResult = await invokeRequestPermissionActor({
|
|
1041
|
-
...input,
|
|
1042
|
-
permissionResult: "granted"
|
|
1043
|
-
});
|
|
1044
|
-
if (motionResult !== "granted") return motionResult;
|
|
1045
|
-
}
|
|
1046
|
-
const { stream, fallbackLevel } = await getIdCameraStream();
|
|
1047
|
-
return {
|
|
1048
|
-
permissionResult: "granted",
|
|
1049
|
-
stream,
|
|
1050
|
-
cameraFallbackLevel: fallbackLevel
|
|
1051
|
-
};
|
|
1052
|
-
}
|
|
1053
|
-
const requestPermissionActor = fromPromise(async ({ input }) => {
|
|
1054
|
-
return requestIdCapturePermission(input);
|
|
1055
|
-
});
|
|
1056
|
-
const initializeCameraActor = fromPromise(async ({ input }) => {
|
|
1057
|
-
return initializeIdCapture(input);
|
|
1058
|
-
});
|
|
1059
|
-
const runDetectionActor = fromCallback(({ input, sendBack }) => {
|
|
1060
|
-
if (!input.frameCapturer || !input.provider) {
|
|
1061
|
-
sendBack({
|
|
1062
|
-
type: "DETECTION_UPDATE",
|
|
1063
|
-
status: "error"
|
|
1064
|
-
});
|
|
1065
|
-
return () => {};
|
|
1066
|
-
}
|
|
1067
|
-
const provider = input.provider;
|
|
1068
|
-
let currentCanvas = null;
|
|
1069
|
-
let bestCanvas = null;
|
|
1070
|
-
let storedQualityElements = {};
|
|
1071
|
-
let isCapturing = false;
|
|
1072
|
-
const timer = BrowserTimerProvider.getInstance();
|
|
1073
|
-
let notificationTimeout = null;
|
|
1074
|
-
let optimizingBoundaryTimeout = null;
|
|
1075
|
-
/**
|
|
1076
|
-
* IDC-05 latch for the boundary clock: whether a boundary is currently
|
|
1077
|
-
* pending. `onCapturing` is WASM's "aggregation window opened" callback and is
|
|
1078
|
-
* the clock's only T0; nothing in WASM enforces that it fires once per window.
|
|
1079
|
-
*/
|
|
1080
|
-
let isOptimizingBoundaryArmed = false;
|
|
1081
|
-
let currentNotificationStatus = null;
|
|
1082
|
-
let lastReportedSide = null;
|
|
1083
|
-
const NOTIFICATION_DURATION_MS = 500;
|
|
1084
|
-
const isReportedSideWrong = () => {
|
|
1085
|
-
if (!lastReportedSide) return false;
|
|
1086
|
-
const detectedSide = lastReportedSide.toLowerCase();
|
|
1087
|
-
if (detectedSide === "wrong") return true;
|
|
1088
|
-
const isBackDetected = detectedSide.includes("back") && !detectedSide.includes("front");
|
|
1089
|
-
const isFrontDetected = detectedSide.includes("front") && !detectedSide.includes("back");
|
|
1090
|
-
return input.currentMode === "front" && isBackDetected || input.currentMode === "back" && isFrontDetected;
|
|
1091
|
-
};
|
|
1092
|
-
const clearNotificationTimeout = () => {
|
|
1093
|
-
if (notificationTimeout) {
|
|
1094
|
-
timer.clearTimeout(notificationTimeout);
|
|
1095
|
-
notificationTimeout = null;
|
|
1096
|
-
currentNotificationStatus = null;
|
|
1097
|
-
}
|
|
1098
|
-
};
|
|
1099
|
-
const clearOptimizingBoundary = () => {
|
|
1100
|
-
if (optimizingBoundaryTimeout) {
|
|
1101
|
-
timer.clearTimeout(optimizingBoundaryTimeout);
|
|
1102
|
-
optimizingBoundaryTimeout = null;
|
|
1103
|
-
}
|
|
1104
|
-
isOptimizingBoundaryArmed = false;
|
|
1105
|
-
};
|
|
1106
|
-
/**
|
|
1107
|
-
* IDC-05 boundary clock — the actor's *only* timer, and the only piece of the
|
|
1108
|
-
* optimizing phase it owns. WASM's `CapturingManager` opens the
|
|
1109
|
-
* frames-aggregation window at `onCapturing` and closes it with `onCapture` at
|
|
1110
|
-
* `T0 + framesAggregationInterval` (already resolved to
|
|
1111
|
-
* `captureWindowMs + optimizingDwellMs`). The phase begins at
|
|
1112
|
-
* `T0 + captureWindowMs`, so it is timed from the very callback that defines
|
|
1113
|
-
* T0; how long it then lasts is the machine's business.
|
|
1114
|
-
*
|
|
1115
|
-
* No best frame yet at that point means the session simply behaves like the
|
|
1116
|
-
* countdown arm — no event, no phase — which mirrors iOS's "auto capture with
|
|
1117
|
-
* no best crop yet" fallback.
|
|
1118
|
-
*
|
|
1119
|
-
* At most one boundary pending at a time — see `isOptimizingBoundaryArmed`.
|
|
1120
|
-
*/
|
|
1121
|
-
const scheduleOptimizingBoundary = () => {
|
|
1122
|
-
if (input.optimizingAfterMs == null || isOptimizingBoundaryArmed) return;
|
|
1123
|
-
isOptimizingBoundaryArmed = true;
|
|
1124
|
-
optimizingBoundaryTimeout = timer.setTimeout(() => {
|
|
1125
|
-
optimizingBoundaryTimeout = null;
|
|
1126
|
-
isOptimizingBoundaryArmed = false;
|
|
1127
|
-
enterOptimizing();
|
|
1128
|
-
}, input.optimizingAfterMs);
|
|
1129
|
-
};
|
|
1130
|
-
/**
|
|
1131
|
-
* Reports the boundary with the candidate frame to freeze. Silent when there
|
|
1132
|
-
* is no candidate — no event means no phase, and the session behaves like the
|
|
1133
|
-
* countdown arm (see `scheduleOptimizingBoundary`).
|
|
1134
|
-
*/
|
|
1135
|
-
const enterOptimizing = () => {
|
|
1136
|
-
const candidateCanvas = bestCanvas?.clone();
|
|
1137
|
-
if (!candidateCanvas) return;
|
|
1138
|
-
sendBack({
|
|
1139
|
-
type: "DETECTION_OPTIMIZING",
|
|
1140
|
-
candidateCanvas
|
|
1141
|
-
});
|
|
1142
|
-
};
|
|
1143
|
-
const sendNotification = (status) => {
|
|
1144
|
-
if (isReportedSideWrong()) return;
|
|
1145
|
-
if (notificationTimeout && currentNotificationStatus !== status) return;
|
|
1146
|
-
if (notificationTimeout && currentNotificationStatus === status) timer.clearTimeout(notificationTimeout);
|
|
1147
|
-
currentNotificationStatus = status;
|
|
1148
|
-
trueSightHintTransition("module.id-capture", "idScan", status);
|
|
1149
|
-
sendBack({
|
|
1150
|
-
type: "DETECTION_UPDATE",
|
|
1151
|
-
status
|
|
1152
|
-
});
|
|
1153
|
-
notificationTimeout = timer.setTimeout(() => {
|
|
1154
|
-
notificationTimeout = null;
|
|
1155
|
-
currentNotificationStatus = null;
|
|
1156
|
-
sendBack({
|
|
1157
|
-
type: "DETECTION_UPDATE",
|
|
1158
|
-
status: "detecting"
|
|
1159
|
-
});
|
|
1160
|
-
}, NOTIFICATION_DURATION_MS);
|
|
1161
|
-
};
|
|
1162
|
-
const canvas = input.frameCapturer.getLatestCanvas();
|
|
1163
|
-
const windowDimensions = getWindowDimensions(canvas?.width() ?? 1280, canvas?.height() ?? 720);
|
|
1164
|
-
const DEFAULT_GEOMETRY = {
|
|
1165
|
-
areaDown: 25e3,
|
|
1166
|
-
areaUp: 55e3,
|
|
1167
|
-
areaIOSPassportUp: 3e4,
|
|
1168
|
-
areaIOSPassportDown: 2e4,
|
|
1169
|
-
widthIOSUp: 160,
|
|
1170
|
-
widthIOSDown: 85,
|
|
1171
|
-
widthDown: 110,
|
|
1172
|
-
widthUp: 205
|
|
1173
|
-
};
|
|
1174
|
-
if (input.config.geometry) provider.setGeometry({
|
|
1175
|
-
...input.config.geometry,
|
|
1176
|
-
windowOuterWidth: windowDimensions.outerWidth,
|
|
1177
|
-
windowOuterHeight: windowDimensions.outerHeight,
|
|
1178
|
-
windowInnerWidth: windowDimensions.innerWidth,
|
|
1179
|
-
windowInnerHeight: windowDimensions.innerHeight
|
|
1180
|
-
});
|
|
1181
|
-
else provider.setGeometry({
|
|
1182
|
-
...DEFAULT_GEOMETRY,
|
|
1183
|
-
windowOuterWidth: windowDimensions.outerWidth,
|
|
1184
|
-
windowOuterHeight: windowDimensions.outerHeight,
|
|
1185
|
-
windowInnerWidth: windowDimensions.innerWidth,
|
|
1186
|
-
windowInnerHeight: windowDimensions.innerHeight
|
|
1187
|
-
});
|
|
1188
|
-
const idType = input.currentMode === "back" ? "BackId" : input.currentMode === "passport" ? "Passport" : "FrontId";
|
|
1189
|
-
provider.setSettings({
|
|
1190
|
-
isFixedMask: input.config.settings?.isFixedMask ?? false,
|
|
1191
|
-
isIPhone14OrHigher: input.config.settings?.isIPhone14OrHigher ?? false,
|
|
1192
|
-
idType,
|
|
1193
|
-
blurCheckEnabled: input.config.settings?.blurCheckEnabled ?? false,
|
|
1194
|
-
glareCheckEnabled: input.config.settings?.glareCheckEnabled ?? false,
|
|
1195
|
-
faceQualityCheckEnabled: input.config.settings?.faceQualityCheckEnabled ?? true,
|
|
1196
|
-
iouCheckEnabled: input.config.settings?.iouCheckEnabled ?? true,
|
|
1197
|
-
fpsLimitEnabled: input.config.settings?.fpsLimitEnabled ?? false
|
|
1198
|
-
});
|
|
1199
|
-
provider.setThresholds(resolveIdCaptureThresholds(input.config));
|
|
1200
|
-
const modelType = input.config.modelVersion ?? "v2";
|
|
1201
|
-
provider.setModelType(modelType);
|
|
1202
|
-
provider.setCallbacks({
|
|
1203
|
-
onFarAway: () => {
|
|
1204
|
-
if (!isCapturing) sendNotification("farAway");
|
|
1205
|
-
},
|
|
1206
|
-
onDetectionStarted: () => {},
|
|
1207
|
-
onMaskChange: (_show, _mask, _top, orientation) => {
|
|
1208
|
-
sendBack({
|
|
1209
|
-
type: "ORIENTATION_CHANGE",
|
|
1210
|
-
orientation
|
|
1211
|
-
});
|
|
1212
|
-
},
|
|
1213
|
-
onBlur: () => {
|
|
1214
|
-
if (!isCapturing) sendNotification("blur");
|
|
1215
|
-
},
|
|
1216
|
-
onGlare: () => {
|
|
1217
|
-
if (!isCapturing) sendNotification("glare");
|
|
1218
|
-
},
|
|
1219
|
-
onIdNotDetected: () => {
|
|
1220
|
-
if (!isCapturing) {
|
|
1221
|
-
trueSightHintTransition("module.id-capture", "idScan", "idNotDetected");
|
|
1222
|
-
sendBack({
|
|
1223
|
-
type: "DETECTION_UPDATE",
|
|
1224
|
-
status: "idNotDetected"
|
|
1225
|
-
});
|
|
1226
|
-
}
|
|
1227
|
-
},
|
|
1228
|
-
onSwitchToManualCapture: () => {
|
|
1229
|
-
isCapturing = false;
|
|
1230
|
-
clearOptimizingBoundary();
|
|
1231
|
-
sendBack({ type: "SWITCH_TO_MANUAL_CAPTURE" });
|
|
1232
|
-
},
|
|
1233
|
-
onCapturing: () => {
|
|
1234
|
-
clearNotificationTimeout();
|
|
1235
|
-
lastReportedSide = null;
|
|
1236
|
-
isCapturing = true;
|
|
1237
|
-
trueSightHintTransition("module.id-capture", "idScan", "capturing");
|
|
1238
|
-
sendBack({
|
|
1239
|
-
type: "DETECTION_UPDATE",
|
|
1240
|
-
status: "capturing"
|
|
1241
|
-
});
|
|
1242
|
-
scheduleOptimizingBoundary();
|
|
1243
|
-
},
|
|
1244
|
-
onBestFrame: (blur, glare, orientation) => {
|
|
1245
|
-
if (currentCanvas) {
|
|
1246
|
-
bestCanvas = currentCanvas.clone();
|
|
1247
|
-
storedQualityElements = {
|
|
1248
|
-
glare,
|
|
1249
|
-
sharpness: blur
|
|
1250
|
-
};
|
|
1251
|
-
}
|
|
1252
|
-
if (orientation === "horizontal" || orientation === "vertical") sendBack({
|
|
1253
|
-
type: "ORIENTATION_CHANGE",
|
|
1254
|
-
orientation
|
|
1255
|
-
});
|
|
1256
|
-
},
|
|
1257
|
-
onCapture: () => {
|
|
1258
|
-
isCapturing = false;
|
|
1259
|
-
if (isOptimizingBoundaryArmed) {
|
|
1260
|
-
clearOptimizingBoundary();
|
|
1261
|
-
enterOptimizing();
|
|
1262
|
-
}
|
|
1263
|
-
if (!bestCanvas) {
|
|
1264
|
-
const clonedCanvas = currentCanvas?.clone();
|
|
1265
|
-
if (clonedCanvas) sendBack({
|
|
1266
|
-
type: "DETECTION_SUCCESS",
|
|
1267
|
-
canvas: clonedCanvas,
|
|
1268
|
-
qualityElements: {}
|
|
1269
|
-
});
|
|
1270
|
-
return;
|
|
1271
|
-
}
|
|
1272
|
-
sendBack({
|
|
1273
|
-
type: "DETECTION_SUCCESS",
|
|
1274
|
-
canvas: bestCanvas,
|
|
1275
|
-
qualityElements: storedQualityElements
|
|
1276
|
-
});
|
|
1277
|
-
},
|
|
1278
|
-
onIdTypeChange: (idType) => {
|
|
1279
|
-
sendBack({
|
|
1280
|
-
type: "ID_TYPE_CHANGE",
|
|
1281
|
-
idType
|
|
1282
|
-
});
|
|
1283
|
-
},
|
|
1284
|
-
onIdSideChange: (side) => {
|
|
1285
|
-
if (isCapturing) return;
|
|
1286
|
-
lastReportedSide = side;
|
|
1287
|
-
if (isReportedSideWrong()) clearNotificationTimeout();
|
|
1288
|
-
sendBack({
|
|
1289
|
-
type: "ID_SIDE_CHANGE",
|
|
1290
|
-
side
|
|
1291
|
-
});
|
|
1292
|
-
},
|
|
1293
|
-
onCapturingCounterValueChange: (value) => {
|
|
1294
|
-
sendBack({
|
|
1295
|
-
type: "COUNTER_VALUE_CHANGE",
|
|
1296
|
-
value
|
|
1297
|
-
});
|
|
1298
|
-
},
|
|
1299
|
-
onBarcodeDecoded: (decoded) => {
|
|
1300
|
-
sendBack({
|
|
1301
|
-
type: "BARCODE_DECODED",
|
|
1302
|
-
decoded
|
|
1303
|
-
});
|
|
1304
|
-
}
|
|
1305
|
-
});
|
|
1306
|
-
const barcodeCaptureEnabled = input.config.usSmartCapture === true && input.currentMode === "back";
|
|
1307
|
-
provider.setBarcodeCaptureEnabled(barcodeCaptureEnabled);
|
|
1308
|
-
provider.setBarcodeAutoCaptureOnDecode(false);
|
|
1309
|
-
if (barcodeCaptureEnabled) provider.setBarcodeEnhancementModel().catch(() => {});
|
|
1310
|
-
sendBack({
|
|
1311
|
-
type: "DETECTION_UPDATE",
|
|
1312
|
-
status: "detecting"
|
|
1313
|
-
});
|
|
1314
|
-
const session = new StreamCanvasProcessingSession({
|
|
1315
|
-
capturer: input.frameCapturer,
|
|
1316
|
-
provider: {
|
|
1317
|
-
processFrame: async (frame) => {
|
|
1318
|
-
currentCanvas = IncodeCanvas.fromImageData(frame);
|
|
1319
|
-
await provider.processFrame(frame);
|
|
1320
|
-
},
|
|
1321
|
-
reset: () => {
|
|
1322
|
-
if (notificationTimeout) {
|
|
1323
|
-
timer.clearTimeout(notificationTimeout);
|
|
1324
|
-
notificationTimeout = null;
|
|
1325
|
-
currentNotificationStatus = null;
|
|
1326
|
-
}
|
|
1327
|
-
clearOptimizingBoundary();
|
|
1328
|
-
currentCanvas = null;
|
|
1329
|
-
bestCanvas = null;
|
|
1330
|
-
storedQualityElements = {};
|
|
1331
|
-
isCapturing = false;
|
|
1332
|
-
lastReportedSide = null;
|
|
1333
|
-
provider.resetDetectionState();
|
|
1334
|
-
}
|
|
1335
|
-
}
|
|
1336
|
-
});
|
|
1337
|
-
noteTrueSightCaptureActivity(true);
|
|
1338
|
-
sendBack({
|
|
1339
|
-
type: "DETECTION_RESET_READY",
|
|
1340
|
-
reset: () => {
|
|
1341
|
-
provider.reset();
|
|
1342
|
-
}
|
|
1343
|
-
});
|
|
1344
|
-
return () => {
|
|
1345
|
-
clearNotificationTimeout();
|
|
1346
|
-
clearOptimizingBoundary();
|
|
1347
|
-
session?.dispose();
|
|
1348
|
-
noteTrueSightCaptureActivity(false);
|
|
1349
|
-
};
|
|
1350
|
-
});
|
|
1351
|
-
const uploadProgressTickerActor = fromCallback(({ sendBack }) => {
|
|
1352
|
-
const timer = BrowserTimerProvider.getInstance();
|
|
1353
|
-
const interval = timer.setInterval(() => {
|
|
1354
|
-
sendBack({ type: "UPLOAD_PROGRESS_TICK" });
|
|
1355
|
-
}, 400);
|
|
1356
|
-
return () => timer.clearInterval(interval);
|
|
1357
|
-
});
|
|
1358
|
-
const uploadIdImageActor = fromPromise(async ({ input, signal }) => {
|
|
1359
|
-
const image = input.canvas.getBase64Image();
|
|
1360
|
-
if (!image) throw new Error(ID_ERROR_CODES.UPLOAD_ERROR);
|
|
1361
|
-
let metadata;
|
|
1362
|
-
if (input.deepsightService) try {
|
|
1363
|
-
const sessionToken = getToken();
|
|
1364
|
-
const frameSource = input.type === "back" ? "BACK_ID" : "FRONT_ID";
|
|
1365
|
-
await input.deepsightService.performVirtualCameraCheck(sessionToken, frameSource);
|
|
1366
|
-
const imageData = input.canvas.getImageData();
|
|
1367
|
-
if (imageData) await input.deepsightService.analyzeFrame(imageData);
|
|
1368
|
-
const analysisStatus = input.deepsightService.getAnalysisStatus();
|
|
1369
|
-
const motionStatus = input.deepsightService.getMotionStatus();
|
|
1370
|
-
if (input.type === "front") await addDeviceStats({
|
|
1371
|
-
frontIdStatsAnalysisStatus: analysisStatus,
|
|
1372
|
-
backIdStatsAnalysisStatus: "",
|
|
1373
|
-
selfieStatsAnalysisStatus: "",
|
|
1374
|
-
motionStatus
|
|
1375
|
-
});
|
|
1376
|
-
else await addDeviceStats({
|
|
1377
|
-
frontIdStatsAnalysisStatus: "",
|
|
1378
|
-
backIdStatsAnalysisStatus: analysisStatus,
|
|
1379
|
-
selfieStatsAnalysisStatus: "",
|
|
1380
|
-
motionStatus
|
|
1381
|
-
});
|
|
1382
|
-
metadata = input.deepsightService.getMetadata();
|
|
1383
|
-
} catch (error) {
|
|
1384
|
-
trueSightLog("warning", "deepsight", "idScan", `deepsight id analysis failed error=${String(error)}`);
|
|
1385
|
-
}
|
|
1386
|
-
const imageData = input.canvas?.getImageData() ?? void 0;
|
|
1387
|
-
const logs = input.deepsightService?.getPipelineState() ?? "";
|
|
1388
|
-
input.dependencies?.trackCaptureAttemptFinished?.({
|
|
1389
|
-
logs,
|
|
1390
|
-
resolution: input.captureResolution,
|
|
1391
|
-
fallbackLevel: input.cameraFallbackLevel
|
|
1392
|
-
});
|
|
1393
|
-
return uploadIdImage({
|
|
1394
|
-
image,
|
|
1395
|
-
type: input.type,
|
|
1396
|
-
sendBase64: true,
|
|
1397
|
-
glare: input.qualityElements?.glare,
|
|
1398
|
-
sharpness: input.qualityElements?.sharpness,
|
|
1399
|
-
ageAssurance: input.ageAssurance,
|
|
1400
|
-
signal,
|
|
1401
|
-
onProgress: input.onProgress,
|
|
1402
|
-
metadata,
|
|
1403
|
-
analyticsProvider: input.analyticsProvider,
|
|
1404
|
-
imageData,
|
|
1405
|
-
isSecondId: input.isSecondId,
|
|
1406
|
-
onlyFront: input.onlyFront,
|
|
1407
|
-
extractIdFace: input.extractIdFace
|
|
1408
|
-
});
|
|
1409
|
-
});
|
|
1410
|
-
const processIdActor = fromPromise(async ({ input, signal }) => {
|
|
1411
|
-
return processId(input.isSecondId, "", signal);
|
|
1412
|
-
});
|
|
1413
|
-
const submitBarcodeActor = fromPromise(async ({ input, signal }) => {
|
|
1414
|
-
const [response] = await Promise.all([addBarcode({
|
|
1415
|
-
rawBarcode: input.rawBarcode,
|
|
1416
|
-
metrics: input.metrics,
|
|
1417
|
-
processId: input.processId,
|
|
1418
|
-
signal
|
|
1419
|
-
}), input.minDurationMs ? sleep(input.minDurationMs) : Promise.resolve()]);
|
|
1420
|
-
return response;
|
|
1421
|
-
});
|
|
1422
|
-
const startRecordingActor = fromPromise(async ({ input }) => {
|
|
1423
|
-
if (!input.stream) return;
|
|
1424
|
-
const type = input.currentMode === "back" ? "backId" : "frontId";
|
|
1425
|
-
return startRecordingSession({
|
|
1426
|
-
config: input.config,
|
|
1427
|
-
stream: input.stream,
|
|
1428
|
-
existing: input.existing,
|
|
1429
|
-
type
|
|
1430
|
-
});
|
|
1431
|
-
});
|
|
1432
|
-
const initializeDeepsightSessionActor = fromPromise(async ({ input }) => {
|
|
1433
|
-
if (!input.dependencies) return;
|
|
1434
|
-
const { loadDeepsightSession } = await import("./deepsightLoader--wMKWECS.esm.js");
|
|
1435
|
-
return loadDeepsightSession({
|
|
1436
|
-
ds: input.ds,
|
|
1437
|
-
storage: input.dependencies.storage,
|
|
1438
|
-
disableIpify: input.disableIpify
|
|
1439
|
-
});
|
|
1440
|
-
});
|
|
1441
|
-
const checkVirtualCameraActor = fromPromise(async ({ input }) => {
|
|
1442
|
-
if (!input.deepsightService || !input.stream) return false;
|
|
1443
|
-
const videoTrack = input.stream.getVideoTracks()[0];
|
|
1444
|
-
if (!videoTrack) return false;
|
|
1445
|
-
return input.deepsightService.checkVirtualCamera(videoTrack);
|
|
1446
|
-
});
|
|
1447
|
-
//#endregion
|
|
1448
|
-
//#region src/modules/id/idCaptureActions.ts
|
|
1449
|
-
function performStopMediaStream(context) {
|
|
1450
|
-
context.frameCapturer?.dispose();
|
|
1451
|
-
if (context.stream) stopStream(context.stream);
|
|
1452
|
-
}
|
|
1453
|
-
function performDisposeProvider(context) {
|
|
1454
|
-
context.provider?.dispose?.();
|
|
1455
|
-
}
|
|
1456
|
-
function performCleanupDeepsight(context) {
|
|
1457
|
-
context.deepsightService?.cleanup();
|
|
1458
|
-
}
|
|
1459
|
-
function performResetForBackCapture(context) {
|
|
1460
|
-
context.frameCapturer?.dispose();
|
|
1461
|
-
if (context.stream) stopStream(context.stream);
|
|
1462
|
-
context.provider?.reset();
|
|
1463
|
-
}
|
|
1464
|
-
function performResetForFrontCapture(context) {
|
|
1465
|
-
context.frameCapturer?.dispose();
|
|
1466
|
-
if (context.stream) stopStream(context.stream);
|
|
1467
|
-
context.provider?.reset();
|
|
1468
|
-
}
|
|
1469
|
-
function performResetDetection(context) {
|
|
1470
|
-
context.resetDetection?.();
|
|
1471
|
-
}
|
|
1472
|
-
function performReportCaptureOptimizingAssignment(context) {
|
|
1473
|
-
if (context.config.supportsOptimizingStatus !== true) return;
|
|
1474
|
-
const assignment = exposeExperimentOnce(CAPTURE_OPTIMIZING);
|
|
1475
|
-
if (!assignment) return;
|
|
1476
|
-
recordExperimentAssignmentOnce(eventModuleNames.idCapture, CAPTURE_OPTIMIZING.storeParam, assignment);
|
|
1477
|
-
}
|
|
1478
|
-
function performStopMediaRecording(context) {
|
|
1479
|
-
if (context.recordingSession) stopRecording(context.recordingSession);
|
|
1480
|
-
}
|
|
1481
|
-
function getStreamFromEvent(event) {
|
|
1482
|
-
if ("output" in event) return event.output.stream;
|
|
1483
|
-
}
|
|
1484
|
-
function getPermissionResultFromEvent(event) {
|
|
1485
|
-
if (!("output" in event)) return;
|
|
1486
|
-
const { output } = event;
|
|
1487
|
-
if (output === "granted" || output === "denied" || output === "prompt") return output;
|
|
1488
|
-
if (typeof output === "object" && output !== null && "permissionResult" in output) {
|
|
1489
|
-
const result = output.permissionResult;
|
|
1490
|
-
if (result === "granted" || result === "denied" || result === "prompt") return result;
|
|
1491
|
-
}
|
|
1492
|
-
}
|
|
1493
|
-
function getProviderFromEvent(event) {
|
|
1494
|
-
if ("output" in event) return event.output.provider;
|
|
1495
|
-
}
|
|
1496
|
-
function getCaptureResolutionFromEvent(event) {
|
|
1497
|
-
if ("output" in event) return event.output.captureResolution;
|
|
1498
|
-
}
|
|
1499
|
-
function getCameraFallbackLevelFromEvent(event) {
|
|
1500
|
-
if ("output" in event) return event.output.cameraFallbackLevel;
|
|
1501
|
-
}
|
|
1502
|
-
function getFrameCapturerFromEvent(event) {
|
|
1503
|
-
if ("output" in event) {
|
|
1504
|
-
const output = event.output;
|
|
1505
|
-
if (output.stream) return new StreamCanvasCapture(output.stream);
|
|
1506
|
-
}
|
|
1507
|
-
}
|
|
1508
|
-
function getResetContextValues(context) {
|
|
1509
|
-
context.provider?.reset();
|
|
1510
|
-
const currentMode = context.config.onlyBack ? "back" : !context.config.enableId && context.config.enablePassport ? "passport" : context.config.usSmartCapture ? "back" : "front";
|
|
1511
|
-
return {
|
|
1512
|
-
stream: void 0,
|
|
1513
|
-
provider: context.provider,
|
|
1514
|
-
frameCapturer: void 0,
|
|
1515
|
-
error: void 0,
|
|
1516
|
-
detectionStatus: "idle",
|
|
1517
|
-
counterValue: 0,
|
|
1518
|
-
orientation: void 0,
|
|
1519
|
-
capturedImages: {},
|
|
1520
|
-
captureOnlyImages: {},
|
|
1521
|
-
uploadResponse: void 0,
|
|
1522
|
-
decodedBarcode: null,
|
|
1523
|
-
barcodeFastPathAttempted: false,
|
|
1524
|
-
barcodeFastPathCaptured: false,
|
|
1525
|
-
recordingSession: void 0,
|
|
1526
|
-
attemptsRemaining: context.config.captureAttempts,
|
|
1527
|
-
expiredAttempts: 0,
|
|
1528
|
-
skipProcessId: false,
|
|
1529
|
-
expiredFromUpload: false,
|
|
1530
|
-
isDigitalUpload: false,
|
|
1531
|
-
exhaustedFromUpload: false,
|
|
1532
|
-
forceFinishAfterProcessing: false,
|
|
1533
|
-
uploadError: void 0,
|
|
1534
|
-
permissionResult: void 0,
|
|
1535
|
-
resetDetection: void 0,
|
|
1536
|
-
idType: void 0,
|
|
1537
|
-
qualityElements: void 0,
|
|
1538
|
-
previewImageUrl: void 0,
|
|
1539
|
-
...getClearOptimizingValues(context),
|
|
1540
|
-
uploadProgress: void 0,
|
|
1541
|
-
currentMode,
|
|
1542
|
-
selectedDocumentType: void 0,
|
|
1543
|
-
manualCaptureTriggered: false,
|
|
1544
|
-
captureResolution: void 0,
|
|
1545
|
-
cameraFallbackLevel: void 0
|
|
1546
|
-
};
|
|
1547
|
-
}
|
|
1548
|
-
function getClearUploadFailureValues(context) {
|
|
1549
|
-
if (context.previewImageUrl) revokeObjectURL(context.previewImageUrl);
|
|
1550
|
-
return {
|
|
1551
|
-
uploadError: void 0,
|
|
1552
|
-
detectionStatus: "idle",
|
|
1553
|
-
previewImageUrl: void 0,
|
|
1554
|
-
...getClearOptimizingValues(context),
|
|
1555
|
-
uploadProgress: void 0
|
|
1556
|
-
};
|
|
1557
|
-
}
|
|
1558
|
-
function getUploadValidationError(context) {
|
|
1559
|
-
if (!context.uploadResponse) return ID_ERROR_CODES.SERVER;
|
|
1560
|
-
return validateUploadResponse(context.uploadResponse, {
|
|
1561
|
-
skipGlareFront: context.uploadResponse.skipGlareFront,
|
|
1562
|
-
skipGlareBack: context.uploadResponse.skipGlareBack
|
|
1563
|
-
})?.errorKey ?? ID_ERROR_CODES.SERVER;
|
|
1564
|
-
}
|
|
1565
|
-
function storeCapturedCanvasInProviderLogic(context, event) {
|
|
1566
|
-
let canvas = null;
|
|
1567
|
-
if ("canvas" in event && event.canvas) canvas = event.canvas;
|
|
1568
|
-
else canvas = context.frameCapturer?.getLatestCanvas() ?? null;
|
|
1569
|
-
if (!canvas || !context.provider) return;
|
|
1570
|
-
const canvasWidth = canvas.width();
|
|
1571
|
-
const canvasHeight = canvas.height();
|
|
1572
|
-
if (!canvasWidth || !canvasHeight) return;
|
|
1573
|
-
const originalCanvas = canvas;
|
|
1574
|
-
const frameRect = resolveCaptureFrameRect(context, canvasWidth, canvasHeight);
|
|
1575
|
-
const transformedCanvas = context.provider.transformPerspective(originalCanvas, frameRect);
|
|
1576
|
-
context.provider.setCapturedCanvases(originalCanvas, transformedCanvas);
|
|
1577
|
-
}
|
|
1578
|
-
/**
|
|
1579
|
-
* JPEG quality for the IDC-05 optimizing phase's display-only still.
|
|
1580
|
-
*
|
|
1581
|
-
* `updateBlob()` is synchronous and expensive: `toDataURL` → `atob` → a per-byte
|
|
1582
|
-
* loop building the blob (`IncodeCanvas.base64ToBlob`). At the default quality of
|
|
1583
|
-
* 1.0 on a 1080p frame that is tens of milliseconds of main-thread work — and on
|
|
1584
|
-
* this path it runs inside an `assign`, in the same tick that starts the phase
|
|
1585
|
-
* animation, with the 30fps WASM detection loop still live. Both halves of the
|
|
1586
|
-
* cost scale with the encoded byte count, so dropping quality cuts the encode and
|
|
1587
|
-
* the byte loop together.
|
|
1588
|
-
*
|
|
1589
|
-
* Treatment-arm only, deliberately: the committed frame keeps quality 1.0, since
|
|
1590
|
-
* it is what uploads (`getStoreCapturedImageValues` → `getBase64Image(1.0)`) and
|
|
1591
|
-
* its encode happens on the analyzing screen with no animation to jank. This
|
|
1592
|
-
* still is on screen for one dwell at roughly card size and never leaves the
|
|
1593
|
-
* device.
|
|
1594
|
-
*/
|
|
1595
|
-
const CANDIDATE_FRAME_JPEG_QUALITY = .8;
|
|
1596
|
-
/**
|
|
1597
|
-
* The document's rectangle within a camera frame, in canvas coordinates —
|
|
1598
|
-
* the input to `transformPerspective`.
|
|
1599
|
-
*
|
|
1600
|
-
* Shared by the commit path (`storeCapturedCanvasInProviderLogic`) and the
|
|
1601
|
-
* IDC-05 optimizing phase (`getCandidateFrameValues`) so the still shown
|
|
1602
|
-
* mid-capture is cropped and warped exactly like the frame that later uploads.
|
|
1603
|
-
* Deriving it twice is what made the phase show an uncropped full frame that then
|
|
1604
|
-
* visibly jumped to a cropped one on the analyzing screen.
|
|
1605
|
-
*/
|
|
1606
|
-
function resolveCaptureFrameRect(context, canvasWidth, canvasHeight) {
|
|
1607
|
-
let frameRect;
|
|
1608
|
-
const { innerWidth: viewportWidth, innerHeight: viewportHeight } = getWindowDimensions();
|
|
1609
|
-
if (context.detectionArea) {
|
|
1610
|
-
const scaleX = viewportWidth / canvasWidth;
|
|
1611
|
-
const scaleY = viewportHeight / canvasHeight;
|
|
1612
|
-
const scale = Math.max(scaleX, scaleY);
|
|
1613
|
-
const displayedWidth = canvasWidth * scale;
|
|
1614
|
-
const displayedHeight = canvasHeight * scale;
|
|
1615
|
-
const offsetX = (viewportWidth - displayedWidth) / 2;
|
|
1616
|
-
const offsetY = (viewportHeight - displayedHeight) / 2;
|
|
1617
|
-
frameRect = {
|
|
1618
|
-
x: (context.detectionArea.x - offsetX) / scale,
|
|
1619
|
-
y: (context.detectionArea.y - offsetY) / scale,
|
|
1620
|
-
w: context.detectionArea.width / scale,
|
|
1621
|
-
h: context.detectionArea.height / scale
|
|
1622
|
-
};
|
|
1623
|
-
} else if (context.frameRect) {
|
|
1624
|
-
const scaleX = viewportWidth / canvasWidth;
|
|
1625
|
-
const scaleY = viewportHeight / canvasHeight;
|
|
1626
|
-
const scale = Math.max(scaleX, scaleY);
|
|
1627
|
-
const displayedWidth = canvasWidth * scale;
|
|
1628
|
-
const displayedHeight = canvasHeight * scale;
|
|
1629
|
-
const offsetX = (viewportWidth - displayedWidth) / 2;
|
|
1630
|
-
const offsetY = (viewportHeight - displayedHeight) / 2;
|
|
1631
|
-
frameRect = {
|
|
1632
|
-
x: (context.frameRect.x - offsetX) / scale,
|
|
1633
|
-
y: (context.frameRect.y - offsetY) / scale,
|
|
1634
|
-
w: context.frameRect.w / scale,
|
|
1635
|
-
h: context.frameRect.h / scale
|
|
1636
|
-
};
|
|
1637
|
-
} else {
|
|
1638
|
-
const quadValue = (context.provider?.getLastProcessResult?.())?.quad;
|
|
1639
|
-
const hasQuad = !!quadValue;
|
|
1640
|
-
const quadSize = quadValue?.size ? quadValue.size() : quadValue?.length ?? 0;
|
|
1641
|
-
if (hasQuad && quadSize >= 4 && quadValue.get) {
|
|
1642
|
-
const p0 = quadValue.get(0);
|
|
1643
|
-
const p1 = quadValue.get(1);
|
|
1644
|
-
const p2 = quadValue.get(2);
|
|
1645
|
-
const p3 = quadValue.get(3);
|
|
1646
|
-
const minX = Math.min(p0.x, p1.x, p2.x, p3.x);
|
|
1647
|
-
const maxX = Math.max(p0.x, p1.x, p2.x, p3.x);
|
|
1648
|
-
const minY = Math.min(p0.y, p1.y, p2.y, p3.y);
|
|
1649
|
-
const maxY = Math.max(p0.y, p1.y, p2.y, p3.y);
|
|
1650
|
-
frameRect = {
|
|
1651
|
-
x: minX,
|
|
1652
|
-
y: minY,
|
|
1653
|
-
w: maxX - minX,
|
|
1654
|
-
h: maxY - minY
|
|
1655
|
-
};
|
|
1656
|
-
} else {
|
|
1657
|
-
const frameViewportWidth = Math.min(387, viewportWidth * .9);
|
|
1658
|
-
const frameViewportHeight = frameViewportWidth / (35 / 22);
|
|
1659
|
-
const frameViewportX = (viewportWidth - frameViewportWidth) / 2;
|
|
1660
|
-
const frameViewportY = (viewportHeight - frameViewportHeight) / 2;
|
|
1661
|
-
frameRect = {
|
|
1662
|
-
x: canvasWidth * frameViewportX / viewportWidth,
|
|
1663
|
-
y: canvasHeight * frameViewportY / viewportHeight,
|
|
1664
|
-
w: canvasWidth * frameViewportWidth / viewportWidth,
|
|
1665
|
-
h: canvasHeight * frameViewportHeight / viewportHeight
|
|
1666
|
-
};
|
|
1667
|
-
}
|
|
1668
|
-
}
|
|
1669
|
-
return frameRect;
|
|
1670
|
-
}
|
|
1671
|
-
function getStoreCapturedImageValues(context, event) {
|
|
1672
|
-
if (!context.currentMode) return {
|
|
1673
|
-
capturedImages: context.capturedImages,
|
|
1674
|
-
previewImageUrl: context.previewImageUrl
|
|
1675
|
-
};
|
|
1676
|
-
const transformedCanvas = context.provider?.getCapturedCanvas();
|
|
1677
|
-
const transformedImage = transformedCanvas?.getBase64Image(1, true);
|
|
1678
|
-
let fallbackImage = "";
|
|
1679
|
-
if ("output" in event) fallbackImage = event.output.originalImage ?? "";
|
|
1680
|
-
const imageData = { imageBase64: transformedImage ?? fallbackImage };
|
|
1681
|
-
let capturedImages = context.capturedImages;
|
|
1682
|
-
if (context.currentMode === "front" || context.currentMode === "passport") capturedImages = {
|
|
1683
|
-
...context.capturedImages,
|
|
1684
|
-
front: imageData
|
|
1685
|
-
};
|
|
1686
|
-
else capturedImages = {
|
|
1687
|
-
...context.capturedImages,
|
|
1688
|
-
back: imageData
|
|
1689
|
-
};
|
|
1690
|
-
let previewImageUrl = context.previewImageUrl;
|
|
1691
|
-
if (transformedCanvas) {
|
|
1692
|
-
transformedCanvas.updateBlob();
|
|
1693
|
-
const blobData = transformedCanvas.getBlobData();
|
|
1694
|
-
if (blobData?.url) previewImageUrl = blobData.url;
|
|
1695
|
-
} else if ("canvas" in event && event.canvas) {
|
|
1696
|
-
const canvas = event.canvas;
|
|
1697
|
-
canvas.updateBlob();
|
|
1698
|
-
const blobData = canvas.getBlobData();
|
|
1699
|
-
if (blobData?.url) previewImageUrl = blobData.url;
|
|
1700
|
-
}
|
|
1701
|
-
return {
|
|
1702
|
-
capturedImages,
|
|
1703
|
-
previewImageUrl,
|
|
1704
|
-
...getClearOptimizingValues(context)
|
|
1705
|
-
};
|
|
1706
|
-
}
|
|
1707
|
-
/**
|
|
1708
|
-
* IDC-05: freezes WASM's best-scoring frame *so far* for the optimizing phase.
|
|
1709
|
-
* Display-only — the committed frame arrives later, from `onCapture`, and
|
|
1710
|
-
* `storeCapturedImage` puts that one on `previewImageUrl` while clearing this
|
|
1711
|
-
* one in the same assign, so the rendering layer's
|
|
1712
|
-
* `candidateImageUrl ?? previewImageUrl` falls through to the frame that
|
|
1713
|
-
* actually uploads for the crossfade.
|
|
1714
|
-
*
|
|
1715
|
-
* Revokes any previous URL rather than leaking one per retry.
|
|
1716
|
-
*/
|
|
1717
|
-
function getCandidateFrameValues(context, event) {
|
|
1718
|
-
if (event.type !== "DETECTION_OPTIMIZING" || !event.candidateCanvas) return { candidateImageUrl: context.candidateImageUrl };
|
|
1719
|
-
const candidateCanvas = event.candidateCanvas;
|
|
1720
|
-
const canvas = cropCanvasForPreview(context, candidateCanvas);
|
|
1721
|
-
canvas.updateBlob(CANDIDATE_FRAME_JPEG_QUALITY);
|
|
1722
|
-
const url = canvas.getBlobData()?.url;
|
|
1723
|
-
if (!url) {
|
|
1724
|
-
releasePreviewCanvases(candidateCanvas, canvas, { shouldReleasePreview: true });
|
|
1725
|
-
return { candidateImageUrl: context.candidateImageUrl };
|
|
1726
|
-
}
|
|
1727
|
-
releasePreviewCanvases(candidateCanvas, canvas, { shouldReleasePreview: false });
|
|
1728
|
-
if (context.candidateImageUrl) revokeObjectURL(context.candidateImageUrl);
|
|
1729
|
-
return { candidateImageUrl: url };
|
|
1730
|
-
}
|
|
1731
|
-
/**
|
|
1732
|
-
* Reclaims the full-frame canvases the phase allocated. At 1080p each is ~8MB of
|
|
1733
|
-
* backing store, and `release()` frees it now instead of at the next GC — which
|
|
1734
|
-
* is what matters on iOS Safari, where canvas memory is its own budget.
|
|
1735
|
-
*
|
|
1736
|
-
* `source` — the clone the detection actor snapshotted — is always dead by the
|
|
1737
|
-
* time this runs: its pixels live on in `preview`'s blob.
|
|
1738
|
-
*
|
|
1739
|
-
* `preview` is the caller's decision, because `release()` also revokes
|
|
1740
|
-
* `blobData.url`. On the success path that URL is the very thing being handed to
|
|
1741
|
-
* the machine as `candidateImageUrl`, so releasing it would blank the phase's
|
|
1742
|
-
* own still; pass `shouldReleasePreview: true` only where no URL survives. Either way
|
|
1743
|
-
* the identity guard covers `transformPerspective` returning the canvas it was
|
|
1744
|
-
* given (no provider, or a WASM failure), so the aliased canvas is never
|
|
1745
|
-
* released twice or released out from under a live URL.
|
|
1746
|
-
*/
|
|
1747
|
-
function releasePreviewCanvases(source, preview, { shouldReleasePreview }) {
|
|
1748
|
-
if (preview === source) {
|
|
1749
|
-
if (shouldReleasePreview) source.release();
|
|
1750
|
-
return;
|
|
1751
|
-
}
|
|
1752
|
-
if (shouldReleasePreview) preview.release();
|
|
1753
|
-
source.release();
|
|
1754
|
-
}
|
|
1755
|
-
function cropCanvasForPreview(context, canvas) {
|
|
1756
|
-
const canvasWidth = canvas.width();
|
|
1757
|
-
const canvasHeight = canvas.height();
|
|
1758
|
-
if (!context.provider || !canvasWidth || !canvasHeight) return canvas;
|
|
1759
|
-
const frameRect = resolveCaptureFrameRect(context, canvasWidth, canvasHeight);
|
|
1760
|
-
return context.provider.transformPerspective(canvas, frameRect);
|
|
1761
|
-
}
|
|
1762
|
-
/**
|
|
1763
|
-
* Drops the IDC-05 best-so-far still at every attempt/side boundary. Unlike
|
|
1764
|
-
* `previewImageUrl` it is never preserved into `flipPreview` (it was never a
|
|
1765
|
-
* committed frame), so it can always be revoked outright.
|
|
1766
|
-
*
|
|
1767
|
-
* Clears `stashedCommit` alongside it: a commit parked for the phase's dwell is
|
|
1768
|
-
* only meaningful inside that phase, and holding the canvas reference past it
|
|
1769
|
-
* would keep a full-res frame alive for the rest of the attempt.
|
|
1770
|
-
*/
|
|
1771
|
-
function getClearOptimizingValues(context) {
|
|
1772
|
-
if (context.candidateImageUrl) revokeObjectURL(context.candidateImageUrl);
|
|
1773
|
-
return {
|
|
1774
|
-
candidateImageUrl: void 0,
|
|
1775
|
-
stashedCommit: void 0
|
|
1776
|
-
};
|
|
1777
|
-
}
|
|
1778
|
-
function getDetectionStatusFromUpdate(context, event) {
|
|
1779
|
-
if (event.type === "DETECTION_UPDATE") {
|
|
1780
|
-
const newStatus = event.status;
|
|
1781
|
-
const currentStatus = context.detectionStatus;
|
|
1782
|
-
if (currentStatus === "wrongSide") {
|
|
1783
|
-
if (!(newStatus === "capturing" || newStatus === "manualCapture" || newStatus === "offline")) return currentStatus;
|
|
1784
|
-
return newStatus;
|
|
1785
|
-
}
|
|
1786
|
-
if ((newStatus === "blur" || newStatus === "glare") && currentStatus === "farAway") return currentStatus;
|
|
1787
|
-
if ((newStatus === "wrongSide" || newStatus === "farAway") && (currentStatus === "blur" || currentStatus === "glare")) return newStatus;
|
|
1788
|
-
return newStatus;
|
|
1789
|
-
}
|
|
1790
|
-
return "idle";
|
|
1791
|
-
}
|
|
1792
|
-
function getDetectionStatusFromSideChange(context, side) {
|
|
1793
|
-
const detectedSide = side?.toLowerCase() || "";
|
|
1794
|
-
const currentMode = context.currentMode;
|
|
1795
|
-
if (detectedSide === "wrong") return "wrongSide";
|
|
1796
|
-
const isBackDetected = detectedSide.includes("back") && !detectedSide.includes("front");
|
|
1797
|
-
const isFrontDetected = detectedSide.includes("front") && !detectedSide.includes("back");
|
|
1798
|
-
if (currentMode === "front" && isBackDetected || currentMode === "back" && isFrontDetected) return "wrongSide";
|
|
1799
|
-
if (currentMode === "front" && isFrontDetected || currentMode === "back" && isBackDetected || currentMode === "passport") return "detecting";
|
|
1800
|
-
return "detecting";
|
|
1801
|
-
}
|
|
1802
|
-
function getCurrentModeFromEvent(context, event) {
|
|
1803
|
-
if ("documentType" in event) {
|
|
1804
|
-
if (event.documentType === "passport") return "passport";
|
|
1805
|
-
return context.config.usSmartCapture ? "back" : "front";
|
|
1806
|
-
}
|
|
1807
|
-
if (event.type === "FRONT_COMPLETE") return "back";
|
|
1808
|
-
return context.currentMode;
|
|
1809
|
-
}
|
|
1810
|
-
/**
|
|
1811
|
-
* Maps an `AddBarcodeV3Response` (US Smart Capture) into a synthetic
|
|
1812
|
-
* `uploadResponse` so the barcode submit path composes with the existing
|
|
1813
|
-
* downstream logic: `shouldContinueToFront` reads `forceFrontIdCapture`, and
|
|
1814
|
-
* `skipProcessId` is derived from `idValidationCompleted`. `classification` /
|
|
1815
|
-
* `readability` are forced `true` (the barcode response carries no image-quality
|
|
1816
|
-
* fields); the barcode path lands on `success` directly, bypassing upload
|
|
1817
|
-
* validation. Only ever *sets* the skip — an existing skip is preserved.
|
|
1818
|
-
*/
|
|
1819
|
-
function getBarcodeResponseValues(context, event) {
|
|
1820
|
-
const output = event.output;
|
|
1821
|
-
return {
|
|
1822
|
-
uploadResponse: {
|
|
1823
|
-
sharpness: 0,
|
|
1824
|
-
correctSharpness: true,
|
|
1825
|
-
glare: 0,
|
|
1826
|
-
correctGlare: true,
|
|
1827
|
-
horizontalResolution: 0,
|
|
1828
|
-
classification: true,
|
|
1829
|
-
readability: true,
|
|
1830
|
-
typeOfId: "",
|
|
1831
|
-
issueYear: 0,
|
|
1832
|
-
issueName: "",
|
|
1833
|
-
sessionStatus: output?.sessionStatus ?? "",
|
|
1834
|
-
countryCode: output?.countryCode ?? "",
|
|
1835
|
-
forceFrontIdCapture: output?.forceFrontIdCapture,
|
|
1836
|
-
idValidationCompleted: output?.idValidationCompleted,
|
|
1837
|
-
isDocumentExpired: output?.isDocumentExpired,
|
|
1838
|
-
success: output?.success
|
|
1839
|
-
},
|
|
1840
|
-
skipProcessId: output?.idValidationCompleted === true || context.skipProcessId
|
|
1841
|
-
};
|
|
1842
|
-
}
|
|
1843
|
-
//#endregion
|
|
1844
|
-
//#region src/modules/id/idCaptureStateMachine.ts
|
|
1845
|
-
/**
|
|
1846
|
-
* Shown/logged when an ID capture module has no accepted documents and no
|
|
1847
|
-
* other capture option enabled — there is nothing to capture (ENG-43983).
|
|
1848
|
-
*/
|
|
1849
|
-
const ID_CAPTURE_NO_DOCUMENT_TYPES_ERROR = "ID capture module has no accepted documents and no capture option enabled";
|
|
1850
|
-
function getIdErrorCodeFromUnknown(error) {
|
|
1851
|
-
if (error instanceof Error) {
|
|
1852
|
-
const message = error.message;
|
|
1853
|
-
return Object.values(ID_ERROR_CODES).find((value) => message.includes(value));
|
|
1854
|
-
}
|
|
1855
|
-
}
|
|
1856
|
-
const idCaptureMachine = setup({
|
|
1857
|
-
types: {
|
|
1858
|
-
context: {},
|
|
1859
|
-
events: {},
|
|
1860
|
-
input: {},
|
|
1861
|
-
output: {}
|
|
1862
|
-
},
|
|
1863
|
-
actors: {
|
|
1864
|
-
checkPermission: checkPermissionActor,
|
|
1865
|
-
requestPermission: requestPermissionActor,
|
|
1866
|
-
initializeCamera: initializeCameraActor,
|
|
1867
|
-
runDetection: runDetectionActor,
|
|
1868
|
-
uploadIdImage: uploadIdImageActor,
|
|
1869
|
-
uploadProgressTicker: uploadProgressTickerActor,
|
|
1870
|
-
processId: processIdActor,
|
|
1871
|
-
submitBarcode: submitBarcodeActor,
|
|
1872
|
-
startRecording: startRecordingActor,
|
|
1873
|
-
initializeDeepsightSession: initializeDeepsightSessionActor,
|
|
1874
|
-
checkVirtualCamera: checkVirtualCameraActor,
|
|
1875
|
-
manualUploadMachine,
|
|
1876
|
-
digitalUploadMachine
|
|
1877
|
-
},
|
|
1878
|
-
actions: {
|
|
1879
|
-
stopMediaStream: assign(({ context }) => {
|
|
1880
|
-
performStopMediaStream(context);
|
|
1881
|
-
return {
|
|
1882
|
-
stream: void 0,
|
|
1883
|
-
frameCapturer: void 0
|
|
1884
|
-
};
|
|
1885
|
-
}),
|
|
1886
|
-
disposeProvider: ({ context }) => {
|
|
1887
|
-
performDisposeProvider(context);
|
|
1888
|
-
},
|
|
1889
|
-
cleanupDeepsight: ({ context }) => {
|
|
1890
|
-
performCleanupDeepsight(context);
|
|
1891
|
-
},
|
|
1892
|
-
flagIdManualReview: () => {
|
|
1893
|
-
flagIdManualReview();
|
|
1894
|
-
},
|
|
1895
|
-
resetForBackCapture: assign(({ context }) => {
|
|
1896
|
-
performResetForBackCapture(context);
|
|
1897
|
-
return {
|
|
1898
|
-
stream: void 0,
|
|
1899
|
-
frameCapturer: void 0,
|
|
1900
|
-
detectionStatus: "idle",
|
|
1901
|
-
counterValue: 0,
|
|
1902
|
-
orientation: void 0,
|
|
1903
|
-
resetDetection: void 0,
|
|
1904
|
-
idType: void 0,
|
|
1905
|
-
qualityElements: void 0,
|
|
1906
|
-
frameRect: void 0,
|
|
1907
|
-
previewImageUrl: void 0,
|
|
1908
|
-
...getClearOptimizingValues(context),
|
|
1909
|
-
flipPreview: context.previewImageUrl ? {
|
|
1910
|
-
url: context.previewImageUrl,
|
|
1911
|
-
orientation: context.orientation,
|
|
1912
|
-
mode: context.currentMode === "passport" ? "passport" : "id"
|
|
1913
|
-
} : context.flipPreview,
|
|
1914
|
-
uploadProgress: void 0,
|
|
1915
|
-
manualCaptureTriggered: false,
|
|
1916
|
-
attemptsRemaining: context.config.captureAttempts,
|
|
1917
|
-
expiredAttempts: 0,
|
|
1918
|
-
expiredFromUpload: false,
|
|
1919
|
-
exhaustedFromUpload: false,
|
|
1920
|
-
forceFinishAfterProcessing: false,
|
|
1921
|
-
captureResolution: void 0,
|
|
1922
|
-
cameraFallbackLevel: void 0
|
|
1923
|
-
};
|
|
1924
|
-
}),
|
|
1925
|
-
resetForFrontCapture: assign(({ context }) => {
|
|
1926
|
-
performResetForFrontCapture(context);
|
|
1927
|
-
return {
|
|
1928
|
-
stream: void 0,
|
|
1929
|
-
frameCapturer: void 0,
|
|
1930
|
-
detectionStatus: "idle",
|
|
1931
|
-
counterValue: 0,
|
|
1932
|
-
orientation: void 0,
|
|
1933
|
-
resetDetection: void 0,
|
|
1934
|
-
idType: void 0,
|
|
1935
|
-
qualityElements: void 0,
|
|
1936
|
-
frameRect: void 0,
|
|
1937
|
-
previewImageUrl: void 0,
|
|
1938
|
-
...getClearOptimizingValues(context),
|
|
1939
|
-
flipPreview: context.previewImageUrl ? {
|
|
1940
|
-
url: context.previewImageUrl,
|
|
1941
|
-
orientation: context.orientation,
|
|
1942
|
-
mode: context.currentMode === "passport" ? "passport" : "id"
|
|
1943
|
-
} : context.flipPreview,
|
|
1944
|
-
uploadProgress: void 0,
|
|
1945
|
-
manualCaptureTriggered: false,
|
|
1946
|
-
attemptsRemaining: context.config.captureAttempts,
|
|
1947
|
-
expiredAttempts: 0,
|
|
1948
|
-
expiredFromUpload: false,
|
|
1949
|
-
exhaustedFromUpload: false,
|
|
1950
|
-
forceFinishAfterProcessing: false,
|
|
1951
|
-
captureResolution: void 0,
|
|
1952
|
-
cameraFallbackLevel: void 0
|
|
1953
|
-
};
|
|
1954
|
-
}),
|
|
1955
|
-
clearFlipPreview: assign({ flipPreview: void 0 }),
|
|
1956
|
-
prepareForBackCapture: assign(({ context }) => {
|
|
1957
|
-
context.provider?.reset();
|
|
1958
|
-
return {
|
|
1959
|
-
detectionStatus: "idle",
|
|
1960
|
-
counterValue: 0,
|
|
1961
|
-
orientation: void 0,
|
|
1962
|
-
resetDetection: void 0,
|
|
1963
|
-
idType: void 0,
|
|
1964
|
-
qualityElements: void 0,
|
|
1965
|
-
frameRect: void 0,
|
|
1966
|
-
previewImageUrl: void 0,
|
|
1967
|
-
...getClearOptimizingValues(context),
|
|
1968
|
-
uploadProgress: void 0,
|
|
1969
|
-
manualCaptureTriggered: false,
|
|
1970
|
-
attemptsRemaining: context.config.captureAttempts
|
|
1971
|
-
};
|
|
1972
|
-
}),
|
|
1973
|
-
setStreamAndCapturer: assign({
|
|
1974
|
-
stream: ({ event }) => getStreamFromEvent(event),
|
|
1975
|
-
provider: ({ event }) => getProviderFromEvent(event),
|
|
1976
|
-
frameCapturer: ({ event }) => getFrameCapturerFromEvent(event),
|
|
1977
|
-
captureResolution: ({ event }) => getCaptureResolutionFromEvent(event),
|
|
1978
|
-
cameraFallbackLevel: ({ event }) => getCameraFallbackLevelFromEvent(event)
|
|
1979
|
-
}),
|
|
1980
|
-
setPermissionResultAndStream: assign({
|
|
1981
|
-
permissionResult: ({ context, event }) => getPermissionResultFromEvent(event) ?? context.permissionResult,
|
|
1982
|
-
stream: ({ context, event }) => getStreamFromEvent(event) ?? context.stream,
|
|
1983
|
-
cameraFallbackLevel: ({ context, event }) => getCameraFallbackLevelFromEvent(event) ?? context.cameraFallbackLevel
|
|
1984
|
-
}),
|
|
1985
|
-
trackTutorialId: () => {},
|
|
1986
|
-
trackContinue: () => {},
|
|
1987
|
-
trackCameraId: ({ context }) => {},
|
|
1988
|
-
reportCaptureOptimizingAssignment: ({ context }) => {
|
|
1989
|
-
performReportCaptureOptimizingAssignment(context);
|
|
1990
|
-
},
|
|
1991
|
-
preloadRecordingProvider: ({ context }) => {
|
|
1992
|
-
preloadIdRecordingProvider(context.config);
|
|
1993
|
-
},
|
|
1994
|
-
resetContext: assign(({ context }) => getResetContextValues(context)),
|
|
1995
|
-
resetDetection: ({ context }) => {
|
|
1996
|
-
performResetDetection(context);
|
|
1997
|
-
},
|
|
1998
|
-
captureImage: assign({ qualityElements: ({ event }) => {
|
|
1999
|
-
if ("qualityElements" in event) return event.qualityElements;
|
|
2000
|
-
} }),
|
|
2001
|
-
storeCapturedCanvasInProvider: ({ context, event }) => {
|
|
2002
|
-
storeCapturedCanvasInProviderLogic(context, event);
|
|
2003
|
-
},
|
|
2004
|
-
captureLatestFrame: ({ context }) => {
|
|
2005
|
-
context.frameCapturer?.getLatestCanvas();
|
|
2006
|
-
},
|
|
2007
|
-
clearUploadFailure: assign(({ context }) => getClearUploadFailureValues(context)),
|
|
2008
|
-
clearStreamForRetry: assign(({ context }) => {
|
|
2009
|
-
performStopMediaStream(context);
|
|
2010
|
-
performDisposeProvider(context);
|
|
2011
|
-
return {
|
|
2012
|
-
stream: void 0,
|
|
2013
|
-
provider: void 0,
|
|
2014
|
-
frameCapturer: void 0,
|
|
2015
|
-
captureResolution: void 0,
|
|
2016
|
-
cameraFallbackLevel: void 0
|
|
2017
|
-
};
|
|
2018
|
-
}),
|
|
2019
|
-
decrementAttemptsRemaining: assign(({ context }) => ({ attemptsRemaining: context.attemptsRemaining - 1 })),
|
|
2020
|
-
setUploadErrorFromUploadValidation: assign({ uploadError: ({ context }) => getUploadValidationError(context) }),
|
|
2021
|
-
stopMediaRecording: ({ context }) => {
|
|
2022
|
-
performStopMediaRecording(context);
|
|
2023
|
-
},
|
|
2024
|
-
clearRecordingSession: assign({ recordingSession: () => void 0 }),
|
|
2025
|
-
setSelectedDocument: assign({ selectedDocumentType: ({ event }) => {
|
|
2026
|
-
if ("documentType" in event) return event.documentType;
|
|
2027
|
-
} }),
|
|
2028
|
-
setCurrentMode: assign({ currentMode: ({ event, context }) => getCurrentModeFromEvent(context, event) }),
|
|
2029
|
-
storeCapturedImage: assign(({ context, event }) => getStoreCapturedImageValues(context, event)),
|
|
2030
|
-
setCandidateFrame: assign(({ context, event }) => getCandidateFrameValues(context, event)),
|
|
2031
|
-
/**
|
|
2032
|
-
* IDC-05: parks WASM's commit while the optimizing phase spends the rest of
|
|
2033
|
-
* its dwell. The frame travels in context only for that stretch —
|
|
2034
|
-
* `releaseStashedCommit` re-raises it and `getClearOptimizingValues` drops it
|
|
2035
|
-
* on every other exit from the phase.
|
|
2036
|
-
*/
|
|
2037
|
-
stashCommittedFrame: assign({ stashedCommit: ({ event }) => {
|
|
2038
|
-
const commit = event;
|
|
2039
|
-
return {
|
|
2040
|
-
canvas: commit.canvas,
|
|
2041
|
-
qualityElements: commit.qualityElements
|
|
2042
|
-
};
|
|
2043
|
-
} }),
|
|
2044
|
-
/**
|
|
2045
|
-
* IDC-05: hands a parked commit back to the machine as the very event that
|
|
2046
|
-
* would have carried it, so `capturing`'s entry actions stay event-driven.
|
|
2047
|
-
* Re-raised rather than read from context by `capturing` because
|
|
2048
|
-
* `storeCapturedCanvasInProvider` falls back to the *live* frame when the
|
|
2049
|
-
* entering event has no canvas — a timer transition into `capturing` would
|
|
2050
|
-
* stage a live frame for upload instead of the one WASM committed.
|
|
2051
|
-
*/
|
|
2052
|
-
releaseStashedCommit: enqueueActions(({ context, enqueue }) => {
|
|
2053
|
-
const stashed = context.stashedCommit;
|
|
2054
|
-
if (!stashed) return;
|
|
2055
|
-
enqueue(raise({
|
|
2056
|
-
type: "DETECTION_SUCCESS",
|
|
2057
|
-
canvas: stashed.canvas,
|
|
2058
|
-
qualityElements: stashed.qualityElements
|
|
2059
|
-
}));
|
|
2060
|
-
}),
|
|
2061
|
-
/**
|
|
2062
|
-
* IDC-05: releases everything the optimizing phase allocated — the parked
|
|
2063
|
-
* commit AND the frozen still's blob URL. Bound to `optimizing.exit`, so it
|
|
2064
|
-
* covers every route out of the phase, not just the two that already clear
|
|
2065
|
-
* up after themselves (`getStoreCapturedImageValues` on the commit,
|
|
2066
|
-
* `optimizingGrace`'s own action on the abandon path). Before this it
|
|
2067
|
-
* cleared only `stashedCommit`, and an exit through the manual-capture
|
|
2068
|
-
* escape leaked the URL until the next attempt/side boundary.
|
|
2069
|
-
*
|
|
2070
|
-
* Safe to revoke here on the commit path: exit and `capturing`'s entry run
|
|
2071
|
-
* in the same macrostep, and `capturing`'s eventless `always` means the UI
|
|
2072
|
-
* only ever observes the resulting `uploading` snapshot — by which point
|
|
2073
|
-
* `previewImageUrl` is set, so `candidateImageUrl ?? previewImageUrl` never
|
|
2074
|
-
* resolves to nothing (see `getStoreCapturedImageValues`).
|
|
2075
|
-
*/
|
|
2076
|
-
clearOptimizingPhase: assign(({ context }) => getClearOptimizingValues(context)),
|
|
2077
|
-
storeBarcodeResponse: assign(({ context, event }) => getBarcodeResponseValues(context, event)),
|
|
2078
|
-
storeDecodedBarcode: assign({ decodedBarcode: ({ event }) => event.decoded }),
|
|
2079
|
-
setBarcodeFastPathAttempted: assign({ barcodeFastPathAttempted: true }),
|
|
2080
|
-
markBarcodeFastPathCaptured: assign({
|
|
2081
|
-
barcodeFastPathCaptured: true,
|
|
2082
|
-
previewImageUrl: void 0
|
|
2083
|
-
}),
|
|
2084
|
-
clearBarcodeFastPathCaptured: assign({ barcodeFastPathCaptured: false }),
|
|
2085
|
-
setDetectionStatus: assign({ detectionStatus: ({ event, context }) => getDetectionStatusFromUpdate(context, event) }),
|
|
2086
|
-
setCounterValue: assign({ counterValue: ({ event }) => {
|
|
2087
|
-
if ("value" in event) return event.value;
|
|
2088
|
-
return 0;
|
|
2089
|
-
} }),
|
|
2090
|
-
setIdType: assign({ idType: ({ event }) => {
|
|
2091
|
-
if ("idType" in event) return event.idType;
|
|
2092
|
-
} }),
|
|
2093
|
-
setOrientation: assign({ orientation: ({ event }) => {
|
|
2094
|
-
if ("orientation" in event) return event.orientation;
|
|
2095
|
-
} }),
|
|
2096
|
-
setFrameRect: assign({ frameRect: ({ event }) => {
|
|
2097
|
-
if ("frameRect" in event) return event.frameRect;
|
|
2098
|
-
} }),
|
|
2099
|
-
setDetectionArea: assign({ detectionArea: ({ event }) => {
|
|
2100
|
-
if ("detectionArea" in event) return event.detectionArea;
|
|
2101
|
-
} }),
|
|
2102
|
-
incrementExpiredAttempts: assign(({ context }) => ({ expiredAttempts: context.expiredAttempts + 1 })),
|
|
2103
|
-
/**
|
|
2104
|
-
* Mirrors the child's successful upload response onto parent context so
|
|
2105
|
-
* the manager mapper (and the workflow orchestrator) can read fields
|
|
2106
|
-
* like `skipBackIdCapture` and `typeOfId`. Also marks the session as a
|
|
2107
|
-
* digital upload so back capture is suppressed regardless of
|
|
2108
|
-
* `alwaysCaptureBackOfId` (digital IDs are single-side, like passports).
|
|
2109
|
-
*
|
|
2110
|
-
* The child machine's `output` is intentionally narrow (`{ result }`);
|
|
2111
|
-
* to avoid breaking the established invoke→onDone contract, we read the
|
|
2112
|
-
* upload response from the child snapshot's context instead of widening
|
|
2113
|
-
* the output shape.
|
|
2114
|
-
*/
|
|
2115
|
-
storeDigitalUploadResponse: assign(({ self }) => {
|
|
2116
|
-
const response = ((self.getSnapshot().children?.["digitalIdUpload"]?.getSnapshot())?.context)?.response;
|
|
2117
|
-
if (!response) return { isDigitalUpload: true };
|
|
2118
|
-
return {
|
|
2119
|
-
uploadResponse: response,
|
|
2120
|
-
isDigitalUpload: true
|
|
2121
|
-
};
|
|
2122
|
-
}),
|
|
2123
|
-
syncAttemptsFromDigitalUpload: assign({ attemptsRemaining: ({ event }) => event.output?.attemptsRemaining ?? 0 }),
|
|
2124
|
-
incrementProcessingExpiredAttempts: assign(({ context }) => ({ processingExpiredAttempts: context.processingExpiredAttempts + 1 })),
|
|
2125
|
-
setSkipProcessId: assign({ skipProcessId: () => true }),
|
|
2126
|
-
setExpiredFromUpload: assign({ expiredFromUpload: () => true }),
|
|
2127
|
-
setExhaustedFromUpload: assign({ exhaustedFromUpload: () => true }),
|
|
2128
|
-
setExpiredRedirected: assign({ expiredRedirected: () => true }),
|
|
2129
|
-
setForceFinishAfterProcessing: assign({ forceFinishAfterProcessing: () => true }),
|
|
2130
|
-
clearExpiredFromUpload: assign({ expiredFromUpload: () => false })
|
|
2131
|
-
},
|
|
2132
|
-
guards: {
|
|
2133
|
-
hasShowTutorial: hasShowTutorialGuard,
|
|
2134
|
-
hasAgeAssurance: hasAgeAssuranceGuard,
|
|
2135
|
-
hasShowDocumentChooser: hasShowDocumentChooserGuard,
|
|
2136
|
-
isPermissionGranted: isPermissionGrantedGuard,
|
|
2137
|
-
isReadyForCapture: isReadyForCaptureGuard,
|
|
2138
|
-
needsMotionPrimeOnly: needsMotionPrimeOnlyGuard,
|
|
2139
|
-
isPermissionDeniedError: isPermissionDeniedErrorGuard,
|
|
2140
|
-
hasStream: hasStreamGuard,
|
|
2141
|
-
hasInitializedCamera: hasInitializedCameraGuard,
|
|
2142
|
-
hasAttemptsRemaining: hasAttemptsRemainingGuard,
|
|
2143
|
-
hasCapturedImage: hasCapturedImageGuard,
|
|
2144
|
-
hasCandidateFrame: hasCandidateFrameGuard,
|
|
2145
|
-
hasStashedCommit: hasStashedCommitGuard,
|
|
2146
|
-
hasUploadValidationError: hasUploadValidationErrorGuard,
|
|
2147
|
-
isFrontMode: isFrontModeGuard,
|
|
2148
|
-
shouldContinueToBack: shouldContinueToBackGuard,
|
|
2149
|
-
shouldContinueToFront: shouldContinueToFrontGuard,
|
|
2150
|
-
hasMandatoryConsent: hasMandatoryConsentGuard,
|
|
2151
|
-
isCaptureOptimizingMode: isCaptureOptimizingModeGuard,
|
|
2152
|
-
supportsOptimizingStatus: supportsOptimizingStatusGuard,
|
|
2153
|
-
isDeepsightEnabled: isDeepsightEnabledGuard,
|
|
2154
|
-
isDeepsightReady: isDeepsightReadyGuard,
|
|
2155
|
-
needsDeepsightInit: needsDeepsightInitGuard,
|
|
2156
|
-
hasOnlyManualUploadAvailable: hasOnlyManualUploadAvailableGuard,
|
|
2157
|
-
hasNoDocumentTypesAvailable: hasNoDocumentTypesAvailableGuard,
|
|
2158
|
-
isManualIdUploadSelected: isManualIdUploadSelectedGuard,
|
|
2159
|
-
isDigitalIdUploadSelected: isDigitalIdUploadSelectedGuard,
|
|
2160
|
-
isUploadExpired: isUploadExpiredGuard,
|
|
2161
|
-
isExpiredAttemptsExhausted: isExpiredAttemptsExhaustedGuard,
|
|
2162
|
-
isNotPassportMode: isNotPassportModeGuard,
|
|
2163
|
-
shouldForceBackOnExpired: shouldForceBackOnExpiredGuard,
|
|
2164
|
-
wasExpiredFromUpload: wasExpiredFromUploadGuard,
|
|
2165
|
-
shouldSkipProcessId: shouldSkipProcessIdGuard,
|
|
2166
|
-
shouldSubmitBarcode: shouldSubmitBarcodeGuard,
|
|
2167
|
-
canRunBarcodeFastPath: canRunBarcodeFastPathGuard,
|
|
2168
|
-
hasManualCaptureTriggered: hasManualCaptureTriggeredGuard,
|
|
2169
|
-
isProcessingExpiredExhausted: isProcessingExpiredExhaustedGuard,
|
|
2170
|
-
shouldProcessAfterExhaustion: shouldProcessAfterExhaustionGuard,
|
|
2171
|
-
forceFinishAfterProcessing: forceFinishAfterProcessingGuard,
|
|
2172
|
-
isBackModeInMultiSideFlow: isBackModeInMultiSideFlowGuard,
|
|
2173
|
-
wasExpiredRedirected: wasExpiredRedirectedGuard,
|
|
2174
|
-
isManualUploadExhausted: ({ event }) => event.output?.result === "exhausted",
|
|
2175
|
-
isDigitalUploadExhausted: ({ event }) => event.output?.result === "exhausted",
|
|
2176
|
-
isDigitalUploadSuccessful: ({ event }) => event.output?.result === "success"
|
|
2177
|
-
},
|
|
2178
|
-
delays: {
|
|
2179
|
-
/**
|
|
2180
|
-
* IDC-05: how long the optimizing phase lasts, on BOTH paths — the auto
|
|
2181
|
-
* path's `optimizing.holding` and the manual path's `optimizingHold`. One
|
|
2182
|
-
* value, read from context rather than hardcoded, so the experiment payload
|
|
2183
|
-
* governs the phase wherever it is played.
|
|
2184
|
-
*
|
|
2185
|
-
* `?? 0` rather than the default dwell, deliberately: neither state is
|
|
2186
|
-
* reachable outside the treatment arm, and the treatment arm is the only
|
|
2187
|
-
* thing that populates `optimizingDwellMs`
|
|
2188
|
-
* (`resolveCaptureOptimizingTreatment` always sets it on its `optimizing`
|
|
2189
|
-
* branch). An absent value here therefore means the wiring between the two
|
|
2190
|
-
* broke, and falling back to the default would silently add a dwell to a
|
|
2191
|
-
* capture that was never supposed to have one. Zero makes that failure a
|
|
2192
|
-
* pass-through instead of a 1.5s regression.
|
|
2193
|
-
*/
|
|
2194
|
-
optimizingDwell: ({ context }) => context.optimizingDwellMs ?? 0,
|
|
2195
|
-
/**
|
|
2196
|
-
* IDC-05: how much longer the machine waits for WASM's commit once the phase
|
|
2197
|
-
* has had its full dwell (`optimizing.released`). Past this, `onCapture` —
|
|
2198
|
-
* the phase's normal exit — is not coming for the window this still belongs
|
|
2199
|
-
* to, and the phase is abandoned.
|
|
2200
|
-
*
|
|
2201
|
-
* A constant, not `dwell + margin`: the dwell has already been spent in
|
|
2202
|
-
* `holding` by the time this arms, so the total from phase entry is
|
|
2203
|
-
* unchanged. It also means the timer stays armed on a partially-resolved
|
|
2204
|
-
* payload, where `optimizingDwell` above collapses to zero.
|
|
2205
|
-
*/
|
|
2206
|
-
optimizingGrace: OPTIMIZING_WATCHDOG_MARGIN_MS
|
|
2207
|
-
}
|
|
2208
|
-
}).createMachine({
|
|
2209
|
-
id: "idCapture",
|
|
2210
|
-
initial: "idle",
|
|
2211
|
-
output: ({ context }) => computeIdCaptureOutput(context),
|
|
2212
|
-
context: ({ input }) => {
|
|
2213
|
-
const currentMode = input.config.onlyBack ? "back" : !input.config.enableId && input.config.enablePassport ? "passport" : input.config.usSmartCapture ? "back" : "front";
|
|
2214
|
-
return {
|
|
2215
|
-
config: input.config,
|
|
2216
|
-
captureFeedbackMode: input.captureFeedbackMode ?? "countdown",
|
|
2217
|
-
captureWindowMs: input.captureWindowMs,
|
|
2218
|
-
optimizingDwellMs: input.optimizingDwellMs,
|
|
2219
|
-
currentMode,
|
|
2220
|
-
selectedDocumentType: void 0,
|
|
2221
|
-
stream: void 0,
|
|
2222
|
-
provider: void 0,
|
|
2223
|
-
frameCapturer: void 0,
|
|
2224
|
-
error: void 0,
|
|
2225
|
-
detectionStatus: "idle",
|
|
2226
|
-
counterValue: 0,
|
|
2227
|
-
orientation: void 0,
|
|
2228
|
-
capturedImages: {},
|
|
2229
|
-
captureOnlyImages: {},
|
|
2230
|
-
uploadResponse: void 0,
|
|
2231
|
-
decodedBarcode: null,
|
|
2232
|
-
barcodeFastPathAttempted: false,
|
|
2233
|
-
barcodeFastPathCaptured: false,
|
|
2234
|
-
recordingSession: void 0,
|
|
2235
|
-
attemptsRemaining: input.config.captureAttempts,
|
|
2236
|
-
expiredAttempts: 0,
|
|
2237
|
-
expiredRedirected: false,
|
|
2238
|
-
processingExpiredAttempts: 0,
|
|
2239
|
-
skipProcessId: input.config.skipProcessId === true,
|
|
2240
|
-
expiredFromUpload: false,
|
|
2241
|
-
isDigitalUpload: false,
|
|
2242
|
-
exhaustedFromUpload: false,
|
|
2243
|
-
forceFinishAfterProcessing: false,
|
|
2244
|
-
uploadError: void 0,
|
|
2245
|
-
permissionResult: void 0,
|
|
2246
|
-
resetDetection: void 0,
|
|
2247
|
-
idType: void 0,
|
|
2248
|
-
qualityElements: void 0,
|
|
2249
|
-
frameRect: void 0,
|
|
2250
|
-
detectionArea: void 0,
|
|
2251
|
-
previewImageUrl: void 0,
|
|
2252
|
-
candidateImageUrl: void 0,
|
|
2253
|
-
uploadProgress: void 0,
|
|
2254
|
-
manualCaptureTriggered: false,
|
|
2255
|
-
deepsightService: void 0,
|
|
2256
|
-
analyticsProvider: input.analyticsProvider,
|
|
2257
|
-
dependencies: input.dependencies,
|
|
2258
|
-
disableIpify: getDisableIpify(),
|
|
2259
|
-
deepsightInitAttempted: false,
|
|
2260
|
-
availableDocumentTypes: getAvailableDocumentTypes(input.config),
|
|
2261
|
-
captureResolution: void 0,
|
|
2262
|
-
cameraFallbackLevel: void 0
|
|
2263
|
-
};
|
|
2264
|
-
},
|
|
2265
|
-
on: {
|
|
2266
|
-
QUIT: { target: "#idCapture.closed" },
|
|
2267
|
-
UPDATE_DETECTION_AREA: { actions: "setDetectionArea" }
|
|
2268
|
-
},
|
|
2269
|
-
states: {
|
|
2270
|
-
idle: { on: { LOAD: [
|
|
2271
|
-
{
|
|
2272
|
-
target: "error",
|
|
2273
|
-
guard: "hasNoDocumentTypesAvailable",
|
|
2274
|
-
actions: [() => console.error(ID_CAPTURE_NO_DOCUMENT_TYPES_ERROR), assign({ error: () => ID_CAPTURE_NO_DOCUMENT_TYPES_ERROR })]
|
|
2275
|
-
},
|
|
2276
|
-
{
|
|
2277
|
-
target: "manualIdUpload",
|
|
2278
|
-
guard: "hasOnlyManualUploadAvailable"
|
|
2279
|
-
},
|
|
2280
|
-
{
|
|
2281
|
-
target: "chooser",
|
|
2282
|
-
guard: "hasShowDocumentChooser"
|
|
2283
|
-
},
|
|
2284
|
-
{
|
|
2285
|
-
target: "ageVerification",
|
|
2286
|
-
guard: "hasAgeAssurance"
|
|
2287
|
-
},
|
|
2288
|
-
{
|
|
2289
|
-
target: "tutorial",
|
|
2290
|
-
guard: "hasShowTutorial"
|
|
2291
|
-
},
|
|
2292
|
-
{ target: "loading" }
|
|
2293
|
-
] } },
|
|
2294
|
-
chooser: { on: { SELECT_DOCUMENT: [
|
|
2295
|
-
{
|
|
2296
|
-
target: "digitalIdUpload",
|
|
2297
|
-
guard: "isDigitalIdUploadSelected",
|
|
2298
|
-
actions: ["setSelectedDocument"]
|
|
2299
|
-
},
|
|
2300
|
-
{
|
|
2301
|
-
target: "manualIdUpload",
|
|
2302
|
-
guard: "isManualIdUploadSelected",
|
|
2303
|
-
actions: ["setSelectedDocument"]
|
|
2304
|
-
},
|
|
2305
|
-
{
|
|
2306
|
-
target: "ageVerification",
|
|
2307
|
-
guard: "hasAgeAssurance",
|
|
2308
|
-
actions: ["setSelectedDocument", "setCurrentMode"]
|
|
2309
|
-
},
|
|
2310
|
-
{
|
|
2311
|
-
target: "tutorial",
|
|
2312
|
-
guard: "hasShowTutorial",
|
|
2313
|
-
actions: ["setSelectedDocument", "setCurrentMode"]
|
|
2314
|
-
},
|
|
2315
|
-
{
|
|
2316
|
-
target: "loading",
|
|
2317
|
-
actions: ["setSelectedDocument", "setCurrentMode"]
|
|
2318
|
-
}
|
|
2319
|
-
] } },
|
|
2320
|
-
ageVerification: { on: { NEXT_STEP: [{
|
|
2321
|
-
target: "tutorial",
|
|
2322
|
-
guard: "hasShowTutorial",
|
|
2323
|
-
actions: "trackContinue"
|
|
2324
|
-
}, {
|
|
2325
|
-
target: "loading",
|
|
2326
|
-
actions: "trackContinue"
|
|
2327
|
-
}] } },
|
|
2328
|
-
loading: {
|
|
2329
|
-
entry: "preloadRecordingProvider",
|
|
2330
|
-
type: "parallel",
|
|
2331
|
-
states: {
|
|
2332
|
-
permissionCheck: {
|
|
2333
|
-
initial: "checking",
|
|
2334
|
-
states: {
|
|
2335
|
-
checking: { invoke: {
|
|
2336
|
-
id: "checkPermissionLoading",
|
|
2337
|
-
src: "checkPermission",
|
|
2338
|
-
onDone: {
|
|
2339
|
-
target: "done",
|
|
2340
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2341
|
-
},
|
|
2342
|
-
onError: {
|
|
2343
|
-
target: "done",
|
|
2344
|
-
actions: assign({ permissionResult: () => "prompt" })
|
|
2345
|
-
}
|
|
2346
|
-
} },
|
|
2347
|
-
done: { type: "final" }
|
|
2348
|
-
}
|
|
2349
|
-
},
|
|
2350
|
-
deepsightInit: {
|
|
2351
|
-
initial: "initializing",
|
|
2352
|
-
states: {
|
|
2353
|
-
initializing: { invoke: {
|
|
2354
|
-
id: "initDeepsightLoading",
|
|
2355
|
-
src: "initializeDeepsightSession",
|
|
2356
|
-
input: ({ context }) => ({
|
|
2357
|
-
ds: context.config.ds,
|
|
2358
|
-
dependencies: context.dependencies,
|
|
2359
|
-
disableIpify: context.disableIpify
|
|
2360
|
-
}),
|
|
2361
|
-
onDone: {
|
|
2362
|
-
target: "done",
|
|
2363
|
-
actions: assign({
|
|
2364
|
-
deepsightService: ({ event }) => event.output,
|
|
2365
|
-
deepsightInitAttempted: () => true
|
|
2366
|
-
})
|
|
2367
|
-
},
|
|
2368
|
-
onError: {
|
|
2369
|
-
target: "done",
|
|
2370
|
-
actions: [assign({ deepsightInitAttempted: () => true }), () => console.warn("Deepsight initialization failed")]
|
|
2371
|
-
}
|
|
2372
|
-
} },
|
|
2373
|
-
done: { type: "final" }
|
|
2374
|
-
}
|
|
2375
|
-
}
|
|
2376
|
-
},
|
|
2377
|
-
onDone: [{
|
|
2378
|
-
target: "capture",
|
|
2379
|
-
guard: "isReadyForCapture"
|
|
2380
|
-
}, { target: "permissions" }]
|
|
2381
|
-
},
|
|
2382
|
-
tutorial: {
|
|
2383
|
-
initial: "checkingPermission",
|
|
2384
|
-
entry: ["trackTutorialId", "preloadRecordingProvider"],
|
|
2385
|
-
states: {
|
|
2386
|
-
checkingPermission: {
|
|
2387
|
-
invoke: {
|
|
2388
|
-
id: "checkPermissionTutorial",
|
|
2389
|
-
src: "checkPermission",
|
|
2390
|
-
onDone: [{
|
|
2391
|
-
target: "initializingCamera",
|
|
2392
|
-
guard: "isReadyForCapture",
|
|
2393
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2394
|
-
}, {
|
|
2395
|
-
target: "ready",
|
|
2396
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2397
|
-
}]
|
|
2398
|
-
},
|
|
2399
|
-
on: { NEXT_STEP: {
|
|
2400
|
-
target: "#idCapture.capture",
|
|
2401
|
-
actions: "trackContinue"
|
|
2402
|
-
} }
|
|
2403
|
-
},
|
|
2404
|
-
initializingCamera: {
|
|
2405
|
-
type: "parallel",
|
|
2406
|
-
states: {
|
|
2407
|
-
cameraInit: {
|
|
2408
|
-
initial: "initializingDeepsight",
|
|
2409
|
-
states: {
|
|
2410
|
-
initializingDeepsight: { invoke: {
|
|
2411
|
-
id: "tutorialInitDeepsight",
|
|
2412
|
-
src: "initializeDeepsightSession",
|
|
2413
|
-
input: ({ context }) => ({
|
|
2414
|
-
ds: context.config.ds,
|
|
2415
|
-
dependencies: context.dependencies,
|
|
2416
|
-
disableIpify: context.disableIpify
|
|
2417
|
-
}),
|
|
2418
|
-
onDone: {
|
|
2419
|
-
target: "initializingStream",
|
|
2420
|
-
actions: assign({
|
|
2421
|
-
deepsightService: ({ event }) => event.output,
|
|
2422
|
-
deepsightInitAttempted: () => true
|
|
2423
|
-
})
|
|
2424
|
-
},
|
|
2425
|
-
onError: {
|
|
2426
|
-
target: "initializingStream",
|
|
2427
|
-
actions: [assign({ deepsightInitAttempted: () => true }), () => console.warn("Deepsight initialization failed in tutorial")]
|
|
2428
|
-
}
|
|
2429
|
-
} },
|
|
2430
|
-
initializingStream: { invoke: {
|
|
2431
|
-
id: "tutorialInitCamera",
|
|
2432
|
-
src: "initializeCamera",
|
|
2433
|
-
input: ({ context }) => ({
|
|
2434
|
-
config: context.config,
|
|
2435
|
-
deepsightService: context.deepsightService
|
|
2436
|
-
}),
|
|
2437
|
-
onDone: {
|
|
2438
|
-
target: "ready",
|
|
2439
|
-
actions: "setStreamAndCapturer"
|
|
2440
|
-
},
|
|
2441
|
-
onError: [{
|
|
2442
|
-
target: "#idCapture.tutorial.ready",
|
|
2443
|
-
guard: "isPermissionDeniedError",
|
|
2444
|
-
actions: assign({ permissionResult: () => {
|
|
2445
|
-
return "denied";
|
|
2446
|
-
} })
|
|
2447
|
-
}, {
|
|
2448
|
-
target: "#idCapture.tutorial.ready",
|
|
2449
|
-
actions: assign({ error: ({ event }) => String(event.error) })
|
|
2450
|
-
}]
|
|
2451
|
-
} },
|
|
2452
|
-
ready: { type: "final" }
|
|
2453
|
-
}
|
|
2454
|
-
},
|
|
2455
|
-
userIntent: {
|
|
2456
|
-
initial: "booting",
|
|
2457
|
-
states: {
|
|
2458
|
-
booting: { on: { NEXT_STEP: {
|
|
2459
|
-
target: "clicked",
|
|
2460
|
-
actions: "trackContinue"
|
|
2461
|
-
} } },
|
|
2462
|
-
clicked: { type: "final" }
|
|
2463
|
-
}
|
|
2464
|
-
}
|
|
2465
|
-
},
|
|
2466
|
-
onDone: { target: "#idCapture.capture" }
|
|
2467
|
-
},
|
|
2468
|
-
ready: { on: { NEXT_STEP: {
|
|
2469
|
-
target: "waitingForPermission",
|
|
2470
|
-
actions: "trackContinue"
|
|
2471
|
-
} } },
|
|
2472
|
-
waitingForPermission: { invoke: {
|
|
2473
|
-
id: "checkPermissionWaiting",
|
|
2474
|
-
src: "checkPermission",
|
|
2475
|
-
onDone: [
|
|
2476
|
-
{
|
|
2477
|
-
target: "#idCapture.capture",
|
|
2478
|
-
guard: "isReadyForCapture",
|
|
2479
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2480
|
-
},
|
|
2481
|
-
{
|
|
2482
|
-
target: "#idCapture.permissions.requesting",
|
|
2483
|
-
guard: "needsMotionPrimeOnly",
|
|
2484
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2485
|
-
},
|
|
2486
|
-
{
|
|
2487
|
-
target: "#idCapture.permissions",
|
|
2488
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2489
|
-
}
|
|
2490
|
-
]
|
|
2491
|
-
} }
|
|
2492
|
-
}
|
|
2493
|
-
},
|
|
2494
|
-
permissions: {
|
|
2495
|
-
entry: "preloadRecordingProvider",
|
|
2496
|
-
initial: "idle",
|
|
2497
|
-
states: {
|
|
2498
|
-
idle: {
|
|
2499
|
-
invoke: {
|
|
2500
|
-
id: "checkPermissionIdle",
|
|
2501
|
-
src: "checkPermission",
|
|
2502
|
-
onDone: [
|
|
2503
|
-
{
|
|
2504
|
-
target: "#idCapture.capture",
|
|
2505
|
-
guard: "isReadyForCapture",
|
|
2506
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2507
|
-
},
|
|
2508
|
-
{
|
|
2509
|
-
target: "denied",
|
|
2510
|
-
guard: ({ event }) => event.output === "denied",
|
|
2511
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2512
|
-
},
|
|
2513
|
-
{
|
|
2514
|
-
target: "motionOnly",
|
|
2515
|
-
guard: "needsMotionPrimeOnly",
|
|
2516
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2517
|
-
},
|
|
2518
|
-
{
|
|
2519
|
-
target: "waitingForUser",
|
|
2520
|
-
actions: assign({ permissionResult: ({ event }) => event.output })
|
|
2521
|
-
}
|
|
2522
|
-
],
|
|
2523
|
-
onError: {
|
|
2524
|
-
target: "waitingForUser",
|
|
2525
|
-
actions: assign({ permissionResult: () => "prompt" })
|
|
2526
|
-
}
|
|
2527
|
-
},
|
|
2528
|
-
on: {
|
|
2529
|
-
REQUEST_PERMISSION: "requesting",
|
|
2530
|
-
GO_TO_LEARN_MORE: "learnMore"
|
|
2531
|
-
}
|
|
2532
|
-
},
|
|
2533
|
-
waitingForUser: { on: {
|
|
2534
|
-
REQUEST_PERMISSION: "requesting",
|
|
2535
|
-
GO_TO_LEARN_MORE: "learnMore"
|
|
2536
|
-
} },
|
|
2537
|
-
motionOnly: { on: { REQUEST_PERMISSION: "requesting" } },
|
|
2538
|
-
learnMore: { on: {
|
|
2539
|
-
BACK: "idle",
|
|
2540
|
-
REQUEST_PERMISSION: "requesting"
|
|
2541
|
-
} },
|
|
2542
|
-
requesting: { invoke: {
|
|
2543
|
-
id: "requestPermission",
|
|
2544
|
-
src: "requestPermission",
|
|
2545
|
-
input: ({ context }) => ({
|
|
2546
|
-
permissionResult: context.permissionResult === "refresh" ? void 0 : context.permissionResult,
|
|
2547
|
-
requestMotionPermission: context.config.ds === true
|
|
2548
|
-
}),
|
|
2549
|
-
onDone: [
|
|
2550
|
-
{
|
|
2551
|
-
target: "#idCapture.capture",
|
|
2552
|
-
guard: "isReadyForCapture",
|
|
2553
|
-
actions: "setPermissionResultAndStream"
|
|
2554
|
-
},
|
|
2555
|
-
{
|
|
2556
|
-
target: "denied",
|
|
2557
|
-
guard: ({ event }) => getPermissionResultFromEvent(event) === "denied",
|
|
2558
|
-
actions: "setPermissionResultAndStream"
|
|
2559
|
-
},
|
|
2560
|
-
{
|
|
2561
|
-
target: "waitingForUser",
|
|
2562
|
-
actions: "setPermissionResultAndStream"
|
|
2563
|
-
}
|
|
2564
|
-
],
|
|
2565
|
-
onError: { target: "denied" }
|
|
2566
|
-
} },
|
|
2567
|
-
denied: { entry: assign({ permissionResult: () => "refresh" }) }
|
|
2568
|
-
}
|
|
2569
|
-
},
|
|
2570
|
-
capture: {
|
|
2571
|
-
initial: "checkingStream",
|
|
2572
|
-
entry: ["trackCameraId", "preloadRecordingProvider"],
|
|
2573
|
-
exit: ["stopMediaRecording", "clearRecordingSession"],
|
|
2574
|
-
on: { SET_FRAME_RECT: { actions: "setFrameRect" } },
|
|
2575
|
-
states: {
|
|
2576
|
-
checkingStream: { always: [
|
|
2577
|
-
{
|
|
2578
|
-
target: "initializingDeepsight",
|
|
2579
|
-
guard: "needsDeepsightInit"
|
|
2580
|
-
},
|
|
2581
|
-
{
|
|
2582
|
-
target: "choosingDetectionStrategy",
|
|
2583
|
-
guard: "hasInitializedCamera"
|
|
2584
|
-
},
|
|
2585
|
-
{ target: "initializing" }
|
|
2586
|
-
] },
|
|
2587
|
-
initializingDeepsight: { invoke: {
|
|
2588
|
-
id: "initDeepsightCapture",
|
|
2589
|
-
src: "initializeDeepsightSession",
|
|
2590
|
-
input: ({ context }) => ({
|
|
2591
|
-
ds: context.config.ds,
|
|
2592
|
-
dependencies: context.dependencies,
|
|
2593
|
-
disableIpify: context.disableIpify
|
|
2594
|
-
}),
|
|
2595
|
-
onDone: {
|
|
2596
|
-
target: "checkingStream",
|
|
2597
|
-
actions: assign({
|
|
2598
|
-
deepsightService: ({ event }) => event.output,
|
|
2599
|
-
deepsightInitAttempted: () => true
|
|
2600
|
-
})
|
|
2601
|
-
},
|
|
2602
|
-
onError: {
|
|
2603
|
-
target: "checkingStream",
|
|
2604
|
-
actions: [assign({ deepsightInitAttempted: () => true }), () => console.warn("Deepsight initialization failed in capture")]
|
|
2605
|
-
}
|
|
2606
|
-
} },
|
|
2607
|
-
initializing: { invoke: {
|
|
2608
|
-
id: "initializeCamera",
|
|
2609
|
-
src: "initializeCamera",
|
|
2610
|
-
input: ({ context }) => ({
|
|
2611
|
-
config: context.config,
|
|
2612
|
-
deepsightService: context.deepsightService,
|
|
2613
|
-
stream: context.stream,
|
|
2614
|
-
cameraFallbackLevel: context.cameraFallbackLevel
|
|
2615
|
-
}),
|
|
2616
|
-
onDone: {
|
|
2617
|
-
target: "choosingDetectionStrategy",
|
|
2618
|
-
actions: "setStreamAndCapturer"
|
|
2619
|
-
},
|
|
2620
|
-
onError: [{
|
|
2621
|
-
target: "#idCapture.permissions",
|
|
2622
|
-
guard: "isPermissionDeniedError",
|
|
2623
|
-
actions: assign({ permissionResult: () => "denied" })
|
|
2624
|
-
}, {
|
|
2625
|
-
target: "#idCapture.error",
|
|
2626
|
-
actions: assign({ error: ({ event }) => String(event.error) })
|
|
2627
|
-
}]
|
|
2628
|
-
} },
|
|
2629
|
-
choosingDetectionStrategy: {
|
|
2630
|
-
entry: ["reportCaptureOptimizingAssignment"],
|
|
2631
|
-
always: [{
|
|
2632
|
-
target: "detectingWithOptimization",
|
|
2633
|
-
guard: and(["isCaptureOptimizingMode", "supportsOptimizingStatus"])
|
|
2634
|
-
}, { target: "detecting" }]
|
|
2635
|
-
},
|
|
2636
|
-
detecting: {
|
|
2637
|
-
always: [{
|
|
2638
|
-
target: "manualCaptureWaiting",
|
|
2639
|
-
guard: "hasManualCaptureTriggered",
|
|
2640
|
-
actions: assign({ detectionStatus: () => "manualCapture" })
|
|
2641
|
-
}],
|
|
2642
|
-
entry: [assign({ detectionStatus: () => "detecting" })],
|
|
2643
|
-
invoke: [{
|
|
2644
|
-
id: "startRecording",
|
|
2645
|
-
src: "startRecording",
|
|
2646
|
-
input: ({ context }) => ({
|
|
2647
|
-
config: context.config,
|
|
2648
|
-
stream: context.stream,
|
|
2649
|
-
existing: context.recordingSession,
|
|
2650
|
-
currentMode: context.currentMode
|
|
2651
|
-
}),
|
|
2652
|
-
onDone: { actions: assign({ recordingSession: ({ context, event }) => {
|
|
2653
|
-
return event.output ?? context.recordingSession;
|
|
2654
|
-
} }) },
|
|
2655
|
-
onError: { actions: () => void 0 }
|
|
2656
|
-
}, {
|
|
2657
|
-
id: "runDetection",
|
|
2658
|
-
src: "runDetection",
|
|
2659
|
-
input: ({ context }) => ({
|
|
2660
|
-
frameCapturer: context.frameCapturer,
|
|
2661
|
-
provider: context.provider,
|
|
2662
|
-
config: context.config,
|
|
2663
|
-
currentMode: context.currentMode,
|
|
2664
|
-
detectionArea: context.detectionArea ?? context.config.detectionArea
|
|
2665
|
-
})
|
|
2666
|
-
}],
|
|
2667
|
-
on: {
|
|
2668
|
-
DETECTION_UPDATE: { actions: "setDetectionStatus" },
|
|
2669
|
-
DETECTION_RESET_READY: { actions: assign({ resetDetection: ({ event }) => event.reset }) },
|
|
2670
|
-
DETECTION_SUCCESS: {
|
|
2671
|
-
target: "capturing",
|
|
2672
|
-
actions: assign({ qualityElements: ({ event }) => event.qualityElements })
|
|
2673
|
-
},
|
|
2674
|
-
BARCODE_DECODED: [{
|
|
2675
|
-
target: "capturingBarcode",
|
|
2676
|
-
guard: "canRunBarcodeFastPath",
|
|
2677
|
-
actions: ["storeDecodedBarcode", "setBarcodeFastPathAttempted"]
|
|
2678
|
-
}, { actions: "storeDecodedBarcode" }],
|
|
2679
|
-
MANUAL_CAPTURE: { target: "capturingManual" },
|
|
2680
|
-
SWITCH_TO_MANUAL_CAPTURE: {
|
|
2681
|
-
target: "manualCaptureWaiting",
|
|
2682
|
-
actions: assign({
|
|
2683
|
-
detectionStatus: () => "manualCapture",
|
|
2684
|
-
manualCaptureTriggered: () => true
|
|
2685
|
-
})
|
|
2686
|
-
},
|
|
2687
|
-
COUNTER_VALUE_CHANGE: { actions: "setCounterValue" },
|
|
2688
|
-
ID_TYPE_CHANGE: { actions: "setIdType" },
|
|
2689
|
-
ID_SIDE_CHANGE: { actions: assign({ detectionStatus: ({ event, context }) => getDetectionStatusFromSideChange(context, event.side) }) },
|
|
2690
|
-
ORIENTATION_CHANGE: { actions: "setOrientation" }
|
|
2691
|
-
}
|
|
2692
|
-
},
|
|
2693
|
-
/**
|
|
2694
|
-
* IDC-05 treatment arm: same detection as `detecting` above (kept in sync by
|
|
2695
|
-
* hand — see the comment there), plus the two-phase searching -> optimizing
|
|
2696
|
-
* phase.
|
|
2697
|
-
*
|
|
2698
|
-
* Two *distinct* state nodes (this one and `detecting`) rather than one
|
|
2699
|
-
* compound state, deliberately: `snapshot.matches({ capture: 'detecting' })`
|
|
2700
|
-
* keeps meaning exactly what it always meant. Folding the phase into
|
|
2701
|
-
* `detecting` as a substate would make every such selector silently true
|
|
2702
|
-
* while the user is being told the capture succeeded — a hazard no type or
|
|
2703
|
-
* test would catch.
|
|
2704
|
-
*/
|
|
2705
|
-
detectingWithOptimization: {
|
|
2706
|
-
entry: assign({ detectionStatus: () => "detecting" }),
|
|
2707
|
-
always: [{
|
|
2708
|
-
target: "manualCaptureWaiting",
|
|
2709
|
-
guard: "hasManualCaptureTriggered",
|
|
2710
|
-
actions: assign({ detectionStatus: () => "manualCapture" })
|
|
2711
|
-
}],
|
|
2712
|
-
invoke: [{
|
|
2713
|
-
id: "startRecording",
|
|
2714
|
-
src: "startRecording",
|
|
2715
|
-
input: ({ context }) => ({
|
|
2716
|
-
config: context.config,
|
|
2717
|
-
stream: context.stream,
|
|
2718
|
-
existing: context.recordingSession,
|
|
2719
|
-
currentMode: context.currentMode
|
|
2720
|
-
}),
|
|
2721
|
-
onDone: { actions: assign({ recordingSession: ({ context, event }) => {
|
|
2722
|
-
return event.output ?? context.recordingSession;
|
|
2723
|
-
} }) },
|
|
2724
|
-
onError: { actions: () => void 0 }
|
|
2725
|
-
}, {
|
|
2726
|
-
id: "runDetection",
|
|
2727
|
-
src: "runDetection",
|
|
2728
|
-
input: ({ context }) => ({
|
|
2729
|
-
frameCapturer: context.frameCapturer,
|
|
2730
|
-
provider: context.provider,
|
|
2731
|
-
config: context.config,
|
|
2732
|
-
currentMode: context.currentMode,
|
|
2733
|
-
detectionArea: context.detectionArea ?? context.config.detectionArea,
|
|
2734
|
-
optimizingAfterMs: context.captureWindowMs
|
|
2735
|
-
})
|
|
2736
|
-
}],
|
|
2737
|
-
on: {
|
|
2738
|
-
DETECTION_SUCCESS: {
|
|
2739
|
-
target: "capturing",
|
|
2740
|
-
actions: assign({ qualityElements: ({ event }) => event.qualityElements })
|
|
2741
|
-
},
|
|
2742
|
-
DETECTION_RESET_READY: { actions: assign({ resetDetection: ({ event }) => event.reset }) },
|
|
2743
|
-
ID_TYPE_CHANGE: { actions: "setIdType" },
|
|
2744
|
-
ORIENTATION_CHANGE: { actions: "setOrientation" },
|
|
2745
|
-
MANUAL_CAPTURE: { target: "#idCapture.capture.capturingManual" },
|
|
2746
|
-
SWITCH_TO_MANUAL_CAPTURE: {
|
|
2747
|
-
target: "#idCapture.capture.manualCaptureWaiting",
|
|
2748
|
-
actions: assign({
|
|
2749
|
-
detectionStatus: () => "manualCapture",
|
|
2750
|
-
manualCaptureTriggered: () => true
|
|
2751
|
-
})
|
|
2752
|
-
}
|
|
2753
|
-
},
|
|
2754
|
-
initial: "searching",
|
|
2755
|
-
states: {
|
|
2756
|
-
searching: { on: {
|
|
2757
|
-
DETECTION_UPDATE: { actions: "setDetectionStatus" },
|
|
2758
|
-
ID_SIDE_CHANGE: { actions: assign({ detectionStatus: ({ context, event }) => getDetectionStatusFromSideChange(context, event.side) }) },
|
|
2759
|
-
BARCODE_DECODED: [{
|
|
2760
|
-
target: "#idCapture.capture.capturingBarcode",
|
|
2761
|
-
guard: "canRunBarcodeFastPath",
|
|
2762
|
-
actions: ["storeDecodedBarcode", "setBarcodeFastPathAttempted"]
|
|
2763
|
-
}, { actions: "storeDecodedBarcode" }],
|
|
2764
|
-
DETECTION_OPTIMIZING: {
|
|
2765
|
-
target: "optimizing",
|
|
2766
|
-
guard: "hasCandidateFrame",
|
|
2767
|
-
actions: "setCandidateFrame"
|
|
2768
|
-
}
|
|
2769
|
-
} },
|
|
2770
|
-
optimizing: {
|
|
2771
|
-
exit: "clearOptimizingPhase",
|
|
2772
|
-
on: {
|
|
2773
|
-
BARCODE_DECODED: { actions: "storeDecodedBarcode" },
|
|
2774
|
-
SWITCH_TO_MANUAL_CAPTURE: {
|
|
2775
|
-
guard: "hasStashedCommit",
|
|
2776
|
-
target: "#idCapture.capture.detectingWithOptimization.optimizing.released"
|
|
2777
|
-
},
|
|
2778
|
-
MANUAL_CAPTURE: {
|
|
2779
|
-
guard: "hasStashedCommit",
|
|
2780
|
-
target: "#idCapture.capture.detectingWithOptimization.optimizing.released"
|
|
2781
|
-
}
|
|
2782
|
-
},
|
|
2783
|
-
initial: "holding",
|
|
2784
|
-
states: {
|
|
2785
|
-
holding: {
|
|
2786
|
-
after: { optimizingDwell: { target: "released" } },
|
|
2787
|
-
on: { DETECTION_SUCCESS: { actions: "stashCommittedFrame" } }
|
|
2788
|
-
},
|
|
2789
|
-
released: {
|
|
2790
|
-
entry: "releaseStashedCommit",
|
|
2791
|
-
after: { optimizingGrace: {
|
|
2792
|
-
target: "#idCapture.capture.detectingWithOptimization.searching",
|
|
2793
|
-
actions: assign({ detectionStatus: () => "detecting" })
|
|
2794
|
-
} }
|
|
2795
|
-
}
|
|
2796
|
-
}
|
|
2797
|
-
}
|
|
2798
|
-
}
|
|
2799
|
-
},
|
|
2800
|
-
manualCaptureWaiting: { on: { MANUAL_CAPTURE: { target: "capturingManual" } } },
|
|
2801
|
-
capturing: {
|
|
2802
|
-
entry: [
|
|
2803
|
-
"captureImage",
|
|
2804
|
-
"storeCapturedCanvasInProvider",
|
|
2805
|
-
"storeCapturedImage"
|
|
2806
|
-
],
|
|
2807
|
-
always: [
|
|
2808
|
-
{
|
|
2809
|
-
target: "submittingBarcode",
|
|
2810
|
-
guard: and(["hasCapturedImage", "shouldSubmitBarcode"])
|
|
2811
|
-
},
|
|
2812
|
-
{
|
|
2813
|
-
target: "uploading",
|
|
2814
|
-
guard: "hasCapturedImage"
|
|
2815
|
-
},
|
|
2816
|
-
{
|
|
2817
|
-
target: "uploadError",
|
|
2818
|
-
actions: assign(({ context }) => ({
|
|
2819
|
-
uploadError: ID_ERROR_CODES.UPLOAD_ERROR,
|
|
2820
|
-
attemptsRemaining: context.attemptsRemaining - 1
|
|
2821
|
-
}))
|
|
2822
|
-
}
|
|
2823
|
-
]
|
|
2824
|
-
},
|
|
2825
|
-
submittingBarcode: { invoke: {
|
|
2826
|
-
id: "submitBarcode",
|
|
2827
|
-
src: "submitBarcode",
|
|
2828
|
-
input: ({ context }) => ({
|
|
2829
|
-
rawBarcode: context.decodedBarcode?.text ?? "",
|
|
2830
|
-
metrics: context.decodedBarcode,
|
|
2831
|
-
processId: context.config.skipProcessId !== true
|
|
2832
|
-
}),
|
|
2833
|
-
onDone: {
|
|
2834
|
-
target: "success",
|
|
2835
|
-
actions: "storeBarcodeResponse"
|
|
2836
|
-
},
|
|
2837
|
-
onError: { target: "uploading" }
|
|
2838
|
-
} },
|
|
2839
|
-
capturingBarcode: {
|
|
2840
|
-
entry: [
|
|
2841
|
-
"captureImage",
|
|
2842
|
-
"storeCapturedCanvasInProvider",
|
|
2843
|
-
"storeCapturedImage"
|
|
2844
|
-
],
|
|
2845
|
-
always: [{ target: "submittingBarcodePreCapture" }]
|
|
2846
|
-
},
|
|
2847
|
-
submittingBarcodePreCapture: { invoke: {
|
|
2848
|
-
id: "submitBarcode",
|
|
2849
|
-
src: "submitBarcode",
|
|
2850
|
-
input: ({ context }) => ({
|
|
2851
|
-
rawBarcode: context.decodedBarcode?.text ?? "",
|
|
2852
|
-
metrics: context.decodedBarcode,
|
|
2853
|
-
processId: context.config.skipProcessId !== true,
|
|
2854
|
-
minDurationMs: 1e3
|
|
2855
|
-
}),
|
|
2856
|
-
onDone: {
|
|
2857
|
-
target: "success",
|
|
2858
|
-
actions: ["storeBarcodeResponse", "markBarcodeFastPathCaptured"]
|
|
2859
|
-
},
|
|
2860
|
-
onError: { target: "choosingDetectionStrategy" }
|
|
2861
|
-
} },
|
|
2862
|
-
capturingManual: {
|
|
2863
|
-
entry: [
|
|
2864
|
-
"captureLatestFrame",
|
|
2865
|
-
"storeCapturedCanvasInProvider",
|
|
2866
|
-
"storeCapturedImage"
|
|
2867
|
-
],
|
|
2868
|
-
always: [
|
|
2869
|
-
{
|
|
2870
|
-
target: "optimizingHold",
|
|
2871
|
-
guard: and([
|
|
2872
|
-
"hasCapturedImage",
|
|
2873
|
-
"isCaptureOptimizingMode",
|
|
2874
|
-
"supportsOptimizingStatus"
|
|
2875
|
-
])
|
|
2876
|
-
},
|
|
2877
|
-
{
|
|
2878
|
-
target: "uploading",
|
|
2879
|
-
guard: "hasCapturedImage"
|
|
2880
|
-
},
|
|
2881
|
-
{
|
|
2882
|
-
target: "uploadError",
|
|
2883
|
-
actions: assign(({ context }) => ({
|
|
2884
|
-
uploadError: ID_ERROR_CODES.UPLOAD_ERROR,
|
|
2885
|
-
attemptsRemaining: context.attemptsRemaining - 1
|
|
2886
|
-
}))
|
|
2887
|
-
}
|
|
2888
|
-
]
|
|
2889
|
-
},
|
|
2890
|
-
optimizingHold: { after: { optimizingDwell: { target: "uploading" } } },
|
|
2891
|
-
uploading: {
|
|
2892
|
-
entry: assign({ uploadProgress: () => 0 }),
|
|
2893
|
-
invoke: [{
|
|
2894
|
-
id: "uploadProgressTicker",
|
|
2895
|
-
src: "uploadProgressTicker"
|
|
2896
|
-
}, {
|
|
2897
|
-
id: "uploadIdImage",
|
|
2898
|
-
src: "uploadIdImage",
|
|
2899
|
-
input: ({ context, self }) => {
|
|
2900
|
-
const canvas = context.provider?.getOriginalCapturedCanvas();
|
|
2901
|
-
if (!canvas) throw new Error(ID_ERROR_CODES.UPLOAD_ERROR);
|
|
2902
|
-
const type = context.currentMode === "back" ? "back" : "front";
|
|
2903
|
-
return {
|
|
2904
|
-
canvas,
|
|
2905
|
-
type,
|
|
2906
|
-
qualityElements: context.qualityElements,
|
|
2907
|
-
onProgress: (progress) => {
|
|
2908
|
-
self.send({
|
|
2909
|
-
type: "UPLOAD_PROGRESS",
|
|
2910
|
-
progress
|
|
2911
|
-
});
|
|
2912
|
-
},
|
|
2913
|
-
deepsightService: context.deepsightService,
|
|
2914
|
-
stream: context.stream,
|
|
2915
|
-
isSecondId: context.config.isSecondId ?? false,
|
|
2916
|
-
onlyFront: type === "front" && (context.config.onlyFront ?? false),
|
|
2917
|
-
ageAssurance: context.config.ageAssurance,
|
|
2918
|
-
dependencies: context.dependencies,
|
|
2919
|
-
captureResolution: context.captureResolution,
|
|
2920
|
-
cameraFallbackLevel: context.cameraFallbackLevel,
|
|
2921
|
-
extractIdFace: context.config.extractIdFace,
|
|
2922
|
-
croppedCanvas: context.provider?.getCapturedCanvas() ?? null
|
|
2923
|
-
};
|
|
2924
|
-
},
|
|
2925
|
-
onDone: {
|
|
2926
|
-
target: "uploadCompleted",
|
|
2927
|
-
actions: [assign({
|
|
2928
|
-
uploadResponse: ({ event }) => event.output,
|
|
2929
|
-
uploadProgress: () => 100,
|
|
2930
|
-
skipProcessId: ({ context, event }) => event.output.idValidationCompleted === true || context.skipProcessId
|
|
2931
|
-
}), "storeCapturedImage"]
|
|
2932
|
-
},
|
|
2933
|
-
onError: {
|
|
2934
|
-
target: "uploadError",
|
|
2935
|
-
actions: assign(({ context, event }) => ({
|
|
2936
|
-
uploadError: getIdErrorCodeFromUnknown(event.error) ?? ID_ERROR_CODES.UPLOAD_ERROR,
|
|
2937
|
-
attemptsRemaining: context.attemptsRemaining - 1
|
|
2938
|
-
}))
|
|
2939
|
-
}
|
|
2940
|
-
}],
|
|
2941
|
-
on: {
|
|
2942
|
-
UPLOAD_PROGRESS: { actions: assign({ uploadProgress: ({ context, event }) => Math.max(context.uploadProgress ?? 0, Math.round(event.progress / 100 * 80)) }) },
|
|
2943
|
-
UPLOAD_PROGRESS_TICK: { actions: assign({ uploadProgress: ({ context }) => Math.min(95, (context.uploadProgress ?? 0) + 1) }) }
|
|
2944
|
-
}
|
|
2945
|
-
},
|
|
2946
|
-
uploadCompleted: { after: { [800]: { target: "validatingUpload" } } },
|
|
2947
|
-
validatingUpload: { always: [
|
|
2948
|
-
{
|
|
2949
|
-
target: "uploadError",
|
|
2950
|
-
guard: "hasUploadValidationError",
|
|
2951
|
-
actions: ["setUploadErrorFromUploadValidation", "decrementAttemptsRemaining"]
|
|
2952
|
-
},
|
|
2953
|
-
{
|
|
2954
|
-
target: "#idCapture.finished",
|
|
2955
|
-
guard: and(["shouldSkipProcessId", "isUploadExpired"])
|
|
2956
|
-
},
|
|
2957
|
-
{
|
|
2958
|
-
target: "#idCapture.expiredExhausted",
|
|
2959
|
-
guard: and([
|
|
2960
|
-
"isNotPassportMode",
|
|
2961
|
-
"isUploadExpired",
|
|
2962
|
-
"wasExpiredRedirected"
|
|
2963
|
-
]),
|
|
2964
|
-
actions: ["setExhaustedFromUpload"]
|
|
2965
|
-
},
|
|
2966
|
-
{
|
|
2967
|
-
target: "#idCapture.expiredExhausted",
|
|
2968
|
-
guard: and([
|
|
2969
|
-
"isNotPassportMode",
|
|
2970
|
-
"isUploadExpired",
|
|
2971
|
-
"isExpiredAttemptsExhausted"
|
|
2972
|
-
]),
|
|
2973
|
-
actions: ["incrementExpiredAttempts", "setExhaustedFromUpload"]
|
|
2974
|
-
},
|
|
2975
|
-
{
|
|
2976
|
-
target: "#idCapture.expired",
|
|
2977
|
-
guard: and(["isNotPassportMode", "isUploadExpired"]),
|
|
2978
|
-
actions: ["incrementExpiredAttempts", "setExpiredFromUpload"]
|
|
2979
|
-
},
|
|
2980
|
-
{ target: "success" }
|
|
2981
|
-
] },
|
|
2982
|
-
uploadError: { on: { CONTINUE_FROM_ERROR: [
|
|
2983
|
-
{
|
|
2984
|
-
target: "checkingStream",
|
|
2985
|
-
guard: "hasAttemptsRemaining",
|
|
2986
|
-
actions: [
|
|
2987
|
-
"resetDetection",
|
|
2988
|
-
"clearUploadFailure",
|
|
2989
|
-
"clearStreamForRetry"
|
|
2990
|
-
]
|
|
2991
|
-
},
|
|
2992
|
-
{
|
|
2993
|
-
target: "#idCapture.frontFinished",
|
|
2994
|
-
guard: "shouldContinueToBack",
|
|
2995
|
-
actions: ["flagIdManualReview"]
|
|
2996
|
-
},
|
|
2997
|
-
{
|
|
2998
|
-
target: "#idCapture.backFinished",
|
|
2999
|
-
guard: "shouldContinueToFront",
|
|
3000
|
-
actions: ["flagIdManualReview"]
|
|
3001
|
-
},
|
|
3002
|
-
{
|
|
3003
|
-
target: "#idCapture.processing",
|
|
3004
|
-
actions: ["flagIdManualReview"]
|
|
3005
|
-
}
|
|
3006
|
-
] } },
|
|
3007
|
-
success: {
|
|
3008
|
-
exit: "clearBarcodeFastPathCaptured",
|
|
3009
|
-
on: { NEXT_STEP: [
|
|
3010
|
-
{
|
|
3011
|
-
target: "#idCapture.mandatoryConsent",
|
|
3012
|
-
guard: "hasMandatoryConsent"
|
|
3013
|
-
},
|
|
3014
|
-
{
|
|
3015
|
-
target: "#idCapture.frontFinished",
|
|
3016
|
-
guard: "shouldContinueToBack"
|
|
3017
|
-
},
|
|
3018
|
-
{
|
|
3019
|
-
target: "#idCapture.backFinished",
|
|
3020
|
-
guard: "shouldContinueToFront"
|
|
3021
|
-
},
|
|
3022
|
-
{ target: "#idCapture.processing" }
|
|
3023
|
-
] }
|
|
3024
|
-
}
|
|
3025
|
-
}
|
|
3026
|
-
},
|
|
3027
|
-
mandatoryConsent: { on: {
|
|
3028
|
-
CONSENT_ACCEPT: [
|
|
3029
|
-
{
|
|
3030
|
-
target: "frontFinished",
|
|
3031
|
-
guard: "shouldContinueToBack"
|
|
3032
|
-
},
|
|
3033
|
-
{
|
|
3034
|
-
target: "backFinished",
|
|
3035
|
-
guard: "shouldContinueToFront"
|
|
3036
|
-
},
|
|
3037
|
-
{ target: "processing" }
|
|
3038
|
-
],
|
|
3039
|
-
CONSENT_CANCEL: { target: "closed" }
|
|
3040
|
-
} },
|
|
3041
|
-
frontFinished: {
|
|
3042
|
-
entry: ["stopMediaRecording", "resetForBackCapture"],
|
|
3043
|
-
type: "parallel",
|
|
3044
|
-
states: {
|
|
3045
|
-
cameraInit: {
|
|
3046
|
-
initial: "checking",
|
|
3047
|
-
states: {
|
|
3048
|
-
checking: { always: [{
|
|
3049
|
-
target: "ready",
|
|
3050
|
-
guard: "hasStream"
|
|
3051
|
-
}, { target: "initializingStream" }] },
|
|
3052
|
-
initializingStream: { invoke: {
|
|
3053
|
-
id: "frontFinishedInitCamera",
|
|
3054
|
-
src: "initializeCamera",
|
|
3055
|
-
input: ({ context }) => ({
|
|
3056
|
-
config: context.config,
|
|
3057
|
-
deepsightService: context.deepsightService
|
|
3058
|
-
}),
|
|
3059
|
-
onDone: {
|
|
3060
|
-
target: "ready",
|
|
3061
|
-
actions: "setStreamAndCapturer"
|
|
3062
|
-
},
|
|
3063
|
-
onError: {
|
|
3064
|
-
target: "ready",
|
|
3065
|
-
actions: () => {
|
|
3066
|
-
console.warn("Camera initialization failed during flip transition");
|
|
3067
|
-
}
|
|
3068
|
-
}
|
|
3069
|
-
} },
|
|
3070
|
-
ready: { type: "final" }
|
|
3071
|
-
}
|
|
3072
|
-
},
|
|
3073
|
-
userIntent: {
|
|
3074
|
-
initial: "waiting",
|
|
3075
|
-
states: {
|
|
3076
|
-
waiting: { on: { CONTINUE_TO_BACK: {
|
|
3077
|
-
target: "clicked",
|
|
3078
|
-
actions: assign({ currentMode: () => "back" })
|
|
3079
|
-
} } },
|
|
3080
|
-
clicked: { type: "final" }
|
|
3081
|
-
}
|
|
3082
|
-
}
|
|
3083
|
-
},
|
|
3084
|
-
onDone: [{
|
|
3085
|
-
target: "#idCapture.capture.choosingDetectionStrategy",
|
|
3086
|
-
guard: "hasStream",
|
|
3087
|
-
actions: "clearFlipPreview"
|
|
3088
|
-
}, {
|
|
3089
|
-
target: "#idCapture.capture",
|
|
3090
|
-
actions: "clearFlipPreview"
|
|
3091
|
-
}]
|
|
3092
|
-
},
|
|
3093
|
-
backFinished: {
|
|
3094
|
-
entry: ["stopMediaRecording", "resetForFrontCapture"],
|
|
3095
|
-
type: "parallel",
|
|
3096
|
-
states: {
|
|
3097
|
-
cameraInit: {
|
|
3098
|
-
initial: "checking",
|
|
3099
|
-
states: {
|
|
3100
|
-
checking: { always: [{
|
|
3101
|
-
target: "ready",
|
|
3102
|
-
guard: "hasStream"
|
|
3103
|
-
}, { target: "initializingStream" }] },
|
|
3104
|
-
initializingStream: { invoke: {
|
|
3105
|
-
id: "backFinishedInitCamera",
|
|
3106
|
-
src: "initializeCamera",
|
|
3107
|
-
input: ({ context }) => ({
|
|
3108
|
-
config: context.config,
|
|
3109
|
-
deepsightService: context.deepsightService
|
|
3110
|
-
}),
|
|
3111
|
-
onDone: {
|
|
3112
|
-
target: "ready",
|
|
3113
|
-
actions: "setStreamAndCapturer"
|
|
3114
|
-
},
|
|
3115
|
-
onError: {
|
|
3116
|
-
target: "ready",
|
|
3117
|
-
actions: () => {
|
|
3118
|
-
console.warn("Camera initialization failed during flip transition");
|
|
3119
|
-
}
|
|
3120
|
-
}
|
|
3121
|
-
} },
|
|
3122
|
-
ready: { type: "final" }
|
|
3123
|
-
}
|
|
3124
|
-
},
|
|
3125
|
-
userIntent: {
|
|
3126
|
-
initial: "waiting",
|
|
3127
|
-
states: {
|
|
3128
|
-
waiting: { on: { CONTINUE_TO_FRONT: {
|
|
3129
|
-
target: "clicked",
|
|
3130
|
-
actions: assign({ currentMode: () => "front" })
|
|
3131
|
-
} } },
|
|
3132
|
-
clicked: { type: "final" }
|
|
3133
|
-
}
|
|
3134
|
-
}
|
|
3135
|
-
},
|
|
3136
|
-
onDone: [{
|
|
3137
|
-
target: "#idCapture.capture.choosingDetectionStrategy",
|
|
3138
|
-
guard: "hasStream",
|
|
3139
|
-
actions: "clearFlipPreview"
|
|
3140
|
-
}, {
|
|
3141
|
-
target: "#idCapture.capture",
|
|
3142
|
-
actions: "clearFlipPreview"
|
|
3143
|
-
}]
|
|
3144
|
-
},
|
|
3145
|
-
processing: {
|
|
3146
|
-
entry: "stopMediaStream",
|
|
3147
|
-
always: [{
|
|
3148
|
-
target: "finished",
|
|
3149
|
-
guard: "shouldSkipProcessId"
|
|
3150
|
-
}],
|
|
3151
|
-
invoke: {
|
|
3152
|
-
id: "processId",
|
|
3153
|
-
src: "processId",
|
|
3154
|
-
input: ({ context }) => ({ isSecondId: context.config.isSecondId ?? false }),
|
|
3155
|
-
onDone: [
|
|
3156
|
-
{
|
|
3157
|
-
target: "finished",
|
|
3158
|
-
guard: "forceFinishAfterProcessing"
|
|
3159
|
-
},
|
|
3160
|
-
{
|
|
3161
|
-
target: "expiredExhausted",
|
|
3162
|
-
guard: and([({ event }) => event.output.isDocumentExpired, "isProcessingExpiredExhausted"]),
|
|
3163
|
-
actions: ["incrementProcessingExpiredAttempts"]
|
|
3164
|
-
},
|
|
3165
|
-
{
|
|
3166
|
-
target: "expired",
|
|
3167
|
-
guard: ({ event }) => event.output.isDocumentExpired,
|
|
3168
|
-
actions: ["incrementProcessingExpiredAttempts", "clearExpiredFromUpload"]
|
|
3169
|
-
},
|
|
3170
|
-
{ target: "finished" }
|
|
3171
|
-
],
|
|
3172
|
-
onError: { target: "finished" }
|
|
3173
|
-
}
|
|
3174
|
-
},
|
|
3175
|
-
expired: { on: { RETRY_CAPTURE: [
|
|
3176
|
-
{
|
|
3177
|
-
target: "#idCapture.backFinished",
|
|
3178
|
-
guard: and([
|
|
3179
|
-
"wasExpiredFromUpload",
|
|
3180
|
-
"isBackModeInMultiSideFlow",
|
|
3181
|
-
not("wasExpiredRedirected")
|
|
3182
|
-
]),
|
|
3183
|
-
actions: [
|
|
3184
|
-
"resetDetection",
|
|
3185
|
-
"clearExpiredFromUpload",
|
|
3186
|
-
"clearUploadFailure",
|
|
3187
|
-
"setExpiredRedirected"
|
|
3188
|
-
]
|
|
3189
|
-
},
|
|
3190
|
-
{
|
|
3191
|
-
target: "#idCapture.capture",
|
|
3192
|
-
guard: "wasExpiredFromUpload",
|
|
3193
|
-
actions: [
|
|
3194
|
-
"resetDetection",
|
|
3195
|
-
"clearExpiredFromUpload",
|
|
3196
|
-
"clearUploadFailure"
|
|
3197
|
-
]
|
|
3198
|
-
},
|
|
3199
|
-
{
|
|
3200
|
-
target: "chooser",
|
|
3201
|
-
guard: "hasShowDocumentChooser",
|
|
3202
|
-
actions: ["resetContext"]
|
|
3203
|
-
},
|
|
3204
|
-
{
|
|
3205
|
-
target: "ageVerification",
|
|
3206
|
-
guard: "hasAgeAssurance",
|
|
3207
|
-
actions: "resetContext"
|
|
3208
|
-
},
|
|
3209
|
-
{
|
|
3210
|
-
target: "tutorial",
|
|
3211
|
-
guard: "hasShowTutorial",
|
|
3212
|
-
actions: "resetContext"
|
|
3213
|
-
},
|
|
3214
|
-
{
|
|
3215
|
-
target: "loading",
|
|
3216
|
-
actions: "resetContext"
|
|
3217
|
-
}
|
|
3218
|
-
] } },
|
|
3219
|
-
expiredExhausted: {
|
|
3220
|
-
entry: "flagIdManualReview",
|
|
3221
|
-
on: { CONTINUE_EXHAUSTED: [
|
|
3222
|
-
{
|
|
3223
|
-
target: "#idCapture.frontFinished",
|
|
3224
|
-
guard: "shouldForceBackOnExpired",
|
|
3225
|
-
actions: ["setSkipProcessId"]
|
|
3226
|
-
},
|
|
3227
|
-
{
|
|
3228
|
-
target: "#idCapture.processing",
|
|
3229
|
-
guard: "shouldProcessAfterExhaustion",
|
|
3230
|
-
actions: ["setForceFinishAfterProcessing"]
|
|
3231
|
-
},
|
|
3232
|
-
{
|
|
3233
|
-
target: "#idCapture.finished",
|
|
3234
|
-
actions: ["setSkipProcessId"]
|
|
3235
|
-
}
|
|
3236
|
-
] }
|
|
3237
|
-
},
|
|
3238
|
-
finished: {
|
|
3239
|
-
entry: [
|
|
3240
|
-
"stopMediaRecording",
|
|
3241
|
-
"stopMediaStream",
|
|
3242
|
-
"disposeProvider",
|
|
3243
|
-
"cleanupDeepsight"
|
|
3244
|
-
],
|
|
3245
|
-
type: "final"
|
|
3246
|
-
},
|
|
3247
|
-
closed: {
|
|
3248
|
-
entry: [
|
|
3249
|
-
"stopMediaStream",
|
|
3250
|
-
"disposeProvider",
|
|
3251
|
-
"cleanupDeepsight"
|
|
3252
|
-
],
|
|
3253
|
-
type: "final"
|
|
3254
|
-
},
|
|
3255
|
-
error: {
|
|
3256
|
-
entry: [
|
|
3257
|
-
"stopMediaStream",
|
|
3258
|
-
"disposeProvider",
|
|
3259
|
-
"cleanupDeepsight"
|
|
3260
|
-
],
|
|
3261
|
-
on: { RESET: {
|
|
3262
|
-
target: "idle",
|
|
3263
|
-
actions: "resetContext"
|
|
3264
|
-
} }
|
|
3265
|
-
},
|
|
3266
|
-
manualIdUpload: {
|
|
3267
|
-
invoke: {
|
|
3268
|
-
id: "manualIdUpload",
|
|
3269
|
-
src: "manualUploadMachine",
|
|
3270
|
-
input: ({ context }) => ({
|
|
3271
|
-
isSecondId: context.config.isSecondId ?? false,
|
|
3272
|
-
onlyFront: context.config.onlyFront ?? false,
|
|
3273
|
-
captureAttempts: context.config.captureAttempts,
|
|
3274
|
-
extractIdFace: context.config.extractIdFace
|
|
3275
|
-
}),
|
|
3276
|
-
onSnapshot: { actions: () => {} },
|
|
3277
|
-
onDone: [{
|
|
3278
|
-
guard: "isManualUploadExhausted",
|
|
3279
|
-
target: "#idCapture.finished"
|
|
3280
|
-
}, { target: "#idCapture.processing" }],
|
|
3281
|
-
onError: {
|
|
3282
|
-
target: "#idCapture.error",
|
|
3283
|
-
actions: assign({ error: ({ event }) => String(event.error) })
|
|
3284
|
-
}
|
|
3285
|
-
},
|
|
3286
|
-
on: {
|
|
3287
|
-
QUIT: { target: "closed" },
|
|
3288
|
-
MANUAL_UPLOAD_TAB_CHANGED: { actions: sendTo("manualIdUpload", ({ event }) => event) },
|
|
3289
|
-
MANUAL_UPLOAD_FILE_SELECTED: { actions: sendTo("manualIdUpload", ({ event }) => event) },
|
|
3290
|
-
MANUAL_UPLOAD_CONTINUE: { actions: sendTo("manualIdUpload", ({ event }) => event) },
|
|
3291
|
-
MANUAL_UPLOAD_RESET: { actions: sendTo("manualIdUpload", ({ event }) => event) }
|
|
3292
|
-
}
|
|
3293
|
-
},
|
|
3294
|
-
digitalIdUpload: {
|
|
3295
|
-
invoke: {
|
|
3296
|
-
id: "digitalIdUpload",
|
|
3297
|
-
src: "digitalUploadMachine",
|
|
3298
|
-
input: ({ context }) => ({
|
|
3299
|
-
showTutorial: context.config.showTutorial,
|
|
3300
|
-
attemptsRemaining: context.attemptsRemaining,
|
|
3301
|
-
extractIdFace: context.config.extractIdFace
|
|
3302
|
-
}),
|
|
3303
|
-
onSnapshot: { actions: () => {} },
|
|
3304
|
-
onDone: [
|
|
3305
|
-
{
|
|
3306
|
-
guard: "isDigitalUploadExhausted",
|
|
3307
|
-
target: "#idCapture.finished",
|
|
3308
|
-
actions: ["syncAttemptsFromDigitalUpload"]
|
|
3309
|
-
},
|
|
3310
|
-
{
|
|
3311
|
-
guard: "isDigitalUploadSuccessful",
|
|
3312
|
-
target: "#idCapture.processing",
|
|
3313
|
-
actions: ["syncAttemptsFromDigitalUpload", "storeDigitalUploadResponse"]
|
|
3314
|
-
},
|
|
3315
|
-
{
|
|
3316
|
-
target: "#idCapture.error",
|
|
3317
|
-
actions: assign({ error: () => "Digital upload finished without output" })
|
|
3318
|
-
}
|
|
3319
|
-
],
|
|
3320
|
-
onError: {
|
|
3321
|
-
target: "#idCapture.error",
|
|
3322
|
-
actions: assign({ error: ({ event }) => String(event.error) })
|
|
3323
|
-
}
|
|
3324
|
-
},
|
|
3325
|
-
on: {
|
|
3326
|
-
QUIT: { target: "closed" },
|
|
3327
|
-
DIGITAL_UPLOAD_NEXT_STEP: { actions: sendTo("digitalIdUpload", { type: "NEXT_STEP" }) },
|
|
3328
|
-
DIGITAL_UPLOAD_FILE_PICKED: { actions: sendTo("digitalIdUpload", ({ event }) => ({
|
|
3329
|
-
type: "FILE_PICKED",
|
|
3330
|
-
file: event.file
|
|
3331
|
-
})) },
|
|
3332
|
-
DIGITAL_UPLOAD_CONFIRM: { actions: sendTo("digitalIdUpload", { type: "CONFIRM" }) },
|
|
3333
|
-
DIGITAL_UPLOAD_REPLACE: { actions: sendTo("digitalIdUpload", { type: "REPLACE" }) },
|
|
3334
|
-
DIGITAL_UPLOAD_RETRY: { actions: sendTo("digitalIdUpload", { type: "RETRY" }) },
|
|
3335
|
-
DIGITAL_UPLOAD_SCAN_INSTEAD: { actions: sendTo("digitalIdUpload", { type: "SCAN_INSTEAD" }) },
|
|
3336
|
-
DIGITAL_UPLOAD_CHOOSE_ANOTHER: { actions: sendTo("digitalIdUpload", { type: "CHOOSE_ANOTHER" }) }
|
|
3337
|
-
}
|
|
3338
|
-
}
|
|
3339
|
-
}
|
|
3340
|
-
});
|
|
3341
|
-
//#endregion
|
|
3342
|
-
export { MANUAL_UPLOAD_MAX_RETRIES as a, MANUAL_UPLOAD_MAX_FILE_SIZE_BYTES as i, getManualUploadTabs as n, MANUAL_UPLOAD_EXHAUSTION_FORWARD_MS as r, idCaptureMachine as t };
|