@incodetech/core 2.2.0 → 2.3.0-rc.1

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