@incodetech/core 2.2.0-rc.8 → 2.3.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_NOTICES.txt +281 -0
- package/dist/BaseWasmProvider-Dyi6dKp1.d.ts +65 -0
- package/dist/{BrowserDiagnosticsCryptoProvider-DslcXorZ.esm.js → BrowserDiagnosticsCryptoProvider-C_9o3L2L.esm.js} +1 -1
- package/dist/{BrowserVisibilityObserverProvider-BX1BiLDK.esm.js → BrowserVisibilityObserverProvider-BrJN1B8A.esm.js} +2 -0
- package/dist/FaceDetectionProvider-DTetAE8H.esm.js +476 -0
- package/dist/FaceDetectionProvider-LdZ47bWy.d.ts +36 -0
- package/dist/{IIdCaptureCapability-DHTT3FC2.d.ts → IIdCaptureCapability-RNiFhvXR.d.ts} +7 -33
- package/dist/IWasmUtilCapability-CXXDA5l1.d.ts +159 -0
- package/dist/{MotionSensorProvider-DGiV77J_.esm.js → MotionSensorProvider-BgTYwg9L.esm.js} +1 -1
- package/dist/{deepsightService-DLVQS_RH.d.ts → StreamCanvasCapture-B3YT2Bt6.d.ts} +54 -41
- package/dist/{StreamCanvasCapture-D2XcXCZ4.esm.js → StreamCanvasCapture-C9jtgBdT.esm.js} +2 -2
- package/dist/{addressSearch-D1XpBdUS.esm.js → addressSearch-BRSu_aGA.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-Bg9ynGum.esm.js} +2 -2
- package/dist/{antifraudStateMachine-Bf_JVNwn.esm.js → antifraudStateMachine-BHxehiJZ.esm.js} +1 -1
- package/dist/{apiError-D4rZe9BR.esm.js → apiError-D0v5hFyN.esm.js} +14 -2
- package/dist/authentication.d.ts +3 -3
- package/dist/authentication.esm.js +2 -2
- package/dist/{authenticationManager-EfCuQy_Y.esm.js → authenticationManager-C4B4-29g.esm.js} +5 -5
- package/dist/{authenticationManager-BBMGTcwW.d.ts → authenticationManager-DXTIUcma.d.ts} +7 -1
- package/dist/{authenticationStateMachine-B9l3sHEg.esm.js → authenticationStateMachine-DJ0zUm-A.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-Bfvkq7Cy.esm.js +69 -0
- package/dist/certificateIssuanceManager-DCgEidHz.d.ts +312 -0
- package/dist/{certificateIssuanceStateMachine-D_R92TYu.esm.js → certificateIssuanceStateMachine-BBD5h8c4.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-B5Vqdez-.esm.js} +2 -2
- package/dist/{consentManager-3Pbtj-RV.d.ts → consentManager-uhDPdU6i.d.ts} +4 -4
- package/dist/{consentStateMachine-D9D4ON8Z.esm.js → consentStateMachine-DbUmqWgV.esm.js} +1 -1
- package/dist/createCameraCycleOwnership-DQ5-F2oW.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-QMOGwHXR.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-D1ppROcF.esm.js} +2 -2
- package/dist/{curpValidationManager-DVGr7Fq7.d.ts → curpValidationManager-SSKNrm5Z.d.ts} +1 -1
- package/dist/{curpValidationStateMachine-Ds7KMacK.esm.js → curpValidationStateMachine-DvUPC_8S.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-2j_PBq4U.esm.js +264 -0
- package/dist/customFieldsManager-8-W2KY4n.d.ts +141 -0
- package/dist/customWatchlistManager-DUVrEdw9.esm.js +73 -0
- package/dist/customWatchlistManager-PBWHr_oM.d.ts +64 -0
- package/dist/{customWatchlistStateMachine-YWSgKLbF.esm.js → customWatchlistStateMachine-qZVgkKgP.esm.js} +1 -1
- package/dist/{deepsightLoader-DEcRUKfT.esm.js → deepsightLoader-Dm7ejW4v.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-DR_Wv-3H.esm.js} +2 -2
- package/dist/{documentCaptureManager-B3t0ydtg.d.ts → documentCaptureManager-DensIj5F.d.ts} +83 -83
- package/dist/{documentCaptureStateMachine-BM4Ex_5x.esm.js → documentCaptureStateMachine-CWOATHfE.esm.js} +5 -5
- package/dist/dynamic-forms.d.ts +1 -1
- package/dist/dynamic-forms.esm.js +2 -2
- package/dist/{dynamicFormsManager-fhK0yINk.d.ts → dynamicFormsManager-D5R_uxLQ.d.ts} +25 -3
- package/dist/{dynamicFormsManager-CmvBSrzC.esm.js → dynamicFormsManager-Dt98SDfV.esm.js} +16 -5
- package/dist/{dynamicFormsStateMachine-C37Rtz1G.esm.js → dynamicFormsStateMachine-obKr4IIp.esm.js} +35 -3
- package/dist/ekyb.d.ts +1 -1
- package/dist/ekyb.esm.js +3 -3
- package/dist/{ekybManager-Bx6dG89U.esm.js → ekybManager-DNZKrKF3.esm.js} +2 -2
- package/dist/{ekybStateMachine-uscz9zIj.esm.js → ekybStateMachine-DjhHQXZ8.esm.js} +3 -3
- package/dist/ekyc.esm.js +2 -2
- package/dist/{ekycManager-DgT48ky6.esm.js → ekycManager-CmQBpeiI.esm.js} +2 -2
- package/dist/{ekycStateMachine-CQwqiR-R.esm.js → ekycStateMachine-CmdW2gVm.esm.js} +2 -2
- package/dist/electronic-signature.d.ts +3 -3
- package/dist/electronic-signature.esm.js +2 -2
- package/dist/electronicSignatureManager-Ds-KEVTq.d.ts +2786 -0
- package/dist/{electronicSignatureManager-_QiHi1U5.esm.js → electronicSignatureManager-DzulxM4_.esm.js} +357 -51
- package/dist/email.esm.js +2 -2
- package/dist/{emailManager-BY0jeYwR.esm.js → emailManager-B5ek_UfM.esm.js} +2 -2
- package/dist/{emailStateMachine-Crw8QVmc.esm.js → emailStateMachine-CyPFZ7dW.esm.js} +1 -1
- package/dist/{endpoints-CCzL3XD_.esm.js → endpoints-D3B9mUHh.esm.js} +24 -7
- 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-BxWPpxyd.d.ts → faceCaptureManagerFactory-CvtqcLxs.d.ts} +87 -54
- package/dist/{faceCaptureManagerFactory-Bkueb8mk.esm.js → faceCaptureManagerFactory-pCmG4MeF.esm.js} +68 -7
- package/dist/faceCaptureSetup-BSextack.esm.js +2106 -0
- package/dist/{faceMatchManager-Ri4UbNz0.esm.js → faceMatchManager-Caal2zyV.esm.js} +2 -2
- package/dist/{faceMatchStateMachine-20DdZ3jg.esm.js → faceMatchStateMachine-BUc5FXYy.esm.js} +1 -1
- package/dist/{feature-management-B3Uygq6K.esm.js → feature-management-B0sGlozZ.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-BIs6HPJG.esm.js} +2 -2
- package/dist/fiscal-qr.d.ts +2 -56
- package/dist/fiscal-qr.esm.js +2 -308
- package/dist/fiscalQrManager-Bp_-3LJr.esm.js +34131 -0
- package/dist/fiscalQrManager-CHcBJwUM.d.ts +68 -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-UakxNaeg.esm.js → flowCompletionService-CLtbWhSK.esm.js} +2 -2
- package/dist/{flowServices-CD5m8HqZ.esm.js → flowServices-B5FwukTQ.esm.js} +91 -26
- package/dist/geolocation.esm.js +2 -2
- package/dist/{geolocationManager-Bz6wJrfI.esm.js → geolocationManager-DIw-xq9a.esm.js} +2 -2
- package/dist/{geolocationStateMachine-psEJIVjN.esm.js → geolocationStateMachine-DpG0TFOU.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-D02vT4yY.d.ts +63 -0
- package/dist/governmentValidationManager-TjC9iVjH.esm.js +79 -0
- package/dist/governmentValidationStateMachine-D1ZnEqdd.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-BcxjQDI3.esm.js +484 -0
- package/dist/{idCaptureManager-CqrqSjJV.d.ts → idCaptureManager-CvmHOWWd.d.ts} +227 -39
- package/dist/{idCaptureManager-BJAquKfp.esm.js → idCaptureManager-Vby8oYqh.esm.js} +259 -46
- package/dist/{idCaptureServices-CM6ki4IH.esm.js → idCaptureServices-CJIxD9ep.esm.js} +342 -31
- package/dist/idCaptureStateMachine-CmqihkUy.esm.js +5343 -0
- package/dist/{idOcrManager-DXc_xRN7.d.ts → idOcrManager-BF_cXZq8.d.ts} +1 -1
- package/dist/{idOcrManager-BIQYQXXj.esm.js → idOcrManager-DHU22hVn.esm.js} +2 -2
- package/dist/{idOcrStateMachine-cSxzHpHt.esm.js → idOcrStateMachine-33UvRAHE.esm.js} +1 -1
- package/dist/{idVerificationManager-JpV_SAsl.esm.js → idVerificationManager-CyaixD0D.esm.js} +2 -2
- package/dist/{idVerificationStateMachine-nPeUNyFq.esm.js → idVerificationStateMachine-BPGrQZEm.esm.js} +1 -1
- package/dist/identity-reuse.esm.js +2 -2
- package/dist/{identityReuseManager-kNCg9AbD.esm.js → identityReuseManager-CWaNHBO3.esm.js} +2 -2
- package/dist/{identityReuseStateMachine-DyulxDjP.esm.js → identityReuseStateMachine-CQgnATo5.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-DyPzUmsZ.d.ts → mandatoryConsentManager-CJSyhTpi.d.ts} +5 -5
- package/dist/{mandatoryConsentManager-B4Niyg_u.esm.js → mandatoryConsentManager-Du-m-tZ_.esm.js} +2 -2
- package/dist/{mandatoryConsentStateMachine-B4-1u-L8.esm.js → mandatoryConsentStateMachine-DSDAk7WZ.esm.js} +1 -1
- package/dist/multipartRecordingService-B3C_zlev.esm.js +594 -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-N1-sbrY4.esm.js} +2 -2
- package/dist/{phoneStateMachine-Ba0wKHyX.esm.js → phoneStateMachine-jl8LJKCo.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/recordingsRepository-CCWy13M-.esm.js +72 -0
- package/dist/redirect-to-mobile.esm.js +2 -2
- package/dist/{redirectToMobileManager-y4VQB11M.esm.js → redirectToMobileManager-DsFzdTwA.esm.js} +2 -2
- package/dist/{redirectToMobileStateMachine-Cyv2x0PP.esm.js → redirectToMobileStateMachine-v3otpT-L.esm.js} +1 -1
- package/dist/{rolldown-runtime-FZ4Itg2g.esm.js → rolldown-runtime-FDOR9p9I.esm.js} +1 -19
- package/dist/{runChildModule-BR2RIfRg.esm.js → runChildModule-TuyGE00X.esm.js} +3 -21
- package/dist/safeStorage-B-trhxg6.esm.js +423 -0
- package/dist/{sdkVersion-BWOdgLZ1.esm.js → sdkVersion-CLxKvdyz.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-C77GXJH6.esm.js} +30 -4
- package/dist/{selfieManager-BlImAV-k.esm.js → selfieManager-CihVnODO.esm.js} +5 -5
- package/dist/{selfieManager-DwlCppg0.d.ts → selfieManager-D1KRJ39M.d.ts} +8 -11
- package/dist/selfieStateMachine-fwMmNtOi.esm.js +69 -0
- package/dist/{session-Bp17qJsu.esm.js → session-BHIeAamR.esm.js} +4 -5
- package/dist/session.d.ts +21 -11
- package/dist/session.esm.js +5 -5
- package/dist/{sessionInitializer-CcqQD9Q4.esm.js → sessionInitializer-BLoK7SP9.esm.js} +187 -68
- package/dist/{setup-BgoWtvIS.d.ts → setup-Cv-JM9QC.d.ts} +63 -69
- package/dist/{setup-CXj5ozZN.esm.js → setup-msLybMbC.esm.js} +226 -100
- package/dist/signature.esm.js +2 -2
- package/dist/{signatureManager-Ca43yhwk.esm.js → signatureManager-ChsB-nMD.esm.js} +2 -2
- package/dist/{signatureStateMachine-K1LMRrxG.esm.js → signatureStateMachine-BHPwkJZS.esm.js} +1 -1
- package/dist/{src-0Jurt29N.esm.js → src-35ekGRzK.esm.js} +1 -1
- package/dist/{stats-B0nFKawG.esm.js → stats-DkK-f8JT.esm.js} +1 -1
- package/dist/stats.esm.js +1 -1
- package/dist/{trueSightService-D05SY_Ij.esm.js → trueSightService-CKrrfV0Q.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-CM-jtjJ2.d.ts} +6 -81
- package/dist/{types-Bdf8_LYB2.d.ts → types-CjKBS37a2.d.ts} +303 -13
- 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-ZT1XFIJ8.d.ts +6 -0
- package/dist/video-selfie.d.ts +59 -35
- package/dist/video-selfie.esm.js +510 -601
- package/dist/{videoSelfieCameraWarmer-BhTWYfGn.esm.js → videoSelfieCameraWarmer-CB1IzZkt.esm.js} +14 -153
- package/dist/videoSelfieFlowModuleMachine-BUe2uACW.esm.js +32 -0
- package/dist/{videoSelfieStepDetector-D3oo2ofo.d.ts → videoSelfieStepDetector-5YHFe0Mq.d.ts} +21 -5
- package/dist/virtualCameraCheck-WOloJ-do.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-CpuuB1J2.esm.js +107 -0
- package/dist/watchlistForBusinessManager-CsnJnG-C.d.ts +99 -0
- package/dist/{watchlistForBusinessStateMachine-CxFnlshm.esm.js → watchlistForBusinessStateMachine-DEzgjz7C.esm.js} +13 -6
- package/dist/{watchlistManager-LoNZH9qm.esm.js → watchlistManager-CI8BHFob.esm.js} +2 -2
- package/dist/{watchlistStateMachine-DIKQDoUT.esm.js → watchlistStateMachine-DvOby3a-.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-BECAis8R.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-fi-Gq1AH.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-CB62pUQf.esm.js +0 -646
- package/dist/openviduLazy-CCDpFWg1.esm.js +0 -10
- package/dist/recordingService-BRgmVnUT.esm.js +0 -329
- package/dist/safeStorage-Ep56I-f_.esm.js +0 -982
- package/dist/selfieStateMachine-CPXEC4wV.esm.js +0 -55
- package/dist/trueSight-CY0Ibfm9.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
package/dist/video-selfie.esm.js
CHANGED
|
@@ -1,431 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { t as ensureWasmPipelines } from "./setup-msLybMbC.esm.js";
|
|
2
|
+
import { r as WasmUtilProvider } from "./safeStorage-B-trhxg6.esm.js";
|
|
3
3
|
import { t as BrowserTimerProvider } from "./BrowserTimerProvider-BXhgNxLt.esm.js";
|
|
4
4
|
import { t as api } from "./api-Bx3gKW_y.esm.js";
|
|
5
|
-
import { t as endpoints } from "./endpoints-
|
|
6
|
-
import { d as
|
|
7
|
-
import { i as assign, s as createActor, t as setup, u as createManager } from "./xstate.esm-BuFLFuzz.esm.js";
|
|
5
|
+
import { t as endpoints } from "./endpoints-D3B9mUHh.esm.js";
|
|
6
|
+
import { d as facingModeForStep, f as resolveVideoSelfieSteps, p as videoSelfieWasmPipelines } from "./flowServices-B5FwukTQ.esm.js";
|
|
7
|
+
import { i as assign, r as sendTo, s as createActor, t as setup, u as createManager } from "./xstate.esm-BuFLFuzz.esm.js";
|
|
8
8
|
import { n as fromPromise, t as fromCallback } from "./xstate-actors.esm-BXeQ-Ucz.esm.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
* very small timeslices reliably.
|
|
19
|
-
*/
|
|
20
|
-
const TIMESLICE_MS = 500;
|
|
21
|
-
/**
|
|
22
|
-
* Encoder target for the full video-selfie session. Higher than the
|
|
23
|
-
* short-clip liveness path (0.5–1 Mbps) so a multi-minute session keeps
|
|
24
|
-
* usable quality. It's a ceiling — a still scene still encodes well below it.
|
|
25
|
-
*/
|
|
26
|
-
const VIDEO_BITS_PER_SECOND = 25e5;
|
|
27
|
-
/**
|
|
28
|
-
* Records a stream and emits every `MediaRecorder` timeslice blob as its own
|
|
29
|
-
* part, in order. Each blob is a whole container fragment (WebM cluster /
|
|
30
|
-
* fMP4 `moof`+`mdat`), which is the property the video-selfie-service's
|
|
31
|
-
* gap-splicing depends on — parts must never cut a fragment at a byte
|
|
32
|
-
* offset. The service stages sub-5 MiB chunks and combines them server-side,
|
|
33
|
-
* so emitting the smallest whole-fragment unit (~0.5 s of video) maximizes
|
|
34
|
-
* what an interrupted session can salvage.
|
|
35
|
-
*
|
|
36
|
-
* Unlike the short-clip liveness recorder, this does NOT auto-pause on
|
|
37
|
-
* `visibilitychange`: a video-selfie session must record continuously, and a
|
|
38
|
-
* pause with no resume would silently truncate the recording the moment the
|
|
39
|
-
* tab lost visibility.
|
|
40
|
-
*/
|
|
41
|
-
var MultipartRecordingProvider = class {
|
|
42
|
-
constructor() {
|
|
43
|
-
this.mediaRecorder = null;
|
|
44
|
-
this._isRecording = false;
|
|
45
|
-
this._hasError = false;
|
|
46
|
-
this._error = null;
|
|
47
|
-
this.mimeType = "";
|
|
48
|
-
this.partNumber = 0;
|
|
49
|
-
this.onPart = null;
|
|
50
|
-
}
|
|
51
|
-
get isRecording() {
|
|
52
|
-
return this._isRecording;
|
|
53
|
-
}
|
|
54
|
-
get hasError() {
|
|
55
|
-
return this._hasError;
|
|
56
|
-
}
|
|
57
|
-
get error() {
|
|
58
|
-
return this._error;
|
|
59
|
-
}
|
|
60
|
-
startRecording(stream, onPart) {
|
|
61
|
-
this.reset();
|
|
62
|
-
this.partNumber = 0;
|
|
63
|
-
this.onPart = onPart;
|
|
64
|
-
try {
|
|
65
|
-
this.mimeType = getSupportedMediaRecorderMimeType();
|
|
66
|
-
const recorder = new MediaRecorder(stream.clone(), {
|
|
67
|
-
mimeType: this.mimeType,
|
|
68
|
-
videoBitsPerSecond: VIDEO_BITS_PER_SECOND
|
|
69
|
-
});
|
|
70
|
-
recorder.ondataavailable = (event) => {
|
|
71
|
-
if (event.data.size > 0 && this.onPart) {
|
|
72
|
-
this.partNumber += 1;
|
|
73
|
-
this.onPart({
|
|
74
|
-
chunk: event.data,
|
|
75
|
-
partNumber: this.partNumber
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
recorder.onerror = (event) => {
|
|
80
|
-
const detail = event instanceof ErrorEvent && event.error instanceof Error ? event.error.message : event.type;
|
|
81
|
-
this._error = `Recording error: ${detail}`;
|
|
82
|
-
this._isRecording = false;
|
|
83
|
-
this._hasError = true;
|
|
84
|
-
};
|
|
85
|
-
recorder.start(TIMESLICE_MS);
|
|
86
|
-
this.mediaRecorder = recorder;
|
|
87
|
-
this._isRecording = true;
|
|
88
|
-
this._error = null;
|
|
89
|
-
this._hasError = false;
|
|
90
|
-
} catch (err) {
|
|
91
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
92
|
-
this._error = `Failed to start recording: ${detail}`;
|
|
93
|
-
this._hasError = true;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
stopRecording() {
|
|
97
|
-
const recorder = this.mediaRecorder;
|
|
98
|
-
return new Promise((resolve) => {
|
|
99
|
-
if (recorder && this._isRecording) {
|
|
100
|
-
recorder.onstop = () => {
|
|
101
|
-
resolve();
|
|
102
|
-
};
|
|
103
|
-
recorder.stop();
|
|
104
|
-
this._isRecording = false;
|
|
105
|
-
} else resolve();
|
|
106
|
-
recorder?.stream?.getTracks().forEach((track) => track.stop());
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
reset() {
|
|
110
|
-
const recorder = this.mediaRecorder;
|
|
111
|
-
if (recorder) {
|
|
112
|
-
recorder.ondataavailable = null;
|
|
113
|
-
recorder.onerror = null;
|
|
114
|
-
recorder.onstop = null;
|
|
115
|
-
if (recorder.state !== "inactive") recorder.stop();
|
|
116
|
-
recorder.stream.getTracks().forEach((track) => track.stop());
|
|
117
|
-
this.mediaRecorder = null;
|
|
118
|
-
}
|
|
119
|
-
this.onPart = null;
|
|
120
|
-
this._isRecording = false;
|
|
121
|
-
this._error = null;
|
|
122
|
-
this._hasError = false;
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
//#endregion
|
|
126
|
-
//#region ../infra/src/providers/browser/BrowserNetworkStatusProvider.ts
|
|
127
|
-
var BrowserNetworkStatusProvider = class {
|
|
128
|
-
onOnline(listener) {
|
|
129
|
-
if (typeof window === "undefined" || typeof window.addEventListener !== "function") return () => {};
|
|
130
|
-
window.addEventListener("online", listener);
|
|
131
|
-
return () => {
|
|
132
|
-
window.removeEventListener("online", listener);
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
//#endregion
|
|
137
|
-
//#region src/internal/recordings/videoSelfieChunkUploader.ts
|
|
138
|
-
/**
|
|
139
|
-
* How many part uploads run concurrently. The service allows 10 rps with a
|
|
140
|
-
* burst of 30 per session; a real recorder emits ~2 chunks/s, so this cap
|
|
141
|
-
* only matters when a backlog is draining after a network stall.
|
|
142
|
-
*/
|
|
143
|
-
const MAX_IN_FLIGHT = 3;
|
|
144
|
-
/** Attempts per chunk in the live round (first try + retries). */
|
|
145
|
-
const MAX_ATTEMPTS = 4;
|
|
146
|
-
/** Extra attempts per parked chunk during the final drain() round. */
|
|
147
|
-
const DRAIN_ATTEMPTS = 2;
|
|
148
|
-
const BACKOFF_BASE_MS = 500;
|
|
149
|
-
const BACKOFF_CAP_MS = 8e3;
|
|
150
|
-
/** Upper bound honored for a server-sent `Retry-After` (seconds). */
|
|
151
|
-
const RETRY_AFTER_CAP_MS = 3e4;
|
|
152
|
-
/**
|
|
153
|
-
* Ceiling on un-acknowledged chunk bytes held in memory. On a network slower
|
|
154
|
-
* than the encoder the backlog grows without bound; past this the upload
|
|
155
|
-
* cannot realistically catch up, so the uploader fails instead of eating
|
|
156
|
-
* memory on a low-end device. ~48 MiB ≈ 2.5 minutes of video at our bitrate.
|
|
157
|
-
*/
|
|
158
|
-
const MAX_BUFFERED_BYTES = 48 * 1024 * 1024;
|
|
159
|
-
function httpStatusOf$1(error) {
|
|
160
|
-
if (typeof error === "object" && error !== null && "status" in error && typeof error.status === "number") return error.status;
|
|
161
|
-
return null;
|
|
162
|
-
}
|
|
163
|
-
function retryAfterMsOf(error) {
|
|
164
|
-
if (typeof error === "object" && error !== null && "headers" in error && typeof error.headers === "object") {
|
|
165
|
-
const headers = error.headers;
|
|
166
|
-
const seconds = Number(headers?.["retry-after"]);
|
|
167
|
-
if (Number.isFinite(seconds) && seconds >= 0) return Math.min(seconds * 1e3, RETRY_AFTER_CAP_MS);
|
|
168
|
-
}
|
|
169
|
-
return null;
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Uploads video-selfie chunks with the client-side half of the service's
|
|
173
|
-
* resilience contract (`video-selfie-service` README, "What a client can
|
|
174
|
-
* rely on"):
|
|
175
|
-
*
|
|
176
|
-
* - **Keep-until-ack** — every chunk is held in memory until its upload
|
|
177
|
-
* returns 200 (a hole in the sequence can only be filled by that exact
|
|
178
|
-
* data). Acked bytes are durable in S3 (stored as a part or staged), so
|
|
179
|
-
* the blob is released the moment the ack lands.
|
|
180
|
-
* - **Retry with backoff** — transient failures (network error/timeout,
|
|
181
|
-
* 408, 429, 5xx) retry the same bytes under the same partNumber with
|
|
182
|
-
* exponential backoff + full jitter; 429 honors the server's
|
|
183
|
-
* `Retry-After`. Chunks may land out of order — the service stages them.
|
|
184
|
-
* - **Park, then drain** — a chunk that exhausts its live retries is parked
|
|
185
|
-
* (blob kept) without failing the recording; {@link drain} gives every
|
|
186
|
-
* parked chunk a final round once recording stops, so a mid-recording
|
|
187
|
-
* network outage only fails the upload if it persists to the end. A
|
|
188
|
-
* browser `online` event un-parks early: parked chunks get a fresh live
|
|
189
|
-
* round as soon as connectivity returns instead of waiting for stop.
|
|
190
|
-
* - **409 is fatal** — a newer initiate fenced this session out ("latest
|
|
191
|
-
* initiate wins"); no retry can succeed, so the uploader stops.
|
|
192
|
-
* - **Bounded memory** — when un-acked bytes exceed the ceiling the
|
|
193
|
-
* uploader fails rather than buffering a runaway backlog.
|
|
194
|
-
*/
|
|
195
|
-
var VideoSelfieChunkUploader = class {
|
|
196
|
-
constructor(session, dependencies = {}) {
|
|
197
|
-
this.queue = [];
|
|
198
|
-
this.parked = [];
|
|
199
|
-
this.inFlight = 0;
|
|
200
|
-
this.bufferedBytes = 0;
|
|
201
|
-
this.fatal = false;
|
|
202
|
-
this.disposed = false;
|
|
203
|
-
this.tasks = [];
|
|
204
|
-
this.session = session;
|
|
205
|
-
this.timer = dependencies.timer ?? BrowserTimerProvider.getInstance();
|
|
206
|
-
this.jitter = dependencies.jitter ?? Math.random;
|
|
207
|
-
const networkStatus = dependencies.networkStatus ?? new BrowserNetworkStatusProvider();
|
|
208
|
-
this.unsubscribeOnline = networkStatus.onOnline(() => this.unparkEarly());
|
|
209
|
-
}
|
|
210
|
-
/** True once the upload cannot complete (fenced out or over the memory cap). */
|
|
211
|
-
get failed() {
|
|
212
|
-
return this.fatal;
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* Accepts the next chunk for upload. Non-blocking: the upload (and any
|
|
216
|
-
* retries) run in the background; failures surface through {@link failed}
|
|
217
|
-
* and {@link drain}.
|
|
218
|
-
*/
|
|
219
|
-
enqueue(partNumber, chunk) {
|
|
220
|
-
if (this.fatal || this.disposed) return;
|
|
221
|
-
this.bufferedBytes += chunk.size;
|
|
222
|
-
if (this.bufferedBytes > MAX_BUFFERED_BYTES) {
|
|
223
|
-
this.fatal = true;
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
this.queue.push({
|
|
227
|
-
partNumber,
|
|
228
|
-
chunk,
|
|
229
|
-
attempts: 0
|
|
230
|
-
});
|
|
231
|
-
this.pump();
|
|
232
|
-
}
|
|
233
|
-
/**
|
|
234
|
-
* Waits for every accepted chunk to be acknowledged, giving parked chunks
|
|
235
|
-
* one final retry round. Returns `true` when all chunks landed and the
|
|
236
|
-
* upload can be completed.
|
|
237
|
-
*/
|
|
238
|
-
async drain() {
|
|
239
|
-
this.unsubscribeOnline();
|
|
240
|
-
await this.settleLiveRound();
|
|
241
|
-
while (!this.fatal && this.parked.length > 0) {
|
|
242
|
-
const chunk = this.parked.shift();
|
|
243
|
-
chunk.attempts = MAX_ATTEMPTS - DRAIN_ATTEMPTS;
|
|
244
|
-
this.queue.push(chunk);
|
|
245
|
-
this.pump();
|
|
246
|
-
await this.settleLiveRound();
|
|
247
|
-
if (this.parked.some((p) => p.partNumber === chunk.partNumber)) return false;
|
|
248
|
-
}
|
|
249
|
-
return !this.fatal && this.parked.length === 0;
|
|
250
|
-
}
|
|
251
|
-
/** Cancels all pending work; held blobs are released. */
|
|
252
|
-
dispose() {
|
|
253
|
-
this.disposed = true;
|
|
254
|
-
this.queue = [];
|
|
255
|
-
this.parked = [];
|
|
256
|
-
this.unsubscribeOnline();
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* Connectivity is back (browser `online` event) — give parked chunks a
|
|
260
|
-
* fresh live round right away instead of holding them until {@link drain}.
|
|
261
|
-
* The event is only a hint: chunks that still fail simply park again.
|
|
262
|
-
*/
|
|
263
|
-
unparkEarly() {
|
|
264
|
-
if (this.fatal || this.disposed || this.parked.length === 0) return;
|
|
265
|
-
for (const chunk of this.parked.splice(0)) {
|
|
266
|
-
chunk.attempts = 0;
|
|
267
|
-
this.queue.push(chunk);
|
|
268
|
-
}
|
|
269
|
-
this.pump();
|
|
270
|
-
}
|
|
271
|
-
async settleLiveRound() {
|
|
272
|
-
while (this.tasks.length > 0) {
|
|
273
|
-
const snapshot = [...this.tasks];
|
|
274
|
-
await Promise.all(snapshot);
|
|
275
|
-
this.tasks = this.tasks.filter((task) => !snapshot.includes(task));
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
pump() {
|
|
279
|
-
while (!this.fatal && !this.disposed && this.inFlight < MAX_IN_FLIGHT && this.queue.length > 0) {
|
|
280
|
-
const chunk = this.queue.shift();
|
|
281
|
-
this.inFlight += 1;
|
|
282
|
-
const task = this.uploadWithRetry(chunk).finally(() => {
|
|
283
|
-
this.inFlight -= 1;
|
|
284
|
-
this.pump();
|
|
285
|
-
});
|
|
286
|
-
this.tasks.push(task);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
async uploadWithRetry(pending) {
|
|
290
|
-
while (!this.disposed) {
|
|
291
|
-
pending.attempts += 1;
|
|
292
|
-
try {
|
|
293
|
-
await uploadVideoSelfiePart(this.session, pending.partNumber, pending.chunk);
|
|
294
|
-
this.bufferedBytes -= pending.chunk.size;
|
|
295
|
-
return;
|
|
296
|
-
} catch (error) {
|
|
297
|
-
const status = httpStatusOf$1(error);
|
|
298
|
-
if (status === 409) {
|
|
299
|
-
this.fatal = true;
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
if (status !== null && status >= 400 && status < 500 && status !== 408 && status !== 429 || pending.attempts >= MAX_ATTEMPTS) {
|
|
303
|
-
this.parked.push(pending);
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
await this.delayBeforeRetry(pending.attempts, error);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
delayBeforeRetry(attempt, error) {
|
|
311
|
-
const retryAfterMs = retryAfterMsOf(error);
|
|
312
|
-
const backoffCeiling = Math.min(BACKOFF_BASE_MS * 2 ** (attempt - 1), BACKOFF_CAP_MS);
|
|
313
|
-
const waitMs = retryAfterMs ?? backoffCeiling / 2 + this.jitter() * (backoffCeiling / 2);
|
|
314
|
-
return new Promise((resolve) => {
|
|
315
|
-
this.timer.setTimeout(resolve, waitMs);
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
|
-
//#endregion
|
|
320
|
-
//#region src/internal/recordings/multipartRecordingService.ts
|
|
321
|
-
/** Attempts for `complete` — documented safe to repeat if the response was lost. */
|
|
322
|
-
const COMPLETE_ATTEMPTS = 3;
|
|
323
|
-
const COMPLETE_BACKOFF_MS = 500;
|
|
324
|
-
function httpStatusOf(error) {
|
|
325
|
-
if (typeof error === "object" && error !== null && "status" in error && typeof error.status === "number") return error.status;
|
|
326
|
-
return null;
|
|
9
|
+
import { t as BrowserVisibilityObserverProvider } from "./BrowserVisibilityObserverProvider-BrJN1B8A.esm.js";
|
|
10
|
+
import { t as MultipartRecordingService } from "./multipartRecordingService-B3C_zlev.esm.js";
|
|
11
|
+
import { i as CameraCompositor } from "./idCaptureDefaults-BcxjQDI3.esm.js";
|
|
12
|
+
import { t as VIDEO_SELFIE_VALIDATION_ATTEMPTS_EXHAUSTED_CODE } from "./advanceableErrors-CpF2cBy6.esm.js";
|
|
13
|
+
import { a as isConnectionError, n as defaultAcquireCamera, r as createDefaultStepDetector, t as createVideoSelfieCameraWarmer } from "./videoSelfieCameraWarmer-CB1IzZkt.esm.js";
|
|
14
|
+
import { t as videoSelfieFlowModuleMachine } from "./videoSelfieFlowModuleMachine-BUe2uACW.esm.js";
|
|
15
|
+
//#region src/modules/video-selfie/videoSelfieWasm.ts
|
|
16
|
+
function warmupVideoSelfieWasm(config, steps = resolveVideoSelfieSteps(config)) {
|
|
17
|
+
return ensureWasmPipelines(videoSelfieWasmPipelines(config, steps));
|
|
327
18
|
}
|
|
328
|
-
/**
|
|
329
|
-
* Records the camera on-device and streams it to the backend as it is
|
|
330
|
-
* captured, using the video-selfie-service multipart upload protocol
|
|
331
|
-
* (`/v1/video-upload/*`).
|
|
332
|
-
*
|
|
333
|
-
* This is the Video Selfie module's client-side recorder and is deliberately
|
|
334
|
-
* independent of the face-capture recording services (`LocalRecordingService`
|
|
335
|
-
* / `OpenViduRecordingService`) — it is the replacement for server-side
|
|
336
|
-
* (OpenVidu) recording, not a sibling of it.
|
|
337
|
-
*
|
|
338
|
-
* Every ~1 s recorder blob uploads as its own chunk, concurrently with
|
|
339
|
-
* recording, through {@link VideoSelfieChunkUploader} (keep-until-ack +
|
|
340
|
-
* retry with backoff — see its doc for the full policy). The service stages
|
|
341
|
-
* sub-5 MiB chunks and combines them server-side, so `stop()` only drains
|
|
342
|
-
* the stragglers and finalizes; client memory holds un-acked chunks only.
|
|
343
|
-
* No client-side encryption: video is encrypted at rest server-side
|
|
344
|
-
* (S3 SSE-AES-256).
|
|
345
|
-
*/
|
|
346
|
-
var MultipartRecordingService = class {
|
|
347
|
-
constructor() {
|
|
348
|
-
this.recorder = new MultipartRecordingProvider();
|
|
349
|
-
this.timer = BrowserTimerProvider.getInstance();
|
|
350
|
-
this.session = null;
|
|
351
|
-
this.uploader = null;
|
|
352
|
-
this.chunksEmitted = 0;
|
|
353
|
-
}
|
|
354
|
-
get isRecording() {
|
|
355
|
-
return this.recorder.isRecording;
|
|
356
|
-
}
|
|
357
|
-
async start(stream) {
|
|
358
|
-
let initiated = await initiateVideoSelfieUpload();
|
|
359
|
-
if (initiated.parts.length > 0) {
|
|
360
|
-
await abortVideoSelfieUpload(initiated).catch(() => {});
|
|
361
|
-
initiated = await initiateVideoSelfieUpload();
|
|
362
|
-
}
|
|
363
|
-
this.session = {
|
|
364
|
-
uploadId: initiated.uploadId,
|
|
365
|
-
epoch: initiated.epoch
|
|
366
|
-
};
|
|
367
|
-
this.uploader = new VideoSelfieChunkUploader(this.session);
|
|
368
|
-
this.chunksEmitted = 0;
|
|
369
|
-
this.recorder.startRecording(stream, ({ chunk, partNumber }) => {
|
|
370
|
-
this.chunksEmitted += 1;
|
|
371
|
-
this.uploader?.enqueue(partNumber, chunk);
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
async stop() {
|
|
375
|
-
const session = this.session;
|
|
376
|
-
const uploader = this.uploader;
|
|
377
|
-
if (!this.recorder.isRecording || !session || !uploader) return { recordingId: null };
|
|
378
|
-
await this.recorder.stopRecording();
|
|
379
|
-
if (!await uploader.drain() || uploader.failed || this.chunksEmitted === 0) {
|
|
380
|
-
this.abandonUpload(session);
|
|
381
|
-
return { recordingId: null };
|
|
382
|
-
}
|
|
383
|
-
try {
|
|
384
|
-
await this.completeWithRetry(session);
|
|
385
|
-
this.session = null;
|
|
386
|
-
this.uploader = null;
|
|
387
|
-
return { recordingId: session.uploadId };
|
|
388
|
-
} catch {
|
|
389
|
-
this.abandonUpload(session);
|
|
390
|
-
return { recordingId: null };
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
cleanup() {
|
|
394
|
-
if (this.session) this.abandonUpload(this.session);
|
|
395
|
-
this.recorder.reset();
|
|
396
|
-
}
|
|
397
|
-
/**
|
|
398
|
-
* `complete` is idempotent server-side ("safe to repeat if the response
|
|
399
|
-
* was lost"), so transient failures — network errors, 5xx, 429 — retry a
|
|
400
|
-
* couple of times before the recording is declared failed. A 4xx (e.g.
|
|
401
|
-
* `400` naming a missing part) is permanent: after a clean drain every
|
|
402
|
-
* chunk was acked, so a reported hole cannot be filled from here.
|
|
403
|
-
*/
|
|
404
|
-
async completeWithRetry(session) {
|
|
405
|
-
for (let attempt = 1;; attempt += 1) try {
|
|
406
|
-
await completeVideoSelfieUpload(session);
|
|
407
|
-
return;
|
|
408
|
-
} catch (error) {
|
|
409
|
-
const status = httpStatusOf(error);
|
|
410
|
-
if (status !== null && status >= 400 && status < 500 && status !== 408 && status !== 429 || attempt >= COMPLETE_ATTEMPTS) throw error;
|
|
411
|
-
await new Promise((resolve) => {
|
|
412
|
-
this.timer.setTimeout(resolve, COMPLETE_BACKOFF_MS * attempt);
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
/**
|
|
417
|
-
* Fire-and-forget abort: the upload can no longer complete, so tell the
|
|
418
|
-
* backend to fail it immediately rather than at its expiry. Best-effort —
|
|
419
|
-
* an abort that doesn't land (including a 409 from a newer epoch having
|
|
420
|
-
* taken over) just means the server falls back to expiry or salvage.
|
|
421
|
-
*/
|
|
422
|
-
abandonUpload(session) {
|
|
423
|
-
this.session = null;
|
|
424
|
-
this.uploader?.dispose();
|
|
425
|
-
this.uploader = null;
|
|
426
|
-
abortVideoSelfieUpload(session).catch(() => {});
|
|
427
|
-
}
|
|
428
|
-
};
|
|
429
19
|
//#endregion
|
|
430
20
|
//#region src/modules/video-selfie/videoSelfieRecordingMachine.ts
|
|
431
21
|
/** A detector that never settles — used when a step has no auto-capture yet. */
|
|
@@ -460,21 +50,19 @@ function orientationFromEvent(event) {
|
|
|
460
50
|
const SWITCHING_CAMERA_MIN_DWELL_MS = 3e3;
|
|
461
51
|
const ID_FLIP_DWELL_MS = 4e3;
|
|
462
52
|
const FINAL_SUCCESS_DWELL_MS = 3e3;
|
|
53
|
+
const MAX_VIDEO_LENGTH_ERROR_DWELL_MS = 3e3;
|
|
463
54
|
const VALIDATION_FEEDBACK_DWELL_MS = 3e3;
|
|
464
55
|
const DEFAULT_ATTEMPTS_PER_STEP = 3;
|
|
56
|
+
const DEFAULT_MAX_VIDEO_LENGTH_SECONDS = 300;
|
|
465
57
|
const UNLIMITED_ATTEMPTS = -1;
|
|
466
58
|
function normalizeAttempts(attempts) {
|
|
467
59
|
if (attempts === UNLIMITED_ATTEMPTS) return UNLIMITED_ATTEMPTS;
|
|
468
60
|
if (typeof attempts === "number" && attempts > 0) return attempts;
|
|
469
61
|
return DEFAULT_ATTEMPTS_PER_STEP;
|
|
470
62
|
}
|
|
471
|
-
function
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
function nextModuleIndex(context) {
|
|
475
|
-
let index = context.stepIndex + 1;
|
|
476
|
-
while (isIdStep(context.steps[index])) index += 1;
|
|
477
|
-
return index;
|
|
63
|
+
function normalizeMaxVideoLength(seconds) {
|
|
64
|
+
if (typeof seconds === "number" && Number.isFinite(seconds) && seconds > 0) return seconds;
|
|
65
|
+
return DEFAULT_MAX_VIDEO_LENGTH_SECONDS;
|
|
478
66
|
}
|
|
479
67
|
function waitForDwell(ms, signal) {
|
|
480
68
|
const timerProvider = BrowserTimerProvider.getInstance();
|
|
@@ -495,10 +83,13 @@ function waitForDwell(ms, signal) {
|
|
|
495
83
|
* Orchestrates a multi-step Video Selfie session as ONE continuous recording
|
|
496
84
|
* that follows the camera between steps AND auto-advances per step:
|
|
497
85
|
*
|
|
498
|
-
* idle ─START▶
|
|
499
|
-
*
|
|
500
|
-
*
|
|
501
|
-
*
|
|
86
|
+
* idle ─START▶ [preparingWasm ─▶] acquiringCamera ─▶ starting
|
|
87
|
+
* │
|
|
88
|
+
* ▼
|
|
89
|
+
* recording ⇄ switchingCamera
|
|
90
|
+
* │ (capture validated → DETECTION_DONE,
|
|
91
|
+
* │ or manual NEXT_STEP)
|
|
92
|
+
* last step ─▶ finalizing ─▶ finished
|
|
502
93
|
*
|
|
503
94
|
* While `recording`, a per-step detector runs WASM auto-capture + backend
|
|
504
95
|
* validation; success advances the step (switching the camera when the next
|
|
@@ -519,9 +110,31 @@ const videoSelfieRecordingSetup = setup({
|
|
|
519
110
|
delays: {
|
|
520
111
|
ID_FLIP_DWELL: ID_FLIP_DWELL_MS,
|
|
521
112
|
FINAL_SUCCESS_DWELL: FINAL_SUCCESS_DWELL_MS,
|
|
113
|
+
MAX_VIDEO_LENGTH_ERROR_DWELL: MAX_VIDEO_LENGTH_ERROR_DWELL_MS,
|
|
522
114
|
VALIDATION_FEEDBACK_DWELL: VALIDATION_FEEDBACK_DWELL_MS
|
|
523
115
|
},
|
|
524
116
|
actors: {
|
|
117
|
+
prepareWasm: fromPromise(async ({ input }) => input.ensure()),
|
|
118
|
+
visibilityChanges: fromCallback(({ input, sendBack }) => input.visibilityObserver.onVisibilityChange((visible) => {
|
|
119
|
+
sendBack({ type: visible ? "FOREGROUND" : "BACKGROUND" });
|
|
120
|
+
})),
|
|
121
|
+
executionTimer: fromCallback(({ input, sendBack, receive }) => {
|
|
122
|
+
let handle;
|
|
123
|
+
const cancel = () => {
|
|
124
|
+
if (handle !== void 0) {
|
|
125
|
+
input.timer.clearTimeout(handle);
|
|
126
|
+
handle = void 0;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
receive((event) => {
|
|
130
|
+
cancel();
|
|
131
|
+
if (event.type === "ARM") handle = input.timer.setTimeout(() => {
|
|
132
|
+
handle = void 0;
|
|
133
|
+
sendBack({ type: "MAX_VIDEO_LENGTH_REACHED" });
|
|
134
|
+
}, event.durationMs);
|
|
135
|
+
});
|
|
136
|
+
return cancel;
|
|
137
|
+
}),
|
|
525
138
|
acquireCamera: fromPromise(async ({ input, signal }) => {
|
|
526
139
|
const stream = await input.acquire(input.facingMode, input.withAudio);
|
|
527
140
|
if (signal.aborted) {
|
|
@@ -551,6 +164,13 @@ const videoSelfieRecordingSetup = setup({
|
|
|
551
164
|
await input.service.start(input.stream);
|
|
552
165
|
}),
|
|
553
166
|
finalizeRecording: fromPromise(async ({ input }) => input.service.stop()),
|
|
167
|
+
pauseCapture: fromPromise(async ({ input }) => {
|
|
168
|
+
const paused = input.service.pause();
|
|
169
|
+
input.compositor.pause();
|
|
170
|
+
return paused;
|
|
171
|
+
}),
|
|
172
|
+
resumeCompositor: fromPromise(async ({ input, signal }) => input.compositor.resume(signal)),
|
|
173
|
+
resumeRecorder: fromPromise(async ({ input }) => input.service.resume()),
|
|
554
174
|
detectStep: fromCallback(({ input, sendBack }) => {
|
|
555
175
|
const controller = new AbortController();
|
|
556
176
|
input.detect({
|
|
@@ -592,16 +212,16 @@ const videoSelfieRecordingSetup = setup({
|
|
|
592
212
|
})
|
|
593
213
|
},
|
|
594
214
|
actions: {
|
|
215
|
+
armExecutionTimer: sendTo("executionTimer", ({ context }) => ({
|
|
216
|
+
type: "ARM",
|
|
217
|
+
durationMs: context.maxVideoLengthSeconds * 1e3
|
|
218
|
+
})),
|
|
219
|
+
cancelExecutionTimer: sendTo("executionTimer", { type: "CANCEL" }),
|
|
595
220
|
advanceStep: assign({
|
|
596
221
|
stepIndex: ({ context }) => context.stepIndex + 1,
|
|
597
222
|
attemptsRemaining: ({ context }) => context.attemptsPerStep,
|
|
598
223
|
validationFailure: () => void 0
|
|
599
224
|
}),
|
|
600
|
-
advancePastIdSection: assign({
|
|
601
|
-
stepIndex: ({ context }) => nextModuleIndex(context),
|
|
602
|
-
attemptsRemaining: ({ context }) => context.attemptsPerStep,
|
|
603
|
-
validationFailure: () => void 0
|
|
604
|
-
}),
|
|
605
225
|
setDetectionStatus: assign({ detectionStatus: ({ event }) => detectionStatusFromEvent(event) }),
|
|
606
226
|
setOrientation: assign({ orientation: ({ event }) => orientationFromEvent(event) }),
|
|
607
227
|
setDetectionError: assign({ detectionError: ({ event }) => detectionErrorFromEvent(event) }),
|
|
@@ -624,10 +244,24 @@ const videoSelfieRecordingSetup = setup({
|
|
|
624
244
|
validationFailure: () => void 0,
|
|
625
245
|
orientation: () => void 0
|
|
626
246
|
}),
|
|
247
|
+
markPageHidden: assign({ isPageVisible: () => false }),
|
|
248
|
+
markPageVisible: assign({ isPageVisible: () => true }),
|
|
249
|
+
prepareRecordingSuspension: assign({
|
|
250
|
+
isPageVisible: () => false,
|
|
251
|
+
resumeState: () => "recording"
|
|
252
|
+
}),
|
|
627
253
|
setUploadFailedError: assign({
|
|
628
254
|
error: () => "Video upload failed",
|
|
629
255
|
errorKind: () => "connection"
|
|
630
256
|
}),
|
|
257
|
+
setMaxVideoLengthReached: assign({
|
|
258
|
+
error: () => "maxVideoLengthReached",
|
|
259
|
+
errorKind: () => "maxVideoLengthReached"
|
|
260
|
+
}),
|
|
261
|
+
setValidationAttemptsExhausted: assign({
|
|
262
|
+
error: () => "Video selfie validation attempts exhausted",
|
|
263
|
+
errorKind: () => "validationAttemptsExhausted"
|
|
264
|
+
}),
|
|
631
265
|
resetSession: assign(({ context }) => ({
|
|
632
266
|
stepIndex: 0,
|
|
633
267
|
stream: void 0,
|
|
@@ -639,26 +273,54 @@ const videoSelfieRecordingSetup = setup({
|
|
|
639
273
|
attemptsRemaining: context.attemptsPerStep,
|
|
640
274
|
recordingId: null,
|
|
641
275
|
error: void 0,
|
|
642
|
-
errorKind: void 0
|
|
276
|
+
errorKind: void 0,
|
|
277
|
+
resumeState: "recording"
|
|
643
278
|
})),
|
|
644
279
|
cleanup: ({ context }) => {
|
|
645
280
|
context.service.cleanup();
|
|
646
281
|
context.compositor.stop();
|
|
647
282
|
context.stream?.getTracks().forEach((track) => track.stop());
|
|
648
|
-
}
|
|
283
|
+
},
|
|
284
|
+
setTechnicalActorError: assign({
|
|
285
|
+
error: ({ event }) => errorFromEvent(event),
|
|
286
|
+
errorKind: () => "technical"
|
|
287
|
+
}),
|
|
288
|
+
setAudioEndedError: assign({
|
|
289
|
+
error: () => "Audio track ended while the app was backgrounded",
|
|
290
|
+
errorKind: () => "technical"
|
|
291
|
+
}),
|
|
292
|
+
setCameraResumeError: assign({
|
|
293
|
+
error: () => "Camera did not produce a fresh frame after foregrounding",
|
|
294
|
+
errorKind: () => "technical"
|
|
295
|
+
}),
|
|
296
|
+
setRecorderResumeError: assign({
|
|
297
|
+
error: () => "Recording could not resume after foregrounding",
|
|
298
|
+
errorKind: () => "technical"
|
|
299
|
+
}),
|
|
300
|
+
setPauseError: assign({
|
|
301
|
+
error: () => "Recording could not be paused before backgrounding",
|
|
302
|
+
errorKind: () => "technical"
|
|
303
|
+
})
|
|
649
304
|
},
|
|
650
305
|
guards: {
|
|
306
|
+
shouldEnterWasmGate: ({ context }) => context.ensureWasmReady !== void 0 && context.errorKind !== "maxVideoLengthReached" && context.errorKind !== "validationAttemptsExhausted",
|
|
651
307
|
isLastStep: ({ context }) => context.stepIndex >= context.steps.length - 1,
|
|
652
308
|
hasAttemptsRemaining: ({ context }) => context.attemptsRemaining === UNLIMITED_ATTEMPTS || context.attemptsRemaining > 0,
|
|
653
309
|
nextStepFlipsId: ({ context }) => context.steps[context.stepIndex] === "frontId" && context.steps[context.stepIndex + 1] === "backId",
|
|
654
|
-
exhaustedIdFinishes: ({ context }) => isIdStep(context.steps[context.stepIndex]) && nextModuleIndex(context) >= context.steps.length,
|
|
655
|
-
nextModuleFlipsCamera: ({ context }) => isIdStep(context.steps[context.stepIndex]) && facingModeForStep(context.steps[context.stepIndex]) !== facingModeForStep(context.steps[nextModuleIndex(context)]),
|
|
656
|
-
isIdExhaustion: ({ context }) => isIdStep(context.steps[context.stepIndex]),
|
|
657
|
-
exhaustedNonIdFinishes: ({ context }) => !isIdStep(context.steps[context.stepIndex]) && context.stepIndex >= context.steps.length - 1,
|
|
658
|
-
exhaustedNonIdNextStepFlipsCamera: ({ context }) => !isIdStep(context.steps[context.stepIndex]) && facingModeForStep(context.steps[context.stepIndex]) !== facingModeForStep(context.steps[context.stepIndex + 1]),
|
|
659
|
-
isNonIdExhaustion: ({ context }) => !isIdStep(context.steps[context.stepIndex]),
|
|
660
310
|
nextStepFlipsCamera: ({ context }) => facingModeForStep(context.steps[context.stepIndex]) !== facingModeForStep(context.steps[context.stepIndex + 1]),
|
|
661
|
-
uploadReturnedNoRecordingId: ({ event }) => recordingIdFromEvent(event) === null
|
|
311
|
+
uploadReturnedNoRecordingId: ({ event }) => recordingIdFromEvent(event) === null,
|
|
312
|
+
maxVideoLengthWasReached: ({ context }) => context.errorKind === "maxVideoLengthReached",
|
|
313
|
+
validationAttemptsWereExhausted: ({ context }) => context.errorKind === "validationAttemptsExhausted",
|
|
314
|
+
errorIsRetryable: ({ context }) => context.errorKind !== "maxVideoLengthReached" && context.errorKind !== "validationAttemptsExhausted",
|
|
315
|
+
pageIsHidden: ({ context }) => !context.isPageVisible,
|
|
316
|
+
pauseFailed: ({ event }) => !event.output,
|
|
317
|
+
pauseSucceededWhileVisible: ({ context, event }) => context.isPageVisible && event.output,
|
|
318
|
+
compositorAudioEnded: ({ event }) => event.output === "audio-ended",
|
|
319
|
+
compositorDidNotResume: ({ event }) => event.output !== "resumed",
|
|
320
|
+
forceVideoRecovery: ({ context }) => context.resumeState === "switchingCamera",
|
|
321
|
+
recorderResumeFailed: ({ event }) => !event.output,
|
|
322
|
+
resumeValidationFeedback: ({ context }) => context.resumeState === "validationFeedback",
|
|
323
|
+
resumeFlippingId: ({ context }) => context.resumeState === "flippingId"
|
|
662
324
|
}
|
|
663
325
|
});
|
|
664
326
|
const ADVANCE_TRANSITIONS = [
|
|
@@ -684,29 +346,63 @@ const ADVANCE_TRANSITIONS = [
|
|
|
684
346
|
const videoSelfieRecordingMachine = videoSelfieRecordingSetup.createMachine({
|
|
685
347
|
id: "videoSelfieRecording",
|
|
686
348
|
initial: "idle",
|
|
687
|
-
context: ({ input }) =>
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
349
|
+
context: ({ input }) => {
|
|
350
|
+
const visibilityObserver = input.visibilityObserver;
|
|
351
|
+
return {
|
|
352
|
+
service: input.dependencies?.createRecordingService?.() ?? new MultipartRecordingService(),
|
|
353
|
+
compositor: input.dependencies?.createCompositor?.() ?? new CameraCompositor(),
|
|
354
|
+
acquireCamera: input.dependencies?.acquireCamera ?? defaultAcquireCamera,
|
|
355
|
+
ensureWasmReady: input.ensureWasmReady,
|
|
356
|
+
detect: input.dependencies?.detect ?? manualStepDetector,
|
|
357
|
+
timer: input.dependencies?.timer ?? BrowserTimerProvider.getInstance(),
|
|
358
|
+
visibilityObserver,
|
|
359
|
+
isPageVisible: visibilityObserver.isVisible(),
|
|
360
|
+
resumeState: "recording",
|
|
361
|
+
steps: input.steps && input.steps.length > 0 ? input.steps : ["selfie"],
|
|
362
|
+
stepIndex: 0,
|
|
363
|
+
stream: void 0,
|
|
364
|
+
composite: void 0,
|
|
365
|
+
detectionStatus: void 0,
|
|
366
|
+
orientation: void 0,
|
|
367
|
+
detectionError: void 0,
|
|
368
|
+
validationFailure: void 0,
|
|
369
|
+
attemptsPerStep: normalizeAttempts(input.attemptsPerStep),
|
|
370
|
+
attemptsRemaining: normalizeAttempts(input.attemptsPerStep),
|
|
371
|
+
maxVideoLengthSeconds: normalizeMaxVideoLength(input.maxVideoLengthSeconds),
|
|
372
|
+
recordingId: null,
|
|
373
|
+
error: void 0,
|
|
374
|
+
errorKind: void 0,
|
|
375
|
+
switchingCameraMinDwellMs: input.dependencies?.switchingCameraMinDwellMs ?? SWITCHING_CAMERA_MIN_DWELL_MS
|
|
376
|
+
};
|
|
377
|
+
},
|
|
378
|
+
invoke: [{
|
|
379
|
+
id: "executionTimer",
|
|
380
|
+
src: "executionTimer",
|
|
381
|
+
input: ({ context }) => ({ timer: context.timer })
|
|
382
|
+
}, {
|
|
383
|
+
id: "visibilityChanges",
|
|
384
|
+
src: "visibilityChanges",
|
|
385
|
+
input: ({ context }) => ({ visibilityObserver: context.visibilityObserver })
|
|
386
|
+
}],
|
|
387
|
+
on: {
|
|
388
|
+
ABORT: { target: ".aborted" },
|
|
389
|
+
BACKGROUND: { actions: "markPageHidden" },
|
|
390
|
+
FOREGROUND: { actions: "markPageVisible" }
|
|
391
|
+
},
|
|
708
392
|
states: {
|
|
709
|
-
idle: { on: { START: {
|
|
393
|
+
idle: { on: { START: [{
|
|
394
|
+
target: "preparingWasm",
|
|
395
|
+
guard: "shouldEnterWasmGate"
|
|
396
|
+
}, { target: "acquiringCamera" }] } },
|
|
397
|
+
preparingWasm: { invoke: {
|
|
398
|
+
src: "prepareWasm",
|
|
399
|
+
input: ({ context }) => ({ ensure: context.ensureWasmReady }),
|
|
400
|
+
onDone: { target: "acquiringCamera" },
|
|
401
|
+
onError: {
|
|
402
|
+
target: "error",
|
|
403
|
+
actions: "setTechnicalActorError"
|
|
404
|
+
}
|
|
405
|
+
} },
|
|
710
406
|
acquiringCamera: { invoke: {
|
|
711
407
|
src: "acquireCamera",
|
|
712
408
|
input: ({ context }) => ({
|
|
@@ -734,7 +430,14 @@ const videoSelfieRecordingMachine = videoSelfieRecordingSetup.createMachine({
|
|
|
734
430
|
service: context.service,
|
|
735
431
|
stream: context.composite
|
|
736
432
|
}),
|
|
737
|
-
onDone: {
|
|
433
|
+
onDone: [{
|
|
434
|
+
target: "pausing",
|
|
435
|
+
guard: "pageIsHidden",
|
|
436
|
+
actions: ["armExecutionTimer", "prepareRecordingSuspension"]
|
|
437
|
+
}, {
|
|
438
|
+
target: "recording",
|
|
439
|
+
actions: "armExecutionTimer"
|
|
440
|
+
}],
|
|
738
441
|
onError: {
|
|
739
442
|
target: "error",
|
|
740
443
|
actions: assign({ error: ({ event }) => errorFromEvent(event) })
|
|
@@ -751,6 +454,14 @@ const videoSelfieRecordingMachine = videoSelfieRecordingSetup.createMachine({
|
|
|
751
454
|
})
|
|
752
455
|
},
|
|
753
456
|
on: {
|
|
457
|
+
BACKGROUND: {
|
|
458
|
+
target: "pausing",
|
|
459
|
+
actions: "prepareRecordingSuspension"
|
|
460
|
+
},
|
|
461
|
+
MAX_VIDEO_LENGTH_REACHED: {
|
|
462
|
+
target: "finalizing",
|
|
463
|
+
actions: "setMaxVideoLengthReached"
|
|
464
|
+
},
|
|
754
465
|
DETECTION_STATUS: { actions: "setDetectionStatus" },
|
|
755
466
|
ORIENTATION: { actions: "setOrientation" },
|
|
756
467
|
DETECTION_DONE: ADVANCE_TRANSITIONS,
|
|
@@ -769,111 +480,354 @@ const videoSelfieRecordingMachine = videoSelfieRecordingSetup.createMachine({
|
|
|
769
480
|
}
|
|
770
481
|
}
|
|
771
482
|
},
|
|
772
|
-
validationFeedback: {
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
guard: "nextModuleFlipsCamera",
|
|
783
|
-
actions: "advancePastIdSection"
|
|
483
|
+
validationFeedback: {
|
|
484
|
+
on: {
|
|
485
|
+
BACKGROUND: {
|
|
486
|
+
target: "pausing",
|
|
487
|
+
actions: ["markPageHidden", assign({ resumeState: () => "validationFeedback" })]
|
|
488
|
+
},
|
|
489
|
+
MAX_VIDEO_LENGTH_REACHED: {
|
|
490
|
+
target: "finalizing",
|
|
491
|
+
actions: "setMaxVideoLengthReached"
|
|
492
|
+
}
|
|
784
493
|
},
|
|
785
|
-
{
|
|
494
|
+
after: { VALIDATION_FEEDBACK_DWELL: [{
|
|
786
495
|
target: "recording",
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
actions: "advancePastIdSection"
|
|
790
|
-
},
|
|
791
|
-
{
|
|
496
|
+
guard: "hasAttemptsRemaining"
|
|
497
|
+
}, {
|
|
792
498
|
target: "finalizing",
|
|
793
|
-
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
target: "switchingCamera",
|
|
797
|
-
guard: "exhaustedNonIdNextStepFlipsCamera",
|
|
798
|
-
actions: "advanceStep"
|
|
799
|
-
},
|
|
800
|
-
{
|
|
801
|
-
target: "recording",
|
|
802
|
-
reenter: true,
|
|
803
|
-
guard: "isNonIdExhaustion",
|
|
804
|
-
actions: "advanceStep"
|
|
805
|
-
}
|
|
806
|
-
]] } },
|
|
499
|
+
actions: "setValidationAttemptsExhausted"
|
|
500
|
+
}] }
|
|
501
|
+
},
|
|
807
502
|
flippingId: {
|
|
808
503
|
after: { ID_FLIP_DWELL: {
|
|
809
504
|
target: "recording",
|
|
810
505
|
actions: "advanceStep"
|
|
811
506
|
} },
|
|
812
|
-
on: {
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
507
|
+
on: {
|
|
508
|
+
BACKGROUND: {
|
|
509
|
+
target: "pausing",
|
|
510
|
+
actions: ["markPageHidden", assign({ resumeState: () => "flippingId" })]
|
|
511
|
+
},
|
|
512
|
+
MAX_VIDEO_LENGTH_REACHED: {
|
|
513
|
+
target: "finalizing",
|
|
514
|
+
actions: "setMaxVideoLengthReached"
|
|
515
|
+
},
|
|
516
|
+
NEXT_STEP: {
|
|
517
|
+
target: "recording",
|
|
518
|
+
actions: "advanceStep"
|
|
519
|
+
}
|
|
520
|
+
}
|
|
816
521
|
},
|
|
817
|
-
switchingCamera: {
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
context.compositor.switchVideo(eventOutputStream(event));
|
|
828
|
-
}, assign({ stream: ({ event }) => eventOutputStream(event) })]
|
|
522
|
+
switchingCamera: {
|
|
523
|
+
on: {
|
|
524
|
+
BACKGROUND: {
|
|
525
|
+
target: "pausing",
|
|
526
|
+
actions: ["markPageHidden", assign({ resumeState: () => "switchingCamera" })]
|
|
527
|
+
},
|
|
528
|
+
MAX_VIDEO_LENGTH_REACHED: {
|
|
529
|
+
target: "finalizing",
|
|
530
|
+
actions: "setMaxVideoLengthReached"
|
|
531
|
+
}
|
|
829
532
|
},
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
533
|
+
invoke: {
|
|
534
|
+
src: "switchCamera",
|
|
535
|
+
input: ({ context }) => ({
|
|
536
|
+
acquire: context.acquireCamera,
|
|
537
|
+
facingMode: facingModeForStep(context.steps[context.stepIndex]),
|
|
538
|
+
minDwellMs: context.switchingCameraMinDwellMs
|
|
539
|
+
}),
|
|
540
|
+
onDone: {
|
|
541
|
+
target: "recording",
|
|
542
|
+
actions: [({ context, event }) => {
|
|
543
|
+
context.compositor.switchVideo(eventOutputStream(event));
|
|
544
|
+
}, assign({ stream: ({ event }) => eventOutputStream(event) })]
|
|
545
|
+
},
|
|
546
|
+
onError: {
|
|
547
|
+
target: "error",
|
|
548
|
+
actions: assign({ error: ({ event }) => errorFromEvent(event) })
|
|
549
|
+
}
|
|
833
550
|
}
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
551
|
+
},
|
|
552
|
+
pausing: {
|
|
553
|
+
on: { MAX_VIDEO_LENGTH_REACHED: { actions: "setMaxVideoLengthReached" } },
|
|
554
|
+
invoke: {
|
|
555
|
+
src: "pauseCapture",
|
|
556
|
+
input: ({ context }) => ({
|
|
557
|
+
service: context.service,
|
|
558
|
+
compositor: context.compositor
|
|
559
|
+
}),
|
|
560
|
+
onDone: [
|
|
561
|
+
{
|
|
562
|
+
target: "finalizing",
|
|
563
|
+
guard: "maxVideoLengthWasReached"
|
|
564
|
+
},
|
|
565
|
+
{
|
|
566
|
+
target: "error",
|
|
567
|
+
guard: "pauseFailed",
|
|
568
|
+
actions: "setPauseError"
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
target: "resumingCompositor",
|
|
572
|
+
guard: "pauseSucceededWhileVisible"
|
|
573
|
+
},
|
|
574
|
+
{ target: "suspended" }
|
|
575
|
+
],
|
|
576
|
+
onError: [{
|
|
577
|
+
target: "finalizing",
|
|
578
|
+
guard: "maxVideoLengthWasReached"
|
|
579
|
+
}, {
|
|
580
|
+
target: "error",
|
|
581
|
+
actions: "setTechnicalActorError"
|
|
582
|
+
}]
|
|
583
|
+
}
|
|
584
|
+
},
|
|
585
|
+
suspended: { on: {
|
|
586
|
+
FOREGROUND: {
|
|
587
|
+
target: "resumingCompositor",
|
|
588
|
+
actions: "markPageVisible"
|
|
589
|
+
},
|
|
590
|
+
MAX_VIDEO_LENGTH_REACHED: {
|
|
591
|
+
target: "finalizing",
|
|
592
|
+
actions: "setMaxVideoLengthReached"
|
|
849
593
|
}
|
|
850
594
|
} },
|
|
595
|
+
resumingCompositor: {
|
|
596
|
+
on: {
|
|
597
|
+
BACKGROUND: {
|
|
598
|
+
target: "pausing",
|
|
599
|
+
actions: "markPageHidden"
|
|
600
|
+
},
|
|
601
|
+
MAX_VIDEO_LENGTH_REACHED: {
|
|
602
|
+
target: "finalizing",
|
|
603
|
+
actions: "setMaxVideoLengthReached"
|
|
604
|
+
}
|
|
605
|
+
},
|
|
606
|
+
invoke: {
|
|
607
|
+
src: "resumeCompositor",
|
|
608
|
+
input: ({ context }) => ({ compositor: context.compositor }),
|
|
609
|
+
onDone: [
|
|
610
|
+
{
|
|
611
|
+
target: "error",
|
|
612
|
+
guard: "compositorAudioEnded",
|
|
613
|
+
actions: "setAudioEndedError"
|
|
614
|
+
},
|
|
615
|
+
{
|
|
616
|
+
target: "reacquiringCamera",
|
|
617
|
+
guard: "forceVideoRecovery"
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
target: "reacquiringCamera",
|
|
621
|
+
guard: "compositorDidNotResume"
|
|
622
|
+
},
|
|
623
|
+
{ target: "resumingRecorder" }
|
|
624
|
+
],
|
|
625
|
+
onError: {
|
|
626
|
+
target: "error",
|
|
627
|
+
actions: "setTechnicalActorError"
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
},
|
|
631
|
+
reacquiringCamera: {
|
|
632
|
+
on: {
|
|
633
|
+
BACKGROUND: {
|
|
634
|
+
target: "pausing",
|
|
635
|
+
actions: "markPageHidden"
|
|
636
|
+
},
|
|
637
|
+
MAX_VIDEO_LENGTH_REACHED: {
|
|
638
|
+
target: "finalizing",
|
|
639
|
+
actions: "setMaxVideoLengthReached"
|
|
640
|
+
}
|
|
641
|
+
},
|
|
642
|
+
invoke: {
|
|
643
|
+
src: "acquireCamera",
|
|
644
|
+
input: ({ context }) => ({
|
|
645
|
+
acquire: context.acquireCamera,
|
|
646
|
+
facingMode: facingModeForStep(context.steps[context.stepIndex]),
|
|
647
|
+
withAudio: false
|
|
648
|
+
}),
|
|
649
|
+
onDone: {
|
|
650
|
+
target: "validatingRecoveredCamera",
|
|
651
|
+
actions: [({ context, event }) => {
|
|
652
|
+
context.compositor.switchVideo(eventOutputStream(event));
|
|
653
|
+
}, assign({ stream: ({ event }) => eventOutputStream(event) })]
|
|
654
|
+
},
|
|
655
|
+
onError: {
|
|
656
|
+
target: "error",
|
|
657
|
+
actions: "setTechnicalActorError"
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
},
|
|
661
|
+
validatingRecoveredCamera: {
|
|
662
|
+
on: {
|
|
663
|
+
BACKGROUND: {
|
|
664
|
+
target: "pausing",
|
|
665
|
+
actions: "markPageHidden"
|
|
666
|
+
},
|
|
667
|
+
MAX_VIDEO_LENGTH_REACHED: {
|
|
668
|
+
target: "finalizing",
|
|
669
|
+
actions: "setMaxVideoLengthReached"
|
|
670
|
+
}
|
|
671
|
+
},
|
|
672
|
+
invoke: {
|
|
673
|
+
src: "resumeCompositor",
|
|
674
|
+
input: ({ context }) => ({ compositor: context.compositor }),
|
|
675
|
+
onDone: [
|
|
676
|
+
{
|
|
677
|
+
target: "error",
|
|
678
|
+
guard: "compositorAudioEnded",
|
|
679
|
+
actions: "setAudioEndedError"
|
|
680
|
+
},
|
|
681
|
+
{
|
|
682
|
+
target: "error",
|
|
683
|
+
guard: "compositorDidNotResume",
|
|
684
|
+
actions: "setCameraResumeError"
|
|
685
|
+
},
|
|
686
|
+
{ target: "resumingRecorder" }
|
|
687
|
+
],
|
|
688
|
+
onError: {
|
|
689
|
+
target: "error",
|
|
690
|
+
actions: "setTechnicalActorError"
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
},
|
|
694
|
+
resumingRecorder: {
|
|
695
|
+
on: {
|
|
696
|
+
BACKGROUND: {
|
|
697
|
+
target: "pausing",
|
|
698
|
+
actions: "markPageHidden"
|
|
699
|
+
},
|
|
700
|
+
MAX_VIDEO_LENGTH_REACHED: {
|
|
701
|
+
target: "finalizing",
|
|
702
|
+
actions: "setMaxVideoLengthReached"
|
|
703
|
+
}
|
|
704
|
+
},
|
|
705
|
+
invoke: {
|
|
706
|
+
src: "resumeRecorder",
|
|
707
|
+
input: ({ context }) => ({ service: context.service }),
|
|
708
|
+
onDone: [
|
|
709
|
+
{
|
|
710
|
+
target: "error",
|
|
711
|
+
guard: "recorderResumeFailed",
|
|
712
|
+
actions: "setRecorderResumeError"
|
|
713
|
+
},
|
|
714
|
+
{
|
|
715
|
+
target: "validationFeedback",
|
|
716
|
+
guard: "resumeValidationFeedback"
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
target: "flippingId",
|
|
720
|
+
guard: "resumeFlippingId"
|
|
721
|
+
},
|
|
722
|
+
{ target: "recording" }
|
|
723
|
+
],
|
|
724
|
+
onError: {
|
|
725
|
+
target: "error",
|
|
726
|
+
actions: "setTechnicalActorError"
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
},
|
|
730
|
+
finalizing: {
|
|
731
|
+
entry: "cancelExecutionTimer",
|
|
732
|
+
invoke: {
|
|
733
|
+
src: "finalizeRecording",
|
|
734
|
+
input: ({ context }) => ({ service: context.service }),
|
|
735
|
+
onDone: [
|
|
736
|
+
{
|
|
737
|
+
target: "error",
|
|
738
|
+
guard: "maxVideoLengthWasReached",
|
|
739
|
+
actions: assign({ recordingId: ({ event }) => recordingIdFromEvent(event) })
|
|
740
|
+
},
|
|
741
|
+
{
|
|
742
|
+
target: "error",
|
|
743
|
+
guard: "validationAttemptsWereExhausted",
|
|
744
|
+
actions: assign({ recordingId: ({ event }) => recordingIdFromEvent(event) })
|
|
745
|
+
},
|
|
746
|
+
{
|
|
747
|
+
target: "error",
|
|
748
|
+
guard: "uploadReturnedNoRecordingId",
|
|
749
|
+
actions: [assign({ recordingId: ({ event }) => recordingIdFromEvent(event) }), "setUploadFailedError"]
|
|
750
|
+
},
|
|
751
|
+
{
|
|
752
|
+
target: "success",
|
|
753
|
+
actions: assign({ recordingId: ({ event }) => recordingIdFromEvent(event) })
|
|
754
|
+
}
|
|
755
|
+
],
|
|
756
|
+
onError: [
|
|
757
|
+
{
|
|
758
|
+
target: "error",
|
|
759
|
+
guard: "maxVideoLengthWasReached"
|
|
760
|
+
},
|
|
761
|
+
{
|
|
762
|
+
target: "error",
|
|
763
|
+
guard: "validationAttemptsWereExhausted"
|
|
764
|
+
},
|
|
765
|
+
{
|
|
766
|
+
target: "error",
|
|
767
|
+
actions: assign({ error: ({ event }) => errorFromEvent(event) })
|
|
768
|
+
}
|
|
769
|
+
]
|
|
770
|
+
}
|
|
771
|
+
},
|
|
851
772
|
success: {
|
|
852
|
-
entry: "cleanup",
|
|
773
|
+
entry: ["cancelExecutionTimer", "cleanup"],
|
|
853
774
|
after: { FINAL_SUCCESS_DWELL: "finished" }
|
|
854
775
|
},
|
|
855
776
|
finished: { type: "final" },
|
|
856
777
|
error: {
|
|
857
|
-
entry: "cleanup",
|
|
858
|
-
|
|
778
|
+
entry: ["cancelExecutionTimer", "cleanup"],
|
|
779
|
+
after: { MAX_VIDEO_LENGTH_ERROR_DWELL: {
|
|
780
|
+
target: "finished",
|
|
781
|
+
guard: "maxVideoLengthWasReached"
|
|
782
|
+
} },
|
|
783
|
+
on: { RETRY: [{
|
|
784
|
+
target: "preparingWasm",
|
|
785
|
+
guard: "shouldEnterWasmGate",
|
|
786
|
+
actions: "resetSession"
|
|
787
|
+
}, {
|
|
859
788
|
target: "acquiringCamera",
|
|
789
|
+
guard: "errorIsRetryable",
|
|
860
790
|
actions: "resetSession"
|
|
861
|
-
} }
|
|
791
|
+
}] }
|
|
862
792
|
},
|
|
863
793
|
aborted: {
|
|
864
794
|
type: "final",
|
|
865
|
-
entry: "cleanup"
|
|
795
|
+
entry: ["cancelExecutionTimer", "cleanup"]
|
|
866
796
|
}
|
|
867
797
|
}
|
|
868
798
|
});
|
|
869
799
|
//#endregion
|
|
870
800
|
//#region src/modules/video-selfie/videoSelfieRecordingActor.ts
|
|
871
|
-
function
|
|
801
|
+
function getRecordingSteps(options) {
|
|
802
|
+
if (options.steps && options.steps.length > 0) return options.steps;
|
|
803
|
+
if (options.config) return resolveVideoSelfieSteps(options.config);
|
|
804
|
+
}
|
|
805
|
+
function createRetryablePreparation(prepare) {
|
|
806
|
+
let readiness;
|
|
807
|
+
return () => {
|
|
808
|
+
if (!readiness) {
|
|
809
|
+
readiness = Promise.resolve().then(prepare).catch((error) => {
|
|
810
|
+
readiness = void 0;
|
|
811
|
+
throw error;
|
|
812
|
+
});
|
|
813
|
+
readiness.catch(() => void 0);
|
|
814
|
+
}
|
|
815
|
+
return readiness;
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
function createVideoSelfieRecordingActor(visibilityObserver, options = {}) {
|
|
872
819
|
const config = options.config;
|
|
820
|
+
const steps = getRecordingSteps(options);
|
|
873
821
|
const detect = options.dependencies?.detect ?? (config ? createDefaultStepDetector(config, { getWasmUtil: () => WasmUtilProvider.getInstance() }) : void 0);
|
|
822
|
+
const prepareWasm = config && steps ? () => warmupVideoSelfieWasm(config, steps) : void 0;
|
|
823
|
+
const ensureWasmReady = prepareWasm ? createRetryablePreparation(prepareWasm) : void 0;
|
|
824
|
+
if (ensureWasmReady) ensureWasmReady();
|
|
874
825
|
return createActor(videoSelfieRecordingMachine, { input: {
|
|
875
|
-
steps
|
|
826
|
+
steps,
|
|
876
827
|
attemptsPerStep: config?.numberOfTries,
|
|
828
|
+
maxVideoLengthSeconds: config?.maxWaitingVideoSelfieFile,
|
|
829
|
+
visibilityObserver,
|
|
830
|
+
ensureWasmReady,
|
|
877
831
|
dependencies: {
|
|
878
832
|
...options.dependencies,
|
|
879
833
|
detect
|
|
@@ -885,7 +839,7 @@ function createVideoSelfieRecordingActor(options = {}) {
|
|
|
885
839
|
function mapState(snapshot) {
|
|
886
840
|
const value = typeof snapshot.value === "string" ? snapshot.value : "idle";
|
|
887
841
|
const { context } = snapshot;
|
|
888
|
-
const status = value === "acquiringCamera" ? "starting" : value;
|
|
842
|
+
const status = value === "preparingWasm" || value === "acquiringCamera" ? "starting" : value === "pausing" || value === "suspended" || value === "resumingCompositor" || value === "reacquiringCamera" || value === "validatingRecoveredCamera" || value === "resumingRecorder" ? "recording" : value;
|
|
889
843
|
const steps = context.steps;
|
|
890
844
|
const stepIndex = context.stepIndex;
|
|
891
845
|
return {
|
|
@@ -935,7 +889,7 @@ function createApi({ actor }) {
|
|
|
935
889
|
* `nextStep()`, and `abort()`.
|
|
936
890
|
*/
|
|
937
891
|
function createVideoSelfieRecordingManager(options = {}) {
|
|
938
|
-
const actor = createVideoSelfieRecordingActor(options);
|
|
892
|
+
const actor = createVideoSelfieRecordingActor(options.dependencies?.visibilityObserver ?? new BrowserVisibilityObserverProvider(), options);
|
|
939
893
|
const manager = createManager({
|
|
940
894
|
actor,
|
|
941
895
|
mapState,
|
|
@@ -950,21 +904,6 @@ function createVideoSelfieRecordingManager(options = {}) {
|
|
|
950
904
|
};
|
|
951
905
|
}
|
|
952
906
|
//#endregion
|
|
953
|
-
//#region src/modules/video-selfie/videoSelfieWasm.ts
|
|
954
|
-
/**
|
|
955
|
-
* Warms the WASM pipelines the Video Selfie flow needs (face detection, plus the
|
|
956
|
-
* ID-capture pipeline when `checkIdScan` is on), reusing the WASM config stored
|
|
957
|
-
* by `setup({ wasm })`.
|
|
958
|
-
*
|
|
959
|
-
* Idempotent and safe to call eagerly — the UI invokes it when the tutorial
|
|
960
|
-
* mounts so the models finish loading while the user reads the instructions, and
|
|
961
|
-
* detection is ready the instant recording starts (mirrors how the selfie and ID
|
|
962
|
-
* modules warm up during their tutorials). No-op when WASM was not configured.
|
|
963
|
-
*/
|
|
964
|
-
function warmupVideoSelfieWasm(config) {
|
|
965
|
-
return ensureWasmPipelines(videoSelfieWasmPipelines(config));
|
|
966
|
-
}
|
|
967
|
-
//#endregion
|
|
968
907
|
//#region src/modules/video-selfie/videoSelfieSpeechService.ts
|
|
969
908
|
/**
|
|
970
909
|
* Fetches `count` random challenge questions the user answers out loud. The
|
|
@@ -1071,7 +1010,7 @@ let context;
|
|
|
1071
1010
|
* let recorder = new MediaRecorder(stream)
|
|
1072
1011
|
* })
|
|
1073
1012
|
*/
|
|
1074
|
-
var MediaRecorder
|
|
1013
|
+
var MediaRecorder = class MediaRecorder {
|
|
1075
1014
|
/**
|
|
1076
1015
|
* @param {MediaStream} stream The audio stream to record.
|
|
1077
1016
|
*/
|
|
@@ -1088,7 +1027,7 @@ var MediaRecorder$1 = class MediaRecorder$1 {
|
|
|
1088
1027
|
*/
|
|
1089
1028
|
this.state = "inactive";
|
|
1090
1029
|
this.em = document.createDocumentFragment();
|
|
1091
|
-
this.encoder = createWorker(MediaRecorder
|
|
1030
|
+
this.encoder = createWorker(MediaRecorder.encoder);
|
|
1092
1031
|
let recorder = this;
|
|
1093
1032
|
this.encoder.addEventListener("message", (e) => {
|
|
1094
1033
|
let event = new Event("dataavailable");
|
|
@@ -1238,7 +1177,7 @@ var MediaRecorder$1 = class MediaRecorder$1 {
|
|
|
1238
1177
|
* The MIME type that is being used for recording.
|
|
1239
1178
|
* @type {string}
|
|
1240
1179
|
*/
|
|
1241
|
-
MediaRecorder
|
|
1180
|
+
MediaRecorder.prototype.mimeType = "audio/wav";
|
|
1242
1181
|
/**
|
|
1243
1182
|
* Returns `true` if the MIME type specified is one the polyfill can record.
|
|
1244
1183
|
*
|
|
@@ -1248,8 +1187,8 @@ MediaRecorder$1.prototype.mimeType = "audio/wav";
|
|
|
1248
1187
|
*
|
|
1249
1188
|
* @return {boolean} `true` on `audio/wav` and `audio/mpeg` MIME type.
|
|
1250
1189
|
*/
|
|
1251
|
-
MediaRecorder
|
|
1252
|
-
return MediaRecorder
|
|
1190
|
+
MediaRecorder.isTypeSupported = (mimeType) => {
|
|
1191
|
+
return MediaRecorder.prototype.mimeType === mimeType;
|
|
1253
1192
|
};
|
|
1254
1193
|
/**
|
|
1255
1194
|
* `true` if MediaRecorder can not be polyfilled in the current browser.
|
|
@@ -1260,7 +1199,7 @@ MediaRecorder$1.isTypeSupported = (mimeType) => {
|
|
|
1260
1199
|
* showWarning('Audio recording is not supported in this browser')
|
|
1261
1200
|
* }
|
|
1262
1201
|
*/
|
|
1263
|
-
MediaRecorder
|
|
1202
|
+
MediaRecorder.notSupported = !navigator.mediaDevices || !AudioContext;
|
|
1264
1203
|
/**
|
|
1265
1204
|
* Converts RAW audio buffer to compressed audio files.
|
|
1266
1205
|
* It will be loaded to Web Worker.
|
|
@@ -1271,7 +1210,7 @@ MediaRecorder$1.notSupported = !navigator.mediaDevices || !AudioContext;
|
|
|
1271
1210
|
* MediaRecorder.prototype.mimeType = 'audio/ogg'
|
|
1272
1211
|
* MediaRecorder.encoder = oggEncoder
|
|
1273
1212
|
*/
|
|
1274
|
-
MediaRecorder
|
|
1213
|
+
MediaRecorder.encoder = wave_encoder_default;
|
|
1275
1214
|
//#endregion
|
|
1276
1215
|
//#region ../../node_modules/.pnpm/audio-recorder-polyfill@0.4.1/node_modules/audio-recorder-polyfill/mpeg-encoder/index.js
|
|
1277
1216
|
var mpeg_encoder_default = () => {
|
|
@@ -1332,7 +1271,7 @@ function blobToRawBase64(blob) {
|
|
|
1332
1271
|
}
|
|
1333
1272
|
//#endregion
|
|
1334
1273
|
//#region ../infra/src/providers/browser/VoiceRecordingProvider.ts
|
|
1335
|
-
const AudioRecorderPolyfill = MediaRecorder
|
|
1274
|
+
const AudioRecorderPolyfill = MediaRecorder;
|
|
1336
1275
|
AudioRecorderPolyfill.encoder = mpeg_encoder_default;
|
|
1337
1276
|
AudioRecorderPolyfill.prototype.mimeType = "audio/mpeg";
|
|
1338
1277
|
const MIME_TYPE = "audio/mpeg";
|
|
@@ -1419,34 +1358,4 @@ function createConsentRecorder() {
|
|
|
1419
1358
|
};
|
|
1420
1359
|
}
|
|
1421
1360
|
//#endregion
|
|
1422
|
-
|
|
1423
|
-
/**
|
|
1424
|
-
* Parked flow-module machine for the `VIDEO_ONBOARDING` step.
|
|
1425
|
-
*
|
|
1426
|
-
* The video-selfie UI component owns the entire capture / streaming / upload
|
|
1427
|
-
* lifecycle (it creates its own {@link createVideoSelfieRecordingManager}) and
|
|
1428
|
-
* signals completion to the flow via `flowManager.completeModule()`
|
|
1429
|
-
* (`MODULE_COMPLETE`). This machine therefore only needs to hold the step open:
|
|
1430
|
-
* it starts in a non-final `running` state and never transitions, so the
|
|
1431
|
-
* orchestrated flow stays in `runningModule` until the UI advances it.
|
|
1432
|
-
*
|
|
1433
|
-
* **Completion contract:** the L2 `incode-video-selfie` web component calls
|
|
1434
|
-
* `flowManager.completeModule()` once the recording manager reaches `finished`.
|
|
1435
|
-
* Recoverable errors stay inside the module until the user retries.
|
|
1436
|
-
*
|
|
1437
|
-
* **Abort / unmount:** if the user closes the module or the web component
|
|
1438
|
-
* unmounts before completion, the orchestrated flow manager's existing close /
|
|
1439
|
-
* abort path (`MODULE_CLOSE` / session teardown) is responsible for exiting the
|
|
1440
|
-
* step. This parked machine does not model those paths itself.
|
|
1441
|
-
*
|
|
1442
|
-
* Contrast {@link noOpFlowModuleMachine}, whose initial state is `final` — that
|
|
1443
|
-
* is used for headless steps (e.g. `IP_ADDRESS`) that must complete instantly
|
|
1444
|
-
* with no UI. Using a no-op here would skip the video-selfie UI entirely.
|
|
1445
|
-
*/
|
|
1446
|
-
const videoSelfieFlowModuleMachine = setup({}).createMachine({
|
|
1447
|
-
id: "videoSelfieFlowModule",
|
|
1448
|
-
initial: "running",
|
|
1449
|
-
states: { running: {} }
|
|
1450
|
-
});
|
|
1451
|
-
//#endregion
|
|
1452
|
-
export { createConsentRecorder, createVideoSelfieCameraWarmer, createVideoSelfieRecordingManager, facingModeForStep, getVideoSelfieQuestions, getVoiceConsentPhrase, resolveVideoSelfieSteps, videoSelfieFlowModuleMachine, videoSelfieWasmPipelines, warmupVideoSelfieWasm };
|
|
1361
|
+
export { VIDEO_SELFIE_VALIDATION_ATTEMPTS_EXHAUSTED_CODE, createConsentRecorder, createVideoSelfieCameraWarmer, createVideoSelfieRecordingManager, facingModeForStep, getVideoSelfieQuestions, getVoiceConsentPhrase, resolveVideoSelfieSteps, videoSelfieFlowModuleMachine, videoSelfieWasmPipelines, warmupVideoSelfieWasm };
|