@incodetech/core 2.1.1 → 2.2.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 (328) hide show
  1. package/dist/{3dAvatarProvider-BwOmTMOy.esm.js → 3dAvatarProvider-g02DTFqT.esm.js} +811 -880
  2. package/dist/Actor-iTq7YY48.d.ts +1 -0
  3. package/dist/BrowserDiagnosticsCryptoProvider-CriIh1Gt.esm.js +95 -0
  4. package/dist/BrowserLazyImportProvider-BhoA957O.esm.js +114 -0
  5. package/dist/{BrowserStorageProvider-CBHBhKQN.esm.js → BrowserStorageProvider-k-FDkC4W.esm.js} +2 -4
  6. package/dist/{BrowserTimerProvider-CHloo0eQ.esm.js → BrowserTimerProvider-BXhgNxLt.esm.js} +1 -2
  7. package/dist/{BrowserVisibilityObserverProvider-GBS6XSii.esm.js → BrowserVisibilityObserverProvider-BX1BiLDK.esm.js} +1 -2
  8. package/dist/Face2DProvider-UUQt_vRC.esm.js +437 -0
  9. package/dist/{createFaceAvatar-CpdYp9Iy.d.ts → FaceDetectionProvider-Mh6q3EbA.d.ts} +107 -159
  10. package/dist/IBrowserEnvironmentCapability-DEaRRk-R.esm.js +9 -0
  11. package/dist/IFaceAvatarCapability-BrL19G0s.d.ts +23 -0
  12. package/dist/IFeatureManagementCapability-DdEUp6tB.d.ts +1125 -0
  13. package/dist/IIdCaptureCapability-DHTT3FC2.d.ts +237 -0
  14. package/dist/IStorageCapability-ORkQfK3F.d.ts +242 -0
  15. package/dist/{ITimerCapability-DJ73P4RK.esm.js → ITimerCapability-DgdDzp8G.esm.js} +1 -2
  16. package/dist/{Manager-goNPc_h_.d.ts → Manager-CQQ99QOI.d.ts} +1 -0
  17. package/dist/{MotionSensorProvider-BHuHoYvJ.esm.js → MotionSensorProvider-DGiV77J_.esm.js} +2 -37
  18. package/dist/{OpenViduRecordingProvider-CK6A5kiU.esm.js → OpenViduRecordingProvider-Du98qevC.esm.js} +2 -4
  19. package/dist/PrivacyLensProvider-D8PS7AJa.esm.js +405 -0
  20. package/dist/StateMachine-EDpYWy0i.d.ts +6 -0
  21. package/dist/{StreamCanvasCapture-CAqUdVkM.esm.js → StreamCanvasCapture-D2XcXCZ4.esm.js} +2 -4
  22. package/dist/{addressSearch-D7msRieq.esm.js → addressSearch-DQyrvDQj.esm.js} +10 -21
  23. package/dist/ae-signature.d.ts +4 -6
  24. package/dist/ae-signature.esm.js +10 -11
  25. package/dist/antifraud.d.ts +1 -6
  26. package/dist/antifraud.esm.js +3 -8
  27. package/dist/{antifraudManager-5KA84wtF.esm.js → antifraudManager-B8Plzf7a.esm.js} +11 -8
  28. package/dist/{antifraudManager-DCiNI6np.d.ts → antifraudManager-BY36bS12.d.ts} +3 -3
  29. package/dist/{antifraudStateMachine-BQVw46N5.esm.js → antifraudStateMachine-r4VxSBS4.esm.js} +5 -7
  30. package/dist/api-Bx3gKW_y.esm.js +129 -0
  31. package/dist/{apiError-DkOXfFBu.esm.js → apiError-DZfAyExM.esm.js} +25 -3
  32. package/dist/authentication.d.ts +3 -19
  33. package/dist/authentication.esm.js +3 -35
  34. package/dist/{authenticationManager-BeT6tNZm.d.ts → authenticationManager-BBMGTcwW.d.ts} +3 -4
  35. package/dist/{authenticationManager-BryLnSaF.esm.js → authenticationManager-DscbQwIl.esm.js} +7 -10
  36. package/dist/{authenticationStateMachine-DbdxfGHx.esm.js → authenticationStateMachine-SyuM00Fa.esm.js} +11 -15
  37. package/dist/avatar.d.ts +2 -2
  38. package/dist/avatar.esm.js +2 -3
  39. package/dist/avatar2dWarm-DqucNFX4.esm.js +1330 -0
  40. package/dist/avatarStats-CdUOb3VD.esm.js +136 -0
  41. package/dist/{backCameraStream-ChrMTJv-.esm.js → backCameraStream-CUeYm5eu.esm.js} +20 -8
  42. package/dist/browser-DlFgHpoC-DnyrCR8r.esm.js +1513 -0
  43. package/dist/callback-645_omgz.d.ts +133 -0
  44. package/dist/camera-_2sXMXiF.esm.js +140 -0
  45. package/dist/camera.d.ts +19 -2
  46. package/dist/camera.esm.js +2 -6
  47. package/dist/{canvas-Pi10hG_l.esm.js → canvas-E1zGkel4.esm.js} +1 -2
  48. package/dist/certificate-issuance.d.ts +34 -39
  49. package/dist/certificate-issuance.esm.js +4 -11
  50. package/dist/{certificateIssuanceStateMachine-DlZQT1_u.esm.js → certificateIssuanceStateMachine-COd7_l2T.esm.js} +7 -11
  51. package/dist/consent.d.ts +1 -4
  52. package/dist/consent.esm.js +3 -8
  53. package/dist/{consentManager-BwNu-uC-.esm.js → consentManager-BApTlfA0.esm.js} +5 -7
  54. package/dist/{consentManager-B4PMGXW-.d.ts → consentManager-uhDPdU6i.d.ts} +55 -61
  55. package/dist/{consentStateMachine-BOkVFiU7.esm.js → consentStateMachine-WD-S-Yhs.esm.js} +5 -7
  56. package/dist/{cpf-16m_cGAM.esm.js → cpf-BIADjddF.esm.js} +1 -2
  57. package/dist/createFaceAvatar-BEj18KXi.d.ts +50 -0
  58. package/dist/createFaceAvatar-DQKaRise.esm.js +103 -0
  59. package/dist/cross-document-data-match.d.ts +2 -26
  60. package/dist/cross-document-data-match.esm.js +2 -71
  61. package/dist/crossDocumentDataMatchManager-Dq8Z3SOg.d.ts +41 -0
  62. package/dist/crossDocumentDataMatchManager-OmYvyung.esm.js +84 -0
  63. package/dist/curp-validation.d.ts +1 -11
  64. package/dist/curp-validation.esm.js +3 -8
  65. package/dist/{curpValidationManager-CoqODZx5.d.ts → curpValidationManager-DVGr7Fq7.d.ts} +4 -6
  66. package/dist/{curpValidationManager-Cbji2inV.esm.js → curpValidationManager-UZxcrsrz.esm.js} +11 -7
  67. package/dist/{curpValidationStateMachine-Dlw4qfFb.esm.js → curpValidationStateMachine-9KwnqeoB.esm.js} +22 -14
  68. package/dist/custom-fields.d.ts +2 -5
  69. package/dist/custom-fields.esm.js +24 -11
  70. package/dist/custom-watchlist.d.ts +1 -3
  71. package/dist/custom-watchlist.esm.js +11 -10
  72. package/dist/{customWatchlistStateMachine-D8w0mNxm.esm.js → customWatchlistStateMachine-B_ey3TFj.esm.js} +5 -7
  73. package/dist/{dateUtils-BW6mBV6p.esm.js → dateUtils-CvG0FvK8.esm.js} +1 -2
  74. package/dist/{deepsightService-CViys6T4.esm.js → deepsightLoader-DcWjMC6A.esm.js} +68 -14
  75. package/dist/{deepsightService-BuTOFTr8.d.ts → deepsightService-DLVQS_RH.d.ts} +41 -2
  76. package/dist/device.d.ts +10 -2
  77. package/dist/device.esm.js +21 -21
  78. package/dist/document-capture.d.ts +3 -1816
  79. package/dist/document-capture.esm.js +3 -245
  80. package/dist/document-upload.d.ts +48 -55
  81. package/dist/document-upload.esm.js +8 -14
  82. package/dist/documentCaptureManager-B4Kivr8_.d.ts +2062 -0
  83. package/dist/documentCaptureManager-DszmcU-l.esm.js +296 -0
  84. package/dist/{documentCaptureStateMachine-BkTvU3yq.esm.js → documentCaptureStateMachine-D2jBwwVb.esm.js} +66 -40
  85. package/dist/dynamic-forms.d.ts +2 -4
  86. package/dist/dynamic-forms.esm.js +3 -9
  87. package/dist/{dynamicFormsManager-CHXUBNs4.esm.js → dynamicFormsManager-BoZ2-OUI.esm.js} +48 -9
  88. package/dist/{dynamicFormsManager-CKZkE7Wo.d.ts → dynamicFormsManager-fhK0yINk.d.ts} +22 -46
  89. package/dist/{dynamicFormsStateMachine-DJ1HGZff.esm.js → dynamicFormsStateMachine-D0RzkoEV.esm.js} +161 -34
  90. package/dist/ekyb.d.ts +5 -137
  91. package/dist/ekyb.esm.js +4 -179
  92. package/dist/ekybManager-DTvfxAOZ.esm.js +178 -0
  93. package/dist/ekybManager-Dzswb_b8.d.ts +114 -0
  94. package/dist/{ekybStateMachine-D9GzA4MW.esm.js → ekybStateMachine-BlTIozb6.esm.js} +16 -193
  95. package/dist/ekyc.d.ts +2 -79
  96. package/dist/ekyc.esm.js +4 -154
  97. package/dist/ekycManager-BFpHbBoT.d.ts +97 -0
  98. package/dist/ekycManager-oTstTJuL.esm.js +156 -0
  99. package/dist/{ekycStateMachine-DnVRiu3s.esm.js → ekycStateMachine-DHvksnrr.esm.js} +141 -423
  100. package/dist/ekycUtils-Dew1rBG0.esm.js +223 -0
  101. package/dist/electronic-signature.d.ts +3 -5
  102. package/dist/electronic-signature.esm.js +2 -10
  103. package/dist/{index-36QX_21w.d.ts → electronicSignatureManager-CcUXQZS7.d.ts} +220 -251
  104. package/dist/{electronicSignatureManager-DESRgObX.esm.js → electronicSignatureManager-DRYlHPjT.esm.js} +47 -33
  105. package/dist/email.d.ts +1 -5
  106. package/dist/email.esm.js +3 -10
  107. package/dist/{emailManager-CMS4q_r6.d.ts → emailManager-CADXW_9X.d.ts} +4 -7
  108. package/dist/{emailManager-B9Vrv3Ma.esm.js → emailManager-tE-YvNtS.esm.js} +76 -12
  109. package/dist/{emailStateMachine-CbmKFVSi.esm.js → emailStateMachine-Bm894MHB.esm.js} +7 -9
  110. package/dist/{endpoints-CwrFQfW7.esm.js → endpoints-CCzL3XD_.esm.js} +55 -6
  111. package/dist/{events-1wxZ97yf.esm.js → events-CxfNJVZW.esm.js} +43 -176
  112. package/dist/events.d.ts +28 -10
  113. package/dist/events.esm.js +2 -4
  114. package/dist/extensibility.d.ts +37 -37
  115. package/dist/extensibility.esm.js +31 -80
  116. package/dist/{externalFetch-hvmz_npP.esm.js → externalFetch-BKBThAUC.esm.js} +2 -4
  117. package/dist/face-match.d.ts +2 -225
  118. package/dist/face-match.esm.js +3 -173
  119. package/dist/{faceCaptureManagerFactory-C9TiGbkA.esm.js → faceCaptureManagerFactory-BDAsBCkh.esm.js} +52 -31
  120. package/dist/{faceCaptureManagerFactory-DiJ64oem.d.ts → faceCaptureManagerFactory-BxWPpxyd.d.ts} +63 -24
  121. package/dist/{faceCaptureSetup-BqhqfFHL.esm.js → faceCaptureSetup-C7Qv79fA.esm.js} +57 -36
  122. package/dist/faceMatchManager-BXp2WUT-.esm.js +201 -0
  123. package/dist/faceMatchManager-BnvrZM2F.d.ts +268 -0
  124. package/dist/{faceMatchStateMachine-MDb30gCm.esm.js → faceMatchStateMachine-CJiO2yLO.esm.js} +14 -10
  125. package/dist/feature-management-DS_Nj5Gg.esm.js +615 -0
  126. package/dist/feature-management.d.ts +173 -0
  127. package/dist/feature-management.esm.js +2 -0
  128. package/dist/field-comparison.d.ts +1 -4
  129. package/dist/field-comparison.esm.js +2 -7
  130. package/dist/{fieldComparisonManager-OLKVsG2Z.d.ts → fieldComparisonManager-CBvEGxFx.d.ts} +3 -5
  131. package/dist/{fieldComparisonManager-Cw4uzD7S.esm.js → fieldComparisonManager-DhnYdYZ2.esm.js} +6 -11
  132. package/dist/fiscal-qr.d.ts +1 -6
  133. package/dist/fiscal-qr.esm.js +14 -29
  134. package/dist/flow-events.d.ts +2 -9
  135. package/dist/flow.d.ts +59 -21
  136. package/dist/flow.esm.js +132 -49
  137. package/dist/{flowCompletionService-B6P6_EF3.esm.js → flowCompletionService-BSe3p7pg.esm.js} +4 -6
  138. package/dist/flowServices-unhF9V9F.esm.js +620 -0
  139. package/dist/geolocation.d.ts +1 -4
  140. package/dist/geolocation.esm.js +3 -9
  141. package/dist/{geolocationManager-CF6-NizA.esm.js → geolocationManager-Bv9MSVNr.esm.js} +44 -16
  142. package/dist/geolocationManager-Cz744E5S.d.ts +506 -0
  143. package/dist/{geolocationStateMachine-CD2XJs1b.esm.js → geolocationStateMachine-BxD6JK1M.esm.js} +53 -28
  144. package/dist/{getBrowser-1yNcfFZR.esm.js → getBrowser-Cb8Zgrgp.esm.js} +1 -2
  145. package/dist/getBrowser-DNrQeL4T.esm.js +16 -0
  146. package/dist/getDeviceClass-9y-kbVDw.esm.js +19 -0
  147. package/dist/{getDeviceClass-C-Dg6IsJ.esm.js → getDeviceClass-CeBiEayS.esm.js} +1 -2
  148. package/dist/getParsedUserAgent-pJjATANs.esm.js +1622 -0
  149. package/dist/government-validation.d.ts +3 -6
  150. package/dist/government-validation.esm.js +7 -13
  151. package/dist/{governmentValidationStateMachine-BE5wiQ7Y.esm.js → governmentValidationStateMachine-BYKYUdza.esm.js} +8 -11
  152. package/dist/home.d.ts +14 -22
  153. package/dist/home.esm.js +3 -8
  154. package/dist/http.d.ts +0 -1
  155. package/dist/http.esm.js +2 -4
  156. package/dist/id-ocr.d.ts +8 -7
  157. package/dist/id-ocr.esm.js +20 -9
  158. package/dist/id-selfie-flow.d.ts +179 -0
  159. package/dist/id-selfie-flow.esm.js +917 -0
  160. package/dist/id-verification.d.ts +2 -191
  161. package/dist/id-verification.esm.js +3 -43
  162. package/dist/id.d.ts +7 -18
  163. package/dist/id.esm.js +47 -53
  164. package/dist/{idCaptureDefaults-CZajItdO.esm.js → idCaptureDefaults-WeHbQM7W.esm.js} +54 -17
  165. package/dist/idCaptureManager-BjU-Wyow.d.ts +429 -0
  166. package/dist/{idCaptureManager-DASPUMtC.esm.js → idCaptureManager-BjiBSrHm.esm.js} +173 -34
  167. package/dist/idCaptureServices-CFDwqTtQ.esm.js +396 -0
  168. package/dist/{idCaptureStateMachine-DZ2ZTSxu.esm.js → idCaptureStateMachine-CRwQh8jc.esm.js} +438 -585
  169. package/dist/{idOcrManager-Tm4LzKR0.esm.js → idOcrManager-CvJZhmBR.esm.js} +4 -7
  170. package/dist/{idOcrManager-DLfAjDZn.d.ts → idOcrManager-DXc_xRN7.d.ts} +62 -229
  171. package/dist/{idOcrStateMachine-BJxZCxwS.esm.js → idOcrStateMachine-Bq_e3l4E.esm.js} +15 -20
  172. package/dist/idVerificationManager-BB4Pj_N6.d.ts +197 -0
  173. package/dist/idVerificationManager-CduNXhWd.esm.js +51 -0
  174. package/dist/{idVerificationStateMachine-DXN9WcdM.esm.js → idVerificationStateMachine-GEQWUPU2.esm.js} +5 -7
  175. package/dist/identity-reuse.d.ts +1 -4
  176. package/dist/identity-reuse.esm.js +3 -8
  177. package/dist/{identityReuseManager-LjkPvSQN.esm.js → identityReuseManager-D5vXknnJ.esm.js} +24 -7
  178. package/dist/{identityReuseManager-CLVOYxcp.d.ts → identityReuseManager-v2TH5g7e.d.ts} +38 -43
  179. package/dist/{identityReuseStateMachine-Bp-zONoV.esm.js → identityReuseStateMachine-AubRPhIi.esm.js} +6 -8
  180. package/dist/index-B8weJxmL.d.ts +1 -0
  181. package/dist/index-BKOWUhxG.d.ts +258 -0
  182. package/dist/{index-DrpWp15Z.d.ts → index-CLMF0QLQ.d.ts} +3 -3
  183. package/dist/index.d.ts +1 -3
  184. package/dist/index.esm.js +2 -15
  185. package/dist/{invokeOnCaptureCallback-CCS2Ruzi.esm.js → invokeOnCaptureCallback-1m1VJ3Q4.esm.js} +2 -4
  186. package/dist/{lib-Bjd6nOLG.esm.js → lib-DAyUtOTj.esm.js} +1510 -1589
  187. package/dist/mandatory-consent.d.ts +2 -10
  188. package/dist/mandatory-consent.esm.js +3 -8
  189. package/dist/{mandatoryConsentManager-DeBmOHcQ.d.ts → mandatoryConsentManager-B29kR0XA.d.ts} +60 -85
  190. package/dist/{mandatoryConsentManager-DZ26sg4B.esm.js → mandatoryConsentManager-BeELm1zS.esm.js} +4 -7
  191. package/dist/{mandatoryConsentStateMachine-_44ZoDSh.esm.js → mandatoryConsentStateMachine-zroQGzwb.esm.js} +5 -7
  192. package/dist/manualReviewService-D4IkipnN.esm.js +15 -0
  193. package/dist/{mediaRecorderOptions-CClCKAiF.esm.js → mediaRecorderOptions-dALSV8af.esm.js} +2 -4
  194. package/dist/{mediapipeShared-Bcmkzs3x.esm.js → mediapipeShared-B6oNoXEQ.esm.js} +21 -9
  195. package/dist/{onDeviceFaceResults-DILtthks.esm.js → onDeviceFaceResults-f81FVdQs.esm.js} +30 -87
  196. package/dist/openviduLazy-CCDpFWg1.esm.js +10 -0
  197. package/dist/{otp-B1YeyRXu.d.ts → otp-CEWfTj9v.d.ts} +0 -1
  198. package/dist/{otp-uaXiKt_R.esm.js → otp-D2k3PeSL.esm.js} +3 -14
  199. package/dist/{permissionGuards-BNOe4Tnu.esm.js → permissionGuards-KINpmKtI.esm.js} +2 -4
  200. package/dist/{permissionServices-C_kxhNeo.esm.js → permissionServices-UvUcOSRb.esm.js} +35 -28
  201. package/dist/personhood.d.ts +13 -20
  202. package/dist/personhood.esm.js +153 -85
  203. package/dist/phone.d.ts +1 -5
  204. package/dist/phone.esm.js +3 -10
  205. package/dist/{phoneManager-_KtitbUA.d.ts → phoneManager-BBU8Lq0O.d.ts} +4 -7
  206. package/dist/{phoneManager-CRblfdcI.esm.js → phoneManager-Cpiai2IM.esm.js} +82 -12
  207. package/dist/{phoneStateMachine-DjFGWMjQ.esm.js → phoneStateMachine-E1fUUcNM.esm.js} +7 -9
  208. package/dist/{platform-0Ot-bF_a.esm.js → platform-BJrm5nzZ.esm.js} +31 -11
  209. package/dist/privacyLensWorker-DI-Rg83h.esm.js +355 -0
  210. package/dist/qe-signature.d.ts +4 -6
  211. package/dist/qe-signature.esm.js +10 -11
  212. package/dist/{recordingService-CxaYkITO.esm.js → recordingService-CFpfdXSS.esm.js} +13 -31
  213. package/dist/redirect-to-mobile.d.ts +2 -6
  214. package/dist/redirect-to-mobile.esm.js +3 -10
  215. package/dist/{redirectToMobileManager-dv29o_LS.d.ts → redirectToMobileManager-BD2PvT5B.d.ts} +8 -44
  216. package/dist/{redirectToMobileManager-DbuNUlru.esm.js → redirectToMobileManager-C0dfc7f6.esm.js} +28 -8
  217. package/dist/{redirectToMobileStateMachine-BRaIJWOM.esm.js → redirectToMobileStateMachine-C9SYCJcH.esm.js} +74 -18
  218. package/dist/rolldown-runtime-FZ4Itg2g.esm.js +42 -0
  219. package/dist/{runChildModule-kojSv3MH.esm.js → runChildModule-DpvgAGFA.esm.js} +10 -9
  220. package/dist/{WasmUtilProvider-BgzcXBdl.esm.js → safeStorage-Ep56I-f_.esm.js} +98 -473
  221. package/dist/selfie.d.ts +8 -21
  222. package/dist/selfie.esm.js +40 -47
  223. package/dist/selfieErrorUtils-C2PYBVsp.esm.js +90 -0
  224. package/dist/{selfieManager-B1Px3GGa.esm.js → selfieManager-Br4onIMy.esm.js} +7 -10
  225. package/dist/{selfieManager-4juKfrHG.d.ts → selfieManager-DwlCppg0.d.ts} +3 -4
  226. package/dist/{selfieStateMachine-D0TS93Tu.esm.js → selfieStateMachine-CNGs8vFK.esm.js} +14 -29
  227. package/dist/{session-CLsU2Jnb.esm.js → session-CX2H3tmI.esm.js} +16 -7
  228. package/dist/session.d.ts +12 -10
  229. package/dist/session.esm.js +5 -15
  230. package/dist/sessionInitializer-CV6Rj_dn.esm.js +1865 -0
  231. package/dist/{setup-CfNsYAeB.esm.js → setup-CYdVacqv.esm.js} +319 -137
  232. package/dist/{setup-CmA2apmN.d.ts → setup-DywQeePQ.d.ts} +186 -4
  233. package/dist/signature.d.ts +2 -96
  234. package/dist/signature.esm.js +3 -108
  235. package/dist/signatureManager-DGBSWz2_.d.ts +106 -0
  236. package/dist/signatureManager-DdPgcmou.esm.js +113 -0
  237. package/dist/{signatureStateMachine-CdhlMih-.esm.js → signatureStateMachine-Cf73DGWO.esm.js} +5 -7
  238. package/dist/spawn-D9jgw9pW.d.ts +1441 -0
  239. package/dist/src-0Jurt29N.esm.js +4482 -0
  240. package/dist/{stats-BVy52wLy.esm.js → stats-B0nFKawG.esm.js} +3 -5
  241. package/dist/stats.esm.js +2 -5
  242. package/dist/topLevelStateName-B5i2avbh.esm.js +41 -0
  243. package/dist/{tri-CFAPtAUM.esm.js → tri-4RsGrIt6.esm.js} +3 -119
  244. package/dist/tri.d.ts +2 -2
  245. package/dist/tri.esm-BIjHhBJ2.esm.js +2620 -0
  246. package/dist/tri.esm.js +2 -4
  247. package/dist/trueSight-B8G85W4z.esm.js +1 -0
  248. package/dist/trueSightService-6dTpiaTh.esm.js +1894 -0
  249. package/dist/trust-graph.d.ts +4 -5
  250. package/dist/trust-graph.esm.js +13 -9
  251. package/dist/types-BEwVKkLJ.d.ts +15 -0
  252. package/dist/{types-BKLb3C42.esm.js → types-BN5RPPIZ.esm.js} +1 -2
  253. package/dist/types-BSBzhHRH.d.ts +57 -0
  254. package/dist/types-BX_XkMsQ2.d.ts +21 -0
  255. package/dist/types-BfHiko5D.d.ts +48 -0
  256. package/dist/{types-D8Cl1N2Z.d.ts → types-BfgmV7s72.d.ts} +2 -2
  257. package/dist/types-CJ7Yl9K-2.d.ts +164 -0
  258. package/dist/types-DPIDuhut.d.ts +40 -0
  259. package/dist/types-DVmXIdzW.d.ts +82 -0
  260. package/dist/types-DelMqZLe.d.ts +105 -0
  261. package/dist/types-EELWyWpd.d.ts +6 -0
  262. package/dist/{types-fO6KIdol.d.ts → types-Hmd7U0JA.d.ts} +80 -6
  263. package/dist/{types-BUgeB2X6.d.ts → types-KPvmag_B.d.ts} +7 -7
  264. package/dist/types-M6eb82ra2.d.ts +589 -0
  265. package/dist/{types-DV3wkhQ4.d.ts → types-Vb4P9ovf.d.ts} +1 -3
  266. package/dist/{urlUtils-CpiYwn7w.esm.js → urlUtils-D6phjq1-.esm.js} +1 -2
  267. package/dist/{video-ZY92rkel.esm.js → video-BtSWtHy1.esm.js} +1 -2
  268. package/dist/video-selfie.d.ts +71 -117
  269. package/dist/video-selfie.esm.js +575 -643
  270. package/dist/videoSelfieCameraWarmer-h_VUk5Vu.esm.js +651 -0
  271. package/dist/videoSelfieStepDetector-D3oo2ofo.d.ts +123 -0
  272. package/dist/wasm.d.ts +2 -4
  273. package/dist/wasm.esm.js +4 -15
  274. package/dist/wasmDefaults-DTUrftxR.esm.js +125 -0
  275. package/dist/{wasmDsFlagSync-Ch0mFJNT.esm.js → wasmDsFlagSync-BqUCwLY8.esm.js} +2 -4
  276. package/dist/wasmWebClient-DM8lkb0z.esm.js +407 -0
  277. package/dist/watchlist-for-business.d.ts +1 -3
  278. package/dist/watchlist-for-business.esm.js +9 -9
  279. package/dist/watchlist.d.ts +1 -52
  280. package/dist/watchlist.esm.js +3 -70
  281. package/dist/{watchlistForBusinessStateMachine-R1Yp1g5A.esm.js → watchlistForBusinessStateMachine-BcBMkMvV.esm.js} +5 -7
  282. package/dist/watchlistManager-CjSMmbyq.esm.js +83 -0
  283. package/dist/watchlistManager-DLXef90v.d.ts +68 -0
  284. package/dist/{watchlistStateMachine-D07UVq1m.esm.js → watchlistStateMachine-Bl7Wy9Cm.esm.js} +5 -7
  285. package/dist/workflow.d.ts +239 -203
  286. package/dist/workflow.esm.js +156 -101
  287. package/dist/xstate-actors.esm-CtI5S0f4.esm.js +310 -0
  288. package/dist/{xstate.esm-nY3M5UYm.esm.js → xstate.esm-Cf4e0Cfd.esm.js} +136 -610
  289. package/package.json +14 -9
  290. package/dist/Actor-BwgmOPkb.d.ts +0 -2
  291. package/dist/Face2DProvider-CZU11g6r.esm.js +0 -824
  292. package/dist/FaceDetectionProvider-CPWg-PAH.d.ts +0 -119
  293. package/dist/IWasmUtilCapability-DaSNxgA8.d.ts +0 -150
  294. package/dist/PrivacyLensProvider-B_zrV25p.esm.js +0 -339
  295. package/dist/StateMachine-D5WO6lHS.d.ts +0 -2
  296. package/dist/StreamCanvasCapture-DHaWferF.d.ts +0 -42
  297. package/dist/ae-signature-Pp4oCAHD.esm.js +0 -12
  298. package/dist/api-DsbUi7TO.esm.js +0 -72
  299. package/dist/browser-DlFgHpoC-Br3G10gw.esm.js +0 -1425
  300. package/dist/browserSimulation-DZwEy9bu.esm.js +0 -2804
  301. package/dist/camera-CxxXV0VN.esm.js +0 -79
  302. package/dist/canvas-90BqS0NF.d.ts +0 -112
  303. package/dist/chunk-CIKcdghV.esm.js +0 -49
  304. package/dist/clientLifecycle-VyzRfALg.esm.js +0 -534
  305. package/dist/cpf-ocr.d.ts +0 -10
  306. package/dist/cpf-ocr.esm.js +0 -8
  307. package/dist/cpfOcrManager-9eM4z4o7.esm.js +0 -190
  308. package/dist/cpfOcrManager-C5U9E0hf.d.ts +0 -216
  309. package/dist/createFaceAvatar-BZSg2MNo.esm.js +0 -46
  310. package/dist/deepsightLoader-CU_tiLMx.esm.js +0 -62
  311. package/dist/flowServices-DkQmOkLV.esm.js +0 -208
  312. package/dist/geolocationManager-DaHYFkVO.d.ts +0 -156
  313. package/dist/getDeviceClass-DIjnTPjR.esm.js +0 -14
  314. package/dist/http-CnsKEaJY.esm.js +0 -0
  315. package/dist/idCaptureManager-CwuXtVu6.d.ts +0 -1013
  316. package/dist/index-BAyZ8_iI.d.ts +0 -93
  317. package/dist/openviduLazy-jPgABwrt.esm.js +0 -3
  318. package/dist/openviduLazy-wEojM41w.esm.js +0 -12
  319. package/dist/qe-signature-BnWIpR-O.esm.js +0 -12
  320. package/dist/sessionInitializer-Dj7-aJaP.esm.js +0 -547
  321. package/dist/tri.esm-DDJ1zOqG.esm.js +0 -2593
  322. package/dist/types-BcF-fii5.d.ts +0 -5
  323. package/dist/videoSelfieSteps-Djpv7cjb.esm.js +0 -58
  324. /package/dist/{IVisibilityObserverCapability-BZ1rE7ly.d.ts → IVisibilityObserverCapability-D4tvIB5v.d.ts} +0 -0
  325. /package/dist/{camera-CKU96nwJ.d.ts → camera-9wWD-pwg.d.ts} +0 -0
  326. /package/dist/{flowCompletionService-BOSTlAWo.d.ts → flowCompletionService-BlAHsKyv.d.ts} +0 -0
  327. /package/dist/{types-BgjMAEXl.d.ts → types-Bk_6dmDa.d.ts} +0 -0
  328. /package/dist/{warmup-Dd0iq6KF.d.ts → warmup-Dv2alr2-.d.ts} +0 -0
