@incodetech/core 2.3.2 → 2.4.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. package/THIRD_PARTY_NOTICES.txt +1243 -3
  2. package/dist/Actor-DpTj5PFb.d.ts +1 -0
  3. package/dist/{BaseWasmProvider-Dyi6dKp1.d.ts → BaseWasmProvider-BL9wIRnN.d.ts} +2 -2
  4. package/dist/{FaceDetectionProvider-DtmtCKa9.esm.js → FaceDetectionProvider-BjTer9h3.esm.js} +126 -10
  5. package/dist/HttpRequestError-Bh0pNGSC.esm.js +35 -0
  6. package/dist/{IIdCaptureCapability-RNiFhvXR.d.ts → IIdCaptureCapability-DBsv9-7M.d.ts} +2 -2
  7. package/dist/{IWasmUtilCapability-CNWRl7jr.d.ts → IWasmUtilCapability-CPX0RGdQ.d.ts} +28 -5
  8. package/dist/{Manager-CQQ99QOI.d.ts → Manager-C9T5amUN.d.ts} +7 -1
  9. package/dist/{MotionSensorProvider-DyhbM4Si.esm.js → MotionSensorProvider-DYxh8TjR.esm.js} +1 -1
  10. package/dist/{ekycStateMachine-UeJRO8_p.esm.js → PhoneValidationProvider-SZiOS0jB.esm.js} +232 -827
  11. package/dist/{StreamCanvasCapture-_8gdW5Lk.d.ts → StreamCanvasCapture-DVmzJux5.d.ts} +2 -2
  12. package/dist/{safeStorage-BdU9_m2E.esm.js → WasmUtilProvider-CIdnE7Fx.esm.js} +95 -46
  13. package/dist/{addressSearch-DyHGgeX8.esm.js → addressSearch-BiYZjvp3.esm.js} +143 -4
  14. package/dist/{advanceableErrors-CpF2cBy6.esm.js → advanceableErrors-q_pfU3Cn.esm.js} +5 -4
  15. package/dist/ae-signature.d.ts +2 -2
  16. package/dist/ae-signature.esm.js +1 -1
  17. package/dist/antifraud.d.ts +1 -1
  18. package/dist/antifraud.esm.js +2 -2
  19. package/dist/{antifraudManager-BY36bS12.d.ts → antifraudManager-DbGCvlJs.d.ts} +2 -2
  20. package/dist/{antifraudManager-DNkw66oW.esm.js → antifraudManager-HL08jeDX.esm.js} +3 -3
  21. package/dist/{antifraudStateMachine-DBeq47D2.esm.js → antifraudStateMachine-DoJVzblM.esm.js} +3 -3
  22. package/dist/{apiError-CmGEmaGU.esm.js → apiError-DcSWedC6.esm.js} +2 -1
  23. package/dist/authentication.d.ts +3 -3
  24. package/dist/authentication.esm.js +2 -2
  25. package/dist/{authenticationManager-CboRCl_N.d.ts → authenticationManager-CANv5-W5.d.ts} +2 -8
  26. package/dist/{authenticationManager-BFjSjtQ_.esm.js → authenticationManager-SaiAxqvS.esm.js} +6 -6
  27. package/dist/{authenticationStateMachine-Dfo34ZiI.esm.js → authenticationStateMachine-CHSxmV7z.esm.js} +5 -6
  28. package/dist/avatar.d.ts +1 -1
  29. package/dist/{backCameraStream-B0-YgP_y.esm.js → backCameraStream-CMvXj4X4.esm.js} +1 -1
  30. package/dist/camera.esm.js +1 -1
  31. package/dist/certificate-issuance.d.ts +1 -1
  32. package/dist/certificate-issuance.esm.js +2 -2
  33. package/dist/{certificateIssuanceManager-C3-CI0_s.esm.js → certificateIssuanceManager-CMg4SgL4.esm.js} +3 -3
  34. package/dist/{certificateIssuanceManager-DCgEidHz.d.ts → certificateIssuanceManager-Dr8A4Lgr.d.ts} +2 -3
  35. package/dist/{certificateIssuanceStateMachine-CxqS_nD-.esm.js → certificateIssuanceStateMachine-Cs64QmYH.esm.js} +4 -4
  36. package/dist/consent.d.ts +1 -1
  37. package/dist/consent.esm.js +2 -2
  38. package/dist/{consentManager-B6E1XJDw.esm.js → consentManager-CjrxY737.esm.js} +3 -3
  39. package/dist/{consentManager-2h_w6wFc.d.ts → consentManager-DgzWQpAR.d.ts} +6 -7
  40. package/dist/{consentStateMachine-DTSfdGiW.esm.js → consentStateMachine-BCj5Jb3g.esm.js} +3 -3
  41. package/dist/{createCameraCycleOwnership-DnwTl1ad.esm.js → createCameraCycleOwnership-kdlhkmmY.esm.js} +71 -65
  42. package/dist/{createFaceAvatar-BlcTYgJv.d.ts → createFaceAvatar-DXgmQmQy.d.ts} +1 -1
  43. package/dist/cross-document-data-match.d.ts +1 -1
  44. package/dist/cross-document-data-match.esm.js +1 -1
  45. package/dist/{crossDocumentDataMatchManager-9XhFVZ5S.esm.js → crossDocumentDataMatchManager-BHnGRsto.esm.js} +4 -4
  46. package/dist/{crossDocumentDataMatchManager-Dq8Z3SOg.d.ts → crossDocumentDataMatchManager-yCWCOzcU.d.ts} +2 -2
  47. package/dist/curp-validation.d.ts +1 -1
  48. package/dist/curp-validation.esm.js +2 -2
  49. package/dist/{curpValidationManager-DNuZn9fn.d.ts → curpValidationManager-B-1EZbP_.d.ts} +3 -3
  50. package/dist/{curpValidationManager-DbIMYFcJ.esm.js → curpValidationManager-DBNIn8BF.esm.js} +15 -22
  51. package/dist/{curpValidationStateMachine-g5kMfuLj.esm.js → curpValidationStateMachine-DAxImy8p.esm.js} +4 -4
  52. package/dist/custom-fields.d.ts +1 -1
  53. package/dist/custom-fields.esm.js +1 -1
  54. package/dist/custom-watchlist.d.ts +1 -1
  55. package/dist/custom-watchlist.esm.js +2 -2
  56. package/dist/{customFieldsManager-CzWZTkW-.esm.js → customFieldsManager-BV6UyLFV.esm.js} +4 -4
  57. package/dist/{customFieldsManager-8-W2KY4n.d.ts → customFieldsManager-CF-cO8ap.d.ts} +2 -2
  58. package/dist/{customWatchlistManager-DWTED5Ur.esm.js → customWatchlistManager-DML0UPzf.esm.js} +3 -3
  59. package/dist/{customWatchlistManager-PBWHr_oM.d.ts → customWatchlistManager-DolUswyR.d.ts} +2 -2
  60. package/dist/{customWatchlistStateMachine-DOQou6TW.esm.js → customWatchlistStateMachine-D9gI5uu7.esm.js} +3 -3
  61. package/dist/deepsightLoader-DvfAYnzg.esm.js +55 -0
  62. package/dist/{deepsightLoader-v-dLejS-.esm.js → deepsightService-DLGO9yv1.esm.js} +51 -56
  63. package/dist/device.esm.js +1 -1
  64. package/dist/document-capture.d.ts +2 -2
  65. package/dist/document-capture.esm.js +2 -2
  66. package/dist/{documentCaptureManager-BRPxqYD2.esm.js → documentCaptureManager-C9XUnYU6.esm.js} +17 -18
  67. package/dist/{documentCaptureManager-lEtCM320.d.ts → documentCaptureManager-DkyDtm3Y.d.ts} +11 -34
  68. package/dist/{documentCaptureStateMachine-D312sSIu.esm.js → documentCaptureStateMachine-BHDsCfhL.esm.js} +55 -58
  69. package/dist/dynamic-forms.d.ts +2 -2
  70. package/dist/dynamic-forms.esm.js +2 -2
  71. package/dist/{dynamicFormsManager-C-9Jhnd3.esm.js → dynamicFormsManager-5uIXobxi.esm.js} +3 -3
  72. package/dist/{dynamicFormsManager-D5R_uxLQ.d.ts → dynamicFormsManager-C0dHs1ty.d.ts} +3 -3
  73. package/dist/{dynamicFormsStateMachine-DGI_F2PP.esm.js → dynamicFormsStateMachine-DQmok084.esm.js} +4 -4
  74. package/dist/ekyb.d.ts +5 -5
  75. package/dist/ekyb.esm.js +3 -3
  76. package/dist/{ekybManager-BwRuGAwt.d.ts → ekybManager-BaZ_7CEu.d.ts} +4 -4
  77. package/dist/{ekybManager-DeoMcZEz.esm.js → ekybManager-CazShiQz.esm.js} +23 -27
  78. package/dist/{ekybStateMachine-D1IJ1Z72.esm.js → ekybStateMachine-hstiCNmW.esm.js} +338 -13
  79. package/dist/ekyc.d.ts +2 -2
  80. package/dist/ekyc.esm.js +3 -3
  81. package/dist/{ekycManager-BX2d46FY.esm.js → ekycManager-BdJRUsz0.esm.js} +29 -36
  82. package/dist/{ekycManager-DLzDuBzI.d.ts → ekycManager-DW-ynodd.d.ts} +3 -3
  83. package/dist/ekycStateMachine-x6Klot8g.esm.js +1444 -0
  84. package/dist/{ekycUtils-D6wfSpPN.esm.js → ekycUtils-zY8CdKJL.esm.js} +53 -3
  85. package/dist/electronic-signature.d.ts +1 -1
  86. package/dist/electronic-signature.esm.js +1 -1
  87. package/dist/{electronicSignatureManager-yYUc30na.esm.js → electronicSignatureManager-Bc8spG8p.esm.js} +10 -10
  88. package/dist/{electronicSignatureManager-Ds-KEVTq.d.ts → electronicSignatureManager-DTSLOvKR.d.ts} +2 -3
  89. package/dist/email.d.ts +1 -1
  90. package/dist/email.esm.js +2 -2
  91. package/dist/{emailManager-bR1N5rV_.esm.js → emailManager-CtlKRRaR.esm.js} +20 -26
  92. package/dist/{emailManager-CADXW_9X.d.ts → emailManager-Dy6omJVp.d.ts} +2 -2
  93. package/dist/{emailStateMachine-Bc_6oIYw.esm.js → emailStateMachine-5Neq3rE5.esm.js} +4 -4
  94. package/dist/{endpoints-B-3Q-LUw.esm.js → endpoints-DHzlkQNe.esm.js} +2 -0
  95. package/dist/{events-ijlbX_Wx.esm.js → events-CAgFE-k3.esm.js} +19 -7
  96. package/dist/events.d.ts +3 -2
  97. package/dist/events.esm.js +1 -1
  98. package/dist/extensibility.d.ts +38 -38
  99. package/dist/extensibility.esm.js +36 -36
  100. package/dist/{externalFetch-BKBThAUC.esm.js → externalFetch-DrR9xshk.esm.js} +3 -2
  101. package/dist/face-match.d.ts +1 -1
  102. package/dist/face-match.esm.js +2 -2
  103. package/dist/{faceCaptureManagerFactory-m-7ae67q.d.ts → faceCaptureManagerFactory-jKQ2QtY-.d.ts} +11 -51
  104. package/dist/{faceCaptureManagerFactory-B6i9QcAk.esm.js → faceCaptureManagerFactory-uFm1AcaY.esm.js} +19 -54
  105. package/dist/{faceCaptureSetup-DU1mjRr6.esm.js → faceCaptureSetup-Cu2wabzo.esm.js} +99 -395
  106. package/dist/{faceMatchManager-Bmv0HzuY.esm.js → faceMatchManager-9Nj9aPci.esm.js} +3 -3
  107. package/dist/{faceMatchManager-BnvrZM2F.d.ts → faceMatchManager-DIgG-UFS.d.ts} +1 -2
  108. package/dist/{faceMatchStateMachine-mRIHQ3dA.esm.js → faceMatchStateMachine-B9ZUnlyU.esm.js} +6 -4
  109. package/dist/{feature-management-C8CuN0os.esm.js → feature-management-BTbYruNe.esm.js} +3 -3
  110. package/dist/feature-management.esm.js +1 -1
  111. package/dist/field-comparison.d.ts +2 -2
  112. package/dist/field-comparison.esm.js +1 -1
  113. package/dist/{fieldComparisonManager-CBvEGxFx.d.ts → fieldComparisonManager-CUX4gza2.d.ts} +6 -3
  114. package/dist/{fieldComparisonManager-CC-klG0h.esm.js → fieldComparisonManager-Dk38hXZP.esm.js} +35 -17
  115. package/dist/fiscal-qr.d.ts +1 -1
  116. package/dist/fiscal-qr.esm.js +1 -1
  117. package/dist/{fiscalQrManager-B1STmT6z.d.ts → fiscalQrManager-D0Iy7EKR.d.ts} +2 -2
  118. package/dist/fiscalQrManager-DmBkQfs0.esm.js +6798 -0
  119. package/dist/flow-events.d.ts +1 -1
  120. package/dist/flow.d.ts +14 -13
  121. package/dist/flow.esm.js +14 -14
  122. package/dist/{flowCompletionService-DccgtDnm.esm.js → flowCompletionService-xnn_SlJU.esm.js} +2 -2
  123. package/dist/{flowServices-CdsWsppG.esm.js → flowServices-DA64AEZC.esm.js} +11 -7
  124. package/dist/geolocation.d.ts +1 -1
  125. package/dist/geolocation.esm.js +2 -2
  126. package/dist/{geolocationManager-CGHBxtMb.esm.js → geolocationManager-CqNLY45e.esm.js} +6 -7
  127. package/dist/{geolocationManager-Cz744E5S.d.ts → geolocationManager-Dn24g1fl.d.ts} +2 -3
  128. package/dist/{geolocationStateMachine-CdEb1Gn0.esm.js → geolocationStateMachine-D-cQi7ar.esm.js} +4 -4
  129. package/dist/{getDeviceClass-5NYZg9s6.esm.js → getDeviceClass-bsWdEDxP.esm.js} +1 -1
  130. package/dist/{getParsedUserAgent-B2iFDql1.esm.js → getParsedUserAgent-DhQPeKqw.esm.js} +1 -1
  131. package/dist/government-validation.d.ts +1 -1
  132. package/dist/government-validation.esm.js +2 -2
  133. package/dist/{governmentValidationManager-D02vT4yY.d.ts → governmentValidationManager-B82zOut8.d.ts} +3 -3
  134. package/dist/{governmentValidationManager-CacFOtKO.esm.js → governmentValidationManager-CP0SiOOe.esm.js} +3 -3
  135. package/dist/{governmentValidationStateMachine-CoaZOSTP.esm.js → governmentValidationStateMachine-C3YQ8yCZ.esm.js} +3 -3
  136. package/dist/home.d.ts +3 -26
  137. package/dist/home.esm.js +2 -2
  138. package/dist/id-ocr.d.ts +1 -1
  139. package/dist/id-ocr.esm.js +2 -2
  140. package/dist/id-selfie-flow.d.ts +6 -9
  141. package/dist/id-selfie-flow.esm.js +23 -28
  142. package/dist/id-verification.d.ts +1 -1
  143. package/dist/id-verification.esm.js +2 -2
  144. package/dist/id.d.ts +4 -4
  145. package/dist/id.esm.js +4 -205
  146. package/dist/{idCaptureDefaults-Dl64Trv5.esm.js → idCaptureDefaults-CBg73RnV.esm.js} +8 -5
  147. package/dist/{idCaptureManager-BHwL2Z0V.d.ts → idCaptureManager-BY97SRCV.d.ts} +242 -98
  148. package/dist/{idCaptureManager-BNmVJQkd.esm.js → idCaptureManager-D4V8vXtY.esm.js} +276 -210
  149. package/dist/{idCaptureServices-dtDG2HXS.esm.js → idCaptureServices-DJ33k3-p.esm.js} +21 -39
  150. package/dist/{idCaptureStateMachine-BbiZD3uf.esm.js → idCaptureStateMachine-PJt0yzom.esm.js} +989 -872
  151. package/dist/{idOcrManager-CFlDwUvN.d.ts → idOcrManager-BTdHlJ9D.d.ts} +2 -3
  152. package/dist/{idOcrManager-ByWuQ4ej.esm.js → idOcrManager-DxoCesYP.esm.js} +3 -3
  153. package/dist/{idOcrStateMachine-Bt_abXQQ.esm.js → idOcrStateMachine-kPn7DB2I.esm.js} +3 -3
  154. package/dist/{idVerificationManager-BB4Pj_N6.d.ts → idVerificationManager-BJapZfpy.d.ts} +2 -3
  155. package/dist/{idVerificationManager-DT42c77H.esm.js → idVerificationManager-CDhRUU5n.esm.js} +3 -3
  156. package/dist/{idVerificationStateMachine-DbDVIh9t.esm.js → idVerificationStateMachine-0HTVVxse.esm.js} +3 -3
  157. package/dist/identity-reuse.d.ts +2 -2
  158. package/dist/identity-reuse.esm.js +2 -2
  159. package/dist/{identityReuseManager-yG3acUrQ.esm.js → identityReuseManager-BleUi6TK.esm.js} +26 -13
  160. package/dist/{identityReuseManager-BXEBBI3N.d.ts → identityReuseManager-ooAbp6Kc.d.ts} +164 -46
  161. package/dist/{identityReuseStateMachine-BhAkuIra.esm.js → identityReuseStateMachine-BrBUpfn5.esm.js} +89 -23
  162. package/dist/{index-CeaC32qI.d.ts → index-DfEuu-Ew.d.ts} +2 -2
  163. package/dist/index-DpTj5PFb.d.ts +1 -0
  164. package/dist/index.d.ts +1 -1
  165. package/dist/index.esm.js +1 -1
  166. package/dist/{invokeOnCaptureCallback-BjzPjJ_p.esm.js → invokeOnCaptureCallback-BW7V3vub.esm.js} +1 -1
  167. package/dist/lamejs-B6TzhU5q.esm.js +10 -0
  168. package/dist/mandatory-consent.d.ts +2 -2
  169. package/dist/mandatory-consent.esm.js +2 -2
  170. package/dist/{mandatoryConsentManager-7dI0D08q.esm.js → mandatoryConsentManager-CX_Dyht7.esm.js} +3 -3
  171. package/dist/{mandatoryConsentManager-DFVm_i2B.d.ts → mandatoryConsentManager-TkX57U6f.d.ts} +3 -4
  172. package/dist/{mandatoryConsentStateMachine-DC5Mo6M1.esm.js → mandatoryConsentStateMachine-CoaSB7P7.esm.js} +3 -3
  173. package/dist/{multipartRecordingService-mwKFTlhR.esm.js → multipartRecordingService-DbeQpXdU.esm.js} +2 -2
  174. package/dist/{permissionGuards-D6TfVop2.esm.js → permissionGuards-Bf4LbHjC.esm.js} +1 -1
  175. package/dist/{permissionServices-EY3_Vx6c.esm.js → permissionServices-d2UW0r_L.esm.js} +34 -3
  176. package/dist/phone-number.d.ts +24 -0
  177. package/dist/phone-number.esm.js +1922 -0
  178. package/dist/phone.d.ts +1 -1
  179. package/dist/phone.esm.js +2 -2
  180. package/dist/{phoneManager-IjhSv5XS.esm.js → phoneManager-BGBcpqsk.esm.js} +31 -22
  181. package/dist/{phoneManager-BBU8Lq0O.d.ts → phoneManager-BO-LTih5.d.ts} +16 -3
  182. package/dist/{phoneStateMachine-CXdXufKg.esm.js → phoneStateMachine-CEm2y7yG.esm.js} +39 -20
  183. package/dist/phoneValidation-DnBcNUNh.esm.js +48 -0
  184. package/dist/qe-signature.d.ts +2 -2
  185. package/dist/qe-signature.esm.js +1 -1
  186. package/dist/redirect-to-mobile.d.ts +1 -1
  187. package/dist/redirect-to-mobile.esm.js +2 -2
  188. package/dist/{redirectToMobileManager-FLEWJtv8.esm.js → redirectToMobileManager-B1yQHFLu.esm.js} +4 -4
  189. package/dist/{redirectToMobileManager-BD2PvT5B.d.ts → redirectToMobileManager-CVsvpVbQ.d.ts} +2 -2
  190. package/dist/{redirectToMobileStateMachine-CSWWgUTO.esm.js → redirectToMobileStateMachine--Sr9NEVT.esm.js} +5 -5
  191. package/dist/{rolldown-runtime-FDOR9p9I.esm.js → rolldown-runtime-B-1-B7_t.esm.js} +10 -1
  192. package/dist/{runChildModule-B2Y_hlix.esm.js → runChildModule-vdxQMCmO.esm.js} +13 -12
  193. package/dist/safeStorage-UxDrnjwa.esm.js +35 -0
  194. package/dist/{sdkVersion-N1UiyFiY.esm.js → sdkVersion-F5YZbjip.esm.js} +1 -1
  195. package/dist/selfie.d.ts +4 -4
  196. package/dist/selfie.esm.js +12 -12
  197. package/dist/selfieErrorUtils-D-tsgEuX.esm.js +21 -0
  198. package/dist/{selfieManager-BSZG891S.d.ts → selfieManager-1J0IEyFq.d.ts} +2 -8
  199. package/dist/{selfieManager-AS6wfUvZ.esm.js → selfieManager-26pENXxw.esm.js} +6 -6
  200. package/dist/selfieStateMachine-BhfKsl3I.esm.js +41 -0
  201. package/dist/{session-BESZc05k.esm.js → session-Bu7djCsj.esm.js} +5 -5
  202. package/dist/session.d.ts +15 -3
  203. package/dist/session.esm.js +30 -5
  204. package/dist/sessionInitializer-jxbfCnE-.esm.js +974 -0
  205. package/dist/{setup-BuPbxpwF.esm.js → setup-C38QkrSP.esm.js} +232 -112
  206. package/dist/{setup-Cyko6cAn.d.ts → setup-lgkQ8dJW.d.ts} +20 -11
  207. package/dist/signature.d.ts +1 -1
  208. package/dist/signature.esm.js +2 -2
  209. package/dist/{signatureManager-DGBSWz2_.d.ts → signatureManager-BpVt_Jv7.d.ts} +2 -2
  210. package/dist/{signatureManager-B72np4ZO.esm.js → signatureManager-qqXyH93e.esm.js} +7 -11
  211. package/dist/{signatureStateMachine-ce_XMA3l.esm.js → signatureStateMachine-BkRSrkKp.esm.js} +3 -3
  212. package/dist/splitTrackedName-3zJRd2RD.esm.js +19 -0
  213. package/dist/{src-35ekGRzK.esm.js → src-DJAJjRYQ.esm.js} +1 -1
  214. package/dist/{stats-CZcy2J53.esm.js → stats-DmG_tkGk.esm.js} +1 -1
  215. package/dist/stats.esm.js +1 -1
  216. package/dist/{sessionInitializer-CnhAkMUN.esm.js → thumbmark.esm-CRc0cYvz.esm.js} +33 -776
  217. package/dist/{trueSightService-M5VpCo96.esm.js → trueSightService-BWgRVGIT.esm.js} +893 -900
  218. package/dist/trust-graph.d.ts +1 -2
  219. package/dist/trust-graph.esm.js +2 -2
  220. package/dist/{types-C0oWGUzg.d.ts → types-0L-eFDmr.d.ts} +1 -1
  221. package/dist/{types-C1g9itHE.d.ts → types-BGXxRwQM.d.ts} +6 -7
  222. package/dist/{types-BfgmV7s7.d.ts → types-BQA7lRDV.d.ts} +1 -1
  223. package/dist/{types-CxGdmzxa.d.ts → types-BvFmYX5c.d.ts} +1 -1
  224. package/dist/{types-Cx-1zo-i.d.ts → types-BvLo3U4u.d.ts} +1 -1
  225. package/dist/types-C71Zo6vl.d.ts +6 -0
  226. package/dist/{types-DEGVXwsk2.d.ts → types-CyPUIpzf.d.ts} +110 -62
  227. package/dist/{types-Bx-BWveD.d.ts → types-DTYr9pCB.d.ts} +1 -1
  228. package/dist/{types-BjSly8cp.d.ts → types-DUnFZ08M.d.ts} +1 -1
  229. package/dist/{types-ESdtnHtg.d.ts → types-zpO4fU6a.d.ts} +3 -4
  230. package/dist/{urlUtils-D6phjq1-.esm.js → urlUtils-6jsE6rKp.esm.js} +9 -1
  231. package/dist/video-selfie.d.ts +6 -9
  232. package/dist/video-selfie.esm.js +1386 -1344
  233. package/dist/{videoSelfieCameraWarmer-q9ZjvXu9.esm.js → videoSelfieCameraWarmer-C366RKqu.esm.js} +11 -11
  234. package/dist/{videoSelfieFlowModuleMachine-BUe2uACW.esm.js → videoSelfieFlowModuleMachine-BCFVHBQ1.esm.js} +1 -1
  235. package/dist/{videoSelfieStepDetector-ChYgFM15.d.ts → videoSelfieStepDetector-C5QHOvWb.d.ts} +4 -4
  236. package/dist/videoTrimByCopy-BFfAiNpv.esm.js +15901 -0
  237. package/dist/{warmup-Cis2p6O0.d.ts → warmup-BUPPRAA1.d.ts} +7 -0
  238. package/dist/{warmup-ChDwHSel.esm.js → warmup-DMtbyb2l.esm.js} +27 -9
  239. package/dist/wasm.d.ts +2 -2
  240. package/dist/wasm.esm.js +4 -4
  241. package/dist/{wasmDsFlagSync-DYrLUEII.esm.js → wasmDsFlagSync-BXCGqP48.esm.js} +1 -1
  242. package/dist/{wasmWebClient-B7baE-Wf.esm.js → wasmWebClient-kbYZ2sxw.esm.js} +259 -20
  243. package/dist/watchlist-for-business.d.ts +1 -1
  244. package/dist/watchlist-for-business.esm.js +2 -2
  245. package/dist/watchlist.d.ts +1 -1
  246. package/dist/watchlist.esm.js +2 -2
  247. package/dist/{watchlistForBusinessManager-CsnJnG-C.d.ts → watchlistForBusinessManager-B3GDPZrr.d.ts} +2 -2
  248. package/dist/{watchlistForBusinessManager-CIMkpEhu.esm.js → watchlistForBusinessManager-BvF4jK3S.esm.js} +7 -5
  249. package/dist/{watchlistForBusinessStateMachine-CJ-MvUre.esm.js → watchlistForBusinessStateMachine-121XK-Et.esm.js} +3 -3
  250. package/dist/{watchlistManager-CixcLNDT.esm.js → watchlistManager-CNWEOYSq.esm.js} +3 -3
  251. package/dist/{watchlistManager-DLXef90v.d.ts → watchlistManager-DJQOd8Pw.d.ts} +2 -2
  252. package/dist/{watchlistStateMachine-CBqk2w-h.esm.js → watchlistStateMachine-Dgfm42w2.esm.js} +3 -3
  253. package/dist/workflow.d.ts +34 -5
  254. package/dist/workflow.esm.js +64 -46
  255. package/dist/{xstate-actors.esm-BXeQ-Ucz.esm.js → xstate-actors.esm-8Gzepa_A.esm.js} +1 -1
  256. package/dist/{xstate.esm-BuFLFuzz.esm.js → xstate.esm-DSajW7CJ.esm.js} +24 -10
  257. package/package.json +13 -5
  258. package/dist/Actor-iTq7YY48.d.ts +0 -1
  259. package/dist/StateMachine-EDpYWy0i.d.ts +0 -6
  260. package/dist/fiscalQrManager-DbCVMIBx.esm.js +0 -34143
  261. package/dist/index-B8weJxmL.d.ts +0 -1
  262. package/dist/selfieErrorUtils-UiQ46EBa.esm.js +0 -116
  263. package/dist/selfieStateMachine-DY7vJVNY.esm.js +0 -71
  264. package/dist/types-BN5RPPIZ.esm.js +0 -34
  265. package/dist/types-Bt9RuRqt.d.ts +0 -6
  266. package/dist/virtualCameraCheck-Cjab7FTI.esm.js +0 -48
  267. /package/dist/{types-BSBzhHRH.d.ts → types-BSBzhHRH2.d.ts} +0 -0
