@incodetech/core 2.2.0 → 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.
Files changed (258) hide show
  1. package/THIRD_PARTY_NOTICES.txt +281 -0
  2. package/dist/BaseWasmProvider-Dyi6dKp1.d.ts +65 -0
  3. package/dist/{BrowserDiagnosticsCryptoProvider-B8vorxN5.esm.js → BrowserDiagnosticsCryptoProvider-C_9o3L2L.esm.js} +1 -1
  4. package/dist/{BrowserVisibilityObserverProvider-BX1BiLDK.esm.js → BrowserVisibilityObserverProvider-BrJN1B8A.esm.js} +2 -0
  5. package/dist/FaceDetectionProvider-DTetAE8H.esm.js +476 -0
  6. package/dist/FaceDetectionProvider-LdZ47bWy.d.ts +36 -0
  7. package/dist/{IIdCaptureCapability-DHTT3FC2.d.ts → IIdCaptureCapability-RNiFhvXR.d.ts} +7 -33
  8. package/dist/IWasmUtilCapability-CXXDA5l1.d.ts +159 -0
  9. package/dist/{MotionSensorProvider-DGiV77J_.esm.js → MotionSensorProvider-BgTYwg9L.esm.js} +1 -1
  10. package/dist/{deepsightService-DLVQS_RH.d.ts → StreamCanvasCapture-B3YT2Bt6.d.ts} +54 -41
  11. package/dist/{StreamCanvasCapture-D2XcXCZ4.esm.js → StreamCanvasCapture-C9jtgBdT.esm.js} +2 -2
  12. package/dist/{addressSearch-D1XpBdUS.esm.js → addressSearch-BRSu_aGA.esm.js} +1 -1
  13. package/dist/advanceableErrors-CpF2cBy6.esm.js +21 -0
  14. package/dist/ae-signature.d.ts +4 -2
  15. package/dist/ae-signature.esm.js +1 -1
  16. package/dist/antifraud.esm.js +2 -2
  17. package/dist/{antifraudManager-CQFNgSPt.esm.js → antifraudManager-Bg9ynGum.esm.js} +2 -2
  18. package/dist/{antifraudStateMachine-Bf_JVNwn.esm.js → antifraudStateMachine-BHxehiJZ.esm.js} +1 -1
  19. package/dist/{apiError-BA1d_au0.esm.js → apiError-D0v5hFyN.esm.js} +14 -2
  20. package/dist/authentication.d.ts +3 -3
  21. package/dist/authentication.esm.js +2 -2
  22. package/dist/{authenticationManager-zh9TC62P.esm.js → authenticationManager-C4B4-29g.esm.js} +5 -5
  23. package/dist/{authenticationManager-BBMGTcwW.d.ts → authenticationManager-DXTIUcma.d.ts} +7 -1
  24. package/dist/{authenticationStateMachine-xzi-vnvE.esm.js → authenticationStateMachine-DJ0zUm-A.esm.js} +6 -62
  25. package/dist/avatar.d.ts +1 -2
  26. package/dist/avatar.esm.js +1 -1
  27. package/dist/{backCameraStream-CUeYm5eu.esm.js → backCameraStream-BOtyQowf.esm.js} +83 -22
  28. package/dist/{camera-_2sXMXiF.esm.js → camera-sIa9ceW2.esm.js} +19 -1
  29. package/dist/camera.esm.js +1 -1
  30. package/dist/{canvas-E1zGkel4.esm.js → canvas-BxFzWTt-.esm.js} +19 -0
  31. package/dist/certificate-issuance.d.ts +2 -302
  32. package/dist/certificate-issuance.esm.js +3 -66
  33. package/dist/certificateIssuanceManager-Bfvkq7Cy.esm.js +69 -0
  34. package/dist/certificateIssuanceManager-DCgEidHz.d.ts +312 -0
  35. package/dist/{certificateIssuanceStateMachine-D_R92TYu.esm.js → certificateIssuanceStateMachine-BBD5h8c4.esm.js} +1 -1
  36. package/dist/consent.d.ts +1 -1
  37. package/dist/consent.esm.js +2 -2
  38. package/dist/{consentManager-BxjpLZAG.esm.js → consentManager-B5Vqdez-.esm.js} +2 -2
  39. package/dist/{consentManager-3Pbtj-RV.d.ts → consentManager-uhDPdU6i.d.ts} +4 -4
  40. package/dist/{consentStateMachine-D9D4ON8Z.esm.js → consentStateMachine-DbUmqWgV.esm.js} +1 -1
  41. package/dist/createCameraCycleOwnership-DQ5-F2oW.esm.js +826 -0
  42. package/dist/{createFaceAvatar-DQKaRise.esm.js → createFaceAvatar-BNHdeFj8.esm.js} +2 -2
  43. package/dist/createFaceAvatar-BlcTYgJv.d.ts +497 -0
  44. package/dist/cross-document-data-match.esm.js +1 -1
  45. package/dist/{crossDocumentDataMatchManager-CGT0V6RV.esm.js → crossDocumentDataMatchManager-QMOGwHXR.esm.js} +2 -2
  46. package/dist/curp-validation.d.ts +1 -1
  47. package/dist/curp-validation.esm.js +2 -2
  48. package/dist/{curpValidationManager-6Nmkn5u1.esm.js → curpValidationManager-D1ppROcF.esm.js} +2 -2
  49. package/dist/{curpValidationManager-DVGr7Fq7.d.ts → curpValidationManager-SSKNrm5Z.d.ts} +1 -1
  50. package/dist/{curpValidationStateMachine-Ds7KMacK.esm.js → curpValidationStateMachine-DvUPC_8S.esm.js} +1 -1
  51. package/dist/custom-fields.d.ts +2 -114
  52. package/dist/custom-fields.esm.js +2 -232
  53. package/dist/custom-watchlist.d.ts +2 -51
  54. package/dist/custom-watchlist.esm.js +3 -70
  55. package/dist/customFieldsManager-2j_PBq4U.esm.js +264 -0
  56. package/dist/customFieldsManager-8-W2KY4n.d.ts +141 -0
  57. package/dist/customWatchlistManager-DUVrEdw9.esm.js +73 -0
  58. package/dist/customWatchlistManager-PBWHr_oM.d.ts +64 -0
  59. package/dist/{customWatchlistStateMachine-YWSgKLbF.esm.js → customWatchlistStateMachine-qZVgkKgP.esm.js} +1 -1
  60. package/dist/{deepsightLoader--wMKWECS.esm.js → deepsightLoader-Dm7ejW4v.esm.js} +27 -71
  61. package/dist/device.d.ts +25 -2
  62. package/dist/device.esm.js +69 -7
  63. package/dist/document-capture.d.ts +2 -2
  64. package/dist/document-capture.esm.js +2 -2
  65. package/dist/{documentCaptureManager-DsQQhWry.esm.js → documentCaptureManager-DR_Wv-3H.esm.js} +2 -2
  66. package/dist/{documentCaptureManager-B3t0ydtg.d.ts → documentCaptureManager-DensIj5F.d.ts} +83 -83
  67. package/dist/{documentCaptureStateMachine-BM4Ex_5x.esm.js → documentCaptureStateMachine-CWOATHfE.esm.js} +5 -5
  68. package/dist/dynamic-forms.d.ts +1 -1
  69. package/dist/dynamic-forms.esm.js +2 -2
  70. package/dist/{dynamicFormsManager-fhK0yINk.d.ts → dynamicFormsManager-D5R_uxLQ.d.ts} +25 -3
  71. package/dist/{dynamicFormsManager-fFVIRBNv.esm.js → dynamicFormsManager-Dt98SDfV.esm.js} +16 -5
  72. package/dist/{dynamicFormsStateMachine-D6D7oEYk.esm.js → dynamicFormsStateMachine-obKr4IIp.esm.js} +35 -3
  73. package/dist/ekyb.d.ts +1 -1
  74. package/dist/ekyb.esm.js +3 -3
  75. package/dist/{ekybManager-Y3MkoXpC.esm.js → ekybManager-DNZKrKF3.esm.js} +2 -2
  76. package/dist/{ekybStateMachine-3nlnqdlr.esm.js → ekybStateMachine-DjhHQXZ8.esm.js} +3 -3
  77. package/dist/ekyc.esm.js +2 -2
  78. package/dist/{ekycManager-DgT48ky6.esm.js → ekycManager-CmQBpeiI.esm.js} +2 -2
  79. package/dist/{ekycStateMachine-CQwqiR-R.esm.js → ekycStateMachine-CmdW2gVm.esm.js} +2 -2
  80. package/dist/electronic-signature.d.ts +3 -3
  81. package/dist/electronic-signature.esm.js +2 -2
  82. package/dist/electronicSignatureManager-Ds-KEVTq.d.ts +2786 -0
  83. package/dist/{electronicSignatureManager-DGbAJ00W.esm.js → electronicSignatureManager-DzulxM4_.esm.js} +357 -51
  84. package/dist/email.esm.js +2 -2
  85. package/dist/{emailManager-BY0jeYwR.esm.js → emailManager-B5ek_UfM.esm.js} +2 -2
  86. package/dist/{emailStateMachine-Crw8QVmc.esm.js → emailStateMachine-CyPFZ7dW.esm.js} +1 -1
  87. package/dist/{endpoints-CCzL3XD_.esm.js → endpoints-D3B9mUHh.esm.js} +24 -7
  88. package/dist/{events-DYiyoSlx.esm.js → events-ijlbX_Wx.esm.js} +2 -2
  89. package/dist/events.d.ts +1 -1
  90. package/dist/events.esm.js +1 -1
  91. package/dist/extensibility.d.ts +24 -64
  92. package/dist/extensibility.esm.js +35 -29
  93. package/dist/face-match.esm.js +2 -2
  94. package/dist/{faceCaptureManagerFactory-BxWPpxyd.d.ts → faceCaptureManagerFactory-CvtqcLxs.d.ts} +87 -54
  95. package/dist/{faceCaptureManagerFactory-CVnZ0fa5.esm.js → faceCaptureManagerFactory-pCmG4MeF.esm.js} +68 -7
  96. package/dist/faceCaptureSetup-BSextack.esm.js +2106 -0
  97. package/dist/{faceMatchManager-Ri4UbNz0.esm.js → faceMatchManager-Caal2zyV.esm.js} +2 -2
  98. package/dist/{faceMatchStateMachine-20DdZ3jg.esm.js → faceMatchStateMachine-BUc5FXYy.esm.js} +1 -1
  99. package/dist/{feature-management-CPQ4qv3F.esm.js → feature-management-B0sGlozZ.esm.js} +32 -7
  100. package/dist/feature-management.d.ts +1 -1
  101. package/dist/feature-management.esm.js +1 -1
  102. package/dist/field-comparison.esm.js +1 -1
  103. package/dist/{fieldComparisonManager-Cg6kPQQx.esm.js → fieldComparisonManager-BIs6HPJG.esm.js} +2 -2
  104. package/dist/fiscal-qr.d.ts +2 -56
  105. package/dist/fiscal-qr.esm.js +2 -308
  106. package/dist/fiscalQrManager-Bp_-3LJr.esm.js +34131 -0
  107. package/dist/fiscalQrManager-CHcBJwUM.d.ts +68 -0
  108. package/dist/flow-events.d.ts +1 -1
  109. package/dist/flow.d.ts +212 -185
  110. package/dist/flow.esm.js +119 -30
  111. package/dist/{flowCompletionService-tfeoGre9.esm.js → flowCompletionService-CLtbWhSK.esm.js} +2 -2
  112. package/dist/{flowServices-f5Ruz7R9.esm.js → flowServices-B5FwukTQ.esm.js} +91 -26
  113. package/dist/geolocation.esm.js +2 -2
  114. package/dist/{geolocationManager-CH6RfqFH.esm.js → geolocationManager-DIw-xq9a.esm.js} +2 -2
  115. package/dist/{geolocationStateMachine-DmbWFely.esm.js → geolocationStateMachine-DpG0TFOU.esm.js} +3 -3
  116. package/dist/getBrowser-CBiibsL-.esm.js +19 -0
  117. package/dist/{getBrowser-DNrQeL4T.esm.js → getBrowser-Cbe1C4Tn.esm.js} +2 -1
  118. package/dist/{getDeviceClass-9y-kbVDw.esm.js → getDeviceClass-5NYZg9s6.esm.js} +2 -2
  119. package/dist/getParsedUserAgent-B2iFDql1.esm.js +1278 -0
  120. package/dist/government-validation.d.ts +2 -85
  121. package/dist/government-validation.esm.js +3 -120
  122. package/dist/governmentValidationManager-D02vT4yY.d.ts +63 -0
  123. package/dist/governmentValidationManager-TjC9iVjH.esm.js +79 -0
  124. package/dist/governmentValidationStateMachine-D1ZnEqdd.esm.js +54 -0
  125. package/dist/home.d.ts +1 -1
  126. package/dist/home.esm.js +1 -1
  127. package/dist/id-ocr.d.ts +2 -2
  128. package/dist/id-ocr.esm.js +2 -2
  129. package/dist/id-selfie-flow.d.ts +3 -2
  130. package/dist/id-selfie-flow.esm.js +11 -10
  131. package/dist/id-verification.esm.js +2 -2
  132. package/dist/id.d.ts +29 -5
  133. package/dist/id.esm.js +48 -46
  134. package/dist/idCaptureDefaults-BcxjQDI3.esm.js +484 -0
  135. package/dist/{idCaptureManager-CqrqSjJV.d.ts → idCaptureManager-CvmHOWWd.d.ts} +227 -39
  136. package/dist/{idCaptureManager-BYwTZ2H8.esm.js → idCaptureManager-Vby8oYqh.esm.js} +259 -46
  137. package/dist/{idCaptureServices-44kwQItl.esm.js → idCaptureServices-CJIxD9ep.esm.js} +342 -31
  138. package/dist/idCaptureStateMachine-CmqihkUy.esm.js +5343 -0
  139. package/dist/{idOcrManager-DXc_xRN7.d.ts → idOcrManager-BF_cXZq8.d.ts} +1 -1
  140. package/dist/{idOcrManager-BIQYQXXj.esm.js → idOcrManager-DHU22hVn.esm.js} +2 -2
  141. package/dist/{idOcrStateMachine-cSxzHpHt.esm.js → idOcrStateMachine-33UvRAHE.esm.js} +1 -1
  142. package/dist/{idVerificationManager-JpV_SAsl.esm.js → idVerificationManager-CyaixD0D.esm.js} +2 -2
  143. package/dist/{idVerificationStateMachine-nPeUNyFq.esm.js → idVerificationStateMachine-BPGrQZEm.esm.js} +1 -1
  144. package/dist/identity-reuse.esm.js +2 -2
  145. package/dist/{identityReuseManager-kNCg9AbD.esm.js → identityReuseManager-CWaNHBO3.esm.js} +2 -2
  146. package/dist/{identityReuseStateMachine-DyulxDjP.esm.js → identityReuseStateMachine-CQgnATo5.esm.js} +1 -1
  147. package/dist/{index-CLMF0QLQ.d.ts → index-DLcJT5YP.d.ts} +1 -1
  148. package/dist/index.d.ts +1 -1
  149. package/dist/index.esm.js +1 -1
  150. package/dist/{invokeOnCaptureCallback-GpvMuz9o.esm.js → invokeOnCaptureCallback-BjzPjJ_p.esm.js} +1 -1
  151. package/dist/mandatory-consent.d.ts +2 -2
  152. package/dist/mandatory-consent.esm.js +2 -2
  153. package/dist/{mandatoryConsentManager-DyPzUmsZ.d.ts → mandatoryConsentManager-CJSyhTpi.d.ts} +5 -5
  154. package/dist/{mandatoryConsentManager-B4Niyg_u.esm.js → mandatoryConsentManager-Du-m-tZ_.esm.js} +2 -2
  155. package/dist/{mandatoryConsentStateMachine-B4-1u-L8.esm.js → mandatoryConsentStateMachine-DSDAk7WZ.esm.js} +1 -1
  156. package/dist/multipartRecordingService-B3C_zlev.esm.js +594 -0
  157. package/dist/{permissionGuards-KINpmKtI.esm.js → permissionGuards-uYZYFu4J.esm.js} +1 -1
  158. package/dist/{permissionServices-UvUcOSRb.esm.js → permissionServices-Bj_fyWtv.esm.js} +5 -5
  159. package/dist/personhood.d.ts +6 -5
  160. package/dist/personhood.esm.js +10 -10
  161. package/dist/phone.esm.js +2 -2
  162. package/dist/{phoneManager-FsJ0W2Ei.esm.js → phoneManager-N1-sbrY4.esm.js} +2 -2
  163. package/dist/{phoneStateMachine-Ba0wKHyX.esm.js → phoneStateMachine-jl8LJKCo.esm.js} +1 -1
  164. package/dist/{platform-BJrm5nzZ.esm.js → platform-DkcRc9JV.esm.js} +29 -1
  165. package/dist/qe-signature.d.ts +5 -3
  166. package/dist/qe-signature.esm.js +2 -2
  167. package/dist/recordingsRepository-CCWy13M-.esm.js +72 -0
  168. package/dist/redirect-to-mobile.esm.js +2 -2
  169. package/dist/{redirectToMobileManager-y4VQB11M.esm.js → redirectToMobileManager-DsFzdTwA.esm.js} +2 -2
  170. package/dist/{redirectToMobileStateMachine-Cyv2x0PP.esm.js → redirectToMobileStateMachine-v3otpT-L.esm.js} +1 -1
  171. package/dist/{rolldown-runtime-FZ4Itg2g.esm.js → rolldown-runtime-FDOR9p9I.esm.js} +1 -19
  172. package/dist/{runChildModule-Dukuw23X.esm.js → runChildModule-TuyGE00X.esm.js} +3 -21
  173. package/dist/safeStorage-B-trhxg6.esm.js +423 -0
  174. package/dist/{sdkVersion-D1Bm59g6.esm.js → sdkVersion-CLxKvdyz.esm.js} +1 -1
  175. package/dist/selfie.d.ts +5 -5
  176. package/dist/selfie.esm.js +14 -76
  177. package/dist/{selfieErrorUtils-C2PYBVsp.esm.js → selfieErrorUtils-C77GXJH6.esm.js} +30 -4
  178. package/dist/{selfieManager-Bj6B2ZVy.esm.js → selfieManager-CihVnODO.esm.js} +5 -5
  179. package/dist/{selfieManager-DwlCppg0.d.ts → selfieManager-D1KRJ39M.d.ts} +8 -11
  180. package/dist/selfieStateMachine-fwMmNtOi.esm.js +69 -0
  181. package/dist/{session-BFdLgN4i.esm.js → session-BHIeAamR.esm.js} +4 -5
  182. package/dist/session.d.ts +21 -11
  183. package/dist/session.esm.js +5 -5
  184. package/dist/{sessionInitializer-dlfDehHk.esm.js → sessionInitializer-BLoK7SP9.esm.js} +187 -68
  185. package/dist/{setup-BgoWtvIS.d.ts → setup-Cv-JM9QC.d.ts} +63 -69
  186. package/dist/{setup-BIAtLa8k.esm.js → setup-msLybMbC.esm.js} +226 -100
  187. package/dist/signature.esm.js +2 -2
  188. package/dist/{signatureManager-Ca43yhwk.esm.js → signatureManager-ChsB-nMD.esm.js} +2 -2
  189. package/dist/{signatureStateMachine-K1LMRrxG.esm.js → signatureStateMachine-BHPwkJZS.esm.js} +1 -1
  190. package/dist/{src-0Jurt29N.esm.js → src-35ekGRzK.esm.js} +1 -1
  191. package/dist/{stats-B0nFKawG.esm.js → stats-DkK-f8JT.esm.js} +1 -1
  192. package/dist/stats.esm.js +1 -1
  193. package/dist/{trueSightService---iW2KKJ.esm.js → trueSightService-CKrrfV0Q.esm.js} +7 -7
  194. package/dist/trust-graph.esm.js +1 -1
  195. package/dist/{types-BX_XkMsQ2.d.ts → types-9_esGTPj.d.ts} +1 -1
  196. package/dist/types-BT_Oalip.d.ts +1 -0
  197. package/dist/{types-DelMqZLe.d.ts → types-BjSly8cp.d.ts} +1 -1
  198. package/dist/{types-Hmd7U0JA.d.ts → types-CM-jtjJ2.d.ts} +6 -81
  199. package/dist/{types-Bdf8_LYB2.d.ts → types-CjKBS37a2.d.ts} +303 -13
  200. package/dist/{types-DVmXIdzW.d.ts → types-D0gekt4U.d.ts} +38 -5
  201. package/dist/types-DgDvvzg0.d.ts +10 -0
  202. package/dist/{types-KPvmag_B.d.ts → types-Do5rEXij.d.ts} +7 -4
  203. package/dist/types-ZT1XFIJ8.d.ts +6 -0
  204. package/dist/video-selfie.d.ts +59 -35
  205. package/dist/video-selfie.esm.js +510 -601
  206. package/dist/{videoSelfieCameraWarmer-NEhFZvWx.esm.js → videoSelfieCameraWarmer-CB1IzZkt.esm.js} +14 -153
  207. package/dist/videoSelfieFlowModuleMachine-BUe2uACW.esm.js +32 -0
  208. package/dist/{videoSelfieStepDetector-D3oo2ofo.d.ts → videoSelfieStepDetector-5YHFe0Mq.d.ts} +21 -5
  209. package/dist/virtualCameraCheck-WOloJ-do.esm.js +48 -0
  210. package/dist/warmup-CUUnwYxe.esm.js +714 -0
  211. package/dist/warmup-Cis2p6O0.d.ts +128 -0
  212. package/dist/wasm.d.ts +30 -6
  213. package/dist/wasm.esm.js +36 -4
  214. package/dist/{wasmDsFlagSync-BqUCwLY8.esm.js → wasmDsFlagSync-B2e8p268.esm.js} +2 -2
  215. package/dist/{wasmWebClient-DM8lkb0z.esm.js → wasmWebClient-B7baE-Wf.esm.js} +358 -28
  216. package/dist/watchlist-for-business.d.ts +2 -78
  217. package/dist/watchlist-for-business.esm.js +3 -102
  218. package/dist/watchlist.esm.js +2 -2
  219. package/dist/watchlistForBusinessManager-CpuuB1J2.esm.js +107 -0
  220. package/dist/watchlistForBusinessManager-CsnJnG-C.d.ts +99 -0
  221. package/dist/{watchlistForBusinessStateMachine-CxFnlshm.esm.js → watchlistForBusinessStateMachine-DEzgjz7C.esm.js} +13 -6
  222. package/dist/{watchlistManager-LoNZH9qm.esm.js → watchlistManager-CI8BHFob.esm.js} +2 -2
  223. package/dist/{watchlistStateMachine-DIKQDoUT.esm.js → watchlistStateMachine-DvOby3a-.esm.js} +1 -1
  224. package/dist/workflow.d.ts +12 -8
  225. package/dist/workflow.esm.js +48 -39
  226. package/package.json +4 -10
  227. package/dist/BrowserStorageProvider-k-FDkC4W.esm.js +0 -67
  228. package/dist/FaceDetectionProvider-Mh6q3EbA.d.ts +0 -349
  229. package/dist/IFaceAvatarCapability-BrL19G0s.d.ts +0 -23
  230. package/dist/IStorageCapability-ORkQfK3F.d.ts +0 -242
  231. package/dist/OpenViduRecordingProvider-Du98qevC.esm.js +0 -85
  232. package/dist/createFaceAvatar-BEj18KXi.d.ts +0 -50
  233. package/dist/document-upload.d.ts +0 -325
  234. package/dist/document-upload.esm.js +0 -197
  235. package/dist/electronicSignatureManager-CcUXQZS7.d.ts +0 -1300
  236. package/dist/faceCaptureSetup-Cd-04W_X.esm.js +0 -863
  237. package/dist/getBrowser-Cb8Zgrgp.esm.js +0 -7
  238. package/dist/getParsedUserAgent-pJjATANs.esm.js +0 -1622
  239. package/dist/governmentValidationStateMachine-CK9DrZXX.esm.js +0 -226
  240. package/dist/idCaptureDefaults-WeHbQM7W.esm.js +0 -225
  241. package/dist/idCaptureStateMachine-kZ5OpdfM.esm.js +0 -3342
  242. package/dist/lib-DAyUtOTj.esm.js +0 -12420
  243. package/dist/manualReviewService-D4IkipnN.esm.js +0 -15
  244. package/dist/mediaRecorderOptions-dALSV8af.esm.js +0 -40
  245. package/dist/onDeviceFaceResults-CUHwyZT4.esm.js +0 -646
  246. package/dist/openviduLazy-CCDpFWg1.esm.js +0 -10
  247. package/dist/recordingService-3NSENVwp.esm.js +0 -329
  248. package/dist/safeStorage-Ep56I-f_.esm.js +0 -982
  249. package/dist/selfieStateMachine-CHV_WNst.esm.js +0 -55
  250. package/dist/trueSight-B_icM8r2.esm.js +0 -1
  251. package/dist/types-EELWyWpd.d.ts +0 -6
  252. package/dist/types-Vb4P9ovf.d.ts +0 -22
  253. package/dist/warmup-Dv2alr2-.d.ts +0 -82
  254. package/dist/wasmDefaults-DTUrftxR.esm.js +0 -125
  255. package/dist/{Face2DProvider-UUQt_vRC.esm.js → Face2DProvider-BF48sz5c.esm.js} +1 -1
  256. package/dist/{PrivacyLensProvider-D8PS7AJa.esm.js → PrivacyLensProvider-EwnC_C5n.esm.js} +1 -1
  257. /package/dist/{types-BfgmV7s72.d.ts → types-BfgmV7s7.d.ts} +0 -0
  258. /package/dist/{types-CJ7Yl9K-2.d.ts → types-CJ7Yl9K-.d.ts} +0 -0