@@ -1,422 +1,37 @@
1
- import { t as WasmUtilProvider } from "./WasmUtilProvider-BgzcXBdl.esm.js";
2
- import { t as ensureWasmPipelines } from "./setup-CfNsYAeB.esm.js";
3
- import { t as BrowserTimerProvider } from "./BrowserTimerProvider-CHloo0eQ.esm.js";
4
- import { t as api } from "./api-DsbUi7TO.esm.js";
5
- import "./clientLifecycle-VyzRfALg.esm.js";
6
- import "./events-1wxZ97yf.esm.js";
7
- import { t as endpoints } from "./endpoints-CwrFQfW7.esm.js";
8
- import "./stats-BVy52wLy.esm.js";
9
- import "./sessionInitializer-Dj7-aJaP.esm.js";
10
- import "./browserSimulation-DZwEy9bu.esm.js";
11
- import "./platform-0Ot-bF_a.esm.js";
12
- import "./getBrowser-1yNcfFZR.esm.js";
13
- import "./tri-CFAPtAUM.esm.js";
14
- import { a as fromPromise, i as fromCallback, l as createManager, r as assign, s as createActor, t as setup } from "./xstate.esm-nY3M5UYm.esm.js";
15
- import "./MotionSensorProvider-BHuHoYvJ.esm.js";
16
- import { t as checkPermission } from "./permissionServices-C_kxhNeo.esm.js";
17
- import { i as requestCameraWithFallback, r as requestCameraAccess } from "./camera-CxxXV0VN.esm.js";
18
- import { a as encryptSelfieImage, b as FaceDetectionProvider, l as startDetection, m as uploadSelfie, p as processFace, y as StreamCanvasProcessingSession } from "./onDeviceFaceResults-DILtthks.esm.js";
19
- import "./ITimerCapability-DJ73P4RK.esm.js";
20
- import "./canvas-Pi10hG_l.esm.js";
21
- import { n as getBackCameraStream } from "./backCameraStream-ChrMTJv-.esm.js";
22
- import "./video-ZY92rkel.esm.js";
23
- import { n as getWindowDimensions } from "./getDeviceClass-C-Dg6IsJ.esm.js";
24
- import "./deepsightService-CViys6T4.esm.js";
25
- import "./getDeviceClass-DIjnTPjR.esm.js";
26
- import "./types-BKLb3C42.esm.js";
27
- import { t as StreamCanvasCapture } from "./StreamCanvasCapture-CAqUdVkM.esm.js";
28
- import { n as getSupportedMediaRecorderMimeType } from "./mediaRecorderOptions-CClCKAiF.esm.js";
29
- import { n as resolveVideoSelfieSteps, r as videoSelfieWasmPipelines, t as facingModeForStep } from "./videoSelfieSteps-Djpv7cjb.esm.js";
30
- import { i as IdCaptureProvider, n as DEFAULT_ID_CAPTURE_MODEL_VERSION, r as DEFAULT_ID_CAPTURE_THRESHOLDS, t as DEFAULT_ID_CAPTURE_GEOMETRY } from "./idCaptureDefaults-CZajItdO.esm.js";
31
-
32
- //#region src/modules/video-selfie/videoSelfieCompareService.ts
33
- async function postVideoSelfieCompare(endpoint, base64Image) {
34
- return (await api.post(endpoint, { base64Image })).data;
35
- }
36
- /** Compare a front-ID frame from the video selfie against the captured ID. */
37
- const compareVideoSelfieId = (base64Image) => postVideoSelfieCompare(endpoints.videoSelfieCompareId, base64Image);
38
- /** Compare OCR from a front-ID frame against the captured ID's OCR. */
39
- const compareVideoSelfieOcr = (base64Image) => postVideoSelfieCompare(endpoints.videoSelfieCompareOcr, base64Image);
40
- /** Compare a back-ID frame from the video selfie against the captured ID. */
41
- const compareVideoSelfieBackId = (base64Image) => postVideoSelfieCompare(endpoints.videoSelfieCompareBackId, base64Image);
42
- /** Compare OCR from a back-ID frame against the captured ID's OCR. */
43
- const compareVideoSelfieBackOcr = (base64Image) => postVideoSelfieCompare(endpoints.videoSelfieCompareBackOcr, base64Image);
44
-
45
- //#endregion
46
- //#region src/modules/video-selfie/videoSelfieStepDetector.ts
47
- /** Default autocapture window for the selfie step when the config omits one. */
48
- const SELFIE_AUTOCAPTURE_MS = 1e4;
49
- /**
50
- * Whether the backend reported a confident face match on a front-ID compare.
51
- * The backend normalizes `faceRecognitionConfidence` to 0 (no match) or 1 (match).
52
- */
53
- function isFaceRecognitionMatch(confidence) {
54
- if (typeof confidence !== "number") return true;
55
- return confidence >= 1;
56
- }
57
- /**
58
- * Max selfie capture attempts before the step fails. Each backend rejection
59
- * (e.g. 4077 low quality / liveness) re-arms the pipeline and scans again;
60
- * after this many tries the step rejects. Mirrors V1's `numberOfTries`.
61
- */
62
- const MAX_SELFIE_ATTEMPTS = 3;
63
- /**
64
- * How long the ID step holds on the "success" state (green check) after the
65
- * backend validates a side, before advancing. Gives the user a beat to see the
66
- * capture succeeded instead of the step jumping silently. Mirrors V1's
67
- * IdVideoSelfie success flash.
68
- */
69
- const ID_SUCCESS_DWELL_MS = 900;
70
- /**
71
- * How long an ID step holds the "show the front / back of your ID" instruction
72
- * before autocapture is armed. No frame is captured or validated during this
73
- * window, so the guidance can't be overwritten by capture feedback before the
74
- * user has read it. Mirrors the UI's `ID_INSTRUCTION_DWELL_MS` message pin.
75
- */
76
- const ID_INSTRUCTION_DWELL_MS = 3e3;
77
- /** Resolves after `ms`, or rejects early if `signal` aborts. */
78
- function delay(ms, signal) {
79
- const timerProvider = BrowserTimerProvider.getInstance();
80
- return new Promise((resolve, reject) => {
81
- const timer = timerProvider.setTimeout(() => {
82
- signal.removeEventListener("abort", onAbort);
83
- resolve();
84
- }, ms);
85
- const onAbort = () => {
86
- timerProvider.clearTimeout(timer);
87
- reject(/* @__PURE__ */ new Error("aborted"));
88
- };
89
- signal.addEventListener("abort", onAbort, { once: true });
90
- });
91
- }
92
- /**
93
- * Builds the default per-step detector from the module config. Today it
94
- * auto-captures the `selfie` step (face detection → `add/face` → `process/face`);
95
- * ID / proof-of-address / questions / speech advance manually until their
96
- * detectors land.
97
- */
98
- function createDefaultStepDetector(config, deps) {
99
- return ({ step, stream, signal, onStatus }) => {
100
- if (step === "selfie") return detectSelfie({
101
- config,
102
- deps,
103
- stream,
104
- signal,
105
- onStatus
106
- });
107
- if (step === "frontId" || step === "backId") return detectId({
108
- step,
109
- config,
110
- stream,
111
- signal,
112
- onStatus
113
- });
114
- return new Promise(() => {});
115
- };
116
- }
117
- async function detectSelfie(params) {
118
- const { config, deps, stream, signal, onStatus } = params;
119
- const provider = new FaceDetectionProvider();
120
- await provider.initialize({
121
- autocaptureInterval: SELFIE_AUTOCAPTURE_MS,
122
- useOnDeviceWorkflow: false,
123
- videoSelfie: true
124
- });
125
- provider.setChecksEnabled({
126
- lenses: config.validateLenses ?? false,
127
- mask: config.validateFaceMask ?? false,
128
- closedEyes: config.validateClosedEyes ?? false,
129
- headWear: config.validateHeadCover ?? false,
130
- occlusion: false
131
- });
132
- const imageType = config.useAsSelfie === true ? "selfie" : "videoSelfie";
133
- const capturer = new StreamCanvasCapture(stream);
134
- const detectionConfig = {
135
- showTutorial: false,
136
- validateBrightness: false,
137
- validateLenses: config.validateLenses ?? false,
138
- validateFaceMask: config.validateFaceMask ?? false,
139
- validateClosedEyes: config.validateClosedEyes ?? false,
140
- validateHeadCover: config.validateHeadCover ?? false,
141
- autoCaptureTimeout: SELFIE_AUTOCAPTURE_MS / 1e3
142
- };
143
- const runAttempt = () => new Promise((resolve, reject) => {
144
- const onAbort = () => {
145
- detection.cleanup();
146
- reject(/* @__PURE__ */ new Error("aborted"));
147
- };
148
- const settle = (run) => {
149
- signal.removeEventListener("abort", onAbort);
150
- run();
151
- };
152
- signal.addEventListener("abort", onAbort, { once: true });
153
- const detection = startDetection({
154
- config: detectionConfig,
155
- capturer,
156
- provider,
157
- onUpdate: (status) => onStatus?.(status),
158
- onSuccess: (canvas, faceCoordinates) => {
159
- (async () => {
160
- try {
161
- await uploadSelfie({
162
- encryptedBase64Image: await encryptSelfieImage({
163
- canvas,
164
- dependencies: { getWasmUtil: async () => deps.getWasmUtil() }
165
- }),
166
- faceCoordinates,
167
- imageType
168
- });
169
- await processFace(imageType);
170
- settle(resolve);
171
- } catch (error$1) {
172
- settle(() => reject(error$1 instanceof Error ? error$1 : new Error(String(error$1))));
173
- }
174
- })();
175
- }
176
- });
177
- });
178
- try {
179
- for (let attempt = 1; attempt <= MAX_SELFIE_ATTEMPTS; attempt++) try {
180
- await runAttempt();
181
- return;
182
- } catch (error$1) {
183
- if (signal.aborted || attempt >= MAX_SELFIE_ATTEMPTS) throw error$1;
184
- onStatus?.("error");
185
- provider.reset();
186
- await delay(1500, signal);
187
- }
188
- } finally {
189
- capturer.dispose();
190
- provider.dispose();
191
- }
192
- }
193
- async function detectId(params) {
194
- const { step, config, stream, signal, onStatus } = params;
195
- const provider = new IdCaptureProvider();
196
- await provider.initialize({ videoSelfie: true });
197
- const windowDimensions = getWindowDimensions();
198
- provider.setGeometry({
199
- ...DEFAULT_ID_CAPTURE_GEOMETRY,
200
- windowOuterWidth: windowDimensions.outerWidth,
201
- windowOuterHeight: windowDimensions.outerHeight,
202
- windowInnerWidth: windowDimensions.innerWidth,
203
- windowInnerHeight: windowDimensions.innerHeight
204
- });
205
- provider.setSettings({
206
- isFixedMask: false,
207
- isIPhone14OrHigher: false,
208
- idType: step === "backId" ? "BackId" : "FrontId",
209
- blurCheckEnabled: true,
210
- glareCheckEnabled: false,
211
- faceQualityCheckEnabled: false,
212
- iouCheckEnabled: true,
213
- fpsLimitEnabled: false
214
- });
215
- provider.setThresholds(DEFAULT_ID_CAPTURE_THRESHOLDS);
216
- provider.setModelType(DEFAULT_ID_CAPTURE_MODEL_VERSION);
217
- const capturer = new StreamCanvasCapture(stream);
218
- return new Promise((resolve, reject) => {
219
- let validating = false;
220
- let armed = false;
221
- provider.setCallbacks({
222
- onFarAway: () => {
223
- if (armed && !validating) onStatus?.("tooFar");
224
- },
225
- onBlur: () => {
226
- if (armed && !validating) onStatus?.("blur");
227
- },
228
- onCapturing: () => {
229
- if (!armed || validating) return;
230
- const base64Image = capturer.getLatestCanvas()?.getBase64Image();
231
- if (!base64Image) return;
232
- validating = true;
233
- onStatus?.("capturing");
234
- (async () => {
235
- try {
236
- if (await validateIdFrame(step, config, base64Image)) {
237
- onStatus?.("success");
238
- await delay(ID_SUCCESS_DWELL_MS, signal);
239
- teardown();
240
- resolve();
241
- return;
242
- }
243
- validating = false;
244
- } catch (error$1) {
245
- teardown();
246
- reject(error$1 instanceof Error ? error$1 : new Error(String(error$1)));
247
- }
248
- })();
249
- }
250
- });
251
- const session = new StreamCanvasProcessingSession({
252
- capturer,
253
- provider
254
- });
255
- let toreDown = false;
256
- const teardown = () => {
257
- if (toreDown) return;
258
- toreDown = true;
259
- session.dispose();
260
- capturer.dispose();
261
- provider.dispose();
262
- };
263
- signal.addEventListener("abort", () => {
264
- teardown();
265
- reject(/* @__PURE__ */ new Error("aborted"));
266
- }, { once: true });
267
- delay(ID_INSTRUCTION_DWELL_MS, signal).then(() => {
268
- if (toreDown || signal.aborted) return;
269
- armed = true;
270
- onStatus?.("detecting");
271
- }).catch(() => {});
272
- });
273
- }
274
- /** Runs the configured ID/OCR comparisons for a captured ID frame. */
275
- async function validateIdFrame(step, config, base64Image) {
276
- if (step === "backId") {
277
- if (config.compareBackIdEnabled) {
278
- const result = await compareVideoSelfieBackId(base64Image);
279
- if (result.idSideMatched === false || result.success === false) return false;
280
- }
281
- if (config.compareBackOcrEnabled) {
282
- if ((await compareVideoSelfieBackOcr(base64Image)).success === false) return false;
283
- }
284
- return true;
285
- }
286
- if (config.compareIdEnabled) {
287
- const result = await compareVideoSelfieId(base64Image);
288
- if (result.idTypeMatched === false) return false;
289
- if (typeof result.faceRecognitionConfidence === "number" && !isFaceRecognitionMatch(result.faceRecognitionConfidence)) return false;
290
- }
291
- if (config.compareOcrEnabled) {
292
- if ((await compareVideoSelfieOcr(base64Image)).success === false) return false;
293
- }
294
- return true;
295
- }
296
-
297
- //#endregion
298
- //#region ../infra/src/media/CameraCompositor.ts
299
- /**
300
- * Composites the *active* camera into a canvas and exposes the canvas as a
301
- * single, stable `MediaStream` to record. Switching cameras (front ↔ back)
302
- * just repoints what the canvas draws — the output stream and its audio track
303
- * are never replaced — so a single `MediaRecorder` produces one continuous
304
- * video that follows the camera switches (V1 parity), instead of restarting
305
- * per camera.
306
- *
307
- * The audio track from the initial stream is carried through unchanged across
308
- * video switches, so there's no audio glitch when the camera flips.
309
- */
310
- var CameraCompositor = class {
311
- constructor(options = {}) {
312
- this.canvas = null;
313
- this.ctx = null;
314
- this.video = null;
315
- this.rafId = null;
316
- this.audioTrack = null;
317
- this.videoTrack = null;
318
- this.composite = null;
319
- this.fps = options.fps ?? 30;
320
- }
321
- /**
322
- * Begin compositing `stream` and return the composite stream to record. The
323
- * stream's audio track (if any) is carried through unchanged across later
324
- * `switchVideo` calls.
325
- */
326
- start(stream) {
327
- this.canvas = document.createElement("canvas");
328
- this.ctx = this.canvas.getContext("2d");
329
- this.video = document.createElement("video");
330
- this.video.muted = true;
331
- this.video.playsInline = true;
332
- this.audioTrack = stream.getAudioTracks()[0] ?? null;
333
- this.setVideoSource(stream);
334
- const composite = this.canvas.captureStream(this.fps);
335
- if (this.audioTrack) composite.addTrack(this.audioTrack);
336
- this.composite = composite;
337
- this.startDrawLoop();
338
- return composite;
339
- }
340
- /**
341
- * Swap the camera feeding the canvas without interrupting the composite
342
- * stream. Pass a video-only stream (audio is kept from `start`). The previous
343
- * video track is stopped.
344
- */
345
- switchVideo(stream) {
346
- if (!this.composite) return;
347
- const previousVideoTrack = this.videoTrack;
348
- this.setVideoSource(stream);
349
- if (previousVideoTrack) previousVideoTrack.stop();
350
- }
351
- /** The composite stream being recorded, if compositing is active. */
352
- get stream() {
353
- return this.composite ?? void 0;
354
- }
355
- /** Stop compositing and release the canvas, audio, and video tracks. */
356
- stop() {
357
- if (this.rafId !== null) {
358
- cancelAnimationFrame(this.rafId);
359
- this.rafId = null;
360
- }
361
- this.videoTrack?.stop();
362
- this.audioTrack?.stop();
363
- this.composite?.getTracks().forEach((track) => track.stop());
364
- if (this.video) this.video.srcObject = null;
365
- this.canvas = null;
366
- this.ctx = null;
367
- this.video = null;
368
- this.videoTrack = null;
369
- this.audioTrack = null;
370
- this.composite = null;
371
- }
372
- setVideoSource(stream) {
373
- this.videoTrack = stream.getVideoTracks()[0] ?? null;
374
- const video = this.video;
375
- if (!video) return;
376
- video.srcObject = new MediaStream(stream.getVideoTracks());
377
- video.play().catch(() => {});
378
- }
379
- startDrawLoop() {
380
- const draw = () => {
381
- const video = this.video;
382
- const canvas = this.canvas;
383
- const ctx = this.ctx;
384
- if (video && canvas && ctx && video.videoWidth > 0) {
385
- if (canvas.width !== video.videoWidth || canvas.height !== video.videoHeight) {
386
- canvas.width = video.videoWidth;
387
- canvas.height = video.videoHeight;
388
- }
389
- ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
390
- }
391
- this.rafId = requestAnimationFrame(draw);
392
- };
393
- this.rafId = requestAnimationFrame(draw);
394
- }
395
- };
396
-
397
- //#endregion
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-CYdVacqv.esm.js";
3
+ import { t as BrowserTimerProvider } from "./BrowserTimerProvider-BXhgNxLt.esm.js";
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-unhF9V9F.esm.js";
7
+ import { c as createManager, o as createActor, r as assign, t as setup } from "./xstate.esm-Cf4e0Cfd.esm.js";
8
+ import { n as fromPromise, t as fromCallback } from "./xstate-actors.esm-CtI5S0f4.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-h_VUk5Vu.esm.js";
398
11
  //#region ../infra/src/providers/browser/MultipartRecordingProvider.ts