@@ -1,9 +1,10 @@
1
- import { a as setWebApiHttpTransport, f as deriveSiblingJsPath, i as initializeWasmWebClient, o as setupWasmConnection, p as WASM_MODEL_FILES, r as executeWasmRequest, t as WasmWebClientError, v as buildModelVariantSources } from "./wasmWebClient-B7baE-Wf.esm.js";
1
+ import { a as setWebApiHttpTransport, f as deriveSiblingJsPath, i as initializeWasmWebClient, o as setupWasmConnection, p as WASM_MODEL_FILES, r as executeWasmRequest, t as WasmWebClientError, v as buildModelVariantSources } from "./wasmWebClient-kbYZ2sxw.esm.js";
2
2
  import { t as getTimestamp } from "./IBrowserEnvironmentCapability-DEaRRk-R.esm.js";
3
+ import { n as eventModuleNames } from "./events-CAgFE-k3.esm.js";
3
4
  import { i as isApiConfigured, n as getApi, o as setClient, r as getToken, t as api } from "./api-Bx3gKW_y.esm.js";
4
- import { n as eventModuleNames } from "./events-ijlbX_Wx.esm.js";
5
- import { t as SDK_VERSION } from "./sdkVersion-N1UiyFiY.esm.js";
6
- import { t as endpoints } from "./endpoints-B-3Q-LUw.esm.js";
5
+ import { t as endpoints } from "./endpoints-DHzlkQNe.esm.js";
6
+ import { t as SDK_VERSION } from "./sdkVersion-F5YZbjip.esm.js";
7
+ import { n as reportHttpError, t as HttpRequestError } from "./HttpRequestError-Bh0pNGSC.esm.js";
7
8
  //#region ../infra/src/wasm/wasmDefaults.ts
