@incodetech/core 2.1.0-rc.2 → 2.1.0-rc.3

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 (259) hide show
  1. package/dist/3dAvatarProvider-ChciZmjE.esm.js +28214 -0
  2. package/dist/{BrowserStorageProvider-D5xc7Lqo.esm.js → BrowserStorageProvider-CrrN540a.esm.js} +1 -25
  3. package/dist/BrowserVisibilityObserverProvider-rim9Jrz-.esm.js +25 -0
  4. package/dist/Face2DProvider-BeLlYBbB.esm.js +824 -0
  5. package/dist/FaceDetectionProvider-B78455D4.d.ts +119 -0
  6. package/dist/IVisibilityObserverCapability-BbWjgpiF.d.ts +12 -0
  7. package/dist/IWasmUtilCapability-d2XvzaCk.d.ts +145 -0
  8. package/dist/IpifyProvider-BRW14_uo.esm.js +51 -0
  9. package/dist/{Manager-B2OEDYqf.d.ts → Manager-CJ3G2zqi.d.ts} +1 -4
  10. package/dist/{OpenViduRecordingProvider-DF7A4ZNJ.esm.js → OpenViduRecordingProvider-B_0GKkzc.esm.js} +1 -1
  11. package/dist/PrivacyLensProvider-hDzaDzZ6.esm.js +339 -0
  12. package/dist/StateMachine-C_AY4cs7.d.ts +2 -0
  13. package/dist/{StreamCanvasCapture-Dr5n_iK1.esm.js → StreamCanvasCapture-Bz17q4FP.esm.js} +1 -1
  14. package/dist/StreamCanvasCapture-DS1TOoiH.d.ts +42 -0
  15. package/dist/{WasmUtilProvider-CIu373BZ.esm.js → WasmUtilProvider-ADG54T6M.esm.js} +16 -1
  16. package/dist/{addressSearch-BH96a3fq.esm.js → addressSearch-DJyNTg5S.esm.js} +4 -4
  17. package/dist/{ae-signature-CDEN8y-w.esm.js → ae-signature-DlElqFrZ.esm.js} +1 -1
  18. package/dist/ae-signature.d.ts +4 -3
  19. package/dist/ae-signature.esm.js +10 -9
  20. package/dist/antifraud.d.ts +4 -3
  21. package/dist/antifraud.esm.js +7 -6
  22. package/dist/{antifraudManager-DZifA5zX.esm.js → antifraudManager-BKdQoMFf.esm.js} +4 -3
  23. package/dist/{antifraudManager-B7WQTIdu.d.ts → antifraudManager-DpIvbrZP.d.ts} +2 -2
  24. package/dist/{antifraudStateMachine-DlKrK2hL.esm.js → antifraudStateMachine-C0NGnP9W.esm.js} +3 -3
  25. package/dist/{api-DUZwyz0o.esm.js → api-DsbUi7TO.esm.js} +21 -2
  26. package/dist/authentication.d.ts +19 -12
  27. package/dist/authentication.esm.js +33 -27
  28. package/dist/{authenticationManager-Dve7mGLe.d.ts → authenticationManager-CdPbNS2H.d.ts} +3 -3
  29. package/dist/{authenticationManager-BM4LzyV7.esm.js → authenticationManager-Dtl1vcET.esm.js} +6 -6
  30. package/dist/{authenticationStateMachine-Chx3ySdT.esm.js → authenticationStateMachine-D-hOlg8p.esm.js} +8 -8
  31. package/dist/avatar.d.ts +3 -0
  32. package/dist/avatar.esm.js +3 -0
  33. package/dist/{backCameraStream-iftkf3rd.esm.js → backCameraStream-ZyqrFyjO.esm.js} +3 -3
  34. package/dist/{browser-DlFgHpoC-7tbRR1aR.esm.js → browser-DlFgHpoC-qLKs75Qp.esm.js} +1 -1
  35. package/dist/{browserSimulation-CGjpdNA1.esm.js → browserSimulation-TsSoavQv.esm.js} +153 -1216
  36. package/dist/camera-DUkgmYMo.esm.js +79 -0
  37. package/dist/camera.d.ts +7 -1
  38. package/dist/camera.esm.js +4 -4
  39. package/dist/{StreamCanvasCapture-Ctgyx-oD.d.ts → canvas-CJUmoXSD.d.ts} +1 -41
  40. package/dist/certificate-issuance.d.ts +31 -30
  41. package/dist/certificate-issuance.esm.js +8 -7
  42. package/dist/{certificateIssuanceStateMachine-CLNXtXaC.esm.js → certificateIssuanceStateMachine-C07m7qtP.esm.js} +4 -4
  43. package/dist/clientLifecycle-Ct7h9uxx.esm.js +534 -0
  44. package/dist/consent.d.ts +4 -3
  45. package/dist/consent.esm.js +7 -6
  46. package/dist/{consentManager-psDCeJ0E.esm.js → consentManager-BtnPZUW4.esm.js} +4 -3
  47. package/dist/{consentManager-BqUGU_YD.d.ts → consentManager-DufVo9D9.d.ts} +52 -52
  48. package/dist/{consentStateMachine-DRsFFSHE.esm.js → consentStateMachine-DO2JqoZW.esm.js} +3 -3
  49. package/dist/cpf-ocr.d.ts +4 -3
  50. package/dist/cpf-ocr.esm.js +7 -6
  51. package/dist/{cpfOcrManager-BxcgxvgO.esm.js → cpfOcrManager-C4rLgKsu.esm.js} +6 -5
  52. package/dist/{cpfOcrManager-B2u9hMzd.d.ts → cpfOcrManager-DqZZ94Gt.d.ts} +19 -19
  53. package/dist/createFaceAvatar-B8pFpy6o.d.ts +401 -0
  54. package/dist/createFaceAvatar-BOHDKQRq.esm.js +46 -0
  55. package/dist/cross-document-data-match.d.ts +2 -1
  56. package/dist/cross-document-data-match.esm.js +6 -5
  57. package/dist/curp-validation.d.ts +10 -7
  58. package/dist/curp-validation.esm.js +7 -6
  59. package/dist/{curpValidationManager-BgLDw0Ub.esm.js → curpValidationManager-BafobPXC.esm.js} +4 -3
  60. package/dist/{curpValidationManager-Bt6CVD8b.d.ts → curpValidationManager-Co6LZAHT.d.ts} +3 -3
  61. package/dist/{curpValidationStateMachine-BK_wJ48C.esm.js → curpValidationStateMachine-DXTPK6vI.esm.js} +3 -3
  62. package/dist/custom-fields.d.ts +3 -2
  63. package/dist/custom-fields.esm.js +6 -5
  64. package/dist/custom-watchlist.d.ts +2 -1
  65. package/dist/custom-watchlist.esm.js +6 -5
  66. package/dist/{customWatchlistStateMachine-Bi4P59HM.esm.js → customWatchlistStateMachine-B4G3Chkx.esm.js} +3 -3
  67. package/dist/{deepsightLoader-BMmvk0X6.esm.js → deepsightLoader-DHSVD776.esm.js} +14 -13
  68. package/dist/{deepsightService-CEZrdiW0.esm.js → deepsightService-CDahSjGP.esm.js} +9 -38
  69. package/dist/deepsightService-CMB9XjES.d.ts +69 -0
  70. package/dist/device.d.ts +9 -1
  71. package/dist/device.esm.js +5 -5
  72. package/dist/document-capture.d.ts +175 -174
  73. package/dist/document-capture.esm.js +14 -13
  74. package/dist/document-upload.d.ts +48 -47
  75. package/dist/document-upload.esm.js +9 -8
  76. package/dist/{documentCaptureStateMachine-MpwpJO7t.esm.js → documentCaptureStateMachine-DSOX2epf.esm.js} +7 -7
  77. package/dist/dynamic-forms.d.ts +4 -192
  78. package/dist/dynamic-forms.esm.js +8 -160
  79. package/dist/dynamicFormsManager-BOefZbyF.esm.js +168 -0
  80. package/dist/dynamicFormsManager-CUYLOj9g.d.ts +239 -0
  81. package/dist/{dynamicFormsStateMachine-Do84A4uU.esm.js → dynamicFormsStateMachine-BXHcaocI.esm.js} +4 -4
  82. package/dist/ekyb.d.ts +9 -6
  83. package/dist/ekyb.esm.js +20 -17
  84. package/dist/{ekybStateMachine-nsuPOw3f.esm.js → ekybStateMachine-CCSeqjCt.esm.js} +5 -5
  85. package/dist/ekyc.d.ts +4 -3
  86. package/dist/ekyc.esm.js +9 -8
  87. package/dist/{ekycStateMachine-DcynX0rj.esm.js → ekycStateMachine-DkLVTOyA.esm.js} +5 -5
  88. package/dist/electronic-signature.d.ts +4 -3
  89. package/dist/electronic-signature.esm.js +9 -8
  90. package/dist/{electronicSignatureManager-B63aAuI5.esm.js → electronicSignatureManager-DjzUzqZj.esm.js} +50 -87
  91. package/dist/email.d.ts +5 -4
  92. package/dist/email.esm.js +9 -8
  93. package/dist/{emailManager-DxHjAe5u.esm.js → emailManager-B_XzEsXH.esm.js} +5 -4
  94. package/dist/{emailManager-C6D2u4mQ.d.ts → emailManager-fHASH6uo.d.ts} +3 -3
  95. package/dist/{emailStateMachine-758f34gg.esm.js → emailStateMachine-fqJ42b19.esm.js} +5 -5
  96. package/dist/{endpoints-BM2_j_IE.esm.js → endpoints-BzMJFAPV.esm.js} +13 -0
  97. package/dist/{events-DN-u67gb.esm.js → events-CqGY1yMq.esm.js} +2 -188
  98. package/dist/events.d.ts +2 -0
  99. package/dist/events.esm.js +3 -2
  100. package/dist/extensibility.d.ts +37 -26
  101. package/dist/extensibility.esm.js +74 -59
  102. package/dist/{externalFetch-crimxkN9.esm.js → externalFetch-CyhBfD-n.esm.js} +1 -1
  103. package/dist/face-match.d.ts +2 -2
  104. package/dist/face-match.esm.js +6 -5
  105. package/dist/{faceCaptureManagerFactory-BNXZchWX.esm.js → faceCaptureManagerFactory-2brKTzMb.esm.js} +25 -16
  106. package/dist/faceCaptureManagerFactory-CGKbf7zt.d.ts +400 -0
  107. package/dist/{faceCaptureSetup-Dqb09D24.esm.js → faceCaptureSetup-CDUVU1nl.esm.js} +97 -13
  108. package/dist/{faceMatchStateMachine-FikRaUZH.esm.js → faceMatchStateMachine-DUeUjEPx.esm.js} +3 -3
  109. package/dist/field-comparison.d.ts +4 -3
  110. package/dist/field-comparison.esm.js +6 -5
  111. package/dist/{fieldComparisonManager-Dic0DVgl.esm.js → fieldComparisonManager-B9W0a9A5.esm.js} +5 -4
  112. package/dist/{fieldComparisonManager-BXc6-DJv.d.ts → fieldComparisonManager-DdLqDeB2.d.ts} +2 -2
  113. package/dist/fiscal-qr.d.ts +5 -3
  114. package/dist/fiscal-qr.esm.js +13 -12
  115. package/dist/flow-events.d.ts +8 -6
  116. package/dist/flow.d.ts +21 -13
  117. package/dist/flow.esm.js +28 -19
  118. package/dist/{flowCompletionService-CdGDKv0z.d.ts → flowCompletionService-BIqSTZcd.d.ts} +2 -1
  119. package/dist/{flowCompletionService-D_CsiDZM.esm.js → flowCompletionService-qEqh_g14.esm.js} +3 -3
  120. package/dist/{flowServices-ar5DXv71.esm.js → flowServices-C4piblgx.esm.js} +24 -9
  121. package/dist/geolocation.d.ts +4 -127
  122. package/dist/geolocation.esm.js +8 -115
  123. package/dist/geolocationManager-BP2Do9O-.esm.js +123 -0
  124. package/dist/geolocationManager-Cs50eRlC.d.ts +156 -0
  125. package/dist/{geolocationStateMachine-BWjrMGS_.esm.js → geolocationStateMachine-BYfOOOG0.esm.js} +4 -4
  126. package/dist/{getDeviceClass-rXKlXywy.esm.js → getDeviceClass-DGGzzfqm.esm.js} +1 -1
  127. package/dist/getDeviceData-TrKM8NPh.esm.js +101 -0
  128. package/dist/government-validation.d.ts +4 -3
  129. package/dist/government-validation.esm.js +8 -7
  130. package/dist/{governmentValidationStateMachine-BoF7U1of.esm.js → governmentValidationStateMachine-CwoPPO8b.esm.js} +5 -5
  131. package/dist/home.d.ts +18 -15
  132. package/dist/home.esm.js +4 -3
  133. package/dist/http.esm.js +2 -2
  134. package/dist/id-ocr.d.ts +4 -625
  135. package/dist/id-ocr.esm.js +8 -84
  136. package/dist/id-verification.d.ts +28 -27
  137. package/dist/id-verification.esm.js +6 -5
  138. package/dist/id.d.ts +16 -11
  139. package/dist/id.esm.js +39 -32
  140. package/dist/idCaptureDefaults-DNJON8Xo.esm.js +188 -0
  141. package/dist/{idCaptureManager-BvGUSN2e.d.ts → idCaptureManager-BVdvfJys.d.ts} +40 -10
  142. package/dist/{idCaptureManager-Bm6Wm6Qv.esm.js → idCaptureManager-Bo9DCQSU.esm.js} +14 -11
  143. package/dist/{idCaptureStateMachine-D1YhOj6n.esm.js → idCaptureStateMachine-BeDidMLU.esm.js} +395 -382
  144. package/dist/idOcrManager-BkRDrpZu.esm.js +92 -0
  145. package/dist/idOcrManager-CJzrmM91.d.ts +641 -0
  146. package/dist/{idOcrStateMachine-YMCDGplq.esm.js → idOcrStateMachine-DRZc4FBl.esm.js} +5 -5
  147. package/dist/{idVerificationStateMachine-Bo1IYuZH.esm.js → idVerificationStateMachine-oqiERKpg.esm.js} +3 -3
  148. package/dist/identity-reuse.d.ts +4 -3
  149. package/dist/identity-reuse.esm.js +7 -6
  150. package/dist/{identityReuseManager-D0knIrOy.esm.js → identityReuseManager-Bu62LToE.esm.js} +4 -3
  151. package/dist/{identityReuseManager-DcWSvC-A.d.ts → identityReuseManager-TWKbXuvY.d.ts} +33 -33
  152. package/dist/{identityReuseStateMachine-CSQfZOqD.esm.js → identityReuseStateMachine-BmONeF6B.esm.js} +3 -3
  153. package/dist/{index-BgxYUYuD.d.ts → index-DtUlD-bz.d.ts} +2 -2
  154. package/dist/{index-DV134v62.d.ts → index-Icld-cKW.d.ts} +175 -295
  155. package/dist/index.d.ts +3 -3
  156. package/dist/index.esm.js +16 -13
  157. package/dist/{invokeOnCaptureCallback-Dzemudhk.esm.js → invokeOnCaptureCallback-v_PV_IJz.esm.js} +1 -1
  158. package/dist/{lib-7ZQ9BdKH.esm.js → lib-B050WTth.esm.js} +1 -1
  159. package/dist/mandatory-consent.d.ts +10 -7
  160. package/dist/mandatory-consent.esm.js +7 -6
  161. package/dist/{mandatoryConsentManager-Tzl5Qd35.d.ts → mandatoryConsentManager-Bmdjo14S.d.ts} +50 -50
  162. package/dist/{mandatoryConsentManager-Lon46nPQ.esm.js → mandatoryConsentManager-CQ3jirlZ.esm.js} +4 -3
  163. package/dist/{mandatoryConsentStateMachine-D_dZ7IF6.esm.js → mandatoryConsentStateMachine-DkJJLHqC.esm.js} +3 -3
  164. package/dist/mediaRecorderOptions-C3NAkVgK.esm.js +42 -0
  165. package/dist/mediapipeShared-CRAKVElv.esm.js +67 -0
  166. package/dist/{recordingService-CxMJP4tQ.esm.js → onDeviceFaceResults-DVBggeq8.esm.js} +71 -389
  167. package/dist/{openviduLazy-oAXXI9w_.esm.js → openviduLazy-BTOIauGP.esm.js} +2 -2
  168. package/dist/openviduLazy-Dov8oKfL.esm.js +3 -0
  169. package/dist/{permissionGuards-D-Z-lgNj.esm.js → permissionGuards-BR2oN573.esm.js} +1 -1
  170. package/dist/{permissionServices-CPDboRoE.esm.js → permissionServices-BJhGL13R.esm.js} +7 -4
  171. package/dist/personhood.d.ts +534 -0
  172. package/dist/personhood.esm.js +1494 -0
  173. package/dist/phone.d.ts +5 -4
  174. package/dist/phone.esm.js +9 -8
  175. package/dist/{phoneManager-TSq1Ief6.d.ts → phoneManager-BOTcjXgs.d.ts} +3 -3
  176. package/dist/{phoneManager-Blt4Oc2P.esm.js → phoneManager-BWlxqbyD.esm.js} +5 -4
  177. package/dist/{phoneStateMachine-W3c6Z8sj.esm.js → phoneStateMachine-B_V9nODs.esm.js} +5 -5
  178. package/dist/{qe-signature-CQLK6LKE.esm.js → qe-signature-BhFnI9pT.esm.js} +1 -1
  179. package/dist/qe-signature.d.ts +4 -3
  180. package/dist/qe-signature.esm.js +10 -9
  181. package/dist/recordingService-m_1xCthr.esm.js +347 -0
  182. package/dist/redirect-to-mobile.d.ts +4 -3
  183. package/dist/redirect-to-mobile.esm.js +9 -8
  184. package/dist/{redirectToMobileManager-DCvpKdkD.esm.js → redirectToMobileManager-BaAo9rgi.esm.js} +5 -4
  185. package/dist/{redirectToMobileManager-yOHAmwg-.d.ts → redirectToMobileManager-Br0KZK1G.d.ts} +2 -2
  186. package/dist/{redirectToMobileStateMachine-DC9z4Vfu.esm.js → redirectToMobileStateMachine-DoAnf2ql.esm.js} +10 -12
  187. package/dist/{runChildModule-C9G0wfVC.esm.js → runChildModule-0nQfjVVo.esm.js} +3 -3
  188. package/dist/selfie.d.ts +19 -12
  189. package/dist/selfie.esm.js +34 -28
  190. package/dist/{selfieManager-BRL6c_Oc.esm.js → selfieManager-D_ZFERsE.esm.js} +6 -6
  191. package/dist/{selfieManager-imY2dAcH.d.ts → selfieManager-R0Jw5sjb.d.ts} +3 -3
  192. package/dist/{selfieStateMachine-D2Q0uwDK.esm.js → selfieStateMachine-CIgeeiN9.esm.js} +4 -4
  193. package/dist/{session-Be_IA1e0.esm.js → session-9jIfKFCc.esm.js} +3 -3
  194. package/dist/session.d.ts +7 -5
  195. package/dist/session.esm.js +16 -14
  196. package/dist/{sessionInitializer-CaiGA8GP.esm.js → sessionInitializer-C_TYIgyk.esm.js} +11 -107
  197. package/dist/{setup-BJZAkajt.d.ts → setup-CpRnXxn8.d.ts} +16 -3
  198. package/dist/setup-DHc6OaHm.esm.js +562 -0
  199. package/dist/signature.d.ts +3 -2
  200. package/dist/signature.esm.js +6 -5
  201. package/dist/{signatureStateMachine-DAxXmMrk.esm.js → signatureStateMachine-DtoiPzys.esm.js} +3 -3
  202. package/dist/{stats-DntyIiGr.esm.js → stats-CYcScXcO.esm.js} +2 -2
  203. package/dist/stats.esm.js +3 -3
  204. package/dist/thumbmarkAdapter-fHBUDlAP.esm.js +1194 -0
  205. package/dist/{tri-CtxWthxz.esm.js → tri-BG1iJsr4.esm.js} +12 -2
  206. package/dist/tri.d.ts +1 -1
  207. package/dist/{tri.esm-CrWAulDi.esm.js → tri.esm-DUC01NgO.esm.js} +27 -23
  208. package/dist/tri.esm.js +2 -2
  209. package/dist/trust-graph.d.ts +4 -3
  210. package/dist/trust-graph.esm.js +4 -3
  211. package/dist/{types-DpTWgfKY.d.ts → types-BklZ_Wne.d.ts} +1 -1
  212. package/dist/{types-Dv-9WPJX.d.ts → types-BsYXnC5s.d.ts} +39 -3
  213. package/dist/types-CxW2e0Ar.d.ts +132 -0
  214. package/dist/{types-Z9wv19v2.d.ts → types-DgGlgyZT.d.ts} +1 -1
  215. package/dist/types-ElOJAGaM.esm.js +189 -0
  216. package/dist/video-C2WIj6TS.esm.js +36 -0
  217. package/dist/video-selfie.d.ts +351 -0
  218. package/dist/video-selfie.esm.js +1509 -0
  219. package/dist/videoSelfieSteps-7M5vxKn-.esm.js +58 -0
  220. package/dist/{warmup--6HA3yUR.d.ts → warmup-BJZPQIiX.d.ts} +5 -1
  221. package/dist/wasm.d.ts +4 -4
  222. package/dist/wasm.esm.js +17 -14
  223. package/dist/watchlist-for-business.d.ts +2 -1
  224. package/dist/watchlist-for-business.esm.js +6 -5
  225. package/dist/watchlist.d.ts +2 -1
  226. package/dist/watchlist.esm.js +6 -5
  227. package/dist/{watchlistForBusinessStateMachine-DtefJb-D.esm.js → watchlistForBusinessStateMachine-DvEunDxs.esm.js} +3 -3
  228. package/dist/{watchlistStateMachine-B0aIS2_n.esm.js → watchlistStateMachine-AHXVf-TB.esm.js} +3 -3
  229. package/dist/workflow.d.ts +230 -98
  230. package/dist/workflow.esm.js +123 -79
  231. package/dist/{xstate.esm-Dkm1jy5u.esm.js → xstate.esm-Bomq1a0z.esm.js} +41 -1
  232. package/package.json +16 -1
  233. package/dist/IpifyProvider-oZf7Ke1O.esm.js +0 -167
  234. package/dist/camera-x4LjGTjZ.esm.js +0 -22
  235. package/dist/deepsightService-ByNKY5Jv.d.ts +0 -276
  236. package/dist/faceCaptureManagerFactory-CL-7T_vH.d.ts +0 -731
  237. package/dist/getBrowser-Dv8LZyHE.esm.js +0 -8
  238. package/dist/openviduLazy-B_s6jnEk.esm.js +0 -3
  239. package/dist/setup-C7tintPc.esm.js +0 -1064
  240. /package/dist/{Actor-fIPLXfoi.d.ts → Actor-CGEelYtQ.d.ts} +0 -0
  241. /package/dist/{BrowserTimerProvider-BVgutW_b.esm.js → BrowserTimerProvider-CHloo0eQ.esm.js} +0 -0
  242. /package/dist/{ITimerCapability-BvH0pDwp.esm.js → ITimerCapability-pltuG1E8.esm.js} +0 -0
  243. /package/dist/{MotionSensorProvider-C9fPAJdS.esm.js → MotionSensorProvider-DCbId4De.esm.js} +0 -0
  244. /package/dist/{apiError-D-GTvFrH.esm.js → apiError-DNS2OCEX.esm.js} +0 -0
  245. /package/dist/{camera-biGPWlmx.d.ts → camera-CNVUo-bC.d.ts} +0 -0
  246. /package/dist/{canvas-7uX2izHb.esm.js → canvas-_I95hkPg.esm.js} +0 -0
  247. /package/dist/{chunk-BK1xu56N.esm.js → chunk-CIKcdghV.esm.js} +0 -0
  248. /package/dist/{cpf-xBg-DFNn.esm.js → cpf-BKaho0j_.esm.js} +0 -0
  249. /package/dist/{dateUtils-8dCcuArE.esm.js → dateUtils-7-tQYRNN.esm.js} +0 -0
  250. /package/dist/{getDeviceClass-C0zrM97a.esm.js → getDeviceClass-DavNdcxh.esm.js} +0 -0
  251. /package/dist/{http-CfVTgMfU.esm.js → http-BkiUT7EB.esm.js} +0 -0
  252. /package/dist/{index-52_qi4bd.d.ts → index-XTtxaahe.d.ts} +0 -0
  253. /package/dist/{otp-D87RTwrx.esm.js → otp-Bfnzf7I3.esm.js} +0 -0
  254. /package/dist/{otp-BHJnjEEc.d.ts → otp-M4iy57XY.d.ts} +0 -0
  255. /package/dist/{platform-BfoqeM61.esm.js → platform-uIVQUnJP.esm.js} +0 -0
  256. /package/dist/{types-BdVOWGGW.esm.js → types-CMcxlSmH.esm.js} +0 -0
  257. /package/dist/{types-DYZja-k9.d.ts → types-D_IceWxT.d.ts} +0 -0
  258. /package/dist/{types-F0IXbaCB.d.ts → types-Duy2rDxF.d.ts} +0 -0
  259. /package/dist/{urlUtils-8RNHyW3x.esm.js → urlUtils-BZqFU9rR.esm.js} +0 -0