399
12
  /**
400
- * S3 multipart requires every part except the last to be at least 5 MB, so we
401
- * buffer recorded data until it crosses this threshold before emitting a part.
402
- */
403
- const MIN_PART_SIZE_BYTES = 5 * 1024 * 1024;
404
- /**
405
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.
406
19
  */
407
- const TIMESLICE_MS = 1e3;
20
+ const TIMESLICE_MS = 500;
408
21
  /**
409
22
  * Encoder target for the full video-selfie session. Higher than the
410
- * short-clip liveness path (0.5–1 Mbps) so a multi-minute session keeps usable
411
- * quality and accumulates past the 5 MB part threshold instead of compressing a
412
- * near-static face down to a single sub-5 MB part. It's a ceiling — a still
413
- * scene still encodes well below it.
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.
414
25
  */
415
26
  const VIDEO_BITS_PER_SECOND = 25e5;
416
27
  /**
417
- * Records a stream and streams it out as size-bounded parts for S3 multipart
418
- * upload. Parts are emitted during recording (not buffered to the end), so the
419
- * client never holds more than ~one part in memory regardless of video length.
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.
420
35
  *
421
36
  * Unlike the short-clip liveness recorder, this does NOT auto-pause on
422
37
  * `visibilitychange`: a video-selfie session must record continuously, and a
@@ -430,8 +45,6 @@ var MultipartRecordingProvider = class {
430
45
  this._hasError = false;
431
46
  this._error = null;
432
47
  this.mimeType = "";
433
- this.buffer = [];
434
- this.bufferedBytes = 0;
435
48
  this.partNumber = 0;
436
49
  this.onPart = null;
437
50
  }
@@ -446,8 +59,6 @@ var MultipartRecordingProvider = class {
446
59
  }
447
60
  startRecording(stream, onPart) {
448
61
  this.reset();
449
- this.buffer = [];
450
- this.bufferedBytes = 0;
451
62
  this.partNumber = 0;
452
63
  this.onPart = onPart;
453
64
  try {
@@ -457,14 +68,17 @@ var MultipartRecordingProvider = class {
457
68
  videoBitsPerSecond: VIDEO_BITS_PER_SECOND
458
69
  });
459
70
  recorder.ondataavailable = (event) => {
460
- if (event.data.size > 0) {
461
- this.buffer.push(event.data);
462
- this.bufferedBytes += event.data.size;
463
- if (this.bufferedBytes >= MIN_PART_SIZE_BYTES) this.flushPart();
71
+ if (event.data.size > 0 && this.onPart) {
72
+ this.partNumber += 1;
73
+ this.onPart({
74
+ chunk: event.data,
75
+ partNumber: this.partNumber
76
+ });
464
77
  }
465
78
  };
466
79
  recorder.onerror = (event) => {
467
- this._error = `Recording error: ${event instanceof ErrorEvent && event.error instanceof Error ? event.error.message : event.type}`;
80
+ const detail = event instanceof ErrorEvent && event.error instanceof Error ? event.error.message : event.type;
81
+ this._error = `Recording error: ${detail}`;
468
82
  this._isRecording = false;
469
83
  this._hasError = true;
470
84
  };
@@ -474,7 +88,8 @@ var MultipartRecordingProvider = class {
474
88
  this._error = null;
475
89
  this._hasError = false;
476
90
  } catch (err) {
477
- this._error = `Failed to start recording: ${err instanceof Error ? err.message : String(err)}`;
91
+ const detail = err instanceof Error ? err.message : String(err);
92
+ this._error = `Failed to start recording: ${detail}`;
478
93
  this._hasError = true;
479
94
  }
480
95
  }
@@ -483,7 +98,6 @@ var MultipartRecordingProvider = class {
483
98
  return new Promise((resolve) => {
484
99
  if (recorder && this._isRecording) {
485
100
  recorder.onstop = () => {
486
- this.flushPart();
487
101
  resolve();
488
102
  };
489
103
  recorder.stop();
@@ -503,202 +117,315 @@ var MultipartRecordingProvider = class {
503
117
  this.mediaRecorder = null;
504
118
  }
505
119
  this.onPart = null;
506
- this.buffer = [];
507
- this.bufferedBytes = 0;
508
120
  this._isRecording = false;
509
121
  this._error = null;
510
122
  this._hasError = false;
511
123
  }
512
- flushPart() {
513
- if (this.bufferedBytes === 0 || !this.onPart) return;
514
- const chunk = new Blob(this.buffer, { type: this.mimeType });
515
- this.partNumber += 1;
516
- this.onPart({
517
- chunk,
518
- partNumber: this.partNumber
519
- });
520
- this.buffer = [];
521
- this.bufferedBytes = 0;
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
+ };
522
134
  }
523
135
  };
524
-
525
136
  //#endregion
526
- //#region src/internal/recordings/videoSelfieUploadService.ts
137
+ //#region src/internal/recordings/videoSelfieChunkUploader.ts
527
138
  /**
528
- * Opens a multipart video-selfie upload session. The returned `uploadId`
529
- * identifies the session for subsequent part uploads and completion.
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.
530
142
  */