8
9
  const WASM_CDN_BASE_URL = "https://cdn.incodesmile.com/ml-wasm-kit-release";
9
10
  /** The WASM version bundled and tested with this SDK release. */
@@ -131,6 +132,7 @@ function resolveWasmConfig(overrides) {
131
132
  glueCodeSimdPath: pickPath("glueCodeSimdPath", overrides, glueCodeSimdDefault),
132
133
  modelsBasePath: pickPath("modelsBasePath", overrides, modelsDefault),
133
134
  useSimd: overrides.useSimd,
135
+ showLogs: overrides.showLogs,
134
136
  pipelines: overrides.pipelines,
135
137
  pipelineModels: overrides.pipelineModels,
136
138
  modelUrls: overrides.modelUrls,
@@ -142,970 +144,961 @@ function resolveWasmConfig(overrides) {
142
144
  validateWasmPaths(merged);
143
145
  return merged;
144
146
  }
147
+ /** Hard cap per log message, UTF-8 bytes (contract). */
148
+ const MESSAGE_MAX_BYTES = 8 * 1024;
149
+ const TRUESIGHT_SDK_ID = "IncdOnboarding";
150
+ /** localStorage key prefix for persisted sealed snapshots (A3: one slot per session). */
151
+ const PENDING_STORAGE_KEY_PREFIX = "incode.truesight.pending.";
145
152
  //#endregion
146
- //#region ../infra/src/http/createApi.ts
147
- var FetchHttpError = class extends Error {
148
- constructor(status, statusText, url, method, headers, data) {
149
- super(`HTTP ${status} ${statusText}`);
150
- this.ok = false;
151
- this.status = status;
152
- this.statusText = statusText;
153
- this.url = url;
154
- this.method = method;
155
- this.headers = headers;
156
- this.data = data;
157
- this.name = "FetchHttpError";
158
- }
159
- };
160
- const buildQueryString$1 = (query) => {
161
- if (!query) return "";
162
- const params = new URLSearchParams();
163
- Object.entries(query).forEach(([key, value]) => {
164
- if (value !== void 0 && value !== null) params.append(key, String(value));
165
- });
166
- const str = params.toString();
167
- return str ? `?${str}` : "";
168
- };
169
- const buildUrl$1 = (baseURL, url, query) => {
170
- const queryString = buildQueryString$1(query);
171
- if (url.startsWith("http://") || url.startsWith("https://")) return `${url}${queryString}`;
172
- return `${baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL}${url.startsWith("/") ? url : `/${url}`}${queryString}`;
173
- };
174
- const prepareBody$1 = (body) => {
175
- if (body === null || body === void 0) return null;
176
- if (body instanceof FormData || body instanceof Blob || body instanceof ArrayBuffer) return body;
177
- if (typeof body === "object") return JSON.stringify(body);
178
- return String(body);
179
- };
180
- const parseResponse = async (response, parseType) => {
181
- if (parseType === "response") return response;
182
- if (parseType === "blob") return await response.blob();
183
- if (parseType === "arrayBuffer") return await response.arrayBuffer();
184
- if (parseType === "text") return await response.text();
185
- const contentType = response.headers.get("content-type") ?? "";
186
- if (parseType === "json" || contentType.includes("application/json")) {
187
- const raw = await response.text();
188
- if (raw.length === 0) return "";
189
- try {
190
- return JSON.parse(raw);
191
- } catch {
192
- return raw;
193
- }
194
- }
195
- return await response.text();
196
- };
197
- const requestWithXHR = (fullUrl, method, mergedHeaders, requestBody, timeout, signal, onUploadProgress) => {
198
- return new Promise((resolve, reject) => {
199
- const xhr = new XMLHttpRequest();
200
- xhr.open(method, fullUrl, true);
201
- Object.entries(mergedHeaders).forEach(([key, value]) => {
202
- xhr.setRequestHeader(key, value);
203
- });
204
- xhr.timeout = timeout;
205
- xhr.upload.onprogress = (event) => {
206
- if (event.lengthComputable) {
207
- const percentComplete = event.loaded / event.total * 100;
208
- onUploadProgress(Math.round(percentComplete));
209
- }
210
- };
211
- xhr.onload = () => {
212
- const responseHeaders = {};
213
- xhr.getAllResponseHeaders().split("\r\n").forEach((line) => {
214
- const parts = line.split(": ");
215
- if (parts.length === 2) responseHeaders[parts[0].toLowerCase()] = parts[1];
216
- });
217
- let data;
218
- try {
219
- if ((xhr.getResponseHeader("content-type") ?? "").includes("application/json")) data = JSON.parse(xhr.responseText);
220
- else data = xhr.responseText;
221
- } catch {
222
- data = xhr.responseText;
223
- }
224
- if (xhr.status >= 200 && xhr.status < 300) resolve({
225
- ok: true,
226
- status: xhr.status,
227
- statusText: xhr.statusText,
228
- url: fullUrl,
229
- headers: responseHeaders,
230
- data
231
- });
232
- else reject(new FetchHttpError(xhr.status, xhr.statusText, fullUrl, method, responseHeaders, data));
233
- };
234
- xhr.onerror = () => {
235
- reject(new FetchHttpError(0, "Network Error", fullUrl, method, {}, null));
236
- };
237
- xhr.ontimeout = () => {
238
- reject(new FetchHttpError(0, "Request timeout", fullUrl, method, {}, null));
239
- };
240
- if (signal) signal.addEventListener("abort", () => {
241
- xhr.abort();
242
- reject(new FetchHttpError(0, "Request aborted", fullUrl, method, {}, null));
243
- });
244
- xhr.send(requestBody);
245
- });
246
- };
247
- const createApi = (config) => {
248
- const headers = {
249
- "Content-Type": "application/json",
250
- Accept: "application/json",
251
- "api-version": "1.0",
252
- ...config.customHeaders ?? {}
253
- };
254
- const defaults = {
255
- baseURL: config.apiURL,
256
- headers
257
- };
258
- const client = {
259
- defaults,
260
- async request(requestConfig) {
261
- const { method = "GET", url, headers = {}, query, params, body, signal, timeout: timeoutOverride, parse, onUploadProgress, keepalive } = requestConfig;
262
- const fullUrl = buildUrl$1(defaults.baseURL, url, params ?? query);
263
- const mergedHeaders = {
264
- ...defaults.headers,
265
- ...headers
266
- };
267
- const requestBody = prepareBody$1(body);
268
- const timeout = timeoutOverride ?? config.timeout;
269
- let finalHeaders = mergedHeaders;
270
- if (requestBody === null && (method === "POST" || method === "PUT" || method === "PATCH")) {
271
- const { "Content-Type": _, ...headersWithoutContentType } = mergedHeaders;
272
- finalHeaders = headersWithoutContentType;
273
- }
274
- if (onUploadProgress) {
275
- if (requestBody !== null && typeof ReadableStream !== "undefined" && requestBody instanceof ReadableStream) throw new Error("Upload progress tracking is not supported for ReadableStream bodies");
276
- return requestWithXHR(fullUrl, method, finalHeaders, requestBody, timeout ?? 0, signal, onUploadProgress);
277
- }
278
- const controller = new AbortController();
279
- if (signal) if (signal.aborted) controller.abort();
280
- else signal.addEventListener("abort", () => controller.abort(), { once: true });
281
- const abortSignal = controller.signal;
282
- const timeoutId = timeout === void 0 ? void 0 : setTimeout(() => controller.abort(), timeout);
283
- try {
284
- const response = await fetch(fullUrl, {
285
- method,
286
- headers: finalHeaders,
287
- body: requestBody,
288
- signal: abortSignal,
289
- keepalive
290
- });
291
- if (timeoutId) clearTimeout(timeoutId);
292
- const responseHeaders = {};
293
- response.headers.forEach((value, key) => {
294
- responseHeaders[key] = value;
295
- });
296
- const data = await parseResponse(response, parse);
297
- if (!response.ok) throw new FetchHttpError(response.status, response.statusText, fullUrl, method, responseHeaders, data);
298
- return {
299
- ok: true,
300
- status: response.status,
301
- statusText: response.statusText,
302
- url: fullUrl,
303
- headers: responseHeaders,
304
- data
305
- };
306
- } catch (error) {
307
- if (timeoutId) clearTimeout(timeoutId);
308
- if (error instanceof FetchHttpError) throw error;
309
- if (error instanceof Error && error.name === "AbortError") throw new FetchHttpError(0, "Request timeout", fullUrl, method, {}, null);
310
- throw error;
311
- }
312
- },
313
- get(url, config) {
314
- return client.request({
315
- ...config,
316
- url,
317
- method: "GET"
318
- });
319
- },
320
- post(url, body, config) {
321
- return client.request({
322
- ...config,
323
- url,
324
- body,
325
- method: "POST"
326
- });
327
- },
328
- put(url, body, config) {
329
- return client.request({
330
- ...config,
331
- url,
332
- body,
333
- method: "PUT"
334
- });
335
- },
336
- patch(url, body, config) {
337
- return client.request({
338
- ...config,
339
- url,
340
- body,
341
- method: "PATCH"
342
- });
343
- },
344
- delete(url, config) {
345
- return client.request({
346
- ...config,
347
- url,
348
- method: "DELETE"
349
- });
350
- },
351
- head(url, config) {
352
- return client.request({
353
- ...config,
354
- url,
355
- method: "HEAD"
356
- });
357
- },
358
- options(url, config) {
359
- return client.request({
360
- ...config,
361
- url,
362
- method: "OPTIONS"
363
- });
364
- },
365
- setHeader(name, value) {
366
- defaults.headers[name] = value;
367
- }
368
- };
369
- return client;
370
- };
371
- //#endregion
372
- //#region ../infra/src/http/createWasmApi.ts
373
- const WASM_TIMEOUT_CEILING_MS = 36e5;
374
- const RSA_OAEP_SHA256_SCHEME = "RSA/NONE/OAEPWITHSHA-256ANDMGF1PADDING";
153
+ //#region src/internal/trueSight/sanitize.ts
375
154
  /**
376
- * Builds the base set of HTTP headers that the WASM WebClient sends on every
377
- * request (including the internal `/e2ee/key/v2` and `/e2ee/key` handshake
378
- * calls).
155
+ * Deny-by-default message scrubber — runs at INGESTION (inside the log buffer's
156
+ * `append`), so the buffer, every persisted snapshot, and every upload are
157
+ * already clean; there is no code path around it (ENG-48677 plan §1.2).
158
+ *
159
+ * Ordered pipeline. Two deliberate deviations from the plan's original rule
160
+ * order, both from the P1-A adversarial review (2026-07-23, recorded in the
161
+ * plan's Operating-decisions section):
162
+ * - Inputs are pre-clamped to 2× the message cap BEFORE any regex runs — the
163
+ * unanchored patterns are quadratic on pathological non-matching runs
164
+ * (measured ~4.5 s on a 100 KB run), so regex cost must be bounded first.
165
+ * The final 8 KB cap still runs last.
166
+ * - The base64-blob rule runs BEFORE the digit-run rule — a digit run inside a
167
+ * blob would otherwise split it into sub-64-char fragments that escape
168
+ * redaction.
169
+ *
170
+ * The regex table ships in the P1-A PR description for privacy sign-off (see
171
+ * .agents/guides/privacy.md). Known hardening backlog (D4, Phase 4): formatted
172
+ * phone numbers, unicode digits/emails, fuzz/property tests.
379
173
  */
380
- function buildWasmDefaultHeaders(customHeaders) {
381
- return {
382
- "Content-Type": "application/json",
383
- Accept: "application/json",
384
- "api-version": "1.0",
385
- ...customHeaders ?? {}
386
- };
174
+ /** Three dot-joined base64url segments — JWT/JWS shape. */
175
+ const JWT_PATTERN = /\b[\w-]{8,}\.[\w-]{8,}\.[\w-]{8,}\b/g;
176
+ /**
177
+ * Credential-ish key with a `:`/`=` value (quoted, `Bearer …`, or bare token).
178
+ * The key may carry prefixes (`access_token`, `x-api-key`, `sessionToken`) —
179
+ * a plain \b boundary would miss `_token` since `_` is a word character.
180
+ */
181
+ const CREDENTIAL_KV_PATTERN = /([\w-]*(?:token|api[-_]?key|authorization|auth|secret|password|passwd))\s*[:=]\s*("[^"]*"|'[^']*'|(?:Bearer\s+)?[^\s,;&]+)/gi;
182
+ /** Userinfo credentials in an absolute URL (`https://user:pass@host/…`). */
183
+ const URL_USERINFO_PATTERN = /(\bhttps?:\/\/)[^\s/@]*(?::[^\s/@]*)?@/gi;
184
+ /** Query string / fragment of an absolute URL — kills signed URLs. */
185
+ const URL_TAIL_PATTERN = /(https?:\/\/[^\s?#]+)[?#][^\s]*/g;
186
+ const EMAIL_PATTERN = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g;
187
+ /** base64-ish blobs (media, keys) — 64+ chars of the base64/base64url alphabet. */
188
+ const BASE64_BLOB_PATTERN = /[-A-Za-z0-9+/_]{64,}={0,2}/g;
189
+ /** Runs of 8+ digits — phones, CURP, document numbers. */
190
+ const DIGIT_RUN_PATTERN = /\d{8,}/g;
191
+ const TRUNCATION_SUFFIX = "…[truncated]";
192
+ /** Regex-cost bound: clamp raw input before any pattern runs (see header note). */
193
+ const REGEX_INPUT_MAX_BYTES = MESSAGE_MAX_BYTES * 2;
194
+ function sanitizeMessage(message) {
195
+ return truncateUtf8(truncateUtf8(message, REGEX_INPUT_MAX_BYTES).replace(JWT_PATTERN, "[jwt]").replace(CREDENTIAL_KV_PATTERN, "$1=[redacted]").replace(URL_USERINFO_PATTERN, "$1[redacted]@").replace(URL_TAIL_PATTERN, "$1").replace(EMAIL_PATTERN, "[email]").replace(BASE64_BLOB_PATTERN, (match) => `[blob:${match.length}]`).replace(DIGIT_RUN_PATTERN, "[digits]"), MESSAGE_MAX_BYTES);
387
196
  }
388
- var WasmHttpError = class extends Error {
389
- constructor(status, statusText, url, method, headers, data) {
390
- super(`HTTP ${status} ${statusText}`);
391
- this.ok = false;
392
- this.status = status;
393
- this.statusText = statusText;
394
- this.url = url;
395
- this.method = method;
396
- this.headers = headers;
397
- this.data = data;
398
- this.name = "WasmHttpError";
399
- }
400
- };
401
- const HTTP_METHODS = /* @__PURE__ */ new Set([
402
- "GET",
403
- "POST",
404
- "PUT",
405
- "PATCH",
406
- "DELETE"
407
- ]);
408
- const buildQueryString = (query) => {
409
- if (!query) return "";
410
- const params = new URLSearchParams();
411
- Object.entries(query).forEach(([key, value]) => {
412
- if (value !== void 0 && value !== null) params.append(key, String(value));
413
- });
414
- const str = params.toString();
415
- return str ? `?${str}` : "";
416
- };
417
- const buildUrl = (baseURL, url, query) => {
418
- const queryString = buildQueryString(query);
419
- if (url.startsWith("http://") || url.startsWith("https://")) return `${url}${queryString}`;
420
- return `${baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL}${url.startsWith("/") ? url : `/${url}`}${queryString}`;
421
- };
422
- const prepareBody = (body) => {
423
- if (body === null || body === void 0) return void 0;
424
- if (body instanceof FormData || body instanceof Blob || body instanceof ArrayBuffer || body instanceof Uint8Array || typeof body === "string") return body;
425
- if (typeof body === "object") return body;
426
- return String(body);
427
- };
428
- const normalizeMethod = (method) => {
429
- const upper = method.toUpperCase();
430
- if (!HTTP_METHODS.has(upper)) throw new Error(`Unsupported HTTP method for WASM client: ${method}`);
431
- return upper;
432
- };
433
- const getErrorStatus = (error) => {
434
- if (error instanceof WasmWebClientError) return error.statusCode;
435
- if (typeof error === "object" && error !== null) {
436
- const record = error;
437
- if (typeof record.statusCode === "number") return record.statusCode;
438
- if (typeof record.status === "number") return record.status;
197
+ /**
198
+ * UTF-8 byte length without TextEncoder (banned browser global in L1 —
199
+ * see the no-browser-api-in-core lint rule). Counts by code point.
200
+ */
201
+ function utf8ByteLength(value) {
202
+ let bytes = 0;
203
+ for (const char of value) bytes += codePointByteLength(char);
204
+ return bytes;
205
+ }
206
+ function codePointByteLength(char) {
207
+ const codePoint = char.codePointAt(0) ?? 0;
208
+ if (codePoint < 128) return 1;
209
+ if (codePoint < 2048) return 2;
210
+ if (codePoint < 65536) return 3;
211
+ return 4;
212
+ }
213
+ /** Cuts on a code-point boundary so no surrogate half ever reaches the wire. */
214
+ function truncateUtf8(value, maxBytes) {
215
+ if (utf8ByteLength(value) <= maxBytes) return value;
216
+ const budget = maxBytes - utf8ByteLength(TRUNCATION_SUFFIX);
217
+ let bytes = 0;
218
+ let result = "";
219
+ for (const char of value) {
220
+ const charBytes = codePointByteLength(char);
221
+ if (bytes + charBytes > budget) break;
222
+ bytes += charBytes;
223
+ result += char;
439
224
  }
440
- return 0;
441
- };
442
- const getErrorData = (error) => {
443
- if (error instanceof WasmWebClientError) return error.response?.data ?? null;
444
- return null;
445
- };
446
- const getErrorMessage = (error) => {
447
- if (error instanceof Error) return error.message;
448
- return "WasmWebClient request failed";
449
- };
450
- const withAbortSignal = async (promise, signal, error) => {
451
- if (!signal) return await promise;
452
- if (signal.aborted) throw error;
453
- return await new Promise((resolve, reject) => {
454
- const onAbort = () => reject(error);
455
- signal.addEventListener("abort", onAbort, { once: true });
456
- promise.then(resolve, reject).finally(() => {
457
- signal.removeEventListener("abort", onAbort);
458
- });
459
- });
460
- };
461
- const createWasmApi = async (config) => {
462
- const headers = buildWasmDefaultHeaders(config.customHeaders);
463
- const isEncryptionEnabled = config.isEncryptionEnabled ?? (() => false);
464
- const useSha256 = config.mgf1 === "sha256";
465
- await initializeWasmWebClient(config.wasm);
466
- await setupWasmConnection(config.apiURL, "", config.encryptionEnabled ?? false, headers, useSha256);
467
- const defaults = {
468
- baseURL: config.apiURL,
469
- headers
470
- };
471
- const client = {
472
- defaults,
473
- async request(requestConfig) {
474
- const { method = "GET", url, headers: requestHeaders = {}, query, params, body, signal, timeout: timeoutOverride, onUploadProgress, ie = false } = requestConfig;
475
- const upperMethod = normalizeMethod(method);
476
- const requestParams = params ?? query;
477
- const fullUrl = buildUrl(defaults.baseURL, url, requestParams);
478
- const needsSchemeHeader = useSha256 && isEncryptionEnabled();
479
- const mergedHeaders = {
480
- ...defaults.headers,
481
- ...needsSchemeHeader ? { "X-RSA-Encryption-Scheme": RSA_OAEP_SHA256_SCHEME } : {},
482
- ...requestHeaders
483
- };
484
- const requestBody = prepareBody(body);
485
- const timeout = timeoutOverride ?? config.timeout ?? WASM_TIMEOUT_CEILING_MS;
486
- const wasmProgress = onUploadProgress ? (progress) => {
487
- if (progress.total > 0) onUploadProgress(Math.round(progress.loaded / progress.total * 100));
488
- } : void 0;
489
- const abortError = new WasmHttpError(0, "Request aborted", fullUrl, upperMethod, {}, null);
490
- if (signal?.aborted) throw abortError;
491
- try {
492
- const response = await withAbortSignal(executeWasmRequest(upperMethod, url, requestBody, mergedHeaders, requestParams, timeout, wasmProgress, ie), signal, abortError);
493
- if (response.status < 200 || response.status >= 300) throw new WasmHttpError(response.status, "", fullUrl, upperMethod, {}, response.data);
494
- return {
495
- ok: true,
496
- status: response.status,
497
- statusText: "",
498
- url: fullUrl,
499
- headers: {},
500
- data: response.data
501
- };
502
- } catch (error) {
503
- if (error instanceof WasmHttpError) throw error;
504
- throw new WasmHttpError(getErrorStatus(error), getErrorMessage(error), fullUrl, upperMethod, {}, getErrorData(error));
505
- }
506
- },
507
- get(url, requestConfig) {
508
- return client.request({
509
- ...requestConfig,
510
- url,
511
- method: "GET"
512
- });
513
- },
514
- post(url, body, requestConfig) {
515
- return client.request({
516
- ...requestConfig,
517
- url,
518
- body,
519
- method: "POST"
520
- });
521
- },
522
- put(url, body, requestConfig) {
523
- return client.request({
524
- ...requestConfig,
525
- url,
526
- body,
527
- method: "PUT"
528
- });
529
- },
530
- patch(url, body, requestConfig) {
531
- return client.request({
532
- ...requestConfig,
533
- url,
534
- body,
535
- method: "PATCH"
536
- });
537
- },
538
- delete(url, requestConfig) {
539
- return client.request({
540
- ...requestConfig,
541
- url,
542
- method: "DELETE"
543
- });
544
- },
545
- head() {
546
- return Promise.reject(/* @__PURE__ */ new Error("HEAD is not supported by the WASM HTTP client"));
547
- },
548
- options() {
549
- return Promise.reject(/* @__PURE__ */ new Error("OPTIONS is not supported by the WASM HTTP client"));
550
- },
551
- setHeader(name, value) {
552
- defaults.headers[name] = value;
553
- }
554
- };
555
- return client;
556
- };
225
+ return result + TRUNCATION_SUFFIX;
226
+ }
557
227
  //#endregion
558
- //#region src/internal/http/clientLifecycle.ts
228
+ //#region ../infra/src/crypto/randomUUID.ts
559
229
  /**
560
- * Wraps the active HttpClient as a transport for the C++ `WebApi` host
561
- * adapter. Lets the on-device face-results POST flow through the same
562
- * `httpClient.request()` pipeline as every other endpoint — header
563
- * injection, encryption-state handling, default headers, timeout — instead
564
- * of bypassing it via `executeWasmRequest` directly.
230
+ * Cryptographically-strong UUID v4 (RFC 4122).
565
231
  *
566
- * Protected captures arrive with `ie === true`: the C++ `WebApi` already
567
- * encrypted the body inline, and only the WASM `WebClient` can unwrap it. A
568
- * plain fetch client would post the ciphertext as JSON and the backend
569
- * answers 406. If the plain client is still installed at that point (the
570
- * host called `setup()` without `wasm` and warmed WASM separately), swap to
571
- * the WASM client first. The module is already loaded — the payload came
572
- * out of it — so the swap only creates the `WebClient`.
232
+ * Lives in infra (L0) so Core (L1) can mint secure identifiers without touching
233
+ * the `crypto` browser API directly — Core delegates here, keeping it free of
234
+ * browser globals (enforced by the `no-browser-api-in-core` lint rule). Backed
235
+ * by `crypto.randomUUID`, available in every browser the SDK targets.
573
236
  */
574
- function bindWebApiTransport(client) {
575
- return async (url, body, config) => {
576
- const response = await (config.ie === true && storedHttpConfig && !storedHttpConfig.isWasm ? await ensureWasmHttpClient() : client).request({
577
- method: "POST",
578
- url,
579
- body,
580
- headers: config.headers,
581
- params: config.params,
582
- timeout: config.timeout,
583
- ie: config.ie
584
- });
585
- return {
586
- data: response.data,
587
- status: response.status
588
- };
589
- };
237
+ function randomUUID() {
238
+ return crypto.randomUUID();
590
239
  }
591
- function installClient(client) {
592
- setClient(client);
593
- setWebApiHttpTransport(bindWebApiTransport(client));
240
+ //#endregion
241
+ //#region ../infra/src/time/epochMsToIsoString.ts
242
+ /**
243
+ * Converts an epoch-milliseconds timestamp to a full ISO-8601 UTC string
244
+ * (e.g. `2026-07-23T09:41:00.000Z`).
245
+ *
246
+ * Lives in Infra (L0) so Core can format wire timestamps without touching the
247
+ * `Date` global directly — banned in Core by the `no-browser-api-in-core` lint
248
+ * rule — mirroring the `crypto/randomUUID.ts` free-function precedent.
249
+ * (`DateFormattingProvider.utcToIsoDateString` is date-only and not suitable.)
250
+ */
251
+ function epochMsToIsoString(epochMs) {
252
+ return new Date(epochMs).toISOString();
594
253
  }
595
- async function ensureWasmHttpClient() {
596
- await upgradeToWasmHttpClient(resolveWasmConfig());
597
- return getApi();
254
+ //#endregion
255
+ //#region src/internal/trueSight/recordBuilder.ts
256
+ /**
257
+ * Assembles the exact plaintext contract record — the ONLY place a diagnostics
258
+ * payload is shaped. Pure: same function serves final records, interrupted
259
+ * snapshots, and future incremental slices (ENG-48677 plan §1.1).
260
+ *
261
+ * Deny-by-default is structural here: every field is an explicit literal —
262
+ * nothing is spread from internal state, so no unexpected field can ever leak
263
+ * into an upload.
264
+ *
265
+ * Hard gates enforced:
266
+ * - empty/missing `sessionId` or `startedAt` → returns `null` (upload skipped —
267
+ * expected for sessions that die before `/omni/start`).
268
+ * - `failureReason` present if-and-only-if `outcome === 'failure'` (defaults to
269
+ * `'unknown'` when a failure arrives without one, rather than dropping the record).
270
+ * - fresh record `id` per build; `endedAt` stamped at build time.
271
+ */
272
+ function buildDiagnosticsRecord(meta, logs, outcome, failureReason, recordId) {
273
+ if (!meta.sessionId || meta.startedAtMs === null) return null;
274
+ const flowType = meta.flowType ?? deriveFlowTypeFromSurface(meta.integrationType);
275
+ if (flowType === null) return null;
276
+ return {
277
+ schemaVersion: "1.0",
278
+ id: recordId ?? randomUUID(),
279
+ session: {
280
+ sessionId: meta.sessionId,
281
+ sdkId: TRUESIGHT_SDK_ID,
282
+ sdkVersion: SDK_VERSION,
283
+ platform: "web",
284
+ sdkMode: null,
285
+ browser: meta.browser,
286
+ osVersion: meta.osVersion,
287
+ osLanguage: meta.osLanguage,
288
+ sdkLanguage: meta.sdkLanguage,
289
+ integrationType: meta.integrationType,
290
+ flowType,
291
+ flowId: meta.flowId,
292
+ workflowId: meta.workflowId,
293
+ outcome,
294
+ ...outcome === "failure" ? { failureReason: failureReason ?? "unknown" } : {},
295
+ startedAt: epochMsToIsoString(meta.startedAtMs),
296
+ endedAt: epochMsToIsoString(getTimestamp()),
297
+ testing: meta.testing,
298
+ e2eEncryptionEnabled: meta.e2eEncryptionEnabled,
299
+ configurationId: meta.hasConfigurationId,
300
+ externalCustomerId: meta.hasExternalCustomerId,
301
+ hasProvidedSessionId: meta.hasProvidedSessionId,
302
+ token: meta.hasToken,
303
+ externalToken: meta.hasExternalToken
304
+ },
305
+ logs: logs.map(toContractEntry)
306
+ };
598
307
  }
599
- let storedHttpConfig;
600
- let pendingUpgrade;
601
- /** Reads the current HTTP-client config (or `undefined` if none installed). */
602
- function getStoredHttpConfig() {
603
- return storedHttpConfig;
308
+ /**
309
+ * Wire `flowType` when no orchestrator was OBSERVED (an observed one — set by
310
+ * the bridge on any flow event — always wins). Stage ingest requires a
311
+ * non-null enum (probe 2026-07-23: null/omitted/off-enum all 400), so the
312
+ * entry surface decides, and the mapping is deliberately exhaustive:
313
+ *
314
+ * - `startWorkflow` → 'workflow' (Webflows engine entered, died pre-ready)
315
+ * - `startFlow` → 'flow' (flow/orchestrated manager, died pre-ready)
316
+ * - `startOnboarding`→ 'flow' (self-loading UI wraps the flow engine)
317
+ * - `startOnboardingSection` → null → the BUILD ABORTS (record withheld):
318
+ * a standalone session has no truthful flowType, and mislabeling it as a
319
+ * flow session is worse than skipping the upload. Withheld until the
320
+ * DECIDED BE ask ships (`flowType:"standalone"`, not nullable) — then this
321
+ * branch returns 'standalone' and standalone diagnostics start flowing,
322
+ * coordinated with the BE deploy since off-enum values 400 today.
323
+ */
324
+ function deriveFlowTypeFromSurface(integrationType) {
325
+ switch (integrationType) {
326
+ case "startWorkflow": return "workflow";
327
+ case "startFlow":
328
+ case "startOnboarding": return "flow";
329
+ case "startOnboardingSection": return null;
330
+ }
604
331
  }
605
- /** Whether encryption is currently active on the installed HTTP client. */
606
- function isHttpEncrypted() {
607
- return storedHttpConfig?.encryption.enabled ?? false;
332
+ function toContractEntry(entry) {
333
+ return {
334
+ index: entry.index,
335
+ timestamp: epochMsToIsoString(entry.timestampMs),
336
+ level: entry.level,
337
+ thread: "main",
338
+ message: entry.message,
339
+ subsystem: entry.subsystem,
340
+ category: entry.category
341
+ };
608
342
  }
609
- /** Clears all HTTP-client state. Called by `reset()`. */
610
- function resetHttpClientState() {
611
- storedHttpConfig = void 0;
612
- setWebApiHttpTransport(null);
343
+ function createInitialState() {
344
+ return {
345
+ sessionId: null,
346
+ startedAtMs: null,
347
+ browser: null,
348
+ osVersion: null,
349
+ osLanguage: null,
350
+ sdkLanguage: "en-US",
351
+ integrationType: "startOnboardingSection",
352
+ flowType: null,
353
+ flowId: null,
354
+ workflowId: null,
355
+ testing: false,
356
+ devModeSignal: void 0,
357
+ apiUrlSignal: void 0,
358
+ hasConfigurationId: false,
359
+ hasExternalCustomerId: false,
360
+ hasProvidedSessionId: false,
361
+ hasExternalToken: false
362
+ };
613
363
  }
364
+ let state = createInitialState();
365
+ let sources = {};
366
+ /** Tap for `createSession` — sessionId comes from the returned `interviewId`. */
367
+ function noteSessionCreated(session, options = {}) {}
368
+ function noteEnvironment(environment) {}
614
369
  /**
615
- * Builds (or replaces) the HTTP client when `setup()` receives an `apiURL`.
616
- * Picks `createWasmApi` when `effectiveWasm` is set, otherwise plain
617
- * `createApi`. Wraps the call in handshake-failure context when encryption
618
- * is requested.
370
+ * `testing` heuristic: devMode OR non-prod API host pattern. Always a boolean —
371
+ * the contract requires the field present on every record. Signals MERGE across
372
+ * calls (a later apiUrl-only call must not erase an earlier devMode signal);
373
+ * `testing` is recomputed from the merged pair.
619
374
  */
620
- async function installFreshHttpClient(apiURL, options, effectiveWasm, encryption) {
621
- installClient(effectiveWasm ? await withHandshakeFailureContext(encryption.enabled, () => createWasmApi({
622
- apiURL,
623
- customHeaders: options.customHeaders,
624
- timeout: options.timeout,
625
- wasm: effectiveWasm,
626
- encryptionEnabled: encryption.enabled,
627
- mgf1: encryption.mgf1,
628
- isEncryptionEnabled: isHttpEncrypted
629
- })) : createApi({
630
- apiURL,
631
- customHeaders: options.customHeaders,
632
- timeout: options.timeout
633
- }));
634
- storedHttpConfig = {
635
- apiURL,
636
- customHeaders: options.customHeaders,
637
- timeout: options.timeout,
638
- isWasm: Boolean(effectiveWasm),
639
- encryption
640
- };
375
+ function noteTestingSignals(signals) {}
376
+ /**
377
+ * Live read of the merged testing signal (devMode OR non-prod host). Used to
378
+ * gate host-console self-health noise so production host pages stay quiet while
379
+ * staging/dev keeps the console signal (the record always captures it either
380
+ * way via `trueSightLog`). Same signal the overflow-flush staging gate uses.
381
+ */
382
+ function isTrueSightTesting() {
383
+ return state.testing;
641
384
  }
642
385
  /**
643
- * Replaces the active HTTP client with the WASM-backed one. Used internally
644
- * by lazy-loading UI components (`<incode-flow>`, `<incode-workflow>`) when
645
- * WASM finishes warming up.
646
- *
647
- * No-op when no apiURL was previously configured, or when the active client
648
- * is already WASM-backed. The encryption state (enabled + MGF1 scheme) is
649
- * preserved across the swap — this is *not* a user-facing encryption change.
650
- *
651
- * @internal NOT a public API. Application code should use
652
- * `setup({ wasm: {...} })` instead.
386
+ * Wiring tap for every `initializeSession({ token })`: a token activated
387
+ * before any `createSession` was observed on this page is host-minted, i.e.
388
+ * external. (The exact `token`/`externalToken` web-semantics are a pending
389
+ * Phase 0 contract ask — this inference is the interim mapping.)
653
390
  */
654
- async function upgradeToWasmHttpClient(resolved) {
655
- const stored = storedHttpConfig;
656
- if (!stored || stored.isWasm) return;
657
- pendingUpgrade ??= (async () => {
658
- installClient(await createWasmApi({
659
- apiURL: stored.apiURL,
660
- customHeaders: stored.customHeaders,
661
- timeout: stored.timeout,
662
- wasm: resolved,
663
- encryptionEnabled: stored.encryption.enabled,
664
- mgf1: stored.encryption.mgf1,
665
- isEncryptionEnabled: isHttpEncrypted
666
- }));
667
- storedHttpConfig = {
668
- ...stored,
669
- isWasm: true
670
- };
671
- })().finally(() => {
672
- pendingUpgrade = void 0;
673
- });
674
- return pendingUpgrade;
391
+ function noteTokenActivated() {}
392
+ /** Explicit literal — the metadata half handed to the record builder. */
393
+ function buildSessionMetadata() {
394
+ return {
395
+ sessionId: state.sessionId,
396
+ startedAtMs: state.startedAtMs,
397
+ browser: state.browser,
398
+ osVersion: state.osVersion,
399
+ osLanguage: state.osLanguage,
400
+ sdkLanguage: state.sdkLanguage,
401
+ integrationType: state.integrationType,
402
+ flowType: state.flowType,
403
+ flowId: state.flowId,
404
+ workflowId: state.workflowId,
405
+ testing: state.testing,
406
+ e2eEncryptionEnabled: readE2eEncryptionEnabled(),
407
+ hasConfigurationId: state.hasConfigurationId,
408
+ hasExternalCustomerId: state.hasExternalCustomerId,
409
+ hasProvidedSessionId: state.hasProvidedSessionId,
410
+ hasToken: readHasToken(),
411
+ hasExternalToken: state.hasExternalToken
412
+ };
675
413
  }
676
- /**
677
- * When `wantsEncryption` is true, wraps a call that triggers the in-binary
678
- * RSA/AES handshake so its rejection surfaces as a single, descriptive error
679
- * with the original error preserved as `cause`. Pass-through otherwise.
680
- */
681
- async function withHandshakeFailureContext(wantsEncryption, fn) {
682
- if (!wantsEncryption) return fn();
414
+ /** Fail-open: diagnostics must never throw into the host flow. */
415
+ function readE2eEncryptionEnabled() {
683
416
  try {
684
- return await fn();
685
- } catch (cause) {
686
- const error = /* @__PURE__ */ new Error("Failed to establish encrypted transport. The /e2ee/key handshake did not complete. Verify the apiURL is reachable and that the environment supports E2EE.");
687
- error.cause = cause;
688
- throw error;
417
+ return sources.getE2eEncryptionEnabled?.() ?? false;
418
+ } catch {
419
+ return false;
689
420
  }
690
421
  }
691
- /** Hard cap per log message, UTF-8 bytes (contract). */
692
- const MESSAGE_MAX_BYTES = 8 * 1024;
693
- const TRUESIGHT_SDK_ID = "IncdOnboarding";
694
- /** localStorage key prefix for persisted sealed snapshots (A3: one slot per session). */
695
- const PENDING_STORAGE_KEY_PREFIX = "incode.truesight.pending.";
422
+ /** Fail-open, like readE2eEncryptionEnabled. */
423
+ function readHasToken() {
424
+ try {
425
+ return sources.getHasToken?.() ?? false;
426
+ } catch {
427
+ return false;
428
+ }
429
+ }
430
+ function resetTrueSightMetadata() {
431
+ state = createInitialState();
432
+ sources = {};
433
+ }
696
434
  //#endregion
697
- //#region src/internal/trueSight/sanitize.ts
435
+ //#region src/internal/trueSight/pendingEnvelopeStore.ts
436
+ /** Index slot listing sessionIds with pending entries (no enumeration API). */
437
+ const PENDING_INDEX_KEY = `${PENDING_STORAGE_KEY_PREFIX}index`;
438
+ function slotKey(sessionId) {
439
+ return `${PENDING_STORAGE_KEY_PREFIX}${sessionId}`;
440
+ }
698
441
  /**
699
- * Deny-by-default message scrubber — runs at INGESTION (inside the log buffer's
700
- * `append`), so the buffer, every persisted snapshot, and every upload are
701
- * already clean; there is no code path around it (ENG-48677 plan §1.2).
702
- *
703
- * Ordered pipeline. Two deliberate deviations from the plan's original rule
704
- * order, both from the P1-A adversarial review (2026-07-23, recorded in the
705
- * plan's Operating-decisions section):
706
- * - Inputs are pre-clamped to 2× the message cap BEFORE any regex runs — the
707
- * unanchored patterns are quadratic on pathological non-matching runs
708
- * (measured ~4.5 s on a 100 KB run), so regex cost must be bounded first.
709
- * The final 8 KB cap still runs last.
710
- * - The base64-blob rule runs BEFORE the digit-run rule — a digit run inside a
711
- * blob would otherwise split it into sub-64-char fragments that escape
712
- * redaction.
713
- *
714
- * The regex table ships in the P1-A PR description for privacy sign-off (see
715
- * .agents/guides/privacy.md). Known hardening backlog (D4, Phase 4): formatted
716
- * phone numbers, unicode digits/emails, fuzz/property tests.
442
+ * Adds the session to the pending index. Called once at collection start —
443
+ * long before any page-hide — so the hide path never needs the index
444
+ * read-modify-write and stays a single synchronous-effective write.
717
445
  */
718
- /** Three dot-joined base64url segments — JWT/JWS shape. */
719
- const JWT_PATTERN = /\b[\w-]{8,}\.[\w-]{8,}\.[\w-]{8,}\b/g;
446
+ async function registerPendingSlot(sessionId, deps) {
447
+ try {
448
+ const index = await readIndex(deps.storage);
449
+ if (index.includes(sessionId)) return;
450
+ await deps.storage.set(PENDING_INDEX_KEY, [...index, sessionId]);
451
+ } catch {}
452
+ }
720
453
  /**
721
- * Credential-ish key with a `:`/`=` value (quoted, `Bearer …`, or bare token).
722
- * The key may carry prefixes (`access_token`, `x-api-key`, `sessionToken`) —
723
- * a plain \b boundary would miss `_token` since `_` is a word character.
454
+ * Writes the sealed snapshot into the session's slot. `BrowserStorageProvider`
455
+ * executes the underlying `localStorage.setItem` synchronously in the first
456
+ * slice of the async call, which is what makes this safe to fire (void) from
457
+ * a page-hide handler.
724
458
  */
725
- const CREDENTIAL_KV_PATTERN = /([\w-]*(?:token|api[-_]?key|authorization|auth|secret|password|passwd))\s*[:=]\s*("[^"]*"|'[^']*'|(?:Bearer\s+)?[^\s,;&]+)/gi;
726
- /** Userinfo credentials in an absolute URL (`https://user:pass@host/…`). */
727
- const URL_USERINFO_PATTERN = /(\bhttps?:\/\/)[^\s/@]*(?::[^\s/@]*)?@/gi;
728
- /** Query string / fragment of an absolute URL — kills signed URLs. */
729
- const URL_TAIL_PATTERN = /(https?:\/\/[^\s?#]+)[?#][^\s]*/g;
730
- const EMAIL_PATTERN = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g;
731
- /** base64-ish blobs (media, keys) — 64+ chars of the base64/base64url alphabet. */
732
- const BASE64_BLOB_PATTERN = /[-A-Za-z0-9+/_]{64,}={0,2}/g;
733
- /** Runs of 8+ digits — phones, CURP, document numbers. */
734
- const DIGIT_RUN_PATTERN = /\d{8,}/g;
735
- const TRUNCATION_SUFFIX = "…[truncated]";
736
- /** Regex-cost bound: clamp raw input before any pattern runs (see header note). */
737
- const REGEX_INPUT_MAX_BYTES = MESSAGE_MAX_BYTES * 2;
738
- function sanitizeMessage(message) {
739
- return truncateUtf8(truncateUtf8(message, REGEX_INPUT_MAX_BYTES).replace(JWT_PATTERN, "[jwt]").replace(CREDENTIAL_KV_PATTERN, "$1=[redacted]").replace(URL_USERINFO_PATTERN, "$1[redacted]@").replace(URL_TAIL_PATTERN, "$1").replace(EMAIL_PATTERN, "[email]").replace(BASE64_BLOB_PATTERN, (match) => `[blob:${match.length}]`).replace(DIGIT_RUN_PATTERN, "[digits]"), MESSAGE_MAX_BYTES);
459
+ async function writePendingEnvelope(sessionId, entry, deps) {
460
+ try {
461
+ await deps.storage.set(slotKey(sessionId), entry);
462
+ } catch {}
463
+ }
464
+ /** Removes the entry and its index membership (terminal upload dispatched). */
465
+ async function clearPending(sessionId, deps) {
466
+ try {
467
+ await deps.storage.remove(slotKey(sessionId));
468
+ const index = await readIndex(deps.storage);
469
+ if (index.includes(sessionId)) await deps.storage.set(PENDING_INDEX_KEY, index.filter((candidate) => candidate !== sessionId));
470
+ } catch {}
740
471
  }
741
472
  /**
742
- * UTF-8 byte length without TextEncoder (banned browser global in L1 —
743
- * see the no-browser-api-in-core lint rule). Counts by code point.
473
+ * Next-load recovery, invoked from the first-token-observed hook (A1 — never
474
+ * at `setup()`, which has no auth). For each foreign, old-enough entry: the
475
+ * slot is cleared AT DISPATCH, then the envelope is posted fire-and-forget —
476
+ * no 200-tracking, no retries (A2; a crash between clear and fire loses that
477
+ * record, consistent with no-retry). Entries at/past the retention ceiling
478
+ * are deleted unsent (A4). Never rejects; returns the A5 loss counters.
744
479
  */
745
- function utf8ByteLength(value) {
746
- let bytes = 0;
747
- for (const char of value) bytes += codePointByteLength(char);
748
- return bytes;
480
+ async function recoverPendingEnvelopes(options) {
481
+ const { storage, post, currentSessionId } = options;
482
+ const now = options.now ?? getTimestamp;
483
+ const counters = {
484
+ recovered: 0,
485
+ gcExpired: 0
486
+ };
487
+ try {
488
+ const index = await readIndex(storage);
489
+ if (index.length === 0) return counters;
490
+ const keptInIndex = [];
491
+ for (const sessionId of index) {
492
+ if (sessionId === currentSessionId) {
493
+ keptInIndex.push(sessionId);
494
+ continue;
495
+ }
496
+ const entry = await readEntry(storage, sessionId);
497
+ if (entry === "missing") continue;
498
+ if (entry === "corrupt") {
499
+ counters.gcExpired += 1;
500
+ continue;
501
+ }
502
+ const age = now() - entry.persistedAt;
503
+ if (age >= 6048e5) {
504
+ counters.gcExpired += 1;
505
+ await storage.remove(slotKey(sessionId));
506
+ continue;
507
+ }
508
+ if (age < 12e4) {
509
+ keptInIndex.push(sessionId);
510
+ continue;
511
+ }
512
+ await storage.remove(slotKey(sessionId));
513
+ counters.recovered += 1;
514
+ post(endpoints.diagnosticsData, entry.envelope, {}).catch(() => {});
515
+ }
516
+ await storage.set(PENDING_INDEX_KEY, keptInIndex);
517
+ } catch {}
518
+ return counters;
749
519
  }
750
- function codePointByteLength(char) {
751
- const codePoint = char.codePointAt(0) ?? 0;
752
- if (codePoint < 128) return 1;
753
- if (codePoint < 2048) return 2;
754
- if (codePoint < 65536) return 3;
755
- return 4;
520
+ async function readIndex(storage) {
521
+ const index = await storage.get(PENDING_INDEX_KEY);
522
+ if (!Array.isArray(index)) return [];
523
+ return index.filter((value) => typeof value === "string");
756
524
  }
757
- /** Cuts on a code-point boundary so no surrogate half ever reaches the wire. */
758
- function truncateUtf8(value, maxBytes) {
759
- if (utf8ByteLength(value) <= maxBytes) return value;
760
- const budget = maxBytes - utf8ByteLength(TRUNCATION_SUFFIX);
761
- let bytes = 0;
762
- let result = "";
763
- for (const char of value) {
764
- const charBytes = codePointByteLength(char);
765
- if (bytes + charBytes > budget) break;
766
- bytes += charBytes;
767
- result += char;
525
+ /** Reads one entry; malformed slots are pruned and reported as corrupt. */
526
+ async function readEntry(storage, sessionId) {
527
+ try {
528
+ const value = await storage.get(slotKey(sessionId));
529
+ if (value === null) return "missing";
530
+ if (typeof value === "object" && value.v === 1 && typeof value.persistedAt === "number" && typeof value.envelope === "object") return value;
531
+ await storage.remove(slotKey(sessionId));
532
+ return "corrupt";
533
+ } catch {
534
+ try {
535
+ await storage.remove(slotKey(sessionId));
536
+ } catch {}
537
+ return "corrupt";
768
538
  }
769
- return result + TRUNCATION_SUFFIX;
770
539
  }
771
540
  //#endregion
772
- //#region ../infra/src/crypto/randomUUID.ts
541
+ //#region src/internal/featureConfig/featureConfigService.ts
542
+ let cachedFeatures = null;
773
543
  /**
774
- * Cryptographically-strong UUID v4 (RFC 4122).
775
- *
776
- * Lives in infra (L0) so Core (L1) can mint secure identifiers without touching
777
- * the `crypto` browser API directly — Core delegates here, keeping it free of
778
- * browser globals (enforced by the `no-browser-api-in-core` lint rule). Backed
779
- * by `crypto.randomUUID`, available in every browser the SDK targets.
544
+ * Checks if a feature is enabled in the feature config.
780
545
  */
781
- function randomUUID() {
782
- return crypto.randomUUID();
546
+ function isFeatureEnabled(feature, features) {
547
+ return features?.find((f) => f.feature === feature)?.enabled ?? false;
783
548
  }
784
- //#endregion
785
- //#region ../infra/src/time/epochMsToIsoString.ts
786
549
  /**
787
- * Converts an epoch-milliseconds timestamp to a full ISO-8601 UTC string
788
- * (e.g. `2026-07-23T09:41:00.000Z`).
789
- *
790
- * Lives in Infra (L0) so Core can format wire timestamps without touching the
791
- * `Date` global directly — banned in Core by the `no-browser-api-in-core` lint
792
- * rule — mirroring the `crypto/randomUUID.ts` free-function precedent.
793
- * (`DateFormattingProvider.utcToIsoDateString` is date-only and not suitable.)
550
+ * Fetches feature configuration from the backend.
551
+ * Results are cached for the session lifetime.
794
552
  */
795
- function epochMsToIsoString(epochMs) {
796
- return new Date(epochMs).toISOString();
797
- }
798
- //#endregion
799
- //#region src/internal/trueSight/recordBuilder.ts
800
- /**
801
- * Assembles the exact plaintext contract record — the ONLY place a diagnostics
802
- * payload is shaped. Pure: same function serves final records, interrupted
803
- * snapshots, and future incremental slices (ENG-48677 plan §1.1).
804
- *
805
- * Deny-by-default is structural here: every field is an explicit literal —
806
- * nothing is spread from internal state, so no unexpected field can ever leak
807
- * into an upload.
808
- *
809
- * Hard gates enforced:
810
- * - empty/missing `sessionId` or `startedAt` → returns `null` (upload skipped —
811
- * expected for sessions that die before `/omni/start`).
812
- * - `failureReason` present if-and-only-if `outcome === 'failure'` (defaults to
813
- * `'unknown'` when a failure arrives without one, rather than dropping the record).
814
- * - fresh record `id` per build; `endedAt` stamped at build time.
553
+ async function fetchFeatureConfig(signal) {
554
+ if (cachedFeatures) return cachedFeatures;
555
+ const response = await api.get(endpoints.featureConfig, { signal });
556
+ if (!response.ok) throw new Error(`Failed to fetch feature config: ${response.status} ${response.statusText}`);
557
+ cachedFeatures = response.data;
558
+ return cachedFeatures;
559
+ }
560
+ /**
561
+ * Resets the cached feature config (useful for testing).
815
562
  */
816
- function buildDiagnosticsRecord(meta, logs, outcome, failureReason, recordId) {
817
- if (!meta.sessionId || meta.startedAtMs === null) return null;
818
- const flowType = meta.flowType ?? deriveFlowTypeFromSurface(meta.integrationType);
819
- if (flowType === null) return null;
820
- return {
821
- schemaVersion: "1.0",
822
- id: recordId ?? randomUUID(),
823
- session: {
824
- sessionId: meta.sessionId,
825
- sdkId: TRUESIGHT_SDK_ID,
826
- sdkVersion: SDK_VERSION,
827
- platform: "web",
828
- sdkMode: null,
829
- browser: meta.browser,
830
- osVersion: meta.osVersion,
831
- osLanguage: meta.osLanguage,
832
- sdkLanguage: meta.sdkLanguage,
833
- integrationType: meta.integrationType,
834
- flowType,
835
- flowId: meta.flowId,
836
- workflowId: meta.workflowId,
837
- outcome,
838
- ...outcome === "failure" ? { failureReason: failureReason ?? "unknown" } : {},
839
- startedAt: epochMsToIsoString(meta.startedAtMs),
840
- endedAt: epochMsToIsoString(getTimestamp()),
841
- testing: meta.testing,
842
- e2eEncryptionEnabled: meta.e2eEncryptionEnabled,
843
- configurationId: meta.hasConfigurationId,
844
- externalCustomerId: meta.hasExternalCustomerId,
845
- hasProvidedSessionId: meta.hasProvidedSessionId,
846
- token: meta.hasToken,
847
- externalToken: meta.hasExternalToken
563
+ function resetFeatureConfigCache() {
564
+ cachedFeatures = null;
565
+ }
566
+ //#endregion
567
+ //#region ../infra/src/http/createApi.ts
568
+ var FetchHttpError = class extends HttpRequestError {
569
+ constructor(..._args) {
570
+ super(..._args);
571
+ this.name = "FetchHttpError";
572
+ }
573
+ };
574
+ const buildQueryString$1 = (query) => {
575
+ if (!query) return "";
576
+ const params = new URLSearchParams();
577
+ Object.entries(query).forEach(([key, value]) => {
578
+ if (value !== void 0 && value !== null) params.append(key, String(value));
579
+ });
580
+ const str = params.toString();
581
+ return str ? `?${str}` : "";
582
+ };
583
+ const buildUrl$1 = (baseURL, url, query) => {
584
+ const queryString = buildQueryString$1(query);
585
+ if (url.startsWith("http://") || url.startsWith("https://")) return `${url}${queryString}`;
586
+ return `${baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL}${url.startsWith("/") ? url : `/${url}`}${queryString}`;
587
+ };
588
+ const prepareBody$1 = (body) => {
589
+ if (body === null || body === void 0) return null;
590
+ if (body instanceof FormData || body instanceof Blob || body instanceof ArrayBuffer) return body;
591
+ if (typeof body === "object") return JSON.stringify(body);
592
+ return String(body);
593
+ };
594
+ const parseResponse = async (response, parseType) => {
595
+ if (parseType === "response") return response;
596
+ if (parseType === "blob") return await response.blob();
597
+ if (parseType === "arrayBuffer") return await response.arrayBuffer();
598
+ if (parseType === "text") return await response.text();
599
+ const contentType = response.headers.get("content-type") ?? "";
600
+ if (parseType === "json" || contentType.includes("application/json")) {
601
+ const raw = await response.text();
602
+ if (raw.length === 0) return "";
603
+ try {
604
+ return JSON.parse(raw);
605
+ } catch {
606
+ return raw;
607
+ }
608
+ }
609
+ return await response.text();
610
+ };
611
+ const requestWithXHR = (fullUrl, method, mergedHeaders, requestBody, timeout, signal, onUploadProgress) => {
612
+ return new Promise((resolve, reject) => {
613
+ const xhr = new XMLHttpRequest();
614
+ xhr.open(method, fullUrl, true);
615
+ Object.entries(mergedHeaders).forEach(([key, value]) => {
616
+ xhr.setRequestHeader(key, value);
617
+ });
618
+ xhr.timeout = timeout;
619
+ xhr.upload.onprogress = (event) => {
620
+ if (event.lengthComputable) {
621
+ const percentComplete = event.loaded / event.total * 100;
622
+ onUploadProgress(Math.round(percentComplete));
623
+ }
624
+ };
625
+ xhr.onload = () => {
626
+ const responseHeaders = {};
627
+ xhr.getAllResponseHeaders().split("\r\n").forEach((line) => {
628
+ const parts = line.split(": ");
629
+ if (parts.length === 2) responseHeaders[parts[0].toLowerCase()] = parts[1];
630
+ });
631
+ let data;
632
+ try {
633
+ if ((xhr.getResponseHeader("content-type") ?? "").includes("application/json")) data = JSON.parse(xhr.responseText);
634
+ else data = xhr.responseText;
635
+ } catch {
636
+ data = xhr.responseText;
637
+ }
638
+ if (xhr.status >= 200 && xhr.status < 300) resolve({
639
+ ok: true,
640
+ status: xhr.status,
641
+ statusText: xhr.statusText,
642
+ url: fullUrl,
643
+ headers: responseHeaders,
644
+ data
645
+ });
646
+ else reject(reportHttpError(new FetchHttpError(xhr.status, xhr.statusText, fullUrl, method, responseHeaders, data), mergedHeaders));
647
+ };
648
+ xhr.onerror = () => {
649
+ reject(new FetchHttpError(0, "Network Error", fullUrl, method, {}, null));
650
+ };
651
+ xhr.ontimeout = () => {
652
+ reject(new FetchHttpError(0, "Request timeout", fullUrl, method, {}, null));
653
+ };
654
+ if (signal) signal.addEventListener("abort", () => {
655
+ xhr.abort();
656
+ reject(new FetchHttpError(0, "Request aborted", fullUrl, method, {}, null));
657
+ });
658
+ xhr.send(requestBody);
659
+ });
660
+ };
661
+ const createApi = (config) => {
662
+ const headers = {
663
+ "Content-Type": "application/json",
664
+ Accept: "application/json",
665
+ "api-version": "1.0",
666
+ ...config.customHeaders ?? {}
667
+ };
668
+ const defaults = {
669
+ baseURL: config.apiURL,
670
+ headers
671
+ };
672
+ const client = {
673
+ defaults,
674
+ async request(requestConfig) {
675
+ const { method = "GET", url, headers = {}, query, params, body, signal, timeout: timeoutOverride, parse, onUploadProgress, keepalive } = requestConfig;
676
+ const fullUrl = buildUrl$1(defaults.baseURL, url, params ?? query);
677
+ const mergedHeaders = {
678
+ ...defaults.headers,
679
+ ...headers
680
+ };
681
+ const requestBody = prepareBody$1(body);
682
+ const timeout = timeoutOverride ?? config.timeout;
683
+ let finalHeaders = mergedHeaders;
684
+ if (requestBody === null && (method === "POST" || method === "PUT" || method === "PATCH")) {
685
+ const { "Content-Type": _, ...headersWithoutContentType } = mergedHeaders;
686
+ finalHeaders = headersWithoutContentType;
687
+ }
688
+ if (onUploadProgress) {
689
+ if (requestBody !== null && typeof ReadableStream !== "undefined" && requestBody instanceof ReadableStream) throw new Error("Upload progress tracking is not supported for ReadableStream bodies");
690
+ return requestWithXHR(fullUrl, method, finalHeaders, requestBody, timeout ?? 0, signal, onUploadProgress);
691
+ }
692
+ const controller = new AbortController();
693
+ if (signal) if (signal.aborted) controller.abort();
694
+ else signal.addEventListener("abort", () => controller.abort(), { once: true });
695
+ const abortSignal = controller.signal;
696
+ const timeoutId = timeout === void 0 ? void 0 : setTimeout(() => controller.abort(), timeout);
697
+ try {
698
+ const response = await fetch(fullUrl, {
699
+ method,
700
+ headers: finalHeaders,
701
+ body: requestBody,
702
+ signal: abortSignal,
703
+ keepalive
704
+ });
705
+ if (timeoutId) clearTimeout(timeoutId);
706
+ const responseHeaders = {};
707
+ response.headers.forEach((value, key) => {
708
+ responseHeaders[key] = value;
709
+ });
710
+ const data = await parseResponse(response, parse);
711
+ if (!response.ok) throw reportHttpError(new FetchHttpError(response.status, response.statusText, fullUrl, method, responseHeaders, data), mergedHeaders);
712
+ return {
713
+ ok: true,
714
+ status: response.status,
715
+ statusText: response.statusText,
716
+ url: fullUrl,
717
+ headers: responseHeaders,
718
+ data
719
+ };
720
+ } catch (error) {
721
+ if (timeoutId) clearTimeout(timeoutId);
722
+ if (error instanceof FetchHttpError) throw error;
723
+ if (error instanceof Error && error.name === "AbortError") throw new FetchHttpError(0, "Request timeout", fullUrl, method, {}, null);
724
+ throw error;
725
+ }
848
726
  },
849
- logs: logs.map(toContractEntry)
727
+ get(url, config) {
728
+ return client.request({
729
+ ...config,
730
+ url,
731
+ method: "GET"
732
+ });
733
+ },
734
+ post(url, body, config) {
735
+ return client.request({
736
+ ...config,
737
+ url,
738
+ body,
739
+ method: "POST"
740
+ });
741
+ },
742
+ put(url, body, config) {
743
+ return client.request({
744
+ ...config,
745
+ url,
746
+ body,
747
+ method: "PUT"
748
+ });
749
+ },
750
+ patch(url, body, config) {
751
+ return client.request({
752
+ ...config,
753
+ url,
754
+ body,
755
+ method: "PATCH"
756
+ });
757
+ },
758
+ delete(url, config) {
759
+ return client.request({
760
+ ...config,
761
+ url,
762
+ method: "DELETE"
763
+ });
764
+ },
765
+ head(url, config) {
766
+ return client.request({
767
+ ...config,
768
+ url,
769
+ method: "HEAD"
770
+ });
771
+ },
772
+ options(url, config) {
773
+ return client.request({
774
+ ...config,
775
+ url,
776
+ method: "OPTIONS"
777
+ });
778
+ },
779
+ setHeader(name, value) {
780
+ defaults.headers[name] = value;
781
+ }
850
782
  };
851
- }
783
+ return client;
784
+ };
785
+ //#endregion
786
+ //#region ../infra/src/http/createWasmApi.ts
787
+ const WASM_TIMEOUT_CEILING_MS = 36e5;
788
+ const RSA_OAEP_SHA256_SCHEME = "RSA/NONE/OAEPWITHSHA-256ANDMGF1PADDING";
852
789
  /**
853
- * Wire `flowType` when no orchestrator was OBSERVED (an observed one — set by
854
- * the bridge on any flow event — always wins). Stage ingest requires a
855
- * non-null enum (probe 2026-07-23: null/omitted/off-enum all 400), so the
856
- * entry surface decides, and the mapping is deliberately exhaustive:
857
- *
858
- * - `startWorkflow` → 'workflow' (Webflows engine entered, died pre-ready)
859
- * - `startFlow` → 'flow' (flow/orchestrated manager, died pre-ready)
860
- * - `startOnboarding`→ 'flow' (self-loading UI wraps the flow engine)
861
- * - `startOnboardingSection` → null → the BUILD ABORTS (record withheld):
862
- * a standalone session has no truthful flowType, and mislabeling it as a
863
- * flow session is worse than skipping the upload. Withheld until the
864
- * DECIDED BE ask ships (`flowType:"standalone"`, not nullable) — then this
865
- * branch returns 'standalone' and standalone diagnostics start flowing,
866
- * coordinated with the BE deploy since off-enum values 400 today.
790
+ * Builds the base set of HTTP headers that the WASM WebClient sends on every
791
+ * request (including the internal `/e2ee/key/v2` and `/e2ee/key` handshake
792
+ * calls).
867
793
  */
868
- function deriveFlowTypeFromSurface(integrationType) {
869
- switch (integrationType) {
870
- case "startWorkflow": return "workflow";
871
- case "startFlow":
872
- case "startOnboarding": return "flow";
873
- case "startOnboardingSection": return null;
874
- }
875
- }
876
- function toContractEntry(entry) {
794
+ function buildWasmDefaultHeaders(customHeaders) {
877
795
  return {
878
- index: entry.index,
879
- timestamp: epochMsToIsoString(entry.timestampMs),
880
- level: entry.level,
881
- thread: "main",
882
- message: entry.message,
883
- subsystem: entry.subsystem,
884
- category: entry.category
796
+ "Content-Type": "application/json",
797
+ Accept: "application/json",
798
+ "api-version": "1.0",
799
+ ...customHeaders ?? {}
885
800
  };
886
801
  }
887
- function createInitialState() {
888
- return {
889
- sessionId: null,
890
- startedAtMs: null,
891
- browser: null,
892
- osVersion: null,
893
- osLanguage: null,
894
- sdkLanguage: "en-US",
895
- integrationType: "startOnboardingSection",
896
- flowType: null,
897
- flowId: null,
898
- workflowId: null,
899
- testing: false,
900
- devModeSignal: void 0,
901
- apiUrlSignal: void 0,
902
- hasConfigurationId: false,
903
- hasExternalCustomerId: false,
904
- hasProvidedSessionId: false,
905
- hasExternalToken: false
802
+ var WasmHttpError = class extends HttpRequestError {
803
+ constructor(..._args) {
804
+ super(..._args);
805
+ this.name = "WasmHttpError";
806
+ }
807
+ };
808
+ const HTTP_METHODS = /* @__PURE__ */ new Set([
809
+ "GET",
810
+ "POST",
811
+ "PUT",
812
+ "PATCH",
813
+ "DELETE"
814
+ ]);
815
+ const buildQueryString = (query) => {
816
+ if (!query) return "";
817
+ const params = new URLSearchParams();
818
+ Object.entries(query).forEach(([key, value]) => {
819
+ if (value !== void 0 && value !== null) params.append(key, String(value));
820
+ });
821
+ const str = params.toString();
822
+ return str ? `?${str}` : "";
823
+ };
824
+ const buildUrl = (baseURL, url, query) => {
825
+ const queryString = buildQueryString(query);
826
+ if (url.startsWith("http://") || url.startsWith("https://")) return `${url}${queryString}`;
827
+ return `${baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL}${url.startsWith("/") ? url : `/${url}`}${queryString}`;
828
+ };
829
+ const prepareBody = (body) => {
830
+ if (body === null || body === void 0) return void 0;
831
+ if (body instanceof FormData || body instanceof Blob || body instanceof ArrayBuffer || body instanceof Uint8Array || typeof body === "string") return body;
832
+ if (typeof body === "object") return body;
833
+ return String(body);
834
+ };
835
+ const normalizeMethod = (method) => {
836
+ const upper = method.toUpperCase();
837
+ if (!HTTP_METHODS.has(upper)) throw new Error(`Unsupported HTTP method for WASM client: ${method}`);
838
+ return upper;
839
+ };
840
+ const getErrorStatus = (error) => {
841
+ if (error instanceof WasmWebClientError) return error.statusCode;
842
+ if (typeof error === "object" && error !== null) {
843
+ const record = error;
844
+ if (typeof record.statusCode === "number") return record.statusCode;
845
+ if (typeof record.status === "number") return record.status;
846
+ }
847
+ return 0;
848
+ };
849
+ const getErrorData = (error) => {
850
+ if (error instanceof WasmWebClientError) return error.response?.data ?? null;
851
+ return null;
852
+ };
853
+ const getErrorMessage = (error) => {
854
+ if (error instanceof Error) return error.message;
855
+ return "WasmWebClient request failed";
856
+ };
857
+ const withAbortSignal = async (promise, signal, error) => {
858
+ if (!signal) return await promise;
859
+ if (signal.aborted) throw error();
860
+ return await new Promise((resolve, reject) => {
861
+ const onAbort = () => reject(error());
862
+ signal.addEventListener("abort", onAbort, { once: true });
863
+ promise.then(resolve, reject).finally(() => {
864
+ signal.removeEventListener("abort", onAbort);
865
+ });
866
+ });
867
+ };
868
+ const createWasmApi = async (config) => {
869
+ const headers = buildWasmDefaultHeaders(config.customHeaders);
870
+ const isEncryptionEnabled = config.isEncryptionEnabled ?? (() => false);
871
+ const useSha256 = config.mgf1 === "sha256";
872
+ await initializeWasmWebClient(config.wasm);
873
+ try {
874
+ await setupWasmConnection(config.apiURL, "", config.encryptionEnabled ?? false, headers, useSha256);
875
+ } catch (error) {
876
+ if (!(error instanceof WasmWebClientError)) throw error;
877
+ throw reportHttpError(new WasmHttpError(error.statusCode, "", config.apiURL, "POST", {}, getErrorData(error)), headers);
878
+ }
879
+ const defaults = {
880
+ baseURL: config.apiURL,
881
+ headers
906
882
  };
907
- }
908
- let state = createInitialState();
909
- let sources = {};
910
- /** Tap for `createSession` — sessionId comes from the returned `interviewId`. */
911
- function noteSessionCreated(session, options = {}) {}
912
- function noteEnvironment(environment) {}
913
- /**
914
- * `testing` heuristic: devMode OR non-prod API host pattern. Always a boolean —
915
- * the contract requires the field present on every record. Signals MERGE across
916
- * calls (a later apiUrl-only call must not erase an earlier devMode signal);
917
- * `testing` is recomputed from the merged pair.
918
- */
919
- function noteTestingSignals(signals) {}
920
- /**
921
- * Live read of the merged testing signal (devMode OR non-prod host). Used to
922
- * gate host-console self-health noise so production host pages stay quiet while
923
- * staging/dev keeps the console signal (the record always captures it either
924
- * way via `trueSightLog`). Same signal the overflow-flush staging gate uses.
925
- */
926
- function isTrueSightTesting() {
927
- return state.testing;
928
- }
929
- /**
930
- * Wiring tap for every `initializeSession({ token })`: a token activated
931
- * before any `createSession` was observed on this page is host-minted, i.e.
932
- * external. (The exact `token`/`externalToken` web-semantics are a pending
933
- * Phase 0 contract ask — this inference is the interim mapping.)
934
- */
935
- function noteTokenActivated() {}
936
- /** Explicit literal — the metadata half handed to the record builder. */
937
- function buildSessionMetadata() {
938
- return {
939
- sessionId: state.sessionId,
940
- startedAtMs: state.startedAtMs,
941
- browser: state.browser,
942
- osVersion: state.osVersion,
943
- osLanguage: state.osLanguage,
944
- sdkLanguage: state.sdkLanguage,
945
- integrationType: state.integrationType,
946
- flowType: state.flowType,
947
- flowId: state.flowId,
948
- workflowId: state.workflowId,
949
- testing: state.testing,
950
- e2eEncryptionEnabled: readE2eEncryptionEnabled(),
951
- hasConfigurationId: state.hasConfigurationId,
952
- hasExternalCustomerId: state.hasExternalCustomerId,
953
- hasProvidedSessionId: state.hasProvidedSessionId,
954
- hasToken: readHasToken(),
955
- hasExternalToken: state.hasExternalToken
883
+ const client = {
884
+ defaults,
885
+ async request(requestConfig) {
886
+ const { method = "GET", url, headers: requestHeaders = {}, query, params, body, signal, timeout: timeoutOverride, onUploadProgress, ie = false } = requestConfig;
887
+ const upperMethod = normalizeMethod(method);
888
+ const requestParams = params ?? query;
889
+ const fullUrl = buildUrl(defaults.baseURL, url, requestParams);
890
+ const needsSchemeHeader = useSha256 && isEncryptionEnabled();
891
+ const mergedHeaders = {
892
+ ...defaults.headers,
893
+ ...needsSchemeHeader ? { "X-RSA-Encryption-Scheme": RSA_OAEP_SHA256_SCHEME } : {},
894
+ ...requestHeaders
895
+ };
896
+ const requestBody = prepareBody(body);
897
+ const timeout = timeoutOverride ?? config.timeout ?? WASM_TIMEOUT_CEILING_MS;
898
+ const wasmProgress = onUploadProgress ? (progress) => {
899
+ if (progress.total > 0) onUploadProgress(Math.round(progress.loaded / progress.total * 100));
900
+ } : void 0;
901
+ const abortError = () => new WasmHttpError(0, "Request aborted", fullUrl, upperMethod, {}, null);
902
+ if (signal?.aborted) throw abortError();
903
+ try {
904
+ const response = await withAbortSignal(executeWasmRequest(upperMethod, url, requestBody, mergedHeaders, requestParams, timeout, wasmProgress, ie), signal, abortError);
905
+ if (response.status < 200 || response.status >= 300) throw reportHttpError(new WasmHttpError(response.status, "", fullUrl, upperMethod, {}, response.data), mergedHeaders);
906
+ return {
907
+ ok: true,
908
+ status: response.status,
909
+ statusText: "",
910
+ url: fullUrl,
911
+ headers: {},
912
+ data: response.data
913
+ };
914
+ } catch (error) {
915
+ if (error instanceof WasmHttpError) throw error;
916
+ throw reportHttpError(new WasmHttpError(getErrorStatus(error), getErrorMessage(error), fullUrl, upperMethod, {}, getErrorData(error)), mergedHeaders);
917
+ }
918
+ },
919
+ get(url, requestConfig) {
920
+ return client.request({
921
+ ...requestConfig,
922
+ url,
923
+ method: "GET"
924
+ });
925
+ },
926
+ post(url, body, requestConfig) {
927
+ return client.request({
928
+ ...requestConfig,
929
+ url,
930
+ body,
931
+ method: "POST"
932
+ });
933
+ },
934
+ put(url, body, requestConfig) {
935
+ return client.request({
936
+ ...requestConfig,
937
+ url,
938
+ body,
939
+ method: "PUT"
940
+ });
941
+ },
942
+ patch(url, body, requestConfig) {
943
+ return client.request({
944
+ ...requestConfig,
945
+ url,
946
+ body,
947
+ method: "PATCH"
948
+ });
949
+ },
950
+ delete(url, requestConfig) {
951
+ return client.request({
952
+ ...requestConfig,
953
+ url,
954
+ method: "DELETE"
955
+ });
956
+ },
957
+ head() {
958
+ return Promise.reject(/* @__PURE__ */ new Error("HEAD is not supported by the WASM HTTP client"));
959
+ },
960
+ options() {
961
+ return Promise.reject(/* @__PURE__ */ new Error("OPTIONS is not supported by the WASM HTTP client"));
962
+ },
963
+ setHeader(name, value) {
964
+ defaults.headers[name] = value;
965
+ }
956
966
  };
957
- }
958
- /** Fail-open: diagnostics must never throw into the host flow. */
959
- function readE2eEncryptionEnabled() {
960
- try {
961
- return sources.getE2eEncryptionEnabled?.() ?? false;
962
- } catch {
963
- return false;
964
- }
965
- }
966
- /** Fail-open, like readE2eEncryptionEnabled. */
967
- function readHasToken() {
968
- try {
969
- return sources.getHasToken?.() ?? false;
970
- } catch {
971
- return false;
972
- }
973
- }
974
- function resetTrueSightMetadata() {
975
- state = createInitialState();
976
- sources = {};
977
- }
967
+ return client;
968
+ };
978
969
  //#endregion
979
- //#region src/internal/trueSight/pendingEnvelopeStore.ts
980
- /** Index slot listing sessionIds with pending entries (no enumeration API). */
981
- const PENDING_INDEX_KEY = `${PENDING_STORAGE_KEY_PREFIX}index`;
982
- function slotKey(sessionId) {
983
- return `${PENDING_STORAGE_KEY_PREFIX}${sessionId}`;
984
- }
970
+ //#region src/internal/http/clientLifecycle.ts
985
971
  /**
986
- * Adds the session to the pending index. Called once at collection start —
987
- * long before any page-hide — so the hide path never needs the index
988
- * read-modify-write and stays a single synchronous-effective write.
972
+ * Wraps the active HttpClient as a transport for the C++ `WebApi` host
973
+ * adapter. Lets the on-device face-results POST flow through the same
974
+ * `httpClient.request()` pipeline as every other endpoint — header
975
+ * injection, encryption-state handling, default headers, timeout — instead
976
+ * of bypassing it via `executeWasmRequest` directly.
977
+ *
978
+ * Protected captures arrive with `ie === true`: the C++ `WebApi` already
979
+ * encrypted the body inline, and only the WASM `WebClient` can unwrap it. A
980
+ * plain fetch client would post the ciphertext as JSON and the backend
981
+ * answers 406. If the plain client is still installed at that point (the
982
+ * host called `setup()` without `wasm` and warmed WASM separately), swap to
983
+ * the WASM client first. The module is already loaded — the payload came
984
+ * out of it — so the swap only creates the `WebClient`.
989
985
  */
990
- async function registerPendingSlot(sessionId, deps) {
991
- try {
992
- const index = await readIndex(deps.storage);
993
- if (index.includes(sessionId)) return;
994
- await deps.storage.set(PENDING_INDEX_KEY, [...index, sessionId]);
995
- } catch {}
986
+ function bindWebApiTransport(client) {
987
+ return async (url, body, config) => {
988
+ const response = await (config.ie === true && storedHttpConfig && !storedHttpConfig.isWasm ? await ensureWasmHttpClient() : client).request({
989
+ method: "POST",
990
+ url,
991
+ body,
992
+ headers: config.headers,
993
+ params: config.params,
994
+ timeout: config.timeout,
995
+ ie: config.ie
996
+ });
997
+ return {
998
+ data: response.data,
999
+ status: response.status
1000
+ };
1001
+ };
996
1002
  }
997
- /**
998
- * Writes the sealed snapshot into the session's slot. `BrowserStorageProvider`
999
- * executes the underlying `localStorage.setItem` synchronously in the first
1000
- * slice of the async call, which is what makes this safe to fire (void) from
1001
- * a page-hide handler.
1002
- */
1003
- async function writePendingEnvelope(sessionId, entry, deps) {
1004
- try {
1005
- await deps.storage.set(slotKey(sessionId), entry);
1006
- } catch {}
1003
+ function installClient(client) {
1004
+ setClient(client);
1005
+ setWebApiHttpTransport(bindWebApiTransport(client));
1007
1006
  }
1008
- /** Removes the entry and its index membership (terminal upload dispatched). */
1009
- async function clearPending(sessionId, deps) {
1010
- try {
1011
- await deps.storage.remove(slotKey(sessionId));
1012
- const index = await readIndex(deps.storage);
1013
- if (index.includes(sessionId)) await deps.storage.set(PENDING_INDEX_KEY, index.filter((candidate) => candidate !== sessionId));
1014
- } catch {}
1007
+ async function ensureWasmHttpClient() {
1008
+ await upgradeToWasmHttpClient(resolveWasmConfig());
1009
+ return getApi();
1015
1010
  }
1016
- /**
1017
- * Next-load recovery, invoked from the first-token-observed hook (A1 — never
1018
- * at `setup()`, which has no auth). For each foreign, old-enough entry: the
1019
- * slot is cleared AT DISPATCH, then the envelope is posted fire-and-forget —
1020
- * no 200-tracking, no retries (A2; a crash between clear and fire loses that
1021
- * record, consistent with no-retry). Entries at/past the retention ceiling
1022
- * are deleted unsent (A4). Never rejects; returns the A5 loss counters.
1023
- */
1024
- async function recoverPendingEnvelopes(options) {
1025
- const { storage, post, currentSessionId } = options;
1026
- const now = options.now ?? getTimestamp;
1027
- const counters = {
1028
- recovered: 0,
1029
- gcExpired: 0
1030
- };
1031
- try {
1032
- const index = await readIndex(storage);
1033
- if (index.length === 0) return counters;
1034
- const keptInIndex = [];
1035
- for (const sessionId of index) {
1036
- if (sessionId === currentSessionId) {
1037
- keptInIndex.push(sessionId);
1038
- continue;
1039
- }
1040
- const entry = await readEntry(storage, sessionId);
1041
- if (entry === "missing") continue;
1042
- if (entry === "corrupt") {
1043
- counters.gcExpired += 1;
1044
- continue;
1045
- }
1046
- const age = now() - entry.persistedAt;
1047
- if (age >= 6048e5) {
1048
- counters.gcExpired += 1;
1049
- await storage.remove(slotKey(sessionId));
1050
- continue;
1051
- }
1052
- if (age < 12e4) {
1053
- keptInIndex.push(sessionId);
1054
- continue;
1055
- }
1056
- await storage.remove(slotKey(sessionId));
1057
- counters.recovered += 1;
1058
- post(endpoints.diagnosticsData, entry.envelope, {}).catch(() => {});
1059
- }
1060
- await storage.set(PENDING_INDEX_KEY, keptInIndex);
1061
- } catch {}
1062
- return counters;
1011
+ let storedHttpConfig;
1012
+ let pendingUpgrade;
1013
+ /** Reads the current HTTP-client config (or `undefined` if none installed). */
1014
+ function getStoredHttpConfig() {
1015
+ return storedHttpConfig;
1063
1016
  }
1064
- async function readIndex(storage) {
1065
- const index = await storage.get(PENDING_INDEX_KEY);
1066
- if (!Array.isArray(index)) return [];
1067
- return index.filter((value) => typeof value === "string");
1017
+ /** Whether encryption is currently active on the installed HTTP client. */
1018
+ function isHttpEncrypted() {
1019
+ return storedHttpConfig?.encryption.enabled ?? false;
1068
1020
  }
1069
- /** Reads one entry; malformed slots are pruned and reported as corrupt. */
1070
- async function readEntry(storage, sessionId) {
1071
- try {
1072
- const value = await storage.get(slotKey(sessionId));
1073
- if (value === null) return "missing";
1074
- if (typeof value === "object" && value.v === 1 && typeof value.persistedAt === "number" && typeof value.envelope === "object") return value;
1075
- await storage.remove(slotKey(sessionId));
1076
- return "corrupt";
1077
- } catch {
1078
- try {
1079
- await storage.remove(slotKey(sessionId));
1080
- } catch {}
1081
- return "corrupt";
1082
- }
1021
+ /** Clears all HTTP-client state. Called by `reset()`. */
1022
+ function resetHttpClientState() {
1023
+ storedHttpConfig = void 0;
1024
+ setWebApiHttpTransport(null);
1083
1025
  }
1084
- //#endregion
1085
- //#region src/internal/featureConfig/featureConfigService.ts
1086
- let cachedFeatures = null;
1087
1026
  /**
1088
- * Checks if a feature is enabled in the feature config.
1027
+ * Builds (or replaces) the HTTP client when `setup()` receives an `apiURL`.
1028
+ * Picks `createWasmApi` when `effectiveWasm` is set, otherwise plain
1029
+ * `createApi`. Wraps the call in handshake-failure context when encryption
1030
+ * is requested.
1089
1031
  */
1090
- function isFeatureEnabled(feature, features) {
1091
- return features?.find((f) => f.feature === feature)?.enabled ?? false;
1032
+ async function installFreshHttpClient(apiURL, options, effectiveWasm, encryption) {
1033
+ installClient(effectiveWasm ? await withHandshakeFailureContext(encryption.enabled, () => createWasmApi({
1034
+ apiURL,
1035
+ customHeaders: options.customHeaders,
1036
+ timeout: options.timeout,
1037
+ wasm: effectiveWasm,
1038
+ encryptionEnabled: encryption.enabled,
1039
+ mgf1: encryption.mgf1,
1040
+ isEncryptionEnabled: isHttpEncrypted
1041
+ })) : createApi({
1042
+ apiURL,
1043
+ customHeaders: options.customHeaders,
1044
+ timeout: options.timeout
1045
+ }));
1046
+ storedHttpConfig = {
1047
+ apiURL,
1048
+ customHeaders: options.customHeaders,
1049
+ timeout: options.timeout,
1050
+ isWasm: Boolean(effectiveWasm),
1051
+ encryption
1052
+ };
1092
1053
  }
1093
1054
  /**
1094
- * Fetches feature configuration from the backend.
1095
- * Results are cached for the session lifetime.
1055
+ * Replaces the active HTTP client with the WASM-backed one. Used internally
1056
+ * by lazy-loading UI components (`<incode-flow>`, `<incode-workflow>`) when
1057
+ * WASM finishes warming up.
1058
+ *
1059
+ * No-op when no apiURL was previously configured, or when the active client
1060
+ * is already WASM-backed. The encryption state (enabled + MGF1 scheme) is
1061
+ * preserved across the swap — this is *not* a user-facing encryption change.
1062
+ *
1063
+ * @internal NOT a public API. Application code should use
1064
+ * `setup({ wasm: {...} })` instead.
1096
1065
  */
1097
- async function fetchFeatureConfig(signal) {
1098
- if (cachedFeatures) return cachedFeatures;
1099
- const response = await api.get(endpoints.featureConfig, { signal });
1100
- if (!response.ok) throw new Error(`Failed to fetch feature config: ${response.status} ${response.statusText}`);
1101
- cachedFeatures = response.data;
1102
- return cachedFeatures;
1066
+ async function upgradeToWasmHttpClient(resolved) {
1067
+ const stored = storedHttpConfig;
1068
+ if (!stored || stored.isWasm) return;
1069
+ pendingUpgrade ??= (async () => {
1070
+ installClient(await createWasmApi({
1071
+ apiURL: stored.apiURL,
1072
+ customHeaders: stored.customHeaders,
1073
+ timeout: stored.timeout,
1074
+ wasm: resolved,
1075
+ encryptionEnabled: stored.encryption.enabled,
1076
+ mgf1: stored.encryption.mgf1,
1077
+ isEncryptionEnabled: isHttpEncrypted
1078
+ }));
1079
+ storedHttpConfig = {
1080
+ ...stored,
1081
+ isWasm: true
1082
+ };
1083
+ })().finally(() => {
1084
+ pendingUpgrade = void 0;
1085
+ });
1086
+ return pendingUpgrade;
1103
1087
  }
1104
1088
  /**
1105
- * Resets the cached feature config (useful for testing).
1089
+ * When `wantsEncryption` is true, wraps a call that triggers the in-binary
1090
+ * RSA/AES handshake so its rejection surfaces as a single, descriptive error
1091
+ * with the original error preserved as `cause`. Pass-through otherwise.
1106
1092
  */
1107
- function resetFeatureConfigCache() {
1108
- cachedFeatures = null;
1093
+ async function withHandshakeFailureContext(wantsEncryption, fn) {
1094
+ if (!wantsEncryption) return fn();
1095
+ try {
1096
+ return await fn();
1097
+ } catch (cause) {
1098
+ const error = /* @__PURE__ */ new Error("Failed to establish encrypted transport. The /e2ee/key handshake did not complete. Verify the apiURL is reachable and that the environment supports E2EE.");
1099
+ error.cause = cause;
1100
+ throw error;
1101
+ }
1109
1102
  }
1110
1103
  eventModuleNames.selfie, eventModuleNames.faceCapture, eventModuleNames.authentication, eventModuleNames.authFace, eventModuleNames.mlConsent, eventModuleNames.combinedConsent, eventModuleNames.curpValidation, eventModuleNames.faceMatch, eventModuleNames.qr, eventModuleNames.videoSelfie, eventModuleNames.id, eventModuleNames.idCapture, eventModuleNames.idVerification, eventModuleNames.idOcr, eventModuleNames.document, eventModuleNames.creditCard, eventModuleNames.creditCardBack, eventModuleNames.conference, eventModuleNames.otp, eventModuleNames.signature, eventModuleNames.ekyc, eventModuleNames.watchlist, eventModuleNames.globalWatchList, eventModuleNames.customWatchList, eventModuleNames.email, eventModuleNames.phone, eventModuleNames.instantVerifyEmail, eventModuleNames.instantVerifyConsent, eventModuleNames.forms, eventModuleNames.customModule, eventModuleNames.geolocation, eventModuleNames.ekyb, eventModuleNames.identityReuse, eventModuleNames.antifraud, eventModuleNames.aeSignature, eventModuleNames.qeSignature, eventModuleNames.crossDocumentDataMatch, eventModuleNames.customFields, eventModuleNames.fieldComparison, eventModuleNames.personhood, eventModuleNames.watchlistForBusiness, eventModuleNames.trustGraph, eventModuleNames.certificateIssuance, eventModuleNames.governmentValidation, eventModuleNames.documentUpload, eventModuleNames.home, eventModuleNames.workflow, eventModuleNames.fiscalQr;
1111
1104
  eventModuleNames.id, eventModuleNames.idCapture, eventModuleNames.idVerification, eventModuleNames.idOcr, eventModuleNames.document, eventModuleNames.documentUpload, eventModuleNames.creditCard, eventModuleNames.creditCardBack, eventModuleNames.curpValidation;
@@ -1508,4 +1501,4 @@ function modulePosition(payload) {
1508
1501
  return `${typeof moduleIndex === "number" ? ` index=${moduleIndex}` : ""}${typeof totalModules === "number" ? ` total=${totalModules}` : ""}`;
1509
1502
  }
1510
1503
  //#endregion
1511
- export { DEFAULT_WASM_VERSION as C, resolveWasmConfig as D, getBarcodeEnhanceModelUrl as E, upgradeToWasmHttpClient as S, buildWasmConfigFromBasePath as T, noteTestingSignals as _, notifyTrueSightManagerStopped as a, installFreshHttpClient as b, trueSightHintTransition as c, fetchFeatureConfig as d, isFeatureEnabled as f, noteSessionCreated as g, noteEnvironment as h, notifyTrueSightFlowEvent as i, trueSightLog as l, isTrueSightTesting as m, initializeTrueSightDiagnostics as n, resetTrueSight as o, resetFeatureConfigCache as p, noteTrueSightCaptureActivity as r, startTrueSightCollection as s, finalizeTrueSight as t, categoryForEndpoint as u, noteTokenActivated as v, buildDefaultWasmConfig as w, resetHttpClientState as x, getStoredHttpConfig as y };
1504
+ export { DEFAULT_WASM_VERSION as C, resolveWasmConfig as D, getBarcodeEnhanceModelUrl as E, noteTokenActivated as S, buildWasmConfigFromBasePath as T, resetFeatureConfigCache as _, notifyTrueSightManagerStopped as a, noteSessionCreated as b, trueSightHintTransition as c, getStoredHttpConfig as d, installFreshHttpClient as f, isFeatureEnabled as g, fetchFeatureConfig as h, notifyTrueSightFlowEvent as i, trueSightLog as l, upgradeToWasmHttpClient as m, initializeTrueSightDiagnostics as n, resetTrueSight as o, resetHttpClientState as p, noteTrueSightCaptureActivity as r, startTrueSightCollection as s, finalizeTrueSight as t, categoryForEndpoint as u, isTrueSightTesting as v, buildDefaultWasmConfig as w, noteTestingSignals as x, noteEnvironment as y };