@@ -0,0 +1,1494 @@
1
+ import { t as WasmUtilProvider } from "./WasmUtilProvider-ADG54T6M.esm.js";
2
+ import { t as BrowserTimerProvider } from "./BrowserTimerProvider-CHloo0eQ.esm.js";
3
+ import { t as api } from "./api-DsbUi7TO.esm.js";
4
+ import { a as createApi_default, t as getStoredHttpConfig } from "./clientLifecycle-Ct7h9uxx.esm.js";
5
+ import { n as eventModuleNames } from "./types-ElOJAGaM.esm.js";
6
+ import { t as endpoints } from "./endpoints-BzMJFAPV.esm.js";
7
+ import "./stats-CYcScXcO.esm.js";
8
+ import { n as isBrowserSimulation, o as BrowserEnvironmentProvider } from "./browserSimulation-TsSoavQv.esm.js";
9
+ import { t as getDeviceFingerprintInfo } from "./getDeviceData-TrKM8NPh.esm.js";
10
+ import { t as getThumbmarkId } from "./thumbmarkAdapter-fHBUDlAP.esm.js";
11
+ import "./platform-uIVQUnJP.esm.js";
12
+ import { a as fromPromise, i as fromCallback, l as createManager, r as assign, s as createActor, t as setup } from "./xstate.esm-Bomq1a0z.esm.js";
13
+ import "./MotionSensorProvider-DCbId4De.esm.js";
14
+ import { i as requestPermission, t as checkPermission } from "./permissionServices-BJhGL13R.esm.js";
15
+ import { a as stopCameraStream, r as requestCameraAccess } from "./camera-DUkgmYMo.esm.js";
16
+ import { t as BrowserStorageProvider } from "./BrowserStorageProvider-CrrN540a.esm.js";
17
+ import { b as FaceDetectionProvider, f as stopStream, l as startDetection, s as initializeDeepsightSession } from "./onDeviceFaceResults-DVBggeq8.esm.js";
18
+ import { t as sleep } from "./ITimerCapability-pltuG1E8.esm.js";
19
+ import "./canvas-_I95hkPg.esm.js";
20
+ import "./backCameraStream-ZyqrFyjO.esm.js";
21
+ import "./video-C2WIj6TS.esm.js";
22
+ import "./getDeviceClass-DavNdcxh.esm.js";
23
+ import "./deepsightService-CDahSjGP.esm.js";
24
+ import "./getDeviceClass-DGGzzfqm.esm.js";
25
+ import "./types-CMcxlSmH.esm.js";
26
+ import { t as StreamCanvasCapture } from "./StreamCanvasCapture-Bz17q4FP.esm.js";
27
+
28
+ //#region ../infra/src/crypto/randomUUID.ts
29
+ /**
30
+ * Cryptographically-strong UUID v4 (RFC 4122).
31
+ *
32
+ * Lives in infra (L0) so Core (L1) can mint secure identifiers without touching
33
+ * the `crypto` browser API directly — Core delegates here, keeping it free of
34
+ * browser globals (enforced by the `no-browser-api-in-core` lint rule). Backed
35
+ * by `crypto.randomUUID`, available in every browser the SDK targets.
36
+ */
37
+ function randomUUID() {
38
+ return crypto.randomUUID();
39
+ }
40
+
41
+ //#endregion
42
+ //#region src/modules/personhood/personhoodServices.ts
43
+ /**
44
+ * Config used for the passive liveness pass. Deliberately stripped down from
45
+ * selfie: no recording, no validation rituals, no headwear/mask checks — we
46
+ * want the lowest-friction path to a single head-pose-tracked liveness shot.
47
+ */
48
+ const PERSONHOOD_FACE_CAPTURE_CONFIG = {
49
+ showTutorial: false,
50
+ showPreview: false,
51
+ assistedOnboarding: false,
52
+ enableFaceRecording: false,
53
+ autoCaptureTimeout: 8e3,
54
+ captureAttempts: 2,
55
+ validateLenses: false,
56
+ validateFaceMask: false,
57
+ validateHeadCover: false,
58
+ validateClosedEyes: false,
59
+ validateBrightness: false,
60
+ deepsightLiveness: "SINGLE_FRAME",
61
+ ds: false
62
+ };
63
+ const PERSONHOOD_CAMERA_CONSTRAINTS = {
64
+ video: {
65
+ facingMode: "user",
66
+ height: { ideal: 480 },
67
+ width: { ideal: 640 }
68
+ },
69
+ audio: false
70
+ };
71
+ /**
72
+ * Boots the Deepsight session used to back-stop the on-device liveness check.
73
+ * Independent of `initializePersonhoodCamera` so the two can proceed in
74
+ * parallel during the permission / collect-signals phase.
75
+ */
76
+ async function initializePersonhoodDeepsight(params) {
77
+ return initializeDeepsightSession({
78
+ storage: params.storage,
79
+ ds: false
80
+ });
81
+ }
82
+ /**
83
+ * Boots the camera stream and WASM face-detection pipeline as fast as
84
+ * possible after the user grants permission. Optimized for low latency
85
+ * between "permission granted" and "avatar begins tracking":
86
+ *
87
+ * 1. WASM model loading and `getUserMedia` run **in parallel** — they're
88
+ * independent I/O and were previously sequential, which stacked
89
+ * 50-500ms of avoidable latency.
90
+ * 2. Deepsight PRC warmup (anti-spoof pipeline priming) is fired as a
91
+ * **background task** after the real stream is open. It's not needed
92
+ * for face detection or pose tracking — only for the post-capture
93
+ * `analyzeFrame` step. `analyzeLiveness` degrades gracefully if PRC
94
+ * hasn't finished in time.
95
+ *
96
+ * Earlier versions opened a second hidden camera stream for PRC warmup
97
+ * BEFORE opening the real one, which on Safari/Firefox serialized the
98
+ * two `getUserMedia` calls and added visible lag before the avatar came
99
+ * alive.
100
+ */
101
+ async function initializePersonhoodCamera(params) {
102
+ const provider = new FaceDetectionProvider();
103
+ const [initResult, streamResult] = await Promise.allSettled([provider.initialize({ autocaptureInterval: PERSONHOOD_FACE_CAPTURE_CONFIG.autoCaptureTimeout * 1e3 }), requestCameraAccess(PERSONHOOD_CAMERA_CONSTRAINTS)]);
104
+ if (streamResult.status === "rejected") {
105
+ if (initResult.status === "fulfilled") provider.dispose();
106
+ throw streamResult.reason;
107
+ }
108
+ const stream = streamResult.value;
109
+ if (initResult.status === "rejected") {
110
+ stopCameraStream(stream);
111
+ throw initResult.reason;
112
+ }
113
+ provider.setChecksEnabled({
114
+ lenses: false,
115
+ mask: false,
116
+ closedEyes: false,
117
+ headWear: false,
118
+ occlusion: false
119
+ });
120
+ if (params.deepsightService) params.deepsightService.performPrcCheck({ constraints: PERSONHOOD_CAMERA_CONSTRAINTS }).catch(() => {});
121
+ return {
122
+ stream,
123
+ provider
124
+ };
125
+ }
126
+ /**
127
+ * Wraps the existing face-capture detection loop for the Personhood flow.
128
+ *
129
+ * - Drops the captured canvas (we never upload the raw frame).
130
+ * - Forwards per-frame `onFaceData` into `onPose` so the avatar can mirror
131
+ * the user's head in real time.
132
+ */
133
+ const AUTO_COMPLETE_DEADLINE_MS = 4e3;
134
+ function runPersonhoodDetection(params) {
135
+ let forcedCaptureFired = false;
136
+ const timer = BrowserTimerProvider.getInstance();
137
+ let autoCompleteTimer = null;
138
+ let autoCompleteArmed = false;
139
+ const cancelAutoComplete = () => {
140
+ if (autoCompleteTimer !== null) {
141
+ timer.clearTimeout(autoCompleteTimer);
142
+ autoCompleteTimer = null;
143
+ }
144
+ };
145
+ const fireForceCapture = () => {
146
+ if (forcedCaptureFired) return;
147
+ forcedCaptureFired = true;
148
+ cancelAutoComplete();
149
+ params.provider.forceCapture();
150
+ };
151
+ const armAutoComplete = () => {
152
+ if (autoCompleteArmed) return;
153
+ autoCompleteArmed = true;
154
+ if (!params.autoComplete) return;
155
+ autoCompleteTimer = timer.setTimeout(() => {
156
+ autoCompleteTimer = null;
157
+ fireForceCapture();
158
+ }, AUTO_COMPLETE_DEADLINE_MS);
159
+ };
160
+ const innerResult = startDetection({
161
+ config: PERSONHOOD_FACE_CAPTURE_CONFIG,
162
+ capturer: params.capturer,
163
+ provider: params.provider,
164
+ onUpdate: params.onStatus,
165
+ onFrame: () => armAutoComplete(),
166
+ onPose: (face, frameSize) => {
167
+ let faceSizeRatio;
168
+ if (frameSize && frameSize.width > 0 && frameSize.height > 0 && face.rect.width > 0 && face.rect.height > 0) faceSizeRatio = Math.sqrt(face.rect.width * face.rect.height) / Math.min(frameSize.width, frameSize.height);
169
+ params.onPose({
170
+ pitch: face.pitch,
171
+ yaw: face.yaw,
172
+ roll: face.roll,
173
+ faceSizeRatio
174
+ });
175
+ },
176
+ onSuccess: (canvas) => {
177
+ cancelAutoComplete();
178
+ params.onSuccess(canvas);
179
+ }
180
+ });
181
+ return {
182
+ cleanup: () => {
183
+ cancelAutoComplete();
184
+ innerResult.cleanup();
185
+ },
186
+ reset: innerResult.reset
187
+ };
188
+ }
189
+ /**
190
+ * Runs the Deepsight pipeline against the stream + captured frame and pairs
191
+ * the result with the locally-observed pose motion. All work happens on the
192
+ * device — no network round-trip.
193
+ *
194
+ * The returned `LivenessOutcome` is fed into {@link produceLocalVerdict}:
195
+ * - `virtualCamera: true` → hard reject (OBS/ManyCam)
196
+ * - `analysisStatus !== 'PASS'` → reject with `spoof_suspected`
197
+ * - `yawRange + pitchRange < MIN_POSE_MOTION_DEG` → reject with `no_motion`
198
+ */
199
+ async function analyzeLiveness(params) {
200
+ let virtualCamera = false;
201
+ let analysisStatus = "";
202
+ let motionStatus = "";
203
+ let metadata = "";
204
+ let pipelineState = "";
205
+ const deepsight = params.deepsightService;
206
+ if (deepsight) {
207
+ try {
208
+ const videoTrack = params.stream?.getVideoTracks()[0];
209
+ if (videoTrack) virtualCamera = await deepsight.checkVirtualCamera(videoTrack);
210
+ } catch {}
211
+ try {
212
+ await deepsight.performVirtualCameraCheck(params.token ?? null, "SELFIE");
213
+ } catch {}
214
+ try {
215
+ const imageData = params.capturedImage?.getImageData();
216
+ if (imageData) await deepsight.analyzeFrame(imageData);
217
+ } catch {}
218
+ try {
219
+ analysisStatus = deepsight.getAnalysisStatus();
220
+ motionStatus = deepsight.getMotionStatus();
221
+ pipelineState = deepsight.getPipelineState();
222
+ metadata = deepsight.getMetadata();
223
+ } catch {}
224
+ }
225
+ return {
226
+ virtualCamera,
227
+ analysisStatus,
228
+ motionStatus,
229
+ yawRange: params.yawRange,
230
+ pitchRange: params.pitchRange,
231
+ metadata,
232
+ pipelineState
233
+ };
234
+ }
235
+ /**
236
+ * Minimum combined yaw+pitch range (in degrees) required across the
237
+ * detection window to clear the no-motion guard. A static photo or a
238
+ * face with no head movement will fall below this.
239
+ */
240
+ const MIN_POSE_MOTION_DEG = 4;
241
+ /**
242
+ * Upper bound of motion (degrees) that adds confidence — beyond this,
243
+ * additional head movement doesn't increase our belief that there's a
244
+ * human (and may just be noise from a moving phone).
245
+ */
246
+ const MAX_POSE_MOTION_FOR_BONUS_DEG = 50;
247
+ /**
248
+ * Ceiling for on-device verdicts. Intentionally below 1.0 — nothing short
249
+ * of a signed server round-trip should claim perfect confidence, and the
250
+ * ceiling is strictly below what a server verdict would return so the two
251
+ * paths are distinguishable to integrators.
252
+ */
253
+ const LOCAL_CONFIDENCE_CEILING = .95;
254
+ /**
255
+ * Default pass threshold when `PersonhoodConfig.threshold` is omitted. Single
256
+ * source of truth — keep `PersonhoodConfig.threshold`'s JSDoc and PERSONHOOD.md
257
+ * in sync with this value. (A clean local pass without strong head motion lands
258
+ * around here, so this is the effective on-device gate.)
259
+ */
260
+ const DEFAULT_PERSONHOOD_THRESHOLD = .75;
261
+ /**
262
+ * Produces a verdict entirely on-device using an **additive** confidence
263
+ * model. Each positive signal contributes a measurable amount to the score;
264
+ * penalties subtract. This means clean passes vary — a user who swings
265
+ * through a full head turn scores higher than one who barely moves — which
266
+ * is useful for integrators that want to tune their own thresholds.
267
+ *
268
+ * Positive signals (contribute up to +0.95):
269
+ * - Successful detection → +0.25
270
+ * - Pose motion (linear from min to max) → up to +0.25
271
+ * - Clean device signals (no automation) → +0.05
272
+ * - Deepsight analysis: no explicit spoof → +0.05
273
+ * - Deepsight motion status == PASS → +0.05
274
+ * - Baseline presence → +0.30
275
+ *
276
+ * Penalties (hard rejects or large deductions):
277
+ * - `navigator.webdriver` true → -0.9
278
+ * - Automation markers → -0.9
279
+ * - Headless hints → -0.3
280
+ * - Virtual camera detected → -0.9
281
+ * - Explicit spoof/injection in analysis → -0.4
282
+ * - No head motion (below MIN_POSE_MOTION) → -0.5
283
+ * - Detection didn't reach 'success' → -0.2
284
+ */
285
+ function produceLocalVerdict(params) {
286
+ const threshold = params.threshold ?? DEFAULT_PERSONHOOD_THRESHOLD;
287
+ const reasons = [];
288
+ let confidence = .4;
289
+ if (params.detectionOutcome === "success") confidence += .25;
290
+ else {
291
+ reasons.push(`detection:${params.detectionOutcome}`);
292
+ confidence -= .2;
293
+ }
294
+ if (params.liveness) {
295
+ const motion = params.liveness.yawRange + params.liveness.pitchRange;
296
+ if (motion < MIN_POSE_MOTION_DEG) {
297
+ reasons.push("no_motion");
298
+ confidence -= .5;
299
+ } else {
300
+ const span = MAX_POSE_MOTION_FOR_BONUS_DEG - MIN_POSE_MOTION_DEG;
301
+ const motionRatio = Math.min(1, Math.max(0, (motion - MIN_POSE_MOTION_DEG) / span));
302
+ confidence += .25 * motionRatio;
303
+ }
304
+ if (!hasExplicitSpoofSignal(params.liveness.analysisStatus)) confidence += .05;
305
+ else {
306
+ reasons.push("spoof_suspected");
307
+ confidence -= .4;
308
+ }
309
+ if (isMotionStatusPass(params.liveness.motionStatus)) confidence += .05;
310
+ }
311
+ if (!(params.signals.webdriver || params.signals.emulator || params.signals.headlessHints.length > 0)) confidence += .05;
312
+ if (params.signals.webdriver) {
313
+ reasons.push("webdriver");
314
+ confidence -= .9;
315
+ }
316
+ if (params.signals.emulator) {
317
+ reasons.push("emulator");
318
+ confidence -= .9;
319
+ }
320
+ const SUBSUMED_HINTS = new Set(["navigator.webdriver", "automation-marker"]);
321
+ if (params.signals.headlessHints.filter((hint) => !SUBSUMED_HINTS.has(hint)).length > 0) {
322
+ reasons.push("headless");
323
+ confidence -= .3;
324
+ }
325
+ if (params.liveness?.virtualCamera) {
326
+ reasons.push("virtual_camera");
327
+ confidence -= .9;
328
+ }
329
+ confidence = Math.min(LOCAL_CONFIDENCE_CEILING, Math.max(0, confidence));
330
+ confidence = Math.round(confidence * 1e3) / 1e3;
331
+ if (confidence < threshold && reasons.length === 0) reasons.push("low_confidence");
332
+ const human = confidence >= threshold && reasons.length === 0;
333
+ return {
334
+ human,
335
+ confidence,
336
+ evidenceId: generateEvidenceId(params.siteKey),
337
+ reason: human ? void 0 : reasons.join(","),
338
+ signals: params.signals,
339
+ liveness: params.liveness,
340
+ spoofCheckResults: buildSpoofCheckResults({
341
+ signals: params.signals,
342
+ liveness: params.liveness,
343
+ detectionOutcome: params.detectionOutcome
344
+ })
345
+ };
346
+ }
347
+ function isMotionStatusPass(status) {
348
+ return status.trim().toUpperCase() === "PASS";
349
+ }
350
+ /**
351
+ * Tests whether the Deepsight analysis status contains an explicit spoof /
352
+ * injection / fail signal.
353
+ *
354
+ * The WASM's `getCheck()` returns a pipeline-state blob intended primarily
355
+ * for backend consumption — the server is what turns the blob into a
356
+ * pass/fail. In phase 0 (no session, no backend round-trip) we intentionally
357
+ * only treat the output as a negative signal when it contains an explicit
358
+ * failure token; everything else is indeterminate and we defer to the
359
+ * other local checks (virtual camera + pose motion + device signals).
360
+ *
361
+ * Without this, every clean capture in a session-less dev demo was
362
+ * erroneously flagged as spoof_suspected because the WASM didn't emit
363
+ * literally "PASS".
364
+ */
365
+ function hasExplicitSpoofSignal(status) {
366
+ const normalized = status.toUpperCase();
367
+ return normalized.includes("FAIL") || normalized.includes("SPOOF") || normalized.includes("INJECTION");
368
+ }
369
+ /**
370
+ * Requests a server-side verdict when the browser can't run the on-device
371
+ * liveness pass (no camera, blocked permission, incompatible browser). The
372
+ * same API surface is returned to the widget so integrators see a single
373
+ * universal `{ human, confidence, evidence_id }` shape.
374
+ *
375
+ * The confidence returned by this path is intentionally capped below the
376
+ * on-device ceiling — with no camera we can only score device / behavioural
377
+ * signals, which are weaker evidence of humanness.
378
+ */
379
+ async function requestServerFallbackVerdict(params) {
380
+ if (params.mockFallback) return mockServerFallback(params);
381
+ try {
382
+ const res = await api.post(endpoints.personhoodServerFallback, {
383
+ siteKey: params.siteKey,
384
+ signals: params.signals,
385
+ reason: params.reason
386
+ }, { signal: params.signal });
387
+ if (!res.ok) throw new Error(`POST ${endpoints.personhoodServerFallback} failed: ${res.status} ${res.statusText}`);
388
+ return res.data;
389
+ } catch (error) {
390
+ if (isApiNotConfigured(error)) return mockServerFallback(params);
391
+ throw error;
392
+ }
393
+ }
394
+ async function mockServerFallback(params) {
395
+ await sleep(200);
396
+ const blocked = params.signals.webdriver || params.signals.emulator || params.signals.headlessHints.length > 0;
397
+ const spoofCheckResults = buildSpoofCheckResults({
398
+ signals: params.signals,
399
+ liveness: void 0,
400
+ detectionOutcome: "error"
401
+ });
402
+ if (blocked) return {
403
+ human: false,
404
+ confidence: .1,
405
+ evidenceId: generateEvidenceId(params.siteKey),
406
+ reason: "automation_markers",
407
+ signals: params.signals,
408
+ spoofCheckResults
409
+ };
410
+ return {
411
+ human: true,
412
+ confidence: .72,
413
+ evidenceId: generateEvidenceId(params.siteKey),
414
+ reason: `fallback:${params.reason}`,
415
+ signals: params.signals,
416
+ spoofCheckResults
417
+ };
418
+ }
419
+ /**
420
+ * Pulls a token string out of `/omni/personhood/token`'s response,
421
+ * regardless of which envelope the backend uses. The Incode service
422
+ * surface has historically returned tokens under several keys
423
+ * (`token`, `interviewToken`, `sessionToken`, `access_token`, raw
424
+ * `id`) and a few endpoints return the bare string in the body.
425
+ * Trying each in order and returning the first non-empty value
426
+ * means we don't have to second-guess the contract — when the
427
+ * backend changes shape, the diagnostic log of `res.data` in the
428
+ * caller still surfaces the raw response.
429
+ */
430
+ function extractTokenFromResponse(data) {
431
+ if (typeof data === "string" && data.length > 0) return data;
432
+ if (data && typeof data === "object") {
433
+ const obj = data;
434
+ const candidates = [
435
+ obj.token,
436
+ obj.interviewToken,
437
+ obj.sessionToken,
438
+ obj.access_token,
439
+ obj.accessToken,
440
+ obj.id,
441
+ obj.data?.token,
442
+ obj.data?.interviewToken
443
+ ];
444
+ for (const candidate of candidates) if (typeof candidate === "string" && candidate.length > 0) return candidate;
445
+ }
446
+ }
447
+ /**
448
+ * Pulls the verify endpoint's authoritative pass/fail boolean out
449
+ * of its response, regardless of envelope. Current backend
450
+ * contract: `{ "isHuman": boolean }`. Older / forward-compat
451
+ * shapes also tried so a server-side rename doesn't silently break
452
+ * the client. Returns `undefined` only when no recognizable field
453
+ * is present — caller treats that as "trust the local verdict".
454
+ */
455
+ function extractIsHumanFromResponse(data) {
456
+ if (typeof data === "boolean") return data;
457
+ if (data && typeof data === "object") {
458
+ const obj = data;
459
+ const candidates = [
460
+ obj.isHuman,
461
+ obj.human,
462
+ obj.passed,
463
+ obj.data?.isHuman,
464
+ obj.data?.human,
465
+ obj.result?.isHuman
466
+ ];
467
+ for (const candidate of candidates) if (typeof candidate === "boolean") return candidate;
468
+ }
469
+ }
470
+ /**
471
+ * Mints the personhood `Authorization: Bearer` token via the OAuth2
472
+ * client-credentials grant against {@link endpoints.personhoodOAuthToken}
473
+ * (`POST /omni/oauth2/token`, `application/x-www-form-urlencoded`,
474
+ * `grant_type=client_credentials&scope=openid`). Returns the
475
+ * `access_token` (a signed JWT); the caller (state machine `fetchToken`
476
+ * actor) lands it in actor context where downstream services receive it
477
+ * as an explicit input. No module-level slot — concurrent personhood
478
+ * instances stay isolated, and `actor.stop()` cleans up implicitly.
479
+ *
480
+ * Mock path returns a `mock-token-*` string after a short delay so
481
+ * `mockVerify=true` flows complete without a configured backend.
482
+ *
483
+ * Replaces the removed `GET /omni/personhood/token` (ENG-45783).
484
+ */
485
+ async function fetchPersonhoodAuthToken(params = {}) {
486
+ if (params.mockVerify) {
487
+ await sleep(50);
488
+ return `mock-token-${randomUUID()}`;
489
+ }
490
+ const form = {
491
+ grant_type: "client_credentials",
492
+ scope: "openid"
493
+ };
494
+ if (params.clientId) form.client_id = params.clientId;
495
+ if (params.clientSecret) form.client_secret = params.clientSecret;
496
+ const body = new URLSearchParams(form).toString();
497
+ const authPath = params.authBaseUrl ? endpoints.personhoodOAuthTokenDirect : endpoints.personhoodOAuthToken;
498
+ const reqConfig = {
499
+ signal: params.signal,
500
+ headers: { "Content-Type": "application/x-www-form-urlencoded" }
501
+ };
502
+ try {
503
+ let res;
504
+ if (params.authBaseUrl) res = await createApi_default({
505
+ apiURL: params.authBaseUrl,
506
+ customHeaders: getStoredHttpConfig()?.customHeaders
507
+ }).post(authPath, body, reqConfig);
508
+ else res = await api.post(authPath, body, reqConfig);
509
+ if (!res.ok) throw new Error(`POST ${authPath} failed: ${res.status} ${res.statusText}`);
510
+ const token = extractTokenFromResponse(res.data);
511
+ if (!token) throw new Error(`POST ${authPath} returned no access_token`);
512
+ return token;
513
+ } catch (error) {
514
+ if (isApiNotConfigured(error)) return fetchPersonhoodAuthToken({
515
+ ...params,
516
+ mockVerify: true
517
+ });
518
+ throw error;
519
+ }
520
+ }
521
+ /**
522
+ * Builds the full per-check breakdown that lands on
523
+ * {@link PersonhoodVerdict.spoofCheckResults} and in the verify
524
+ * POST body. One entry per check the SDK ran, with a stable id, a
525
+ * `passed | failed | unknown` outcome, and (on failure) a short
526
+ * tag the server can pattern-match on.
527
+ *
528
+ * This is the single source of truth for "what did the on-device
529
+ * pipeline check?" — both {@link produceLocalVerdict} and the
530
+ * verify POST consume it. Adding a new check here automatically
531
+ * surfaces it to integrators and to the backend without touching
532
+ * the state machine or the verify wire format.
533
+ *
534
+ * Conservative defaults: when a pipeline didn't run (no liveness
535
+ * outcome / Deepsight not initialized), the dependent checks are
536
+ * reported as `unknown`. This lets the server distinguish "we
537
+ * tested and the user passed" from "we couldn't test", which is a
538
+ * meaningful gradient for risk scoring.
539
+ */
540
+ function buildSpoofCheckResults(params) {
541
+ const results = [];
542
+ const { signals, liveness, detectionOutcome } = params;
543
+ if (detectionOutcome === "success") results.push({
544
+ check: "faceDetection",
545
+ result: "passed"
546
+ });
547
+ else results.push({
548
+ check: "faceDetection",
549
+ result: "failed",
550
+ reason: `detection:${detectionOutcome}`
551
+ });
552
+ if (liveness) {
553
+ if (liveness.analysisStatus === "PASS") results.push({
554
+ check: "physicalAttack",
555
+ result: "passed"
556
+ });
557
+ else if (hasExplicitSpoofSignal(liveness.analysisStatus)) results.push({
558
+ check: "physicalAttack",
559
+ result: "failed",
560
+ reason: liveness.analysisStatus || "spoof_suspected"
561
+ });
562
+ else results.push({
563
+ check: "physicalAttack",
564
+ result: "unknown"
565
+ });
566
+ results.push({
567
+ check: "virtualCamera",
568
+ result: liveness.virtualCamera ? "failed" : "passed",
569
+ ...liveness.virtualCamera ? { reason: "virtual_camera" } : {}
570
+ });
571
+ if (liveness.motionStatus === "PASS") results.push({
572
+ check: "motionLiveness",
573
+ result: "passed"
574
+ });
575
+ else if (liveness.motionStatus === "FAIL") results.push({
576
+ check: "motionLiveness",
577
+ result: "failed",
578
+ reason: "no_motion"
579
+ });
580
+ else results.push({
581
+ check: "motionLiveness",
582
+ result: "unknown"
583
+ });
584
+ if (liveness.yawRange + liveness.pitchRange >= MIN_POSE_MOTION_DEG) results.push({
585
+ check: "headMotion",
586
+ result: "passed"
587
+ });
588
+ else results.push({
589
+ check: "headMotion",
590
+ result: "failed",
591
+ reason: "no_motion"
592
+ });
593
+ } else {
594
+ results.push({
595
+ check: "physicalAttack",
596
+ result: "unknown"
597
+ });
598
+ results.push({
599
+ check: "virtualCamera",
600
+ result: "unknown"
601
+ });
602
+ results.push({
603
+ check: "motionLiveness",
604
+ result: "unknown"
605
+ });
606
+ results.push({
607
+ check: "headMotion",
608
+ result: "unknown"
609
+ });
610
+ }
611
+ results.push({
612
+ check: "webdriver",
613
+ result: signals.webdriver ? "failed" : "passed",
614
+ ...signals.webdriver ? { reason: "webdriver" } : {}
615
+ });
616
+ results.push({
617
+ check: "emulator",
618
+ result: signals.emulator ? "failed" : "passed",
619
+ ...signals.emulator ? { reason: "emulator" } : {}
620
+ });
621
+ const independentHeadlessHints = signals.headlessHints.filter((hint) => hint !== "navigator.webdriver" && hint !== "automation-marker");
622
+ results.push({
623
+ check: "headlessBrowser",
624
+ result: independentHeadlessHints.length > 0 ? "failed" : "passed",
625
+ ...independentHeadlessHints.length > 0 ? { reason: independentHeadlessHints.join(",") } : {}
626
+ });
627
+ return results;
628
+ }
629
+ /**
630
+ * Trims the rich client-side {@link SpoofCheckResult} array down to the wire
631
+ * shape the verify POST expects: `check` + `result` only (the `reason` field is
632
+ * dropped — not part of the contract). Entry order is preserved so the server
633
+ * sees them in detection-pipeline order (face → physical → virtual → motion →
634
+ * head → automation). `unknown` results are passed through as-is —
635
+ * `SpoofCheckResultWire.result` is `'passed' | 'failed' | 'unknown'`. (Whether
636
+ * the backend should instead receive only `passed | failed` is an open
637
+ * server-contract question, tracked with the wider verify-contract work.)
638
+ */
639
+ function toWireSpoofCheckResults(results) {
640
+ const wire = [];
641
+ for (const entry of results) wire.push({
642
+ check: entry.check,
643
+ result: entry.result
644
+ });
645
+ return wire;
646
+ }
647
+ /**
648
+ * On-device verify hop — POST `/omni/personhood/verify` with the
649
+ * Deepsight metadata + derived `spoofCheckResults`. The personhood
650
+ * Bearer token (passed in via `params.token`, minted by the OAuth2
651
+ * client-credentials hop and threaded through actor context) is
652
+ * attached as `Authorization: Bearer <token>`.
653
+ *
654
+ * When the server returns a recognizable `isHuman` boolean, that
655
+ * value becomes the authoritative pass/fail on the returned
656
+ * verdict. Otherwise (HTTP error, missing field, network blip,
657
+ * SDK not configured) we fall back to the local on-device verdict
658
+ * the caller passed in — keeping the widget functional in flaky
659
+ * conditions. `mockVerify: true` short-circuits to the fallback
660
+ * verdict without hitting the network.
661
+ */
662
+ async function verifyPersonhoodOnDevice(params) {
663
+ if (params.mockVerify) {
664
+ await sleep(50);
665
+ return params.fallbackVerdict;
666
+ }
667
+ try {
668
+ const personhoodToken = params.token;
669
+ const res = await api.post(endpoints.personhoodOnDeviceVerify, {
670
+ metadata: params.metadata,
671
+ spoofCheckResults: toWireSpoofCheckResults(params.spoofCheckResults)
672
+ }, {
673
+ signal: params.signal,
674
+ ...personhoodToken ? { headers: { Authorization: `Bearer ${personhoodToken}` } } : {}
675
+ });
676
+ if (!res.ok) throw new Error(`POST ${endpoints.personhoodOnDeviceVerify} failed: ${res.status} ${res.statusText}`);
677
+ const serverData = res.data;
678
+ const serverIsHuman = extractIsHumanFromResponse(serverData);
679
+ if (typeof serverIsHuman !== "boolean") return params.fallbackVerdict;
680
+ const finalReason = serverIsHuman ? void 0 : params.fallbackVerdict.reason ?? "server_rejected";
681
+ return {
682
+ ...params.fallbackVerdict,
683
+ human: serverIsHuman,
684
+ confidence: serverIsHuman ? .95 : .05,
685
+ reason: finalReason
686
+ };
687
+ } catch {
688
+ return params.fallbackVerdict;
689
+ }
690
+ }
691
+ function isApiNotConfigured(error) {
692
+ return error instanceof Error && error.message.includes("SDK not configured");
693
+ }
694
+ function generateEvidenceId(siteKey) {
695
+ return `ph_${(siteKey || "site").replace(/[^a-zA-Z0-9_-]/g, "").slice(0, 12)}_${randomUUID().replace(/-/g, "")}`;
696
+ }
697
+
698
+ //#endregion
699
+ //#region src/modules/personhood/personhoodSignals.ts
700
+ /**
701
+ * Returns a placeholder {@link DeviceBehavioralSignals} for the
702
+ * narrow set of code paths that need to operate before the real
703
+ * `collectDeviceBehavioralSignals()` has resolved (or where it
704
+ * errored out and the parallel `signals` branch landed in `done`
705
+ * with `context.signals` still undefined). Single source of truth
706
+ * — every call site that previously inlined this literal now
707
+ * imports from here.
708
+ */
709
+ function emptySignals() {
710
+ return {
711
+ deviceFingerprint: "",
712
+ userAgentClass: "unknown",
713
+ emulator: false,
714
+ webdriver: false,
715
+ headlessHints: []
716
+ };
717
+ }
718
+ /**
719
+ * Collects the device + behavioural bundle returned alongside the human
720
+ * verdict. Intentionally offline-only (no IP geolookup) so a Personhood check
721
+ * does not pay the latency of an external call in the hot path.
722
+ *
723
+ * The bundle is **opaque to the SDK** — the integrator uses these signals for
724
+ * their own dedup/risk logic. Personhood itself does NOT re-identify the human.
725
+ */
726
+ async function collectDeviceBehavioralSignals() {
727
+ const browserEnv = new BrowserEnvironmentProvider();
728
+ const [deviceFingerprint, deviceInfo] = await Promise.all([safeGetFingerprint(), safeGetDeviceInfo()]);
729
+ const webdriver = Boolean(browserEnv.getNavigatorProperty("webdriver"));
730
+ const emulator = isBrowserSimulation(browserEnv);
731
+ const headlessHints = [];
732
+ if (webdriver) headlessHints.push("navigator.webdriver");
733
+ if (emulator) headlessHints.push("automation-marker");
734
+ const plugins = browserEnv.getNavigatorProperty("plugins");
735
+ const userAgent = browserEnv.getNavigatorProperty("userAgent")?.toLowerCase();
736
+ if (plugins && typeof plugins.length === "number" && plugins.length === 0 && userAgent?.includes("headless")) headlessHints.push("headless-user-agent");
737
+ return {
738
+ deviceFingerprint,
739
+ userAgentClass: formatUserAgentClass(deviceInfo),
740
+ emulator,
741
+ webdriver,
742
+ headlessHints
743
+ };
744
+ }
745
+ function formatUserAgentClass(info) {
746
+ if (!info) return "unknown";
747
+ const parts = [
748
+ info.browser?.name,
749
+ info.browser?.version,
750
+ info.os?.name,
751
+ info.os?.version,
752
+ info.device?.model
753
+ ].filter((part) => typeof part === "string" && part.length > 0);
754
+ return parts.length > 0 ? parts.join(" / ") : "unknown";
755
+ }
756
+ async function safeGetFingerprint() {
757
+ try {
758
+ return await getThumbmarkId();
759
+ } catch {
760
+ return "";
761
+ }
762
+ }
763
+ async function safeGetDeviceInfo() {
764
+ try {
765
+ return await getDeviceFingerprintInfo();
766
+ } catch {
767
+ return;
768
+ }
769
+ }
770
+
771
+ //#endregion
772
+ //#region src/modules/personhood/types.ts
773
+ const PERSONHOOD_ERROR_CODES = {
774
+ CAMERA_DENIED: "CAMERA_DENIED",
775
+ DETECTION_FAILED: "DETECTION_FAILED",
776
+ AUTH_TOKEN_FAILED: "AUTH_TOKEN_FAILED",
777
+ VERIFY_FAILED: "VERIFY_FAILED",
778
+ INJECTION_SUSPECTED: "INJECTION_SUSPECTED",
779
+ EMULATOR_DETECTED: "EMULATOR_DETECTED",
780
+ TIMEOUT: "TIMEOUT",
781
+ UNKNOWN: "UNKNOWN"
782
+ };
783
+
784
+ //#endregion
785
+ //#region src/modules/personhood/personhoodStateMachine.ts
786
+ const _personhoodMachine = setup({
787
+ types: {
788
+ context: {},
789
+ events: {},
790
+ input: {}
791
+ },
792
+ actors: {
793
+ checkPermission: fromPromise(async () => {
794
+ return checkPermission();
795
+ }),
796
+ requestPermission: fromPromise(async () => {
797
+ return requestPermission({ requestMotion: false });
798
+ }),
799
+ initializeCamera: fromPromise(async ({ input }) => {
800
+ return initializePersonhoodCamera({ deepsightService: input.deepsightService });
801
+ }),
802
+ initializeDeepsight: fromPromise(async ({ input }) => {
803
+ return initializePersonhoodDeepsight({ storage: input.dependencies.storage });
804
+ }),
805
+ collectSignals: fromPromise(async () => {
806
+ return collectDeviceBehavioralSignals();
807
+ }),
808
+ analyzeLiveness: fromPromise(async ({ input }) => {
809
+ return analyzeLiveness(input);
810
+ }),
811
+ runDetection: fromCallback(({ input, sendBack }) => {
812
+ let yawMin = Infinity;
813
+ let yawMax = -Infinity;
814
+ let pitchMin = Infinity;
815
+ let pitchMax = -Infinity;
816
+ const { cleanup, reset } = runPersonhoodDetection({
817
+ provider: input.provider,
818
+ capturer: input.frameCapturer,
819
+ autoComplete: input.autoComplete,
820
+ onStatus: (status) => sendBack({
821
+ type: "DETECTION_UPDATE",
822
+ status
823
+ }),
824
+ onPose: (pose) => {
825
+ if (pose.yaw < yawMin) yawMin = pose.yaw;
826
+ if (pose.yaw > yawMax) yawMax = pose.yaw;
827
+ if (pose.pitch < pitchMin) pitchMin = pose.pitch;
828
+ if (pose.pitch > pitchMax) pitchMax = pose.pitch;
829
+ },
830
+ onSuccess: (canvas) => {
831
+ sendBack({
832
+ type: "DETECTION_SUCCESS",
833
+ canvas,
834
+ yawRange: yawMax > yawMin ? yawMax - yawMin : 0,
835
+ pitchRange: pitchMax > pitchMin ? pitchMax - pitchMin : 0
836
+ });
837
+ }
838
+ });
839
+ sendBack({
840
+ type: "DETECTION_RESET_READY",
841
+ reset
842
+ });
843
+ return cleanup;
844
+ }),
845
+ produceLocalVerdict: fromPromise(async ({ input }) => {
846
+ return produceLocalVerdict({
847
+ siteKey: input.config.siteKey,
848
+ threshold: input.config.threshold,
849
+ signals: input.signals,
850
+ detectionOutcome: input.detectionStatus,
851
+ liveness: input.liveness
852
+ });
853
+ }),
854
+ requestServerFallback: fromPromise(async ({ input, signal }) => {
855
+ return requestServerFallbackVerdict({
856
+ siteKey: input.config.siteKey,
857
+ signals: input.signals,
858
+ reason: input.reason,
859
+ mockFallback: input.config.mockVerify,
860
+ signal
861
+ });
862
+ }),
863
+ fetchToken: fromPromise(async ({ input, signal }) => {
864
+ return fetchPersonhoodAuthToken({
865
+ clientId: input.config.clientId,
866
+ clientSecret: input.config.clientSecret,
867
+ authBaseUrl: input.config.authBaseUrl,
868
+ mockVerify: input.config.mockVerify,
869
+ signal
870
+ });
871
+ }),
872
+ verifyOnDevice: fromPromise(async ({ input, signal }) => {
873
+ return verifyPersonhoodOnDevice({
874
+ metadata: input.liveness?.metadata ?? "",
875
+ spoofCheckResults: input.localVerdict.spoofCheckResults,
876
+ fallbackVerdict: input.localVerdict,
877
+ mockVerify: input.config.mockVerify,
878
+ token: input.token,
879
+ signal
880
+ });
881
+ })
882
+ },
883
+ actions: {
884
+ setStreamAndProvider: assign(({ event }) => {
885
+ const output = event.output;
886
+ return {
887
+ stream: output.stream,
888
+ provider: output.provider,
889
+ frameCapturer: new StreamCanvasCapture(output.stream)
890
+ };
891
+ }),
892
+ setDetectionStatus: assign({ detectionStatus: ({ event }) => event.status }),
893
+ setCapturedImageAndRangeFromEvent: assign(({ event }) => {
894
+ const e = event;
895
+ return {
896
+ capturedImage: e.canvas,
897
+ yawRange: e.yawRange,
898
+ pitchRange: e.pitchRange
899
+ };
900
+ }),
901
+ setDeepsightServiceFromEvent: assign({ deepsightService: ({ event }) => event.output }),
902
+ setLivenessOutcomeFromEvent: assign({ livenessOutcome: ({ event }) => event.output }),
903
+ setResetDetection: assign({ resetDetection: ({ event }) => event.reset }),
904
+ setSignalsFromEvent: assign({ signals: ({ event }) => event.output }),
905
+ setTokenFromEvent: assign({ token: ({ event }) => event.output }),
906
+ setLocalVerdictFromEvent: assign({ localVerdict: ({ event }) => event.output }),
907
+ setVerdictFromEvent: assign({ verdict: ({ event }) => event.output }),
908
+ setPermissionResultFromEvent: assign({ permissionResult: ({ event }) => event.output }),
909
+ setPermissionDenied: assign({
910
+ permissionResult: () => "denied",
911
+ error: () => ({ code: PERSONHOOD_ERROR_CODES.CAMERA_DENIED })
912
+ }),
913
+ setDetectionError: assign({ error: () => ({ code: PERSONHOOD_ERROR_CODES.DETECTION_FAILED }) }),
914
+ setFallbackReasonNoCamera: assign({ fallbackReason: () => "no_camera" }),
915
+ setTokenError: assign({ error: ({ event }) => ({
916
+ code: PERSONHOOD_ERROR_CODES.AUTH_TOKEN_FAILED,
917
+ message: String(event.error ?? "auth token fetch failed")
918
+ }) }),
919
+ setVerifyError: assign({ error: ({ event }) => ({
920
+ code: PERSONHOOD_ERROR_CODES.VERIFY_FAILED,
921
+ message: String(event.error ?? "verify failed")
922
+ }) }),
923
+ setLocalVerdictError: assign({ error: ({ event }) => ({
924
+ code: PERSONHOOD_ERROR_CODES.UNKNOWN,
925
+ message: String(event.error ?? "local verdict synthesis failed")
926
+ }) }),
927
+ setVerdictToLocal: assign({ verdict: ({ context }) => context.localVerdict }),
928
+ stopMediaStream: assign(({ context }) => {
929
+ context.frameCapturer?.dispose();
930
+ if (context.stream) stopStream(context.stream);
931
+ context.provider?.dispose();
932
+ context.deepsightService?.cleanup();
933
+ return {
934
+ stream: void 0,
935
+ provider: void 0,
936
+ frameCapturer: void 0
937
+ };
938
+ }),
939
+ resetContext: assign({
940
+ permissionResult: () => void 0,
941
+ stream: () => void 0,
942
+ provider: () => void 0,
943
+ frameCapturer: () => void 0,
944
+ deepsightService: () => void 0,
945
+ detectionStatus: () => "idle",
946
+ yawRange: () => 0,
947
+ pitchRange: () => 0,
948
+ capturedImage: () => void 0,
949
+ livenessOutcome: () => void 0,
950
+ signals: () => void 0,
951
+ fallbackReason: () => void 0,
952
+ token: () => void 0,
953
+ localVerdict: () => void 0,
954
+ verdict: () => void 0,
955
+ error: () => void 0,
956
+ resetDetection: () => void 0
957
+ }),
958
+ emitSignal: ({ context, event }) => {
959
+ const listener = context.config.onSignal;
960
+ if (!listener) return;
961
+ if (event.type === "DETECTION_UPDATE") listener({
962
+ type: "detection",
963
+ payload: event.status
964
+ });
965
+ }
966
+ },
967
+ guards: {
968
+ hasShowTutorial: ({ context }) => context.config.showTutorial === true,
969
+ isPermissionGranted: ({ event }) => {
970
+ if ("output" in event) return event.output === "granted";
971
+ return false;
972
+ },
973
+ isPermissionDenied: ({ event }) => {
974
+ if ("output" in event) return event.output === "denied";
975
+ return false;
976
+ },
977
+ hasTokenError: ({ context }) => context.error?.code === PERSONHOOD_ERROR_CODES.AUTH_TOKEN_FAILED,
978
+ isDetectionError: ({ event }) => event.status === "error"
979
+ }
980
+ }).createMachine({
981
+ id: "personhood",
982
+ initial: "idle",
983
+ context: ({ input }) => ({
984
+ config: input.config,
985
+ dependencies: input.dependencies,
986
+ permissionResult: void 0,
987
+ fallbackReason: void 0,
988
+ stream: void 0,
989
+ provider: void 0,
990
+ frameCapturer: void 0,
991
+ deepsightService: void 0,
992
+ detectionStatus: "idle",
993
+ yawRange: 0,
994
+ pitchRange: 0,
995
+ capturedImage: void 0,
996
+ livenessOutcome: void 0,
997
+ signals: void 0,
998
+ token: void 0,
999
+ localVerdict: void 0,
1000
+ verdict: void 0,
1001
+ error: void 0,
1002
+ resetDetection: void 0
1003
+ }),
1004
+ on: { QUIT: { target: "#personhood.closed" } },
1005
+ states: {
1006
+ idle: { on: { LOAD: [{
1007
+ target: "tutorial",
1008
+ guard: "hasShowTutorial"
1009
+ }, { target: "collectingSignals" }] } },
1010
+ tutorial: { on: { NEXT_STEP: { target: "collectingSignals" } } },
1011
+ collectingSignals: {
1012
+ type: "parallel",
1013
+ states: {
1014
+ signals: {
1015
+ initial: "running",
1016
+ states: {
1017
+ running: { invoke: {
1018
+ id: "collectSignals",
1019
+ src: "collectSignals",
1020
+ onDone: {
1021
+ target: "done",
1022
+ actions: "setSignalsFromEvent"
1023
+ },
1024
+ onError: { target: "done" }
1025
+ } },
1026
+ done: { type: "final" }
1027
+ }
1028
+ },
1029
+ deepsight: {
1030
+ initial: "running",
1031
+ states: {
1032
+ running: { invoke: {
1033
+ id: "initializeDeepsight",
1034
+ src: "initializeDeepsight",
1035
+ input: ({ context }) => ({ dependencies: context.dependencies }),
1036
+ onDone: {
1037
+ target: "done",
1038
+ actions: "setDeepsightServiceFromEvent"
1039
+ },
1040
+ onError: { target: "done" }
1041
+ } },
1042
+ done: { type: "final" }
1043
+ }
1044
+ },
1045
+ token: {
1046
+ initial: "running",
1047
+ states: {
1048
+ running: { invoke: {
1049
+ id: "fetchToken",
1050
+ src: "fetchToken",
1051
+ input: ({ context }) => ({ config: context.config }),
1052
+ onDone: {
1053
+ target: "done",
1054
+ actions: "setTokenFromEvent"
1055
+ },
1056
+ onError: {
1057
+ target: "done",
1058
+ actions: "setTokenError"
1059
+ }
1060
+ } },
1061
+ done: { type: "final" }
1062
+ }
1063
+ }
1064
+ },
1065
+ onDone: [{
1066
+ target: "error",
1067
+ guard: "hasTokenError"
1068
+ }, { target: "checkingPermission" }]
1069
+ },
1070
+ checkingPermission: { invoke: {
1071
+ id: "checkPermission",
1072
+ src: "checkPermission",
1073
+ onDone: [
1074
+ {
1075
+ target: "capture",
1076
+ guard: "isPermissionGranted",
1077
+ actions: "setPermissionResultFromEvent"
1078
+ },
1079
+ {
1080
+ target: "permissions.denied",
1081
+ guard: "isPermissionDenied",
1082
+ actions: "setPermissionResultFromEvent"
1083
+ },
1084
+ {
1085
+ target: "permissions",
1086
+ actions: "setPermissionResultFromEvent"
1087
+ }
1088
+ ]
1089
+ } },
1090
+ permissions: {
1091
+ initial: "idle",
1092
+ states: {
1093
+ idle: { on: {
1094
+ REQUEST_PERMISSION: "requesting",
1095
+ GO_TO_LEARN_MORE: "learnMore"
1096
+ } },
1097
+ learnMore: { on: {
1098
+ BACK: "idle",
1099
+ REQUEST_PERMISSION: "requesting"
1100
+ } },
1101
+ requesting: { invoke: {
1102
+ id: "requestPermission",
1103
+ src: "requestPermission",
1104
+ onDone: [
1105
+ {
1106
+ target: "#personhood.capture",
1107
+ guard: "isPermissionGranted",
1108
+ actions: "setPermissionResultFromEvent"
1109
+ },
1110
+ {
1111
+ target: "denied",
1112
+ guard: "isPermissionDenied",
1113
+ actions: "setPermissionResultFromEvent"
1114
+ },
1115
+ {
1116
+ target: "idle",
1117
+ actions: "setPermissionResultFromEvent"
1118
+ }
1119
+ ],
1120
+ onError: {
1121
+ target: "denied",
1122
+ actions: "setPermissionDenied"
1123
+ }
1124
+ } },
1125
+ denied: {
1126
+ entry: "setPermissionDenied",
1127
+ on: { USE_FALLBACK: { target: "#personhood.serverFallback" } }
1128
+ }
1129
+ },
1130
+ on: { USE_FALLBACK: { target: "#personhood.serverFallback" } }
1131
+ },
1132
+ capture: {
1133
+ initial: "initializing",
1134
+ states: {
1135
+ initializing: { invoke: {
1136
+ id: "initializeCamera",
1137
+ src: "initializeCamera",
1138
+ input: ({ context }) => ({ deepsightService: context.deepsightService }),
1139
+ onDone: {
1140
+ target: "detecting",
1141
+ actions: "setStreamAndProvider"
1142
+ },
1143
+ onError: {
1144
+ target: "#personhood.serverFallback",
1145
+ actions: "setFallbackReasonNoCamera"
1146
+ }
1147
+ } },
1148
+ detecting: {
1149
+ invoke: {
1150
+ id: "runDetection",
1151
+ src: "runDetection",
1152
+ input: ({ context }) => ({
1153
+ provider: context.provider,
1154
+ frameCapturer: context.frameCapturer,
1155
+ autoComplete: context.config.autoComplete
1156
+ }),
1157
+ onError: {
1158
+ target: "#personhood.error",
1159
+ actions: "setDetectionError"
1160
+ }
1161
+ },
1162
+ on: {
1163
+ DETECTION_UPDATE: [{
1164
+ guard: "isDetectionError",
1165
+ target: "#personhood.error",
1166
+ actions: [
1167
+ "setDetectionStatus",
1168
+ "setDetectionError",
1169
+ "emitSignal"
1170
+ ]
1171
+ }, { actions: ["setDetectionStatus", "emitSignal"] }],
1172
+ DETECTION_RESET_READY: { actions: "setResetDetection" },
1173
+ DETECTION_SUCCESS: {
1174
+ target: "#personhood.analyzing",
1175
+ actions: "setCapturedImageAndRangeFromEvent"
1176
+ }
1177
+ }
1178
+ }
1179
+ }
1180
+ },
1181
+ analyzing: {
1182
+ exit: "stopMediaStream",
1183
+ invoke: {
1184
+ id: "analyzeLiveness",
1185
+ src: "analyzeLiveness",
1186
+ input: ({ context }) => ({
1187
+ deepsightService: context.deepsightService,
1188
+ stream: context.stream,
1189
+ capturedImage: context.capturedImage,
1190
+ yawRange: context.yawRange,
1191
+ pitchRange: context.pitchRange,
1192
+ token: context.token
1193
+ }),
1194
+ onDone: {
1195
+ target: "processing",
1196
+ actions: "setLivenessOutcomeFromEvent"
1197
+ },
1198
+ onError: { target: "processing" }
1199
+ }
1200
+ },
1201
+ processing: { invoke: {
1202
+ id: "produceLocalVerdict",
1203
+ src: "produceLocalVerdict",
1204
+ input: ({ context }) => ({
1205
+ config: context.config,
1206
+ signals: context.signals ?? emptySignals(),
1207
+ detectionStatus: context.detectionStatus,
1208
+ liveness: context.livenessOutcome
1209
+ }),
1210
+ onDone: {
1211
+ target: "verifyingOnServer",
1212
+ actions: "setLocalVerdictFromEvent"
1213
+ },
1214
+ onError: {
1215
+ target: "error",
1216
+ actions: "setLocalVerdictError"
1217
+ }
1218
+ } },
1219
+ verifyingOnServer: { invoke: {
1220
+ id: "verifyOnDevice",
1221
+ src: "verifyOnDevice",
1222
+ input: ({ context }) => ({
1223
+ config: context.config,
1224
+ liveness: context.livenessOutcome,
1225
+ localVerdict: context.localVerdict,
1226
+ token: context.token
1227
+ }),
1228
+ onDone: {
1229
+ target: "finished",
1230
+ actions: "setVerdictFromEvent"
1231
+ },
1232
+ onError: {
1233
+ target: "finished",
1234
+ actions: "setVerdictToLocal"
1235
+ }
1236
+ } },
1237
+ serverFallback: { invoke: {
1238
+ id: "requestServerFallback",
1239
+ src: "requestServerFallback",
1240
+ input: ({ context }) => ({
1241
+ config: context.config,
1242
+ signals: context.signals ?? emptySignals(),
1243
+ reason: context.fallbackReason ?? "permission_denied"
1244
+ }),
1245
+ onDone: {
1246
+ target: "finished",
1247
+ actions: "setVerdictFromEvent"
1248
+ },
1249
+ onError: {
1250
+ target: "error",
1251
+ actions: "setVerifyError"
1252
+ }
1253
+ } },
1254
+ finished: { type: "final" },
1255
+ closed: {
1256
+ entry: "stopMediaStream",
1257
+ type: "final"
1258
+ },
1259
+ error: {
1260
+ entry: "stopMediaStream",
1261
+ on: { RESET: {
1262
+ target: "idle",
1263
+ actions: "resetContext"
1264
+ } }
1265
+ }
1266
+ }
1267
+ });
1268
+ /**
1269
+ * Public machine value. Typed as `AnyStateMachine` for declaration file
1270
+ * portability — mirrors the convention used by `selfieMachine` and the
1271
+ * other Core modules. Type safety is enforced by the `setup()` config
1272
+ * above, not by the exported binding.
1273
+ */
1274
+ const personhoodMachine = _personhoodMachine;
1275
+
1276
+ //#endregion
1277
+ //#region src/modules/personhood/personhoodActor.ts
1278
+ /**
1279
+ * Production-default {@link PersonhoodDependencies}. Browser storage +
1280
+ * the singleton WASM util. Single source of truth for what the actor
1281
+ * and the manager wire up when the caller doesn't provide their own;
1282
+ * tests and the extensibility layer pass `dependencies` explicitly.
1283
+ */
1284
+ function getDefaultPersonhoodDependencies() {
1285
+ return {
1286
+ storage: new BrowserStorageProvider(),
1287
+ getWasmUtil: () => WasmUtilProvider.getInstance()
1288
+ };
1289
+ }
1290
+ /**
1291
+ * Creates and starts a Personhood XState actor. Defaults to the production
1292
+ * browser storage + WASM providers; passing `dependencies` lets tests and the
1293
+ * extensibility layer swap them for fakes.
1294
+ */
1295
+ function createPersonhoodActor(options) {
1296
+ const dependencies = options.dependencies ?? getDefaultPersonhoodDependencies();
1297
+ return createActor(personhoodMachine, { input: {
1298
+ config: options.config,
1299
+ dependencies
1300
+ } }).start();
1301
+ }
1302
+
1303
+ //#endregion
1304
+ //#region src/modules/personhood/personhoodManager.ts
1305
+ /**
1306
+ * Personhood deliberately opts out of the SDK's manager-instrumentation
1307
+ * analytics pipeline. The widget runs as a self-contained modal/inline
1308
+ * captcha replacement, not as part of the broader onboarding funnel —
1309
+ * it doesn't share an onboarding session token (`/omni/start`) with
1310
+ * the rest of an integrator's flow, so the per-transition events the
1311
+ * default instrumentation would emit can't authenticate against
1312
+ * `/omni/interview-events`. Wiring them up only produced a cascade of
1313
+ * 403s in integrators' devtools (one preflight + one POST per
1314
+ * `screenOpened` / `elementClicked` / `captureAttemptFinished` /
1315
+ * `errorTriggered` transition), with no usable analytics signal on
1316
+ * the receiving end.
1317
+ *
1318
+ * `createManager()` requires the `instrumentation` option to be
1319
+ * present, so we pass a no-op that satisfies the contract without
1320
+ * firing any of the helpers. If a future use case calls for
1321
+ * personhood analytics (integrator opt-in, internal QA dashboard,
1322
+ * etc.) the right move is to re-enable `createManagerInstrumentation`
1323
+ * here gated on a config flag — not to remove this no-op.
1324
+ */
1325
+ function createNoopInstrumentation() {
1326
+ return {
1327
+ moduleName: eventModuleNames.personhood,
1328
+ onModuleOpened: () => void 0,
1329
+ onModuleClosed: () => void 0,
1330
+ getScreenName: () => void 0,
1331
+ onScreenOpened: () => void 0,
1332
+ onScreenClosed: () => void 0,
1333
+ getErrorName: () => void 0,
1334
+ getErrorPayload: () => void 0,
1335
+ onErrorTriggered: () => void 0,
1336
+ onElementClicked: () => void 0,
1337
+ onCaptureAttemptFinished: () => void 0
1338
+ };
1339
+ }
1340
+ function getPermissionSubState(snapshot) {
1341
+ if (snapshot.matches({ permissions: "learnMore" })) return "learnMore";
1342
+ if (snapshot.matches({ permissions: "requesting" })) return "requesting";
1343
+ if (snapshot.matches({ permissions: "denied" })) return "denied";
1344
+ return "idle";
1345
+ }
1346
+ function mapState(snapshot) {
1347
+ const context = snapshot.context;
1348
+ if (snapshot.matches("idle")) return { status: "idle" };
1349
+ if (snapshot.matches("tutorial")) return { status: "tutorial" };
1350
+ if (snapshot.matches("collectingSignals")) return {
1351
+ status: "loading",
1352
+ phase: "collectingSignals"
1353
+ };
1354
+ if (snapshot.matches("checkingPermission")) return {
1355
+ status: "loading",
1356
+ phase: "checkingPermission"
1357
+ };
1358
+ if (snapshot.matches("permissions")) return {
1359
+ status: "permissions",
1360
+ permissionStatus: getPermissionSubState(snapshot)
1361
+ };
1362
+ if (snapshot.matches({ capture: "initializing" })) return {
1363
+ status: "capture",
1364
+ captureStatus: "initializing",
1365
+ detectionStatus: context.detectionStatus,
1366
+ stream: context.stream
1367
+ };
1368
+ if (snapshot.matches("capture")) return {
1369
+ status: "capture",
1370
+ captureStatus: "detecting",
1371
+ detectionStatus: context.detectionStatus,
1372
+ stream: context.stream
1373
+ };
1374
+ if (snapshot.matches("analyzing")) return {
1375
+ status: "processing",
1376
+ source: "analyzing"
1377
+ };
1378
+ if (snapshot.matches("processing")) return {
1379
+ status: "processing",
1380
+ source: "local"
1381
+ };
1382
+ if (snapshot.matches("serverFallback")) return {
1383
+ status: "processing",
1384
+ source: "fallback"
1385
+ };
1386
+ if (snapshot.matches("verifyingOnServer")) return {
1387
+ status: "processing",
1388
+ source: "local"
1389
+ };
1390
+ if (snapshot.matches("finished")) return {
1391
+ status: "finished",
1392
+ verdict: context.verdict ?? {
1393
+ human: false,
1394
+ confidence: 0,
1395
+ evidenceId: "missing",
1396
+ signals: emptySignals(),
1397
+ spoofCheckResults: []
1398
+ }
1399
+ };
1400
+ if (snapshot.matches("closed")) return { status: "closed" };
1401
+ if (snapshot.matches("error")) return {
1402
+ status: "error",
1403
+ error: context.error ?? { code: "UNKNOWN" }
1404
+ };
1405
+ return { status: "idle" };
1406
+ }
1407
+ function createApi({ actor, trackElementClicked }) {
1408
+ return {
1409
+ load() {
1410
+ actor.send({ type: "LOAD" });
1411
+ },
1412
+ nextStep() {
1413
+ trackElementClicked?.("nextStep");
1414
+ actor.send({ type: "NEXT_STEP" });
1415
+ },
1416
+ requestPermission() {
1417
+ trackElementClicked?.("requestPermission");
1418
+ actor.send({ type: "REQUEST_PERMISSION" });
1419
+ },
1420
+ goToLearnMore() {
1421
+ trackElementClicked?.("goToLearnMore");
1422
+ actor.send({ type: "GO_TO_LEARN_MORE" });
1423
+ },
1424
+ back() {
1425
+ trackElementClicked?.("back");
1426
+ actor.send({ type: "BACK" });
1427
+ },
1428
+ close() {
1429
+ trackElementClicked?.("close");
1430
+ actor.send({ type: "QUIT" });
1431
+ },
1432
+ reset() {
1433
+ actor.send({ type: "RESET" });
1434
+ },
1435
+ useFallback() {
1436
+ trackElementClicked?.("useFallback");
1437
+ actor.send({ type: "USE_FALLBACK" });
1438
+ }
1439
+ };
1440
+ }
1441
+ /**
1442
+ * Wraps a pre-built personhood actor in a manager. Internal helper
1443
+ * shared by {@link createPersonhoodManager} (drop-in widget path) and
1444
+ * {@link createPersonhoodManagerFromActor} (extensibility surface).
1445
+ * Centralizing the `createManager(...)` + instrumentation call avoids
1446
+ * two near-identical wrap blocks drifting apart.
1447
+ */
1448
+ function wrapActor(actor) {
1449
+ return createManager({
1450
+ actor,
1451
+ mapState,
1452
+ createApi,
1453
+ instrumentation: createNoopInstrumentation()
1454
+ });
1455
+ }
1456
+ /**
1457
+ * Manager built from an externally-owned actor (extensibility path).
1458
+ */
1459
+ function createPersonhoodManagerFromActor(actor) {
1460
+ return wrapActor(actor);
1461
+ }
1462
+ /**
1463
+ * Creates a Personhood manager for the drop-in widget.
1464
+ *
1465
+ * The manager exposes:
1466
+ * - `state: PersonhoodState` via `getState()` / `subscribe()`
1467
+ * - Lifecycle controls: `load`, `nextStep`, `requestPermission`,
1468
+ * `goToLearnMore`, `back`, `close`, `reset`, `useFallback`, `stop`
1469
+ *
1470
+ * Head-pose is intentionally **not** exposed as a stream. The SDK
1471
+ * extracts pose internally for the server-side `headMotion` spoof
1472
+ * check; UI consumers that need a frame-rate pose signal (avatar
1473
+ * mirroring, etc.) should run their own face-tracking pipeline
1474
+ * (e.g. MediaPipe FaceLandmarker) against `state.stream` instead.
1475
+ *
1476
+ * @example
1477
+ * ```ts
1478
+ * const manager = createPersonhoodManager({
1479
+ * config: { siteKey: 'demo', mockVerify: true },
1480
+ * });
1481
+ * manager.subscribe((state) => {
1482
+ * if (state.status === 'finished') {
1483
+ * console.log('human?', state.verdict.human);
1484
+ * }
1485
+ * });
1486
+ * manager.load();
1487
+ * ```
1488
+ */
1489
+ function createPersonhoodManager(options) {
1490
+ return wrapActor(createPersonhoodActor(options));
1491
+ }
1492
+
1493
+ //#endregion
1494
+ export { PERSONHOOD_ERROR_CODES, createPersonhoodActor, createPersonhoodManager, createPersonhoodManagerFromActor, personhoodMachine };