531
- async function initiateVideoSelfieUpload() {
532
- return (await api.post(endpoints.videoSelfieUploadInitiate, {})).data.uploadId;
533
- }
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;
534
152
  /**
535
- * Uploads a single chunk as a multipart part. The body is the raw video bytes
536
- * (no base64, no client-side encryption encryption at rest is server-side
537
- * S3 SSE). Returns the part number + `eTag` needed to complete the upload.
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.
538
157
  */
539
- async function uploadVideoSelfiePart(uploadId, partNumber, chunk) {
540
- const response = await api.post(endpoints.videoSelfieUploadPart, chunk, {
541
- query: {
542
- uploadId,
543
- partNumber
544
- },
545
- headers: { "Content-Type": "application/octet-stream" }
546
- });
547
- return {
548
- partNumber: response.data.partNumber,
549
- eTag: response.data.eTag
550
- };
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;
551
170
  }
552
171
  /**
553
- * Finalizes the upload. `parts` must be in ascending `partNumber` order, or
554
- * S3 reassembly fails. Returns the server-reported status.
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.
555
194
  */
556
- async function completeVideoSelfieUpload(uploadId, parts) {
557
- return (await api.post(endpoints.videoSelfieUploadComplete, {
558
- uploadId,
559
- parts
560
- })).data.status;
561
- }
562
-
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
+ };
563
319
  //#endregion