@@ -1,431 +1,21 @@
1
- import { r as WasmUtilProvider } from "./safeStorage-Ep56I-f_.esm.js";
2
- import { c as abortVideoSelfieUpload, d as uploadVideoSelfiePart, l as completeVideoSelfieUpload, t as ensureWasmPipelines, u as initiateVideoSelfieUpload } from "./setup-BIAtLa8k.esm.js";
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-CCzL3XD_.esm.js";
6
- import { d as videoSelfieWasmPipelines, l as facingModeForStep, u as resolveVideoSelfieSteps } from "./flowServices-f5Ruz7R9.esm.js";
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 { n as getSupportedMediaRecorderMimeType } from "./mediaRecorderOptions-dALSV8af.esm.js";
10
- import { i as createDefaultStepDetector, n as defaultAcquireCamera, o as isConnectionError, r as CameraCompositor, t as createVideoSelfieCameraWarmer } from "./videoSelfieCameraWarmer-NEhFZvWx.esm.js";
11
- //#region ../infra/src/providers/browser/MultipartRecordingProvider.ts
12
- /**
13
- * How often `MediaRecorder` hands us buffered data (incremental blobs).
14
- * 500 ms keeps each blob — and therefore each upload chunk — small: less
15
- * tail lost when a session is interrupted, and a smaller first blob (init
16
- * header + keyframe), which is the largest and most timeout-prone chunk.
17
- * Not lower: request rate doubles per halving, and browsers stop honoring
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 isIdStep(step) {
472
- return step === "frontId" || step === "backId";
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▶ acquiringCamera ─▶ starting ─▶ recording ⇄ switchingCamera
499
- * │ (capture validated → DETECTION_DONE,
500
- * │ or manual NEXT_STEP)
501
- * last step ─▶ finalizing ─▶ finished
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
- service: input.dependencies?.createRecordingService?.() ?? new MultipartRecordingService(),
689
- compositor: input.dependencies?.createCompositor?.() ?? new CameraCompositor(),
690
- acquireCamera: input.dependencies?.acquireCamera ?? defaultAcquireCamera,
691
- detect: input.dependencies?.detect ?? manualStepDetector,
692
- steps: input.steps && input.steps.length > 0 ? input.steps : ["selfie"],
693
- stepIndex: 0,
694
- stream: void 0,
695
- composite: void 0,
696
- detectionStatus: void 0,
697
- orientation: void 0,
698
- detectionError: void 0,
699
- validationFailure: void 0,
700
- attemptsPerStep: normalizeAttempts(input.attemptsPerStep),
701
- attemptsRemaining: normalizeAttempts(input.attemptsPerStep),
702
- recordingId: null,
703
- error: void 0,
704
- errorKind: void 0,
705
- switchingCameraMinDwellMs: input.dependencies?.switchingCameraMinDwellMs ?? SWITCHING_CAMERA_MIN_DWELL_MS
706
- }),
707
- on: { ABORT: { target: ".aborted" } },
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: { target: "acquiringCamera" } } },
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: { target: "recording" },
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: { after: { VALIDATION_FEEDBACK_DWELL: [{
773
- target: "recording",
774
- guard: "hasAttemptsRemaining"
775
- }, ...[
776
- {
777
- target: "finalizing",
778
- guard: "exhaustedIdFinishes"
779
- },
780
- {
781
- target: "switchingCamera",
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
- reenter: true,
788
- guard: "isIdExhaustion",
789
- actions: "advancePastIdSection"
790
- },
791
- {
496
+ guard: "hasAttemptsRemaining"
497
+ }, {
792
498
  target: "finalizing",
793
- guard: "exhaustedNonIdFinishes"
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: { NEXT_STEP: {
813
- target: "recording",
814
- actions: "advanceStep"
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: { invoke: {
818
- src: "switchCamera",
819
- input: ({ context }) => ({
820
- acquire: context.acquireCamera,
821
- facingMode: facingModeForStep(context.steps[context.stepIndex]),
822
- minDwellMs: context.switchingCameraMinDwellMs
823
- }),
824
- onDone: {
825
- target: "recording",
826
- actions: [({ context, event }) => {
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
- onError: {
831
- target: "error",
832
- actions: assign({ error: ({ event }) => errorFromEvent(event) })
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
- finalizing: { invoke: {
836
- src: "finalizeRecording",
837
- input: ({ context }) => ({ service: context.service }),
838
- onDone: [{
839
- target: "error",
840
- guard: "uploadReturnedNoRecordingId",
841
- actions: [assign({ recordingId: ({ event }) => recordingIdFromEvent(event) }), "setUploadFailedError"]
842
- }, {
843
- target: "success",
844
- actions: assign({ recordingId: ({ event }) => recordingIdFromEvent(event) })
845
- }],
846
- onError: {
847
- target: "error",
848
- actions: assign({ error: ({ event }) => errorFromEvent(event) })
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
- on: { RETRY: {
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 createVideoSelfieRecordingActor(options = {}) {
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: config ? resolveVideoSelfieSteps(config) : void 0,
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$1 = class MediaRecorder$1 {
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$1.encoder);
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$1.prototype.mimeType = "audio/wav";
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$1.isTypeSupported = (mimeType) => {
1252
- return MediaRecorder$1.prototype.mimeType === mimeType;
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$1.notSupported = !navigator.mediaDevices || !AudioContext;
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$1.encoder = wave_encoder_default;
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$1;
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
- //#region src/modules/video-selfie/videoSelfieFlowModuleMachine.ts
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 };