564
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;
327
+ }
565
328
  /**
566
329
  * Records the camera on-device and streams it to the backend as it is
567
- * captured, using the S3 multipart upload protocol
568
- * (`/omni/video-selfie/upload/*`).
330
+ * captured, using the video-selfie-service multipart upload protocol
331
+ * (`/v1/video-upload/*`).
569
332
  *
570
333
  * This is the Video Selfie module's client-side recorder and is deliberately
571
334
  * independent of the face-capture recording services (`LocalRecordingService`
572
335
  * / `OpenViduRecordingService`) — it is the replacement for server-side
573
336
  * (OpenVidu) recording, not a sibling of it.
574
337
  *
575
- * Parts upload concurrently with recording, so `stop()` only flushes the final
576
- * part and finalizes keeping the whole session inside the server's
577
- * video-selfie timeout regardless of length, with client memory bounded to
578
- * ~one part. No client-side encryption: video is encrypted at rest server-side
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
579
344
  * (S3 SSE-AES-256).
580
345
  */
581
346
  var MultipartRecordingService = class {
582
347
  constructor() {
583
348
  this.recorder = new MultipartRecordingProvider();
584
- this.uploadId = null;
585
- this.parts = [];
586
- this.inflight = [];
587
- this.uploadFailed = false;
349
+ this.timer = BrowserTimerProvider.getInstance();
350
+ this.session = null;
351
+ this.uploader = null;
352
+ this.chunksEmitted = 0;
588
353
  }
589
354
  get isRecording() {
590
355
  return this.recorder.isRecording;
591
356
  }
592
357
  async start(stream) {
593
- this.uploadId = await initiateVideoSelfieUpload();
594
- this.parts = [];
595
- this.inflight = [];
596
- this.uploadFailed = false;
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;
597
369
  this.recorder.startRecording(stream, ({ chunk, partNumber }) => {
598
- const uploadId = this.uploadId;
599
- if (!uploadId) return;
600
- const task = uploadVideoSelfiePart(uploadId, partNumber, chunk).then((part) => {
601
- this.parts.push(part);
602
- }).catch(() => {
603
- this.uploadFailed = true;
604
- });
605
- this.inflight.push(task);
370
+ this.chunksEmitted += 1;
371
+ this.uploader?.enqueue(partNumber, chunk);
606
372
  });
607
373
  }
608
374
  async stop() {
609
- const uploadId = this.uploadId;
610
- if (!this.recorder.isRecording || !uploadId) return { recordingId: null };
375
+ const session = this.session;
376
+ const uploader = this.uploader;
377
+ if (!this.recorder.isRecording || !session || !uploader) return { recordingId: null };
611
378
  await this.recorder.stopRecording();
612
- await Promise.all(this.inflight);
613
- if (this.uploadFailed || this.parts.length === 0) return { recordingId: null };
614
- const orderedParts = [...this.parts].sort((a, b) => a.partNumber - b.partNumber);
379
+ if (!await uploader.drain() || uploader.failed || this.chunksEmitted === 0) {
380
+ this.abandonUpload(session);
381
+ return { recordingId: null };
382
+ }
615
383
  try {
616
- await completeVideoSelfieUpload(uploadId, orderedParts);
617
- return { recordingId: uploadId };
384
+ await this.completeWithRetry(session);
385
+ this.session = null;
386
+ this.uploader = null;
387
+ return { recordingId: session.uploadId };
618
388
  } catch {
389
+ this.abandonUpload(session);
619
390
  return { recordingId: null };
620
391
  }
621
392
  }
622
393
  cleanup() {
394
+ if (this.session) this.abandonUpload(this.session);
623
395
  this.recorder.reset();
624
396
  }
625
- };
626
-
627
- //#endregion
628
- //#region src/modules/video-selfie/videoSelfieCameraWarmer.ts
629
- /**
630
- * Acquire the camera for a Video Selfie step. The rear (`environment`) steps
631
- * (frontId / backId / poa) route through {@link getBackCameraStream} so the
632
- * main autofocus lens is selected — Samsung's default `facingMode:environment`
633
- * camera is often a fixed-focus auxiliary lens, which blurs the ID steps and
634
- * stalls capture (client-side blur check is on). This mirrors the ID Capture
635
- * module. `getBackCameraStream` returns video only, so audio is acquired and
636
- * merged separately when the step needs it. Front (`user`) steps keep the
637
- * plain fallback path. Used both as the recording machine's default
638
- * `acquireCamera` dependency and as this warmer's own acquire/fallback.
639
- */
640
- async function defaultAcquireCamera(facingMode, withAudio) {
641
- if (facingMode !== "environment") return requestCameraWithFallback({
642
- video: { facingMode },
643
- audio: withAudio
644
- });
645
- const { stream } = await getBackCameraStream();
646
- if (withAudio) try {
647
- const audioStream = await requestCameraAccess({ audio: true });
648
- for (const audioTrack of audioStream.getAudioTracks()) stream.addTrack(audioTrack);
649
- } catch (error$1) {
650
- stream.getTracks().forEach((track) => track.stop());
651
- throw error$1;
652
- }
653
- return stream;
654
- }
655
- function stopStream(stream) {
656
- stream?.getTracks().forEach((track) => track.stop());
657
- }
658
- /**
659
- * Creates a {@link VideoSelfieCameraWarmer} for the given config. The first
660
- * camera (and whether it needs audio) is derived from the resolved step order —
661
- * the same first acquire the recording machine performs on `START`.
662
- */
663
- function createVideoSelfieCameraWarmer(config) {
664
- const firstFacing = facingModeForStep(resolveVideoSelfieSteps(config)[0] ?? "selfie");
665
- let warming = null;
666
- let warmed = null;
667
- let consumed = false;
668
- return {
669
- warm() {
670
- if (warming) return;
671
- warming = (async () => {
672
- try {
673
- if (await checkPermission() !== "granted") return null;
674
- warmed = await defaultAcquireCamera(firstFacing, true);
675
- return warmed;
676
- } catch {
677
- return null;
678
- }
679
- })();
680
- },
681
- async acquireCamera(facingMode, withAudio) {
682
- if (!consumed && facingMode === firstFacing && withAudio) {
683
- consumed = true;
684
- const stream = warmed ?? (warming ? await warming : null);
685
- warmed = null;
686
- if (stream) return stream;
687
- }
688
- return defaultAcquireCamera(facingMode, withAudio);
689
- },
690
- dispose() {
691
- if (consumed) return;
692
- if (warmed) {
693
- stopStream(warmed);
694
- warmed = null;
695
- } else if (warming) warming.then((stream) => {
696
- if (!consumed) stopStream(stream);
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);
697
413
  });
698
414
  }
699
- };
700
- }
701
-
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
+ };
702
429
  //#endregion
703
430
  //#region src/modules/video-selfie/videoSelfieRecordingMachine.ts
704
431
  /** A detector that never settles — used when a step has no auto-capture yet. */
@@ -718,6 +445,52 @@ function detectionStatusFromEvent(event) {
718
445
  function detectionErrorFromEvent(event) {
719
446
  return event.error;
720
447
  }
448
+ function validationFailureFromEvent(event) {
449
+ return event.failure;
450
+ }
451
+ function errorKindFromEvent(event) {
452
+ return event.kind;
453
+ }
454
+ function retryableFailureFromEvent(event) {
455
+ return event.failure;
456
+ }
457
+ function orientationFromEvent(event) {
458
+ return event.orientation;
459
+ }
460
+ const SWITCHING_CAMERA_MIN_DWELL_MS = 3e3;
461
+ const ID_FLIP_DWELL_MS = 4e3;
462
+ const FINAL_SUCCESS_DWELL_MS = 3e3;
463
+ const VALIDATION_FEEDBACK_DWELL_MS = 3e3;
464
+ const DEFAULT_ATTEMPTS_PER_STEP = 3;
465
+ const UNLIMITED_ATTEMPTS = -1;
466
+ function normalizeAttempts(attempts) {
467
+ if (attempts === UNLIMITED_ATTEMPTS) return UNLIMITED_ATTEMPTS;
468
+ if (typeof attempts === "number" && attempts > 0) return attempts;
469
+ return DEFAULT_ATTEMPTS_PER_STEP;
470
+ }
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;
478
+ }
479
+ function waitForDwell(ms, signal) {
480
+ const timerProvider = BrowserTimerProvider.getInstance();
481
+ return new Promise((resolve) => {
482
+ const onAbort = () => {
483
+ timerProvider.clearTimeout(timer);
484
+ resolve(false);
485
+ };
486
+ const timer = timerProvider.setTimeout(() => {
487
+ signal.removeEventListener("abort", onAbort);
488
+ resolve(true);
489
+ }, ms);
490
+ signal.addEventListener("abort", onAbort, { once: true });
491
+ if (signal.aborted) onAbort();
492
+ });
493
+ }
721
494
  /**
722
495
  * Orchestrates a multi-step Video Selfie session as ONE continuous recording
723
496
  * that follows the camera between steps AND auto-advances per step:
@@ -731,9 +504,9 @@ function detectionErrorFromEvent(event) {
731
504
  * validation; success advances the step (switching the camera when the next
732
505
  * step's facing differs), and the final step finalizes the multipart upload.
733
506
  *
734
- * Teardown: `ABORT` is accepted from ANY non-final state and every terminal
735
- * state runs `cleanup` on entry, so no settled path leaves camera or mic
736
- * tracks running. XState v5 executes NO exit actions on an external
507
+ * Teardown: `ABORT` is accepted from ANY non-final state and every settled
508
+ * path runs `cleanup`, so no path leaves camera or mic tracks running.
509
+ * XState v5 executes NO exit actions on an external
737
510
  * `actor.stop()`, so the manager sends `ABORT` before stopping the actor —
738
511
  * never stop this actor directly without aborting first.
739
512
  */
@@ -743,6 +516,11 @@ const videoSelfieRecordingSetup = setup({
743
516
  events: {},
744
517
  input: {}
745
518
  },
519
+ delays: {
520
+ ID_FLIP_DWELL: ID_FLIP_DWELL_MS,
521
+ FINAL_SUCCESS_DWELL: FINAL_SUCCESS_DWELL_MS,
522
+ VALIDATION_FEEDBACK_DWELL: VALIDATION_FEEDBACK_DWELL_MS
523
+ },
746
524
  actors: {
747
525
  acquireCamera: fromPromise(async ({ input, signal }) => {
748
526
  const stream = await input.acquire(input.facingMode, input.withAudio);
@@ -752,6 +530,23 @@ const videoSelfieRecordingSetup = setup({
752
530
  }
753
531
  return stream;
754
532
  }),
533
+ switchCamera: fromPromise(async ({ input, signal }) => {
534
+ const dwellCompleted = waitForDwell(input.minDwellMs, signal);
535
+ const stream = await input.acquire(input.facingMode, false);
536
+ if (signal.aborted) {
537
+ stream.getTracks().forEach((track) => track.stop());
538
+ throw new Error("Camera switch cancelled");
539
+ }
540
+ if (!await dwellCompleted) {
541
+ stream.getTracks().forEach((track) => track.stop());
542
+ throw new Error("Camera switch cancelled");
543
+ }
544
+ if (signal.aborted) {
545
+ stream.getTracks().forEach((track) => track.stop());
546
+ throw new Error("Camera switch cancelled");
547
+ }
548
+ return stream;
549
+ }),
755
550
  startRecording: fromPromise(async ({ input }) => {
756
551
  await input.service.start(input.stream);
757
552
  }),
@@ -765,35 +560,104 @@ const videoSelfieRecordingSetup = setup({
765
560
  onStatus: (status) => sendBack({
766
561
  type: "DETECTION_STATUS",
767
562
  status
563
+ }),
564
+ onOrientation: (orientation) => sendBack({
565
+ type: "ORIENTATION",
566
+ orientation
768
567
  })
769
- }).then(() => sendBack({ type: "DETECTION_DONE" })).catch((err) => {
568
+ }).then((result) => {
569
+ if (result.outcome === "retryableFailure") {
570
+ sendBack({
571
+ type: "RETRYABLE_FAILURE",
572
+ failure: result.failure
573
+ });
574
+ return;
575
+ }
576
+ if (result.outcome === "validationFailed") {
577
+ sendBack({
578
+ type: "VALIDATION_FAILED",
579
+ failure: result.failure
580
+ });
581
+ return;
582
+ }
583
+ sendBack({ type: "DETECTION_DONE" });
584
+ }).catch((err) => {
770
585
  if (!controller.signal.aborted) sendBack({
771
586
  type: "DETECTION_FAILED",
772
- error: String(err)
587
+ error: String(err),
588
+ kind: isConnectionError(err) ? "connection" : "technical"
773
589
  });
774
590
  });
775
591
  return () => controller.abort();
776
592
  })
777
593
  },
778
594
  actions: {
779
- advanceStep: assign({ stepIndex: ({ context: context$1 }) => context$1.stepIndex + 1 }),
595
+ advanceStep: assign({
596
+ stepIndex: ({ context }) => context.stepIndex + 1,
597
+ attemptsRemaining: ({ context }) => context.attemptsPerStep,
598
+ validationFailure: () => void 0
599
+ }),
600
+ advancePastIdSection: assign({
601
+ stepIndex: ({ context }) => nextModuleIndex(context),
602
+ attemptsRemaining: ({ context }) => context.attemptsPerStep,
603
+ validationFailure: () => void 0
604
+ }),
780
605
  setDetectionStatus: assign({ detectionStatus: ({ event }) => detectionStatusFromEvent(event) }),
606
+ setOrientation: assign({ orientation: ({ event }) => orientationFromEvent(event) }),
781
607
  setDetectionError: assign({ detectionError: ({ event }) => detectionErrorFromEvent(event) }),
782
- setErrorFromDetection: assign({ error: ({ event }) => detectionErrorFromEvent(event) }),
608
+ setValidationFailure: assign(({ context, event }) => ({
609
+ attemptsRemaining: context.attemptsRemaining === UNLIMITED_ATTEMPTS ? UNLIMITED_ATTEMPTS : Math.max(0, context.attemptsRemaining - 1),
610
+ validationFailure: validationFailureFromEvent(event),
611
+ detectionStatus: "error"
612
+ })),
613
+ setUncountedRetryableFailure: assign(({ event }) => ({
614
+ validationFailure: retryableFailureFromEvent(event),
615
+ detectionStatus: "error"
616
+ })),
617
+ setErrorFromDetection: assign({
618
+ error: ({ event }) => detectionErrorFromEvent(event),
619
+ errorKind: ({ event }) => errorKindFromEvent(event)
620
+ }),
783
621
  clearDetectionFeedback: assign({
784
622
  detectionStatus: () => void 0,
785
- detectionError: () => void 0
623
+ detectionError: () => void 0,
624
+ validationFailure: () => void 0,
625
+ orientation: () => void 0
626
+ }),
627
+ setUploadFailedError: assign({
628
+ error: () => "Video upload failed",
629
+ errorKind: () => "connection"
786
630
  }),
787
- setUploadFailedError: assign({ error: () => "Video upload failed" }),
788
- cleanup: ({ context: context$1 }) => {
789
- context$1.service.cleanup();
790
- context$1.compositor.stop();
791
- context$1.stream?.getTracks().forEach((track) => track.stop());
631
+ resetSession: assign(({ context }) => ({
632
+ stepIndex: 0,
633
+ stream: void 0,
634
+ composite: void 0,
635
+ detectionStatus: void 0,
636
+ orientation: void 0,
637
+ detectionError: void 0,
638
+ validationFailure: void 0,
639
+ attemptsRemaining: context.attemptsPerStep,
640
+ recordingId: null,
641
+ error: void 0,
642
+ errorKind: void 0
643
+ })),
644
+ cleanup: ({ context }) => {
645
+ context.service.cleanup();
646
+ context.compositor.stop();
647
+ context.stream?.getTracks().forEach((track) => track.stop());
792
648
  }
793
649
  },
794
650
  guards: {
795
- isLastStep: ({ context: context$1 }) => context$1.stepIndex >= context$1.steps.length - 1,
796
- nextStepFlipsCamera: ({ context: context$1 }) => facingModeForStep(context$1.steps[context$1.stepIndex]) !== facingModeForStep(context$1.steps[context$1.stepIndex + 1]),
651
+ isLastStep: ({ context }) => context.stepIndex >= context.steps.length - 1,
652
+ hasAttemptsRemaining: ({ context }) => context.attemptsRemaining === UNLIMITED_ATTEMPTS || context.attemptsRemaining > 0,
653
+ 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
+ nextStepFlipsCamera: ({ context }) => facingModeForStep(context.steps[context.stepIndex]) !== facingModeForStep(context.steps[context.stepIndex + 1]),
797
661
  uploadReturnedNoRecordingId: ({ event }) => recordingIdFromEvent(event) === null
798
662
  }
799
663
  });
@@ -802,6 +666,10 @@ const ADVANCE_TRANSITIONS = [
802
666
  target: "finalizing",
803
667
  guard: "isLastStep"
804
668
  },
669
+ {
670
+ target: "flippingId",
671
+ guard: "nextStepFlipsId"
672
+ },
805
673
  {
806
674
  target: "switchingCamera",
807
675
  guard: "nextStepFlipsCamera",
@@ -813,7 +681,7 @@ const ADVANCE_TRANSITIONS = [
813
681
  actions: "advanceStep"
814
682
  }
815
683
  ];
816
- const _videoSelfieRecordingMachine = videoSelfieRecordingSetup.createMachine({
684
+ const videoSelfieRecordingMachine = videoSelfieRecordingSetup.createMachine({
817
685
  id: "videoSelfieRecording",
818
686
  initial: "idle",
819
687
  context: ({ input }) => ({
@@ -826,27 +694,33 @@ const _videoSelfieRecordingMachine = videoSelfieRecordingSetup.createMachine({
826
694
  stream: void 0,
827
695
  composite: void 0,
828
696
  detectionStatus: void 0,
697
+ orientation: void 0,
829
698
  detectionError: void 0,
699
+ validationFailure: void 0,
700
+ attemptsPerStep: normalizeAttempts(input.attemptsPerStep),
701
+ attemptsRemaining: normalizeAttempts(input.attemptsPerStep),
830
702
  recordingId: null,
831
- error: void 0
703
+ error: void 0,
704
+ errorKind: void 0,
705
+ switchingCameraMinDwellMs: input.dependencies?.switchingCameraMinDwellMs ?? SWITCHING_CAMERA_MIN_DWELL_MS
832
706
  }),
833
707
  on: { ABORT: { target: ".aborted" } },
834
708
  states: {
835
709
  idle: { on: { START: { target: "acquiringCamera" } } },
836
710
  acquiringCamera: { invoke: {
837
711
  src: "acquireCamera",
838
- input: ({ context: context$1 }) => ({
839
- acquire: context$1.acquireCamera,
840
- facingMode: facingModeForStep(context$1.steps[context$1.stepIndex]),
712
+ input: ({ context }) => ({
713
+ acquire: context.acquireCamera,
714
+ facingMode: facingModeForStep(context.steps[context.stepIndex]),
841
715
  withAudio: true
842
716
  }),
843
717
  onDone: {
844
718
  target: "starting",
845
- actions: [({ context: context$1, event }) => {
846
- context$1.compositor.start(eventOutputStream(event));
719
+ actions: [({ context, event }) => {
720
+ context.compositor.start(eventOutputStream(event));
847
721
  }, assign({
848
722
  stream: ({ event }) => eventOutputStream(event),
849
- composite: ({ context: context$1 }) => context$1.compositor.stream
723
+ composite: ({ context }) => context.compositor.stream
850
724
  })]
851
725
  },
852
726
  onError: {
@@ -856,9 +730,9 @@ const _videoSelfieRecordingMachine = videoSelfieRecordingSetup.createMachine({
856
730
  } },
857
731
  starting: { invoke: {
858
732
  src: "startRecording",
859
- input: ({ context: context$1 }) => ({
860
- service: context$1.service,
861
- stream: context$1.composite
733
+ input: ({ context }) => ({
734
+ service: context.service,
735
+ stream: context.composite
862
736
  }),
863
737
  onDone: { target: "recording" },
864
738
  onError: {
@@ -870,33 +744,87 @@ const _videoSelfieRecordingMachine = videoSelfieRecordingSetup.createMachine({
870
744
  entry: "clearDetectionFeedback",
871
745
  invoke: {
872
746
  src: "detectStep",
873
- input: ({ context: context$1 }) => ({
874
- detect: context$1.detect,
875
- step: context$1.steps[context$1.stepIndex],
876
- stream: context$1.stream
747
+ input: ({ context }) => ({
748
+ detect: context.detect,
749
+ step: context.steps[context.stepIndex],
750
+ stream: context.stream
877
751
  })
878
752
  },
879
753
  on: {
880
754
  DETECTION_STATUS: { actions: "setDetectionStatus" },
755
+ ORIENTATION: { actions: "setOrientation" },
881
756
  DETECTION_DONE: ADVANCE_TRANSITIONS,
882
757
  NEXT_STEP: ADVANCE_TRANSITIONS,
758
+ VALIDATION_FAILED: {
759
+ target: "validationFeedback",
760
+ actions: "setValidationFailure"
761
+ },
762
+ RETRYABLE_FAILURE: {
763
+ target: "validationFeedback",
764
+ actions: "setUncountedRetryableFailure"
765
+ },
883
766
  DETECTION_FAILED: {
884
767
  target: "error",
885
768
  actions: "setErrorFromDetection"
886
769
  }
887
770
  }
888
771
  },
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"
784
+ },
785
+ {
786
+ target: "recording",
787
+ reenter: true,
788
+ guard: "isIdExhaustion",
789
+ actions: "advancePastIdSection"
790
+ },
791
+ {
792
+ 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
+ ]] } },
807
+ flippingId: {
808
+ after: { ID_FLIP_DWELL: {
809
+ target: "recording",
810
+ actions: "advanceStep"
811
+ } },
812
+ on: { NEXT_STEP: {
813
+ target: "recording",
814
+ actions: "advanceStep"
815
+ } }
816
+ },
889
817
  switchingCamera: { invoke: {
890
- src: "acquireCamera",
891
- input: ({ context: context$1 }) => ({
892
- acquire: context$1.acquireCamera,
893
- facingMode: facingModeForStep(context$1.steps[context$1.stepIndex]),
894
- withAudio: false
818
+ src: "switchCamera",
819
+ input: ({ context }) => ({
820
+ acquire: context.acquireCamera,
821
+ facingMode: facingModeForStep(context.steps[context.stepIndex]),
822
+ minDwellMs: context.switchingCameraMinDwellMs
895
823
  }),
896
824
  onDone: {
897
825
  target: "recording",
898
- actions: [({ context: context$1, event }) => {
899
- context$1.compositor.switchVideo(eventOutputStream(event));
826
+ actions: [({ context, event }) => {
827
+ context.compositor.switchVideo(eventOutputStream(event));
900
828
  }, assign({ stream: ({ event }) => eventOutputStream(event) })]
901
829
  },
902
830
  onError: {
@@ -906,13 +834,13 @@ const _videoSelfieRecordingMachine = videoSelfieRecordingSetup.createMachine({
906
834
  } },
907
835
  finalizing: { invoke: {
908
836
  src: "finalizeRecording",
909
- input: ({ context: context$1 }) => ({ service: context$1.service }),
837
+ input: ({ context }) => ({ service: context.service }),
910
838
  onDone: [{
911
839
  target: "error",
912
840
  guard: "uploadReturnedNoRecordingId",
913
841
  actions: [assign({ recordingId: ({ event }) => recordingIdFromEvent(event) }), "setUploadFailedError"]
914
842
  }, {
915
- target: "finished",
843
+ target: "success",
916
844
  actions: assign({ recordingId: ({ event }) => recordingIdFromEvent(event) })
917
845
  }],
918
846
  onError: {
@@ -920,13 +848,17 @@ const _videoSelfieRecordingMachine = videoSelfieRecordingSetup.createMachine({
920
848
  actions: assign({ error: ({ event }) => errorFromEvent(event) })
921
849
  }
922
850
  } },
923
- finished: {
924
- type: "final",
925
- entry: "cleanup"
851
+ success: {
852
+ entry: "cleanup",
853
+ after: { FINAL_SUCCESS_DWELL: "finished" }
926
854
  },
855
+ finished: { type: "final" },
927
856
  error: {
928
- type: "final",
929
- entry: "cleanup"
857
+ entry: "cleanup",
858
+ on: { RETRY: {
859
+ target: "acquiringCamera",
860
+ actions: "resetSession"
861
+ } }
930
862
  },
931
863
  aborted: {
932
864
  type: "final",
@@ -934,8 +866,6 @@ const _videoSelfieRecordingMachine = videoSelfieRecordingSetup.createMachine({
934
866
  }
935
867
  }
936
868
  });
937
- const videoSelfieRecordingMachine = _videoSelfieRecordingMachine;
938
-
939
869
  //#endregion
940
870
  //#region src/modules/video-selfie/videoSelfieRecordingActor.ts
941
871
  function createVideoSelfieRecordingActor(options = {}) {
@@ -943,41 +873,54 @@ function createVideoSelfieRecordingActor(options = {}) {
943
873
  const detect = options.dependencies?.detect ?? (config ? createDefaultStepDetector(config, { getWasmUtil: () => WasmUtilProvider.getInstance() }) : void 0);
944
874
  return createActor(videoSelfieRecordingMachine, { input: {
945
875
  steps: config ? resolveVideoSelfieSteps(config) : void 0,
876
+ attemptsPerStep: config?.numberOfTries,
946
877
  dependencies: {
947
878
  ...options.dependencies,
948
879
  detect
949
880
  }
950
881
  } }).start();
951
882
  }
952
-
953
883
  //#endregion
954
884
  //#region src/modules/video-selfie/videoSelfieRecordingManager.ts
955
885
  function mapState(snapshot) {
956
886
  const value = typeof snapshot.value === "string" ? snapshot.value : "idle";
957
- const { context: context$1 } = snapshot;
887
+ const { context } = snapshot;
958
888
  const status = value === "acquiringCamera" ? "starting" : value;
959
- const steps = context$1.steps;
960
- const stepIndex = context$1.stepIndex;
889
+ const steps = context.steps;
890
+ const stepIndex = context.stepIndex;
961
891
  return {
962
892
  status,
963
893
  step: steps[stepIndex],
964
894
  stepIndex,
965
895
  isLastStep: stepIndex >= steps.length - 1,
966
- stream: context$1.stream,
967
- composite: context$1.composite,
968
- detectionStatus: context$1.detectionStatus,
969
- recordingId: context$1.recordingId,
970
- error: context$1.error
896
+ stream: context.stream,
897
+ composite: context.composite,
898
+ detectionStatus: context.detectionStatus,
899
+ orientation: context.orientation,
900
+ validationFailure: context.validationFailure,
901
+ attemptsRemaining: context.attemptsRemaining,
902
+ recordingId: context.recordingId,
903
+ error: context.error,
904
+ errorKind: context.errorKind
971
905
  };
972
906
  }
973
907
  function createApi({ actor }) {
974
908
  return {
909
+ /** Acquire the first camera, open the upload, and begin recording. */
975
910
  start() {
976
911
  actor.send({ type: "START" });
977
912
  },
913
+ retry() {
914
+ actor.send({ type: "RETRY" });
915
+ },
916
+ /**
917
+ * Advance to the next step. Switches the camera when the next step's
918
+ * facing mode differs; finalizes the upload on the last step.
919
+ */
978
920
  nextStep() {
979
921
  actor.send({ type: "NEXT_STEP" });
980
922
  },
923
+ /** Abandon the session without finalizing the upload. */
981
924
  abort() {
982
925
  actor.send({ type: "ABORT" });
983
926
  }
@@ -1006,7 +949,6 @@ function createVideoSelfieRecordingManager(options = {}) {
1006
949
  }
1007
950
  };
1008
951
  }
1009
-
1010
952
  //#endregion
1011
953
  //#region src/modules/video-selfie/videoSelfieWasm.ts
1012
954
  /**
@@ -1022,7 +964,6 @@ function createVideoSelfieRecordingManager(options = {}) {
1022
964
  function warmupVideoSelfieWasm(config) {
1023
965
  return ensureWasmPipelines(videoSelfieWasmPipelines(config));
1024
966
  }
1025
-
1026
967
  //#endregion
1027
968
  //#region src/modules/video-selfie/videoSelfieSpeechService.ts
1028
969
  /**
@@ -1062,7 +1003,6 @@ async function addSpeech(base64Mp3) {
1062
1003
  return { success: false };
1063
1004
  }
1064
1005
  }
1065
-
1066
1006
  //#endregion
1067
1007
  //#region ../../node_modules/.pnpm/audio-recorder-polyfill@0.4.1/node_modules/audio-recorder-polyfill/wave-encoder/index.js
1068
1008
  var wave_encoder_default = () => {
@@ -1109,7 +1049,6 @@ var wave_encoder_default = () => {
1109
1049
  else if (e.data[0] === "dump") dump(e.data[1]);
1110
1050
  };
1111
1051
  };
1112
-
1113
1052
  //#endregion
1114
1053
  //#region ../../node_modules/.pnpm/audio-recorder-polyfill@0.4.1/node_modules/audio-recorder-polyfill/index.js
1115
1054
  let AudioContext = window.AudioContext || window.webkitAudioContext;
@@ -1333,8 +1272,6 @@ MediaRecorder$1.notSupported = !navigator.mediaDevices || !AudioContext;
1333
1272
  * MediaRecorder.encoder = oggEncoder
1334
1273
  */
1335
1274
  MediaRecorder$1.encoder = wave_encoder_default;
1336
- var audio_recorder_polyfill_default = MediaRecorder$1;
1337
-
1338
1275
  //#endregion
1339
1276
  //#region ../../node_modules/.pnpm/audio-recorder-polyfill@0.4.1/node_modules/audio-recorder-polyfill/mpeg-encoder/index.js
1340
1277
  var mpeg_encoder_default = () => {
@@ -1343,7 +1280,7 @@ var mpeg_encoder_default = () => {
1343
1280
  let KBPS = 128;
1344
1281
  let DEFAULT_SAMPLE_RATE = 44100;
1345
1282
  let encoder;
1346
- let recorded = new Int8Array();
1283
+ let recorded = /* @__PURE__ */ new Int8Array();
1347
1284
  function concat(a, b) {
1348
1285
  if (b.length === 0) return a;
1349
1286
  let c = new Int8Array(a.length + b.length);
@@ -1363,7 +1300,7 @@ var mpeg_encoder_default = () => {
1363
1300
  let buf = encoder.flush();
1364
1301
  recorded = concat(recorded, buf);
1365
1302
  let buffer = recorded.buffer;
1366
- recorded = new Int8Array();
1303
+ recorded = /* @__PURE__ */ new Int8Array();
1367
1304
  postMessage(buffer, [buffer]);
1368
1305
  }
1369
1306
  onmessage = (e) => {
@@ -1372,7 +1309,6 @@ var mpeg_encoder_default = () => {
1372
1309
  else dump(e.data[1]);
1373
1310
  };
1374
1311
  };
1375
-
1376
1312
  //#endregion
1377
1313
  //#region ../infra/src/media/blobEncoding.ts
1378
1314
  /** Encodes a blob as raw base64 bytes (no `data:...;base64,` prefix). */
@@ -1394,10 +1330,9 @@ function blobToRawBase64(blob) {
1394
1330
  reader.readAsDataURL(blob);
1395
1331
  });
1396
1332
  }
1397
-
1398
1333
  //#endregion
1399
1334
  //#region ../infra/src/providers/browser/VoiceRecordingProvider.ts
1400
- const AudioRecorderPolyfill = audio_recorder_polyfill_default;
1335
+ const AudioRecorderPolyfill = MediaRecorder$1;
1401
1336
  AudioRecorderPolyfill.encoder = mpeg_encoder_default;
1402
1337
  AudioRecorderPolyfill.prototype.mimeType = "audio/mpeg";
1403
1338
  const MIME_TYPE = "audio/mpeg";
@@ -1422,7 +1357,8 @@ var VoiceRecordingProvider = class {
1422
1357
  start(stream) {
1423
1358
  this.reset();
1424
1359
  this.chunks = [];
1425
- const recorder = new AudioRecorderPolyfill(new MediaStream(stream.getAudioTracks()).clone());
1360
+ const audioOnly = new MediaStream(stream.getAudioTracks());
1361
+ const recorder = new AudioRecorderPolyfill(audioOnly.clone());
1426
1362
  recorder.mimeType = MIME_TYPE;
1427
1363
  recorder.addEventListener("dataavailable", (event) => {
1428
1364
  if (event.data.size > 0) this.chunks.push(event.data);
@@ -1464,7 +1400,6 @@ var VoiceRecordingProvider = class {
1464
1400
  this._isRecording = false;
1465
1401
  }
1466
1402
  };
1467
-
1468
1403
  //#endregion
1469
1404
  //#region src/modules/video-selfie/videoSelfieConsentRecorder.ts
1470
1405
  function createConsentRecorder() {
@@ -1483,7 +1418,6 @@ function createConsentRecorder() {
1483
1418
  }
1484
1419
  };
1485
1420
  }
1486
-
1487
1421
  //#endregion
1488
1422
  //#region src/modules/video-selfie/videoSelfieFlowModuleMachine.ts
1489
1423
  /**
@@ -1496,10 +1430,9 @@ function createConsentRecorder() {
1496
1430
  * it starts in a non-final `running` state and never transitions, so the
1497
1431
  * orchestrated flow stays in `runningModule` until the UI advances it.
1498
1432
  *
1499
- * **Completion contract:** the L2 `incode-video-selfie` web component MUST call
1500
- * `flowManager.completeModule()` once the recording manager reaches `finished`
1501
- * (success) or `error` (terminal failure). Until that event is sent, the flow
1502
- * orchestrator remains in `runningModule` — this is intentional.
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.
1503
1436
  *
1504
1437
  * **Abort / unmount:** if the user closes the module or the web component
1505
1438
  * unmounts before completion, the orchestrated flow manager's existing close /
@@ -1515,6 +1448,5 @@ const videoSelfieFlowModuleMachine = setup({}).createMachine({
1515
1448
  initial: "running",
1516
1449
  states: { running: {} }
1517
1450
  });
1518
-
1519
1451
  //#endregion
1520
- export { createConsentRecorder, createVideoSelfieCameraWarmer, createVideoSelfieRecordingManager, facingModeForStep, getVideoSelfieQuestions, getVoiceConsentPhrase, resolveVideoSelfieSteps, videoSelfieFlowModuleMachine, videoSelfieWasmPipelines, warmupVideoSelfieWasm };
1452
+ export { createConsentRecorder, createVideoSelfieCameraWarmer, createVideoSelfieRecordingManager, facingModeForStep, getVideoSelfieQuestions, getVoiceConsentPhrase, resolveVideoSelfieSteps, videoSelfieFlowModuleMachine, videoSelfieWasmPipelines, warmupVideoSelfieWasm };