@incodetech/core 2.1.1 → 2.2.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{3dAvatarProvider-BwOmTMOy.esm.js → 3dAvatarProvider-g02DTFqT.esm.js} +811 -880
- package/dist/Actor-iTq7YY48.d.ts +1 -0
- package/dist/BrowserDiagnosticsCryptoProvider-CriIh1Gt.esm.js +95 -0
- package/dist/BrowserLazyImportProvider-BhoA957O.esm.js +114 -0
- package/dist/{BrowserStorageProvider-CBHBhKQN.esm.js → BrowserStorageProvider-k-FDkC4W.esm.js} +2 -4
- package/dist/{BrowserTimerProvider-CHloo0eQ.esm.js → BrowserTimerProvider-BXhgNxLt.esm.js} +1 -2
- package/dist/{BrowserVisibilityObserverProvider-GBS6XSii.esm.js → BrowserVisibilityObserverProvider-BX1BiLDK.esm.js} +1 -2
- package/dist/Face2DProvider-UUQt_vRC.esm.js +437 -0
- package/dist/{createFaceAvatar-CpdYp9Iy.d.ts → FaceDetectionProvider-Mh6q3EbA.d.ts} +107 -159
- package/dist/IBrowserEnvironmentCapability-DEaRRk-R.esm.js +9 -0
- package/dist/IFaceAvatarCapability-BrL19G0s.d.ts +23 -0
- package/dist/IFeatureManagementCapability-DdEUp6tB.d.ts +1125 -0
- package/dist/IIdCaptureCapability-DHTT3FC2.d.ts +237 -0
- package/dist/IStorageCapability-ORkQfK3F.d.ts +242 -0
- package/dist/{ITimerCapability-DJ73P4RK.esm.js → ITimerCapability-DgdDzp8G.esm.js} +1 -2
- package/dist/{Manager-goNPc_h_.d.ts → Manager-CQQ99QOI.d.ts} +1 -0
- package/dist/{MotionSensorProvider-BHuHoYvJ.esm.js → MotionSensorProvider-DGiV77J_.esm.js} +2 -37
- package/dist/{OpenViduRecordingProvider-CK6A5kiU.esm.js → OpenViduRecordingProvider-Du98qevC.esm.js} +2 -4
- package/dist/PrivacyLensProvider-D8PS7AJa.esm.js +405 -0
- package/dist/StateMachine-EDpYWy0i.d.ts +6 -0
- package/dist/{StreamCanvasCapture-CAqUdVkM.esm.js → StreamCanvasCapture-D2XcXCZ4.esm.js} +2 -4
- package/dist/{addressSearch-D7msRieq.esm.js → addressSearch-DQyrvDQj.esm.js} +10 -21
- package/dist/ae-signature.d.ts +4 -6
- package/dist/ae-signature.esm.js +10 -11
- package/dist/antifraud.d.ts +1 -6
- package/dist/antifraud.esm.js +3 -8
- package/dist/{antifraudManager-5KA84wtF.esm.js → antifraudManager-B8Plzf7a.esm.js} +11 -8
- package/dist/{antifraudManager-DCiNI6np.d.ts → antifraudManager-BY36bS12.d.ts} +3 -3
- package/dist/{antifraudStateMachine-BQVw46N5.esm.js → antifraudStateMachine-r4VxSBS4.esm.js} +5 -7
- package/dist/api-Bx3gKW_y.esm.js +129 -0
- package/dist/{apiError-DkOXfFBu.esm.js → apiError-DZfAyExM.esm.js} +25 -3
- package/dist/authentication.d.ts +3 -19
- package/dist/authentication.esm.js +3 -35
- package/dist/{authenticationManager-BeT6tNZm.d.ts → authenticationManager-BBMGTcwW.d.ts} +3 -4
- package/dist/{authenticationManager-BryLnSaF.esm.js → authenticationManager-DscbQwIl.esm.js} +7 -10
- package/dist/{authenticationStateMachine-DbdxfGHx.esm.js → authenticationStateMachine-SyuM00Fa.esm.js} +11 -15
- package/dist/avatar.d.ts +2 -2
- package/dist/avatar.esm.js +2 -3
- package/dist/avatar2dWarm-DqucNFX4.esm.js +1330 -0
- package/dist/avatarStats-CdUOb3VD.esm.js +136 -0
- package/dist/{backCameraStream-ChrMTJv-.esm.js → backCameraStream-CUeYm5eu.esm.js} +20 -8
- package/dist/browser-DlFgHpoC-DnyrCR8r.esm.js +1513 -0
- package/dist/callback-645_omgz.d.ts +133 -0
- package/dist/camera-_2sXMXiF.esm.js +140 -0
- package/dist/camera.d.ts +19 -2
- package/dist/camera.esm.js +2 -6
- package/dist/{canvas-Pi10hG_l.esm.js → canvas-E1zGkel4.esm.js} +1 -2
- package/dist/certificate-issuance.d.ts +34 -39
- package/dist/certificate-issuance.esm.js +4 -11
- package/dist/{certificateIssuanceStateMachine-DlZQT1_u.esm.js → certificateIssuanceStateMachine-COd7_l2T.esm.js} +7 -11
- package/dist/consent.d.ts +1 -4
- package/dist/consent.esm.js +3 -8
- package/dist/{consentManager-BwNu-uC-.esm.js → consentManager-BApTlfA0.esm.js} +5 -7
- package/dist/{consentManager-B4PMGXW-.d.ts → consentManager-uhDPdU6i.d.ts} +55 -61
- package/dist/{consentStateMachine-BOkVFiU7.esm.js → consentStateMachine-WD-S-Yhs.esm.js} +5 -7
- package/dist/{cpf-16m_cGAM.esm.js → cpf-BIADjddF.esm.js} +1 -2
- package/dist/createFaceAvatar-BEj18KXi.d.ts +50 -0
- package/dist/createFaceAvatar-DQKaRise.esm.js +103 -0
- package/dist/cross-document-data-match.d.ts +2 -26
- package/dist/cross-document-data-match.esm.js +2 -71
- package/dist/crossDocumentDataMatchManager-Dq8Z3SOg.d.ts +41 -0
- package/dist/crossDocumentDataMatchManager-OmYvyung.esm.js +84 -0
- package/dist/curp-validation.d.ts +1 -11
- package/dist/curp-validation.esm.js +3 -8
- package/dist/{curpValidationManager-CoqODZx5.d.ts → curpValidationManager-DVGr7Fq7.d.ts} +4 -6
- package/dist/{curpValidationManager-Cbji2inV.esm.js → curpValidationManager-UZxcrsrz.esm.js} +11 -7
- package/dist/{curpValidationStateMachine-Dlw4qfFb.esm.js → curpValidationStateMachine-9KwnqeoB.esm.js} +22 -14
- package/dist/custom-fields.d.ts +2 -5
- package/dist/custom-fields.esm.js +24 -11
- package/dist/custom-watchlist.d.ts +1 -3
- package/dist/custom-watchlist.esm.js +11 -10
- package/dist/{customWatchlistStateMachine-D8w0mNxm.esm.js → customWatchlistStateMachine-B_ey3TFj.esm.js} +5 -7
- package/dist/{dateUtils-BW6mBV6p.esm.js → dateUtils-CvG0FvK8.esm.js} +1 -2
- package/dist/{deepsightService-CViys6T4.esm.js → deepsightLoader-DcWjMC6A.esm.js} +68 -14
- package/dist/{deepsightService-BuTOFTr8.d.ts → deepsightService-DLVQS_RH.d.ts} +41 -2
- package/dist/device.d.ts +10 -2
- package/dist/device.esm.js +21 -21
- package/dist/document-capture.d.ts +3 -1816
- package/dist/document-capture.esm.js +3 -245
- package/dist/document-upload.d.ts +48 -55
- package/dist/document-upload.esm.js +8 -14
- package/dist/documentCaptureManager-B4Kivr8_.d.ts +2062 -0
- package/dist/documentCaptureManager-DszmcU-l.esm.js +296 -0
- package/dist/{documentCaptureStateMachine-BkTvU3yq.esm.js → documentCaptureStateMachine-D2jBwwVb.esm.js} +66 -40
- package/dist/dynamic-forms.d.ts +2 -4
- package/dist/dynamic-forms.esm.js +3 -9
- package/dist/{dynamicFormsManager-CHXUBNs4.esm.js → dynamicFormsManager-BoZ2-OUI.esm.js} +48 -9
- package/dist/{dynamicFormsManager-CKZkE7Wo.d.ts → dynamicFormsManager-fhK0yINk.d.ts} +22 -46
- package/dist/{dynamicFormsStateMachine-DJ1HGZff.esm.js → dynamicFormsStateMachine-D0RzkoEV.esm.js} +161 -34
- package/dist/ekyb.d.ts +5 -137
- package/dist/ekyb.esm.js +4 -179
- package/dist/ekybManager-DTvfxAOZ.esm.js +178 -0
- package/dist/ekybManager-Dzswb_b8.d.ts +114 -0
- package/dist/{ekybStateMachine-D9GzA4MW.esm.js → ekybStateMachine-BlTIozb6.esm.js} +16 -193
- package/dist/ekyc.d.ts +2 -79
- package/dist/ekyc.esm.js +4 -154
- package/dist/ekycManager-BFpHbBoT.d.ts +97 -0
- package/dist/ekycManager-oTstTJuL.esm.js +156 -0
- package/dist/{ekycStateMachine-DnVRiu3s.esm.js → ekycStateMachine-DHvksnrr.esm.js} +141 -423
- package/dist/ekycUtils-Dew1rBG0.esm.js +223 -0
- package/dist/electronic-signature.d.ts +3 -5
- package/dist/electronic-signature.esm.js +2 -10
- package/dist/{index-36QX_21w.d.ts → electronicSignatureManager-CcUXQZS7.d.ts} +220 -251
- package/dist/{electronicSignatureManager-DESRgObX.esm.js → electronicSignatureManager-DRYlHPjT.esm.js} +47 -33
- package/dist/email.d.ts +1 -5
- package/dist/email.esm.js +3 -10
- package/dist/{emailManager-CMS4q_r6.d.ts → emailManager-CADXW_9X.d.ts} +4 -7
- package/dist/{emailManager-B9Vrv3Ma.esm.js → emailManager-tE-YvNtS.esm.js} +76 -12
- package/dist/{emailStateMachine-CbmKFVSi.esm.js → emailStateMachine-Bm894MHB.esm.js} +7 -9
- package/dist/{endpoints-CwrFQfW7.esm.js → endpoints-CCzL3XD_.esm.js} +55 -6
- package/dist/{events-1wxZ97yf.esm.js → events-CxfNJVZW.esm.js} +43 -176
- package/dist/events.d.ts +28 -10
- package/dist/events.esm.js +2 -4
- package/dist/extensibility.d.ts +37 -37
- package/dist/extensibility.esm.js +31 -80
- package/dist/{externalFetch-hvmz_npP.esm.js → externalFetch-BKBThAUC.esm.js} +2 -4
- package/dist/face-match.d.ts +2 -225
- package/dist/face-match.esm.js +3 -173
- package/dist/{faceCaptureManagerFactory-C9TiGbkA.esm.js → faceCaptureManagerFactory-BDAsBCkh.esm.js} +52 -31
- package/dist/{faceCaptureManagerFactory-DiJ64oem.d.ts → faceCaptureManagerFactory-BxWPpxyd.d.ts} +63 -24
- package/dist/{faceCaptureSetup-BqhqfFHL.esm.js → faceCaptureSetup-C7Qv79fA.esm.js} +57 -36
- package/dist/faceMatchManager-BXp2WUT-.esm.js +201 -0
- package/dist/faceMatchManager-BnvrZM2F.d.ts +268 -0
- package/dist/{faceMatchStateMachine-MDb30gCm.esm.js → faceMatchStateMachine-CJiO2yLO.esm.js} +14 -10
- package/dist/feature-management-DS_Nj5Gg.esm.js +615 -0
- package/dist/feature-management.d.ts +173 -0
- package/dist/feature-management.esm.js +2 -0
- package/dist/field-comparison.d.ts +1 -4
- package/dist/field-comparison.esm.js +2 -7
- package/dist/{fieldComparisonManager-OLKVsG2Z.d.ts → fieldComparisonManager-CBvEGxFx.d.ts} +3 -5
- package/dist/{fieldComparisonManager-Cw4uzD7S.esm.js → fieldComparisonManager-DhnYdYZ2.esm.js} +6 -11
- package/dist/fiscal-qr.d.ts +1 -6
- package/dist/fiscal-qr.esm.js +14 -29
- package/dist/flow-events.d.ts +2 -9
- package/dist/flow.d.ts +59 -21
- package/dist/flow.esm.js +132 -49
- package/dist/{flowCompletionService-B6P6_EF3.esm.js → flowCompletionService-BSe3p7pg.esm.js} +4 -6
- package/dist/flowServices-unhF9V9F.esm.js +620 -0
- package/dist/geolocation.d.ts +1 -4
- package/dist/geolocation.esm.js +3 -9
- package/dist/{geolocationManager-CF6-NizA.esm.js → geolocationManager-Bv9MSVNr.esm.js} +44 -16
- package/dist/geolocationManager-Cz744E5S.d.ts +506 -0
- package/dist/{geolocationStateMachine-CD2XJs1b.esm.js → geolocationStateMachine-BxD6JK1M.esm.js} +53 -28
- package/dist/{getBrowser-1yNcfFZR.esm.js → getBrowser-Cb8Zgrgp.esm.js} +1 -2
- package/dist/getBrowser-DNrQeL4T.esm.js +16 -0
- package/dist/getDeviceClass-9y-kbVDw.esm.js +19 -0
- package/dist/{getDeviceClass-C-Dg6IsJ.esm.js → getDeviceClass-CeBiEayS.esm.js} +1 -2
- package/dist/getParsedUserAgent-pJjATANs.esm.js +1622 -0
- package/dist/government-validation.d.ts +3 -6
- package/dist/government-validation.esm.js +7 -13
- package/dist/{governmentValidationStateMachine-BE5wiQ7Y.esm.js → governmentValidationStateMachine-BYKYUdza.esm.js} +8 -11
- package/dist/home.d.ts +14 -22
- package/dist/home.esm.js +3 -8
- package/dist/http.d.ts +0 -1
- package/dist/http.esm.js +2 -4
- package/dist/id-ocr.d.ts +8 -7
- package/dist/id-ocr.esm.js +20 -9
- package/dist/id-selfie-flow.d.ts +179 -0
- package/dist/id-selfie-flow.esm.js +917 -0
- package/dist/id-verification.d.ts +2 -191
- package/dist/id-verification.esm.js +3 -43
- package/dist/id.d.ts +7 -18
- package/dist/id.esm.js +47 -53
- package/dist/{idCaptureDefaults-CZajItdO.esm.js → idCaptureDefaults-WeHbQM7W.esm.js} +54 -17
- package/dist/idCaptureManager-BjU-Wyow.d.ts +429 -0
- package/dist/{idCaptureManager-DASPUMtC.esm.js → idCaptureManager-BjiBSrHm.esm.js} +173 -34
- package/dist/idCaptureServices-CFDwqTtQ.esm.js +396 -0
- package/dist/{idCaptureStateMachine-DZ2ZTSxu.esm.js → idCaptureStateMachine-CRwQh8jc.esm.js} +438 -585
- package/dist/{idOcrManager-Tm4LzKR0.esm.js → idOcrManager-CvJZhmBR.esm.js} +4 -7
- package/dist/{idOcrManager-DLfAjDZn.d.ts → idOcrManager-DXc_xRN7.d.ts} +62 -229
- package/dist/{idOcrStateMachine-BJxZCxwS.esm.js → idOcrStateMachine-Bq_e3l4E.esm.js} +15 -20
- package/dist/idVerificationManager-BB4Pj_N6.d.ts +197 -0
- package/dist/idVerificationManager-CduNXhWd.esm.js +51 -0
- package/dist/{idVerificationStateMachine-DXN9WcdM.esm.js → idVerificationStateMachine-GEQWUPU2.esm.js} +5 -7
- package/dist/identity-reuse.d.ts +1 -4
- package/dist/identity-reuse.esm.js +3 -8
- package/dist/{identityReuseManager-LjkPvSQN.esm.js → identityReuseManager-D5vXknnJ.esm.js} +24 -7
- package/dist/{identityReuseManager-CLVOYxcp.d.ts → identityReuseManager-v2TH5g7e.d.ts} +38 -43
- package/dist/{identityReuseStateMachine-Bp-zONoV.esm.js → identityReuseStateMachine-AubRPhIi.esm.js} +6 -8
- package/dist/index-B8weJxmL.d.ts +1 -0
- package/dist/index-BKOWUhxG.d.ts +258 -0
- package/dist/{index-DrpWp15Z.d.ts → index-CLMF0QLQ.d.ts} +3 -3
- package/dist/index.d.ts +1 -3
- package/dist/index.esm.js +2 -15
- package/dist/{invokeOnCaptureCallback-CCS2Ruzi.esm.js → invokeOnCaptureCallback-1m1VJ3Q4.esm.js} +2 -4
- package/dist/{lib-Bjd6nOLG.esm.js → lib-DAyUtOTj.esm.js} +1510 -1589
- package/dist/mandatory-consent.d.ts +2 -10
- package/dist/mandatory-consent.esm.js +3 -8
- package/dist/{mandatoryConsentManager-DeBmOHcQ.d.ts → mandatoryConsentManager-B29kR0XA.d.ts} +60 -85
- package/dist/{mandatoryConsentManager-DZ26sg4B.esm.js → mandatoryConsentManager-BeELm1zS.esm.js} +4 -7
- package/dist/{mandatoryConsentStateMachine-_44ZoDSh.esm.js → mandatoryConsentStateMachine-zroQGzwb.esm.js} +5 -7
- package/dist/manualReviewService-D4IkipnN.esm.js +15 -0
- package/dist/{mediaRecorderOptions-CClCKAiF.esm.js → mediaRecorderOptions-dALSV8af.esm.js} +2 -4
- package/dist/{mediapipeShared-Bcmkzs3x.esm.js → mediapipeShared-B6oNoXEQ.esm.js} +21 -9
- package/dist/{onDeviceFaceResults-DILtthks.esm.js → onDeviceFaceResults-f81FVdQs.esm.js} +30 -87
- package/dist/openviduLazy-CCDpFWg1.esm.js +10 -0
- package/dist/{otp-B1YeyRXu.d.ts → otp-CEWfTj9v.d.ts} +0 -1
- package/dist/{otp-uaXiKt_R.esm.js → otp-D2k3PeSL.esm.js} +3 -14
- package/dist/{permissionGuards-BNOe4Tnu.esm.js → permissionGuards-KINpmKtI.esm.js} +2 -4
- package/dist/{permissionServices-C_kxhNeo.esm.js → permissionServices-UvUcOSRb.esm.js} +35 -28
- package/dist/personhood.d.ts +13 -20
- package/dist/personhood.esm.js +153 -85
- package/dist/phone.d.ts +1 -5
- package/dist/phone.esm.js +3 -10
- package/dist/{phoneManager-_KtitbUA.d.ts → phoneManager-BBU8Lq0O.d.ts} +4 -7
- package/dist/{phoneManager-CRblfdcI.esm.js → phoneManager-Cpiai2IM.esm.js} +82 -12
- package/dist/{phoneStateMachine-DjFGWMjQ.esm.js → phoneStateMachine-E1fUUcNM.esm.js} +7 -9
- package/dist/{platform-0Ot-bF_a.esm.js → platform-BJrm5nzZ.esm.js} +31 -11
- package/dist/privacyLensWorker-DI-Rg83h.esm.js +355 -0
- package/dist/qe-signature.d.ts +4 -6
- package/dist/qe-signature.esm.js +10 -11
- package/dist/{recordingService-CxaYkITO.esm.js → recordingService-CFpfdXSS.esm.js} +13 -31
- package/dist/redirect-to-mobile.d.ts +2 -6
- package/dist/redirect-to-mobile.esm.js +3 -10
- package/dist/{redirectToMobileManager-dv29o_LS.d.ts → redirectToMobileManager-BD2PvT5B.d.ts} +8 -44
- package/dist/{redirectToMobileManager-DbuNUlru.esm.js → redirectToMobileManager-C0dfc7f6.esm.js} +28 -8
- package/dist/{redirectToMobileStateMachine-BRaIJWOM.esm.js → redirectToMobileStateMachine-C9SYCJcH.esm.js} +74 -18
- package/dist/rolldown-runtime-FZ4Itg2g.esm.js +42 -0
- package/dist/{runChildModule-kojSv3MH.esm.js → runChildModule-DpvgAGFA.esm.js} +10 -9
- package/dist/{WasmUtilProvider-BgzcXBdl.esm.js → safeStorage-Ep56I-f_.esm.js} +98 -473
- package/dist/selfie.d.ts +8 -21
- package/dist/selfie.esm.js +40 -47
- package/dist/selfieErrorUtils-C2PYBVsp.esm.js +90 -0
- package/dist/{selfieManager-B1Px3GGa.esm.js → selfieManager-Br4onIMy.esm.js} +7 -10
- package/dist/{selfieManager-4juKfrHG.d.ts → selfieManager-DwlCppg0.d.ts} +3 -4
- package/dist/{selfieStateMachine-D0TS93Tu.esm.js → selfieStateMachine-CNGs8vFK.esm.js} +14 -29
- package/dist/{session-CLsU2Jnb.esm.js → session-CX2H3tmI.esm.js} +16 -7
- package/dist/session.d.ts +12 -10
- package/dist/session.esm.js +5 -15
- package/dist/sessionInitializer-CV6Rj_dn.esm.js +1865 -0
- package/dist/{setup-CfNsYAeB.esm.js → setup-CYdVacqv.esm.js} +319 -137
- package/dist/{setup-CmA2apmN.d.ts → setup-DywQeePQ.d.ts} +186 -4
- package/dist/signature.d.ts +2 -96
- package/dist/signature.esm.js +3 -108
- package/dist/signatureManager-DGBSWz2_.d.ts +106 -0
- package/dist/signatureManager-DdPgcmou.esm.js +113 -0
- package/dist/{signatureStateMachine-CdhlMih-.esm.js → signatureStateMachine-Cf73DGWO.esm.js} +5 -7
- package/dist/spawn-D9jgw9pW.d.ts +1441 -0
- package/dist/src-0Jurt29N.esm.js +4482 -0
- package/dist/{stats-BVy52wLy.esm.js → stats-B0nFKawG.esm.js} +3 -5
- package/dist/stats.esm.js +2 -5
- package/dist/topLevelStateName-B5i2avbh.esm.js +41 -0
- package/dist/{tri-CFAPtAUM.esm.js → tri-4RsGrIt6.esm.js} +3 -119
- package/dist/tri.d.ts +2 -2
- package/dist/tri.esm-BIjHhBJ2.esm.js +2620 -0
- package/dist/tri.esm.js +2 -4
- package/dist/trueSight-B8G85W4z.esm.js +1 -0
- package/dist/trueSightService-6dTpiaTh.esm.js +1894 -0
- package/dist/trust-graph.d.ts +4 -5
- package/dist/trust-graph.esm.js +13 -9
- package/dist/types-BEwVKkLJ.d.ts +15 -0
- package/dist/{types-BKLb3C42.esm.js → types-BN5RPPIZ.esm.js} +1 -2
- package/dist/types-BSBzhHRH.d.ts +57 -0
- package/dist/types-BX_XkMsQ2.d.ts +21 -0
- package/dist/types-BfHiko5D.d.ts +48 -0
- package/dist/{types-D8Cl1N2Z.d.ts → types-BfgmV7s72.d.ts} +2 -2
- package/dist/types-CJ7Yl9K-2.d.ts +164 -0
- package/dist/types-DPIDuhut.d.ts +40 -0
- package/dist/types-DVmXIdzW.d.ts +82 -0
- package/dist/types-DelMqZLe.d.ts +105 -0
- package/dist/types-EELWyWpd.d.ts +6 -0
- package/dist/{types-fO6KIdol.d.ts → types-Hmd7U0JA.d.ts} +80 -6
- package/dist/{types-BUgeB2X6.d.ts → types-KPvmag_B.d.ts} +7 -7
- package/dist/types-M6eb82ra2.d.ts +589 -0
- package/dist/{types-DV3wkhQ4.d.ts → types-Vb4P9ovf.d.ts} +1 -3
- package/dist/{urlUtils-CpiYwn7w.esm.js → urlUtils-D6phjq1-.esm.js} +1 -2
- package/dist/{video-ZY92rkel.esm.js → video-BtSWtHy1.esm.js} +1 -2
- package/dist/video-selfie.d.ts +71 -117
- package/dist/video-selfie.esm.js +575 -643
- package/dist/videoSelfieCameraWarmer-h_VUk5Vu.esm.js +651 -0
- package/dist/videoSelfieStepDetector-D3oo2ofo.d.ts +123 -0
- package/dist/wasm.d.ts +2 -4
- package/dist/wasm.esm.js +4 -15
- package/dist/wasmDefaults-DTUrftxR.esm.js +125 -0
- package/dist/{wasmDsFlagSync-Ch0mFJNT.esm.js → wasmDsFlagSync-BqUCwLY8.esm.js} +2 -4
- package/dist/wasmWebClient-DM8lkb0z.esm.js +407 -0
- package/dist/watchlist-for-business.d.ts +1 -3
- package/dist/watchlist-for-business.esm.js +9 -9
- package/dist/watchlist.d.ts +1 -52
- package/dist/watchlist.esm.js +3 -70
- package/dist/{watchlistForBusinessStateMachine-R1Yp1g5A.esm.js → watchlistForBusinessStateMachine-BcBMkMvV.esm.js} +5 -7
- package/dist/watchlistManager-CjSMmbyq.esm.js +83 -0
- package/dist/watchlistManager-DLXef90v.d.ts +68 -0
- package/dist/{watchlistStateMachine-D07UVq1m.esm.js → watchlistStateMachine-Bl7Wy9Cm.esm.js} +5 -7
- package/dist/workflow.d.ts +239 -203
- package/dist/workflow.esm.js +156 -101
- package/dist/xstate-actors.esm-CtI5S0f4.esm.js +310 -0
- package/dist/{xstate.esm-nY3M5UYm.esm.js → xstate.esm-Cf4e0Cfd.esm.js} +136 -610
- package/package.json +14 -9
- package/dist/Actor-BwgmOPkb.d.ts +0 -2
- package/dist/Face2DProvider-CZU11g6r.esm.js +0 -824
- package/dist/FaceDetectionProvider-CPWg-PAH.d.ts +0 -119
- package/dist/IWasmUtilCapability-DaSNxgA8.d.ts +0 -150
- package/dist/PrivacyLensProvider-B_zrV25p.esm.js +0 -339
- package/dist/StateMachine-D5WO6lHS.d.ts +0 -2
- package/dist/StreamCanvasCapture-DHaWferF.d.ts +0 -42
- package/dist/ae-signature-Pp4oCAHD.esm.js +0 -12
- package/dist/api-DsbUi7TO.esm.js +0 -72
- package/dist/browser-DlFgHpoC-Br3G10gw.esm.js +0 -1425
- package/dist/browserSimulation-DZwEy9bu.esm.js +0 -2804
- package/dist/camera-CxxXV0VN.esm.js +0 -79
- package/dist/canvas-90BqS0NF.d.ts +0 -112
- package/dist/chunk-CIKcdghV.esm.js +0 -49
- package/dist/clientLifecycle-VyzRfALg.esm.js +0 -534
- package/dist/cpf-ocr.d.ts +0 -10
- package/dist/cpf-ocr.esm.js +0 -8
- package/dist/cpfOcrManager-9eM4z4o7.esm.js +0 -190
- package/dist/cpfOcrManager-C5U9E0hf.d.ts +0 -216
- package/dist/createFaceAvatar-BZSg2MNo.esm.js +0 -46
- package/dist/deepsightLoader-CU_tiLMx.esm.js +0 -62
- package/dist/flowServices-DkQmOkLV.esm.js +0 -208
- package/dist/geolocationManager-DaHYFkVO.d.ts +0 -156
- package/dist/getDeviceClass-DIjnTPjR.esm.js +0 -14
- package/dist/http-CnsKEaJY.esm.js +0 -0
- package/dist/idCaptureManager-CwuXtVu6.d.ts +0 -1013
- package/dist/index-BAyZ8_iI.d.ts +0 -93
- package/dist/openviduLazy-jPgABwrt.esm.js +0 -3
- package/dist/openviduLazy-wEojM41w.esm.js +0 -12
- package/dist/qe-signature-BnWIpR-O.esm.js +0 -12
- package/dist/sessionInitializer-Dj7-aJaP.esm.js +0 -547
- package/dist/tri.esm-DDJ1zOqG.esm.js +0 -2593
- package/dist/types-BcF-fii5.d.ts +0 -5
- package/dist/videoSelfieSteps-Djpv7cjb.esm.js +0 -58
- /package/dist/{IVisibilityObserverCapability-BZ1rE7ly.d.ts → IVisibilityObserverCapability-D4tvIB5v.d.ts} +0 -0
- /package/dist/{camera-CKU96nwJ.d.ts → camera-9wWD-pwg.d.ts} +0 -0
- /package/dist/{flowCompletionService-BOSTlAWo.d.ts → flowCompletionService-BlAHsKyv.d.ts} +0 -0
- /package/dist/{types-BgjMAEXl.d.ts → types-Bk_6dmDa.d.ts} +0 -0
- /package/dist/{warmup-Dd0iq6KF.d.ts → warmup-Dv2alr2-.d.ts} +0 -0
|
@@ -0,0 +1,1894 @@
|
|
|
1
|
+
import { a as setWebApiHttpTransport, i as initializeWasmWebClient, o as setupWasmConnection, r as executeWasmRequest, t as WasmWebClientError } from "./wasmWebClient-DM8lkb0z.esm.js";
|
|
2
|
+
import { t as getTimestamp } from "./IBrowserEnvironmentCapability-DEaRRk-R.esm.js";
|
|
3
|
+
import { i as isApiConfigured, n as getApi, o as setClient, r as getToken, t as api } from "./api-Bx3gKW_y.esm.js";
|
|
4
|
+
import { S as subscribeEvent, n as eventModuleNames } from "./events-CxfNJVZW.esm.js";
|
|
5
|
+
import { t as endpoints } from "./endpoints-CCzL3XD_.esm.js";
|
|
6
|
+
//#region ../infra/src/http/createApi.ts
|
|
7
|
+
var FetchHttpError = class extends Error {
|
|
8
|
+
constructor(status, statusText, url, method, headers, data) {
|
|
9
|
+
super(`HTTP ${status} ${statusText}`);
|
|
10
|
+
this.ok = false;
|
|
11
|
+
this.status = status;
|
|
12
|
+
this.statusText = statusText;
|
|
13
|
+
this.url = url;
|
|
14
|
+
this.method = method;
|
|
15
|
+
this.headers = headers;
|
|
16
|
+
this.data = data;
|
|
17
|
+
this.name = "FetchHttpError";
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const buildQueryString$1 = (query) => {
|
|
21
|
+
if (!query) return "";
|
|
22
|
+
const params = new URLSearchParams();
|
|
23
|
+
Object.entries(query).forEach(([key, value]) => {
|
|
24
|
+
if (value !== void 0 && value !== null) params.append(key, String(value));
|
|
25
|
+
});
|
|
26
|
+
const str = params.toString();
|
|
27
|
+
return str ? `?${str}` : "";
|
|
28
|
+
};
|
|
29
|
+
const buildUrl$1 = (baseURL, url, query) => {
|
|
30
|
+
const queryString = buildQueryString$1(query);
|
|
31
|
+
if (url.startsWith("http://") || url.startsWith("https://")) return `${url}${queryString}`;
|
|
32
|
+
return `${baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL}${url.startsWith("/") ? url : `/${url}`}${queryString}`;
|
|
33
|
+
};
|
|
34
|
+
const prepareBody$1 = (body) => {
|
|
35
|
+
if (body === null || body === void 0) return null;
|
|
36
|
+
if (body instanceof FormData || body instanceof Blob || body instanceof ArrayBuffer) return body;
|
|
37
|
+
if (typeof body === "object") return JSON.stringify(body);
|
|
38
|
+
return String(body);
|
|
39
|
+
};
|
|
40
|
+
const parseResponse = async (response, parseType) => {
|
|
41
|
+
if (parseType === "response") return response;
|
|
42
|
+
if (parseType === "blob") return await response.blob();
|
|
43
|
+
if (parseType === "arrayBuffer") return await response.arrayBuffer();
|
|
44
|
+
if (parseType === "text") return await response.text();
|
|
45
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
46
|
+
if (parseType === "json" || contentType.includes("application/json")) {
|
|
47
|
+
const raw = await response.text();
|
|
48
|
+
if (raw.length === 0) return "";
|
|
49
|
+
try {
|
|
50
|
+
return JSON.parse(raw);
|
|
51
|
+
} catch {
|
|
52
|
+
return raw;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return await response.text();
|
|
56
|
+
};
|
|
57
|
+
const requestWithXHR = (fullUrl, method, mergedHeaders, requestBody, timeout, signal, onUploadProgress) => {
|
|
58
|
+
return new Promise((resolve, reject) => {
|
|
59
|
+
const xhr = new XMLHttpRequest();
|
|
60
|
+
xhr.open(method, fullUrl, true);
|
|
61
|
+
Object.entries(mergedHeaders).forEach(([key, value]) => {
|
|
62
|
+
xhr.setRequestHeader(key, value);
|
|
63
|
+
});
|
|
64
|
+
xhr.timeout = timeout;
|
|
65
|
+
xhr.upload.onprogress = (event) => {
|
|
66
|
+
if (event.lengthComputable) {
|
|
67
|
+
const percentComplete = event.loaded / event.total * 100;
|
|
68
|
+
onUploadProgress(Math.round(percentComplete));
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
xhr.onload = () => {
|
|
72
|
+
const responseHeaders = {};
|
|
73
|
+
xhr.getAllResponseHeaders().split("\r\n").forEach((line) => {
|
|
74
|
+
const parts = line.split(": ");
|
|
75
|
+
if (parts.length === 2) responseHeaders[parts[0].toLowerCase()] = parts[1];
|
|
76
|
+
});
|
|
77
|
+
let data;
|
|
78
|
+
try {
|
|
79
|
+
if ((xhr.getResponseHeader("content-type") ?? "").includes("application/json")) data = JSON.parse(xhr.responseText);
|
|
80
|
+
else data = xhr.responseText;
|
|
81
|
+
} catch {
|
|
82
|
+
data = xhr.responseText;
|
|
83
|
+
}
|
|
84
|
+
if (xhr.status >= 200 && xhr.status < 300) resolve({
|
|
85
|
+
ok: true,
|
|
86
|
+
status: xhr.status,
|
|
87
|
+
statusText: xhr.statusText,
|
|
88
|
+
url: fullUrl,
|
|
89
|
+
headers: responseHeaders,
|
|
90
|
+
data
|
|
91
|
+
});
|
|
92
|
+
else reject(new FetchHttpError(xhr.status, xhr.statusText, fullUrl, method, responseHeaders, data));
|
|
93
|
+
};
|
|
94
|
+
xhr.onerror = () => {
|
|
95
|
+
reject(new FetchHttpError(0, "Network Error", fullUrl, method, {}, null));
|
|
96
|
+
};
|
|
97
|
+
xhr.ontimeout = () => {
|
|
98
|
+
reject(new FetchHttpError(0, "Request timeout", fullUrl, method, {}, null));
|
|
99
|
+
};
|
|
100
|
+
if (signal) signal.addEventListener("abort", () => {
|
|
101
|
+
xhr.abort();
|
|
102
|
+
reject(new FetchHttpError(0, "Request aborted", fullUrl, method, {}, null));
|
|
103
|
+
});
|
|
104
|
+
xhr.send(requestBody);
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
const createApi = (config) => {
|
|
108
|
+
const headers = {
|
|
109
|
+
"Content-Type": "application/json",
|
|
110
|
+
Accept: "application/json",
|
|
111
|
+
"api-version": "1.0",
|
|
112
|
+
...config.customHeaders ?? {}
|
|
113
|
+
};
|
|
114
|
+
const defaults = {
|
|
115
|
+
baseURL: config.apiURL,
|
|
116
|
+
headers
|
|
117
|
+
};
|
|
118
|
+
const client = {
|
|
119
|
+
defaults,
|
|
120
|
+
async request(requestConfig) {
|
|
121
|
+
const { method = "GET", url, headers = {}, query, params, body, signal, timeout: timeoutOverride, parse, onUploadProgress, keepalive } = requestConfig;
|
|
122
|
+
const fullUrl = buildUrl$1(defaults.baseURL, url, params ?? query);
|
|
123
|
+
const mergedHeaders = {
|
|
124
|
+
...defaults.headers,
|
|
125
|
+
...headers
|
|
126
|
+
};
|
|
127
|
+
const requestBody = prepareBody$1(body);
|
|
128
|
+
const timeout = timeoutOverride ?? config.timeout;
|
|
129
|
+
let finalHeaders = mergedHeaders;
|
|
130
|
+
if (requestBody === null && (method === "POST" || method === "PUT" || method === "PATCH")) {
|
|
131
|
+
const { "Content-Type": _, ...headersWithoutContentType } = mergedHeaders;
|
|
132
|
+
finalHeaders = headersWithoutContentType;
|
|
133
|
+
}
|
|
134
|
+
if (onUploadProgress) {
|
|
135
|
+
if (requestBody !== null && typeof ReadableStream !== "undefined" && requestBody instanceof ReadableStream) throw new Error("Upload progress tracking is not supported for ReadableStream bodies");
|
|
136
|
+
return requestWithXHR(fullUrl, method, finalHeaders, requestBody, timeout ?? 0, signal, onUploadProgress);
|
|
137
|
+
}
|
|
138
|
+
const controller = new AbortController();
|
|
139
|
+
if (signal) if (signal.aborted) controller.abort();
|
|
140
|
+
else signal.addEventListener("abort", () => controller.abort(), { once: true });
|
|
141
|
+
const abortSignal = controller.signal;
|
|
142
|
+
const timeoutId = timeout === void 0 ? void 0 : setTimeout(() => controller.abort(), timeout);
|
|
143
|
+
try {
|
|
144
|
+
const response = await fetch(fullUrl, {
|
|
145
|
+
method,
|
|
146
|
+
headers: finalHeaders,
|
|
147
|
+
body: requestBody,
|
|
148
|
+
signal: abortSignal,
|
|
149
|
+
keepalive
|
|
150
|
+
});
|
|
151
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
152
|
+
const responseHeaders = {};
|
|
153
|
+
response.headers.forEach((value, key) => {
|
|
154
|
+
responseHeaders[key] = value;
|
|
155
|
+
});
|
|
156
|
+
const data = await parseResponse(response, parse);
|
|
157
|
+
if (!response.ok) throw new FetchHttpError(response.status, response.statusText, fullUrl, method, responseHeaders, data);
|
|
158
|
+
return {
|
|
159
|
+
ok: true,
|
|
160
|
+
status: response.status,
|
|
161
|
+
statusText: response.statusText,
|
|
162
|
+
url: fullUrl,
|
|
163
|
+
headers: responseHeaders,
|
|
164
|
+
data
|
|
165
|
+
};
|
|
166
|
+
} catch (error) {
|
|
167
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
168
|
+
if (error instanceof FetchHttpError) throw error;
|
|
169
|
+
if (error instanceof Error && error.name === "AbortError") throw new FetchHttpError(0, "Request timeout", fullUrl, method, {}, null);
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
get(url, config) {
|
|
174
|
+
return client.request({
|
|
175
|
+
...config,
|
|
176
|
+
url,
|
|
177
|
+
method: "GET"
|
|
178
|
+
});
|
|
179
|
+
},
|
|
180
|
+
post(url, body, config) {
|
|
181
|
+
return client.request({
|
|
182
|
+
...config,
|
|
183
|
+
url,
|
|
184
|
+
body,
|
|
185
|
+
method: "POST"
|
|
186
|
+
});
|
|
187
|
+
},
|
|
188
|
+
put(url, body, config) {
|
|
189
|
+
return client.request({
|
|
190
|
+
...config,
|
|
191
|
+
url,
|
|
192
|
+
body,
|
|
193
|
+
method: "PUT"
|
|
194
|
+
});
|
|
195
|
+
},
|
|
196
|
+
patch(url, body, config) {
|
|
197
|
+
return client.request({
|
|
198
|
+
...config,
|
|
199
|
+
url,
|
|
200
|
+
body,
|
|
201
|
+
method: "PATCH"
|
|
202
|
+
});
|
|
203
|
+
},
|
|
204
|
+
delete(url, config) {
|
|
205
|
+
return client.request({
|
|
206
|
+
...config,
|
|
207
|
+
url,
|
|
208
|
+
method: "DELETE"
|
|
209
|
+
});
|
|
210
|
+
},
|
|
211
|
+
head(url, config) {
|
|
212
|
+
return client.request({
|
|
213
|
+
...config,
|
|
214
|
+
url,
|
|
215
|
+
method: "HEAD"
|
|
216
|
+
});
|
|
217
|
+
},
|
|
218
|
+
options(url, config) {
|
|
219
|
+
return client.request({
|
|
220
|
+
...config,
|
|
221
|
+
url,
|
|
222
|
+
method: "OPTIONS"
|
|
223
|
+
});
|
|
224
|
+
},
|
|
225
|
+
setHeader(name, value) {
|
|
226
|
+
defaults.headers[name] = value;
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
return client;
|
|
230
|
+
};
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region ../infra/src/http/createWasmApi.ts
|
|
233
|
+
const WASM_TIMEOUT_CEILING_MS = 36e5;
|
|
234
|
+
const RSA_OAEP_SHA256_SCHEME = "RSA/NONE/OAEPWITHSHA-256ANDMGF1PADDING";
|
|
235
|
+
/**
|
|
236
|
+
* Builds the base set of HTTP headers that the WASM WebClient sends on every
|
|
237
|
+
* request (including the internal `/e2ee/key/v2` and `/e2ee/key` handshake
|
|
238
|
+
* calls).
|
|
239
|
+
*/
|
|
240
|
+
function buildWasmDefaultHeaders(customHeaders) {
|
|
241
|
+
return {
|
|
242
|
+
"Content-Type": "application/json",
|
|
243
|
+
Accept: "application/json",
|
|
244
|
+
"api-version": "1.0",
|
|
245
|
+
...customHeaders ?? {}
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
var WasmHttpError = class extends Error {
|
|
249
|
+
constructor(status, statusText, url, method, headers, data) {
|
|
250
|
+
super(`HTTP ${status} ${statusText}`);
|
|
251
|
+
this.ok = false;
|
|
252
|
+
this.status = status;
|
|
253
|
+
this.statusText = statusText;
|
|
254
|
+
this.url = url;
|
|
255
|
+
this.method = method;
|
|
256
|
+
this.headers = headers;
|
|
257
|
+
this.data = data;
|
|
258
|
+
this.name = "WasmHttpError";
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
const HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
262
|
+
"GET",
|
|
263
|
+
"POST",
|
|
264
|
+
"PUT",
|
|
265
|
+
"PATCH",
|
|
266
|
+
"DELETE"
|
|
267
|
+
]);
|
|
268
|
+
const buildQueryString = (query) => {
|
|
269
|
+
if (!query) return "";
|
|
270
|
+
const params = new URLSearchParams();
|
|
271
|
+
Object.entries(query).forEach(([key, value]) => {
|
|
272
|
+
if (value !== void 0 && value !== null) params.append(key, String(value));
|
|
273
|
+
});
|
|
274
|
+
const str = params.toString();
|
|
275
|
+
return str ? `?${str}` : "";
|
|
276
|
+
};
|
|
277
|
+
const buildUrl = (baseURL, url, query) => {
|
|
278
|
+
const queryString = buildQueryString(query);
|
|
279
|
+
if (url.startsWith("http://") || url.startsWith("https://")) return `${url}${queryString}`;
|
|
280
|
+
return `${baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL}${url.startsWith("/") ? url : `/${url}`}${queryString}`;
|
|
281
|
+
};
|
|
282
|
+
const prepareBody = (body) => {
|
|
283
|
+
if (body === null || body === void 0) return void 0;
|
|
284
|
+
if (body instanceof FormData || body instanceof Blob || body instanceof ArrayBuffer || body instanceof Uint8Array || typeof body === "string") return body;
|
|
285
|
+
if (typeof body === "object") return body;
|
|
286
|
+
return String(body);
|
|
287
|
+
};
|
|
288
|
+
const normalizeMethod = (method) => {
|
|
289
|
+
const upper = method.toUpperCase();
|
|
290
|
+
if (!HTTP_METHODS.has(upper)) throw new Error(`Unsupported HTTP method for WASM client: ${method}`);
|
|
291
|
+
return upper;
|
|
292
|
+
};
|
|
293
|
+
const getErrorStatus = (error) => {
|
|
294
|
+
if (error instanceof WasmWebClientError) return error.statusCode;
|
|
295
|
+
if (typeof error === "object" && error !== null) {
|
|
296
|
+
const record = error;
|
|
297
|
+
if (typeof record.statusCode === "number") return record.statusCode;
|
|
298
|
+
if (typeof record.status === "number") return record.status;
|
|
299
|
+
}
|
|
300
|
+
return 0;
|
|
301
|
+
};
|
|
302
|
+
const getErrorData = (error) => {
|
|
303
|
+
if (error instanceof WasmWebClientError) return error.response?.data ?? null;
|
|
304
|
+
return null;
|
|
305
|
+
};
|
|
306
|
+
const getErrorMessage = (error) => {
|
|
307
|
+
if (error instanceof Error) return error.message;
|
|
308
|
+
return "WasmWebClient request failed";
|
|
309
|
+
};
|
|
310
|
+
const withAbortSignal = async (promise, signal, error) => {
|
|
311
|
+
if (!signal) return await promise;
|
|
312
|
+
if (signal.aborted) throw error;
|
|
313
|
+
return await new Promise((resolve, reject) => {
|
|
314
|
+
const onAbort = () => reject(error);
|
|
315
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
316
|
+
promise.then(resolve, reject).finally(() => {
|
|
317
|
+
signal.removeEventListener("abort", onAbort);
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
};
|
|
321
|
+
const createWasmApi = async (config) => {
|
|
322
|
+
const headers = buildWasmDefaultHeaders(config.customHeaders);
|
|
323
|
+
const isEncryptionEnabled = config.isEncryptionEnabled ?? (() => false);
|
|
324
|
+
const useSha256 = config.mgf1 === "sha256";
|
|
325
|
+
await initializeWasmWebClient(config.wasm.wasmPath, config.wasm.wasmSimdPath ?? config.wasm.wasmPath, config.wasm.glueCodePath, config.wasm.glueCodeSimdPath ?? "", config.wasm.useSimd ?? true);
|
|
326
|
+
await setupWasmConnection(config.apiURL, "", config.encryptionEnabled ?? false, headers, useSha256);
|
|
327
|
+
const defaults = {
|
|
328
|
+
baseURL: config.apiURL,
|
|
329
|
+
headers
|
|
330
|
+
};
|
|
331
|
+
const client = {
|
|
332
|
+
defaults,
|
|
333
|
+
async request(requestConfig) {
|
|
334
|
+
const { method = "GET", url, headers: requestHeaders = {}, query, params, body, signal, timeout: timeoutOverride, onUploadProgress, ie = false } = requestConfig;
|
|
335
|
+
const upperMethod = normalizeMethod(method);
|
|
336
|
+
const requestParams = params ?? query;
|
|
337
|
+
const fullUrl = buildUrl(defaults.baseURL, url, requestParams);
|
|
338
|
+
const needsSchemeHeader = ie || useSha256 && isEncryptionEnabled();
|
|
339
|
+
const mergedHeaders = {
|
|
340
|
+
...defaults.headers,
|
|
341
|
+
...needsSchemeHeader ? { "X-RSA-Encryption-Scheme": RSA_OAEP_SHA256_SCHEME } : {},
|
|
342
|
+
...requestHeaders
|
|
343
|
+
};
|
|
344
|
+
const requestBody = prepareBody(body);
|
|
345
|
+
const timeout = timeoutOverride ?? config.timeout ?? WASM_TIMEOUT_CEILING_MS;
|
|
346
|
+
const wasmProgress = onUploadProgress ? (progress) => {
|
|
347
|
+
if (progress.total > 0) onUploadProgress(Math.round(progress.loaded / progress.total * 100));
|
|
348
|
+
} : void 0;
|
|
349
|
+
const abortError = new WasmHttpError(0, "Request aborted", fullUrl, upperMethod, {}, null);
|
|
350
|
+
if (signal?.aborted) throw abortError;
|
|
351
|
+
try {
|
|
352
|
+
const response = await withAbortSignal(executeWasmRequest(upperMethod, url, requestBody, mergedHeaders, requestParams, timeout, wasmProgress, ie), signal, abortError);
|
|
353
|
+
if (response.status < 200 || response.status >= 300) throw new WasmHttpError(response.status, "", fullUrl, upperMethod, {}, response.data);
|
|
354
|
+
return {
|
|
355
|
+
ok: true,
|
|
356
|
+
status: response.status,
|
|
357
|
+
statusText: "",
|
|
358
|
+
url: fullUrl,
|
|
359
|
+
headers: {},
|
|
360
|
+
data: response.data
|
|
361
|
+
};
|
|
362
|
+
} catch (error) {
|
|
363
|
+
if (error instanceof WasmHttpError) throw error;
|
|
364
|
+
throw new WasmHttpError(getErrorStatus(error), getErrorMessage(error), fullUrl, upperMethod, {}, getErrorData(error));
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
get(url, requestConfig) {
|
|
368
|
+
return client.request({
|
|
369
|
+
...requestConfig,
|
|
370
|
+
url,
|
|
371
|
+
method: "GET"
|
|
372
|
+
});
|
|
373
|
+
},
|
|
374
|
+
post(url, body, requestConfig) {
|
|
375
|
+
return client.request({
|
|
376
|
+
...requestConfig,
|
|
377
|
+
url,
|
|
378
|
+
body,
|
|
379
|
+
method: "POST"
|
|
380
|
+
});
|
|
381
|
+
},
|
|
382
|
+
put(url, body, requestConfig) {
|
|
383
|
+
return client.request({
|
|
384
|
+
...requestConfig,
|
|
385
|
+
url,
|
|
386
|
+
body,
|
|
387
|
+
method: "PUT"
|
|
388
|
+
});
|
|
389
|
+
},
|
|
390
|
+
patch(url, body, requestConfig) {
|
|
391
|
+
return client.request({
|
|
392
|
+
...requestConfig,
|
|
393
|
+
url,
|
|
394
|
+
body,
|
|
395
|
+
method: "PATCH"
|
|
396
|
+
});
|
|
397
|
+
},
|
|
398
|
+
delete(url, requestConfig) {
|
|
399
|
+
return client.request({
|
|
400
|
+
...requestConfig,
|
|
401
|
+
url,
|
|
402
|
+
method: "DELETE"
|
|
403
|
+
});
|
|
404
|
+
},
|
|
405
|
+
head() {
|
|
406
|
+
return Promise.reject(/* @__PURE__ */ new Error("HEAD is not supported by the WASM HTTP client"));
|
|
407
|
+
},
|
|
408
|
+
options() {
|
|
409
|
+
return Promise.reject(/* @__PURE__ */ new Error("OPTIONS is not supported by the WASM HTTP client"));
|
|
410
|
+
},
|
|
411
|
+
setHeader(name, value) {
|
|
412
|
+
defaults.headers[name] = value;
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
return client;
|
|
416
|
+
};
|
|
417
|
+
//#endregion
|
|
418
|
+
//#region src/internal/http/clientLifecycle.ts
|
|
419
|
+
/**
|
|
420
|
+
* Wraps the active HttpClient as a transport for the C++ `WebApi` host
|
|
421
|
+
* adapter. Lets the on-device face-results POST flow through the same
|
|
422
|
+
* `httpClient.request()` pipeline as every other endpoint — header
|
|
423
|
+
* injection, encryption-state handling, default headers, timeout — instead
|
|
424
|
+
* of bypassing it via `executeWasmRequest` directly.
|
|
425
|
+
*/
|
|
426
|
+
function bindWebApiTransport(client) {
|
|
427
|
+
return async (url, body, config) => {
|
|
428
|
+
const response = await client.request({
|
|
429
|
+
method: "POST",
|
|
430
|
+
url,
|
|
431
|
+
body,
|
|
432
|
+
headers: config.headers,
|
|
433
|
+
params: config.params,
|
|
434
|
+
timeout: config.timeout,
|
|
435
|
+
ie: config.ie
|
|
436
|
+
});
|
|
437
|
+
return {
|
|
438
|
+
data: response.data,
|
|
439
|
+
status: response.status
|
|
440
|
+
};
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
function installClient(client) {
|
|
444
|
+
setClient(client);
|
|
445
|
+
setWebApiHttpTransport(bindWebApiTransport(client));
|
|
446
|
+
}
|
|
447
|
+
let storedHttpConfig;
|
|
448
|
+
/** Reads the current HTTP-client config (or `undefined` if none installed). */
|
|
449
|
+
function getStoredHttpConfig() {
|
|
450
|
+
return storedHttpConfig;
|
|
451
|
+
}
|
|
452
|
+
/** Whether encryption is currently active on the installed HTTP client. */
|
|
453
|
+
function isHttpEncrypted() {
|
|
454
|
+
return storedHttpConfig?.encryption.enabled ?? false;
|
|
455
|
+
}
|
|
456
|
+
/** Clears all HTTP-client state. Called by `reset()`. */
|
|
457
|
+
function resetHttpClientState() {
|
|
458
|
+
storedHttpConfig = void 0;
|
|
459
|
+
setWebApiHttpTransport(null);
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Builds (or replaces) the HTTP client when `setup()` receives an `apiURL`.
|
|
463
|
+
* Picks `createWasmApi` when `effectiveWasm` is set, otherwise plain
|
|
464
|
+
* `createApi`. Wraps the call in handshake-failure context when encryption
|
|
465
|
+
* is requested.
|
|
466
|
+
*/
|
|
467
|
+
async function installFreshHttpClient(apiURL, options, effectiveWasm, encryption) {
|
|
468
|
+
installClient(effectiveWasm ? await withHandshakeFailureContext(encryption.enabled, () => createWasmApi({
|
|
469
|
+
apiURL,
|
|
470
|
+
customHeaders: options.customHeaders,
|
|
471
|
+
timeout: options.timeout,
|
|
472
|
+
wasm: effectiveWasm,
|
|
473
|
+
encryptionEnabled: encryption.enabled,
|
|
474
|
+
mgf1: encryption.mgf1,
|
|
475
|
+
isEncryptionEnabled: isHttpEncrypted
|
|
476
|
+
})) : createApi({
|
|
477
|
+
apiURL,
|
|
478
|
+
customHeaders: options.customHeaders,
|
|
479
|
+
timeout: options.timeout
|
|
480
|
+
}));
|
|
481
|
+
storedHttpConfig = {
|
|
482
|
+
apiURL,
|
|
483
|
+
customHeaders: options.customHeaders,
|
|
484
|
+
timeout: options.timeout,
|
|
485
|
+
isWasm: Boolean(effectiveWasm),
|
|
486
|
+
encryption
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Replaces the active HTTP client with the WASM-backed one. Used internally
|
|
491
|
+
* by lazy-loading UI components (`<incode-flow>`, `<incode-workflow>`) when
|
|
492
|
+
* WASM finishes warming up.
|
|
493
|
+
*
|
|
494
|
+
* No-op when no apiURL was previously configured, or when the active client
|
|
495
|
+
* is already WASM-backed. The encryption state (enabled + MGF1 scheme) is
|
|
496
|
+
* preserved across the swap — this is *not* a user-facing encryption change.
|
|
497
|
+
*
|
|
498
|
+
* @internal NOT a public API. Application code should use
|
|
499
|
+
* `setup({ wasm: {...} })` instead.
|
|
500
|
+
*/
|
|
501
|
+
async function upgradeToWasmHttpClient(resolved) {
|
|
502
|
+
const stored = storedHttpConfig;
|
|
503
|
+
if (!stored || stored.isWasm) return;
|
|
504
|
+
installClient(await createWasmApi({
|
|
505
|
+
apiURL: stored.apiURL,
|
|
506
|
+
customHeaders: stored.customHeaders,
|
|
507
|
+
timeout: stored.timeout,
|
|
508
|
+
wasm: resolved,
|
|
509
|
+
encryptionEnabled: stored.encryption.enabled,
|
|
510
|
+
mgf1: stored.encryption.mgf1,
|
|
511
|
+
isEncryptionEnabled: isHttpEncrypted
|
|
512
|
+
}));
|
|
513
|
+
storedHttpConfig = {
|
|
514
|
+
...stored,
|
|
515
|
+
isWasm: true
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* When `wantsEncryption` is true, wraps a call that triggers the in-binary
|
|
520
|
+
* RSA/AES handshake so its rejection surfaces as a single, descriptive error
|
|
521
|
+
* with the original error preserved as `cause`. Pass-through otherwise.
|
|
522
|
+
*/
|
|
523
|
+
async function withHandshakeFailureContext(wantsEncryption, fn) {
|
|
524
|
+
if (!wantsEncryption) return fn();
|
|
525
|
+
try {
|
|
526
|
+
return await fn();
|
|
527
|
+
} catch (cause) {
|
|
528
|
+
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.");
|
|
529
|
+
error.cause = cause;
|
|
530
|
+
throw error;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
/** Dirty-timer half of the interrupted-snapshot rebuild debounce (module boundaries + timer). */
|
|
534
|
+
const SNAPSHOT_DIRTY_INTERVAL_MS = 15e3;
|
|
535
|
+
/** Hard cap per log message, UTF-8 bytes (contract). */
|
|
536
|
+
const MESSAGE_MAX_BYTES = 8 * 1024;
|
|
537
|
+
const TRUESIGHT_SDK_ID = "IncdOnboarding";
|
|
538
|
+
/** localStorage key prefix for persisted sealed snapshots (A3: one slot per session). */
|
|
539
|
+
const PENDING_STORAGE_KEY_PREFIX = "incode.truesight.pending.";
|
|
540
|
+
//#endregion
|
|
541
|
+
//#region src/internal/trueSight/sanitize.ts
|
|
542
|
+
/**
|
|
543
|
+
* Deny-by-default message scrubber — runs at INGESTION (inside the log buffer's
|
|
544
|
+
* `append`), so the buffer, every persisted snapshot, and every upload are
|
|
545
|
+
* already clean; there is no code path around it (ENG-48677 plan §1.2).
|
|
546
|
+
*
|
|
547
|
+
* Ordered pipeline. Two deliberate deviations from the plan's original rule
|
|
548
|
+
* order, both from the P1-A adversarial review (2026-07-23, recorded in the
|
|
549
|
+
* plan's Operating-decisions section):
|
|
550
|
+
* - Inputs are pre-clamped to 2× the message cap BEFORE any regex runs — the
|
|
551
|
+
* unanchored patterns are quadratic on pathological non-matching runs
|
|
552
|
+
* (measured ~4.5 s on a 100 KB run), so regex cost must be bounded first.
|
|
553
|
+
* The final 8 KB cap still runs last.
|
|
554
|
+
* - The base64-blob rule runs BEFORE the digit-run rule — a digit run inside a
|
|
555
|
+
* blob would otherwise split it into sub-64-char fragments that escape
|
|
556
|
+
* redaction.
|
|
557
|
+
*
|
|
558
|
+
* The regex table ships in the P1-A PR description for privacy sign-off (see
|
|
559
|
+
* .agents/guides/privacy.md). Known hardening backlog (D4, Phase 4): formatted
|
|
560
|
+
* phone numbers, unicode digits/emails, fuzz/property tests.
|
|
561
|
+
*/
|
|
562
|
+
/** Three dot-joined base64url segments — JWT/JWS shape. */
|
|
563
|
+
const JWT_PATTERN = /\b[\w-]{8,}\.[\w-]{8,}\.[\w-]{8,}\b/g;
|
|
564
|
+
/**
|
|
565
|
+
* Credential-ish key with a `:`/`=` value (quoted, `Bearer …`, or bare token).
|
|
566
|
+
* The key may carry prefixes (`access_token`, `x-api-key`, `sessionToken`) —
|
|
567
|
+
* a plain \b boundary would miss `_token` since `_` is a word character.
|
|
568
|
+
*/
|
|
569
|
+
const CREDENTIAL_KV_PATTERN = /([\w-]*(?:token|api[-_]?key|authorization|auth|secret|password|passwd))\s*[:=]\s*("[^"]*"|'[^']*'|(?:Bearer\s+)?[^\s,;&]+)/gi;
|
|
570
|
+
/** Userinfo credentials in an absolute URL (`https://user:pass@host/…`). */
|
|
571
|
+
const URL_USERINFO_PATTERN = /(\bhttps?:\/\/)[^\s/@]*(?::[^\s/@]*)?@/gi;
|
|
572
|
+
/** Query string / fragment of an absolute URL — kills signed URLs. */
|
|
573
|
+
const URL_TAIL_PATTERN = /(https?:\/\/[^\s?#]+)[?#][^\s]*/g;
|
|
574
|
+
const EMAIL_PATTERN = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g;
|
|
575
|
+
/** base64-ish blobs (media, keys) — 64+ chars of the base64/base64url alphabet. */
|
|
576
|
+
const BASE64_BLOB_PATTERN = /[-A-Za-z0-9+/_]{64,}={0,2}/g;
|
|
577
|
+
/** Runs of 8+ digits — phones, CURP, document numbers. */
|
|
578
|
+
const DIGIT_RUN_PATTERN = /\d{8,}/g;
|
|
579
|
+
const TRUNCATION_SUFFIX = "…[truncated]";
|
|
580
|
+
/** Regex-cost bound: clamp raw input before any pattern runs (see header note). */
|
|
581
|
+
const REGEX_INPUT_MAX_BYTES = MESSAGE_MAX_BYTES * 2;
|
|
582
|
+
function sanitizeMessage(message) {
|
|
583
|
+
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);
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* UTF-8 byte length without TextEncoder (banned browser global in L1 —
|
|
587
|
+
* see the no-browser-api-in-core lint rule). Counts by code point.
|
|
588
|
+
*/
|
|
589
|
+
function utf8ByteLength(value) {
|
|
590
|
+
let bytes = 0;
|
|
591
|
+
for (const char of value) bytes += codePointByteLength(char);
|
|
592
|
+
return bytes;
|
|
593
|
+
}
|
|
594
|
+
function codePointByteLength(char) {
|
|
595
|
+
const codePoint = char.codePointAt(0) ?? 0;
|
|
596
|
+
if (codePoint < 128) return 1;
|
|
597
|
+
if (codePoint < 2048) return 2;
|
|
598
|
+
if (codePoint < 65536) return 3;
|
|
599
|
+
return 4;
|
|
600
|
+
}
|
|
601
|
+
/** Cuts on a code-point boundary so no surrogate half ever reaches the wire. */
|
|
602
|
+
function truncateUtf8(value, maxBytes) {
|
|
603
|
+
if (utf8ByteLength(value) <= maxBytes) return value;
|
|
604
|
+
const budget = maxBytes - utf8ByteLength(TRUNCATION_SUFFIX);
|
|
605
|
+
let bytes = 0;
|
|
606
|
+
let result = "";
|
|
607
|
+
for (const char of value) {
|
|
608
|
+
const charBytes = codePointByteLength(char);
|
|
609
|
+
if (bytes + charBytes > budget) break;
|
|
610
|
+
bytes += charBytes;
|
|
611
|
+
result += char;
|
|
612
|
+
}
|
|
613
|
+
return result + TRUNCATION_SUFFIX;
|
|
614
|
+
}
|
|
615
|
+
const EVICTION_ORDER = [
|
|
616
|
+
"verbose",
|
|
617
|
+
"debug",
|
|
618
|
+
"info"
|
|
619
|
+
];
|
|
620
|
+
function createLogBuffer(options = {}) {
|
|
621
|
+
const flushThresholdBytes = options.flushThresholdBytes ?? 6e5;
|
|
622
|
+
const maxEntries = options.maxEntries ?? 5e3;
|
|
623
|
+
const { onOverflow } = options;
|
|
624
|
+
const entries = [];
|
|
625
|
+
let mode = onOverflow ? "flush" : "evict";
|
|
626
|
+
let nextIndex = 0;
|
|
627
|
+
let bytes = 0;
|
|
628
|
+
let dropped = 0;
|
|
629
|
+
let overflowPending = false;
|
|
630
|
+
function entryCost(entry) {
|
|
631
|
+
return utf8ByteLength(entry.message) + utf8ByteLength(entry.subsystem) + 120;
|
|
632
|
+
}
|
|
633
|
+
function removeAt(position) {
|
|
634
|
+
const [removed] = entries.splice(position, 1);
|
|
635
|
+
bytes -= entryCost(removed);
|
|
636
|
+
dropped += 1;
|
|
637
|
+
}
|
|
638
|
+
/** Lowest level first (oldest within it); warning+ only as the last resort. */
|
|
639
|
+
function evictOne() {
|
|
640
|
+
for (const level of EVICTION_ORDER) {
|
|
641
|
+
const position = entries.findIndex((entry) => entry.level === level);
|
|
642
|
+
if (position !== -1) {
|
|
643
|
+
removeAt(position);
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
removeAt(0);
|
|
648
|
+
}
|
|
649
|
+
function copyOf(entry) {
|
|
650
|
+
return { ...entry };
|
|
651
|
+
}
|
|
652
|
+
return {
|
|
653
|
+
append(level, subsystem, category, message) {
|
|
654
|
+
const entry = {
|
|
655
|
+
index: nextIndex,
|
|
656
|
+
timestampMs: getTimestamp(),
|
|
657
|
+
level,
|
|
658
|
+
subsystem,
|
|
659
|
+
category,
|
|
660
|
+
message: sanitizeMessage(message)
|
|
661
|
+
};
|
|
662
|
+
nextIndex += 1;
|
|
663
|
+
entries.push(entry);
|
|
664
|
+
bytes += entryCost(entry);
|
|
665
|
+
if (mode === "flush" && onOverflow) {
|
|
666
|
+
if (!overflowPending && bytes >= flushThresholdBytes) {
|
|
667
|
+
overflowPending = true;
|
|
668
|
+
onOverflow(entries.map(copyOf));
|
|
669
|
+
}
|
|
670
|
+
} else while (bytes > flushThresholdBytes && entries.length > 1) evictOne();
|
|
671
|
+
while (entries.length > maxEntries) evictOne();
|
|
672
|
+
},
|
|
673
|
+
snapshot() {
|
|
674
|
+
return entries.map(copyOf);
|
|
675
|
+
},
|
|
676
|
+
sliceSince(index) {
|
|
677
|
+
return entries.filter((entry) => entry.index > index).map(copyOf);
|
|
678
|
+
},
|
|
679
|
+
markFlushed(uptoIndex) {
|
|
680
|
+
let removedBytes = 0;
|
|
681
|
+
let keepFrom = 0;
|
|
682
|
+
while (keepFrom < entries.length && entries[keepFrom].index <= uptoIndex) {
|
|
683
|
+
removedBytes += entryCost(entries[keepFrom]);
|
|
684
|
+
keepFrom += 1;
|
|
685
|
+
}
|
|
686
|
+
entries.splice(0, keepFrom);
|
|
687
|
+
bytes -= removedBytes;
|
|
688
|
+
overflowPending = false;
|
|
689
|
+
},
|
|
690
|
+
setOverflowMode(next) {
|
|
691
|
+
mode = next;
|
|
692
|
+
},
|
|
693
|
+
get droppedCount() {
|
|
694
|
+
return dropped;
|
|
695
|
+
},
|
|
696
|
+
get byteEstimate() {
|
|
697
|
+
return bytes;
|
|
698
|
+
}
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
//#endregion
|
|
702
|
+
//#region ../infra/src/crypto/randomUUID.ts
|
|
703
|
+
/**
|
|
704
|
+
* Cryptographically-strong UUID v4 (RFC 4122).
|
|
705
|
+
*
|
|
706
|
+
* Lives in infra (L0) so Core (L1) can mint secure identifiers without touching
|
|
707
|
+
* the `crypto` browser API directly — Core delegates here, keeping it free of
|
|
708
|
+
* browser globals (enforced by the `no-browser-api-in-core` lint rule). Backed
|
|
709
|
+
* by `crypto.randomUUID`, available in every browser the SDK targets.
|
|
710
|
+
*/
|
|
711
|
+
function randomUUID() {
|
|
712
|
+
return crypto.randomUUID();
|
|
713
|
+
}
|
|
714
|
+
//#endregion
|
|
715
|
+
//#region ../infra/src/time/epochMsToIsoString.ts
|
|
716
|
+
/**
|
|
717
|
+
* Converts an epoch-milliseconds timestamp to a full ISO-8601 UTC string
|
|
718
|
+
* (e.g. `2026-07-23T09:41:00.000Z`).
|
|
719
|
+
*
|
|
720
|
+
* Lives in Infra (L0) so Core can format wire timestamps without touching the
|
|
721
|
+
* `Date` global directly — banned in Core by the `no-browser-api-in-core` lint
|
|
722
|
+
* rule — mirroring the `crypto/randomUUID.ts` free-function precedent.
|
|
723
|
+
* (`DateFormattingProvider.utcToIsoDateString` is date-only and not suitable.)
|
|
724
|
+
*/
|
|
725
|
+
function epochMsToIsoString(epochMs) {
|
|
726
|
+
return new Date(epochMs).toISOString();
|
|
727
|
+
}
|
|
728
|
+
//#endregion
|
|
729
|
+
//#region src/internal/version/sdkVersion.ts
|
|
730
|
+
const SDK_VERSION = "2.2.0-rc.0";
|
|
731
|
+
//#endregion
|
|
732
|
+
//#region src/internal/trueSight/recordBuilder.ts
|
|
733
|
+
/**
|
|
734
|
+
* Assembles the exact plaintext contract record — the ONLY place a diagnostics
|
|
735
|
+
* payload is shaped. Pure: same function serves final records, interrupted
|
|
736
|
+
* snapshots, and future incremental slices (ENG-48677 plan §1.1).
|
|
737
|
+
*
|
|
738
|
+
* Deny-by-default is structural here: every field is an explicit literal —
|
|
739
|
+
* nothing is spread from internal state, so no unexpected field can ever leak
|
|
740
|
+
* into an upload.
|
|
741
|
+
*
|
|
742
|
+
* Hard gates enforced:
|
|
743
|
+
* - empty/missing `sessionId` or `startedAt` → returns `null` (upload skipped —
|
|
744
|
+
* expected for sessions that die before `/omni/start`).
|
|
745
|
+
* - `failureReason` present if-and-only-if `outcome === 'failure'` (defaults to
|
|
746
|
+
* `'unknown'` when a failure arrives without one, rather than dropping the record).
|
|
747
|
+
* - fresh record `id` per build; `endedAt` stamped at build time.
|
|
748
|
+
*/
|
|
749
|
+
function buildDiagnosticsRecord(meta, logs, outcome, failureReason, recordId) {
|
|
750
|
+
if (!meta.sessionId || meta.startedAtMs === null) return null;
|
|
751
|
+
const flowType = meta.flowType ?? deriveFlowTypeFromSurface(meta.integrationType);
|
|
752
|
+
if (flowType === null) return null;
|
|
753
|
+
return {
|
|
754
|
+
schemaVersion: "1.0",
|
|
755
|
+
id: recordId ?? randomUUID(),
|
|
756
|
+
session: {
|
|
757
|
+
sessionId: meta.sessionId,
|
|
758
|
+
sdkId: TRUESIGHT_SDK_ID,
|
|
759
|
+
sdkVersion: SDK_VERSION,
|
|
760
|
+
platform: "web",
|
|
761
|
+
sdkMode: null,
|
|
762
|
+
browser: meta.browser,
|
|
763
|
+
osVersion: meta.osVersion,
|
|
764
|
+
osLanguage: meta.osLanguage,
|
|
765
|
+
sdkLanguage: meta.sdkLanguage,
|
|
766
|
+
integrationType: meta.integrationType,
|
|
767
|
+
flowType,
|
|
768
|
+
flowId: meta.flowId,
|
|
769
|
+
workflowId: meta.workflowId,
|
|
770
|
+
outcome,
|
|
771
|
+
...outcome === "failure" ? { failureReason: failureReason ?? "unknown" } : {},
|
|
772
|
+
startedAt: epochMsToIsoString(meta.startedAtMs),
|
|
773
|
+
endedAt: epochMsToIsoString(getTimestamp()),
|
|
774
|
+
testing: meta.testing,
|
|
775
|
+
e2eEncryptionEnabled: meta.e2eEncryptionEnabled,
|
|
776
|
+
configurationId: meta.hasConfigurationId,
|
|
777
|
+
externalCustomerId: meta.hasExternalCustomerId,
|
|
778
|
+
hasProvidedSessionId: meta.hasProvidedSessionId,
|
|
779
|
+
token: meta.hasToken,
|
|
780
|
+
externalToken: meta.hasExternalToken
|
|
781
|
+
},
|
|
782
|
+
logs: logs.map(toContractEntry)
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Wire `flowType` when no orchestrator was OBSERVED (an observed one — set by
|
|
787
|
+
* the bridge on any flow event — always wins). Stage ingest requires a
|
|
788
|
+
* non-null enum (probe 2026-07-23: null/omitted/off-enum all 400), so the
|
|
789
|
+
* entry surface decides, and the mapping is deliberately exhaustive:
|
|
790
|
+
*
|
|
791
|
+
* - `startWorkflow` → 'workflow' (Webflows engine entered, died pre-ready)
|
|
792
|
+
* - `startFlow` → 'flow' (flow/orchestrated manager, died pre-ready)
|
|
793
|
+
* - `startOnboarding`→ 'flow' (self-loading UI wraps the flow engine)
|
|
794
|
+
* - `startOnboardingSection` → null → the BUILD ABORTS (record withheld):
|
|
795
|
+
* a standalone session has no truthful flowType, and mislabeling it as a
|
|
796
|
+
* flow session is worse than skipping the upload. Withheld until the
|
|
797
|
+
* DECIDED BE ask ships (`flowType:"standalone"`, not nullable) — then this
|
|
798
|
+
* branch returns 'standalone' and standalone diagnostics start flowing,
|
|
799
|
+
* coordinated with the BE deploy since off-enum values 400 today.
|
|
800
|
+
*/
|
|
801
|
+
function deriveFlowTypeFromSurface(integrationType) {
|
|
802
|
+
switch (integrationType) {
|
|
803
|
+
case "startWorkflow": return "workflow";
|
|
804
|
+
case "startFlow":
|
|
805
|
+
case "startOnboarding": return "flow";
|
|
806
|
+
case "startOnboardingSection": return null;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
function toContractEntry(entry) {
|
|
810
|
+
return {
|
|
811
|
+
index: entry.index,
|
|
812
|
+
timestamp: epochMsToIsoString(entry.timestampMs),
|
|
813
|
+
level: entry.level,
|
|
814
|
+
thread: "main",
|
|
815
|
+
message: entry.message,
|
|
816
|
+
subsystem: entry.subsystem,
|
|
817
|
+
category: entry.category
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
//#endregion
|
|
821
|
+
//#region src/internal/trueSight/sessionMetadata.ts
|
|
822
|
+
/**
|
|
823
|
+
* Hosts that match this pattern are non-prod by heuristic. Known failure modes
|
|
824
|
+
* (customer CNAMEs, devMode left on in prod) are documented for the planned
|
|
825
|
+
* P1 team review — see plan §Operating decisions (B6).
|
|
826
|
+
*/
|
|
827
|
+
const NON_PROD_HOST_PATTERN = /stage|demo|saas-dev|localhost/i;
|
|
828
|
+
function createInitialState() {
|
|
829
|
+
return {
|
|
830
|
+
sessionId: null,
|
|
831
|
+
startedAtMs: null,
|
|
832
|
+
browser: null,
|
|
833
|
+
osVersion: null,
|
|
834
|
+
osLanguage: null,
|
|
835
|
+
sdkLanguage: "en-US",
|
|
836
|
+
integrationType: "startOnboardingSection",
|
|
837
|
+
flowType: null,
|
|
838
|
+
flowId: null,
|
|
839
|
+
workflowId: null,
|
|
840
|
+
testing: false,
|
|
841
|
+
devModeSignal: void 0,
|
|
842
|
+
apiUrlSignal: void 0,
|
|
843
|
+
hasConfigurationId: false,
|
|
844
|
+
hasExternalCustomerId: false,
|
|
845
|
+
hasProvidedSessionId: false,
|
|
846
|
+
hasExternalToken: false
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
let state = createInitialState();
|
|
850
|
+
let sources = {};
|
|
851
|
+
function stampStartedAtOnce() {
|
|
852
|
+
if (state.startedAtMs === null) state.startedAtMs = getTimestamp();
|
|
853
|
+
}
|
|
854
|
+
/** Tap for `createSession` — sessionId comes from the returned `interviewId`. */
|
|
855
|
+
function noteSessionCreated(session, options = {}) {
|
|
856
|
+
if (session.interviewId) state.sessionId = session.interviewId;
|
|
857
|
+
stampStartedAtOnce();
|
|
858
|
+
state.sdkLanguage = options.language ?? state.sdkLanguage;
|
|
859
|
+
state.hasConfigurationId = state.hasConfigurationId || options.configurationId !== void 0;
|
|
860
|
+
state.hasExternalCustomerId = state.hasExternalCustomerId || options.externalCustomerId !== void 0;
|
|
861
|
+
state.hasProvidedSessionId = state.hasProvidedSessionId || options.interviewId !== void 0;
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* Fallback sessionId for host-minted-token integrations that never called
|
|
865
|
+
* `createSession`: `Features.sessionIdentifier` — used only when no
|
|
866
|
+
* `interviewId` was observed.
|
|
867
|
+
*/
|
|
868
|
+
function noteFeatureConfig(features) {
|
|
869
|
+
if (!state.sessionId && features.sessionIdentifier) {
|
|
870
|
+
state.sessionId = features.sessionIdentifier;
|
|
871
|
+
stampStartedAtOnce();
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* Entry-surface discriminator. `startOnboardingSection` is the default (weakest
|
|
876
|
+
* signal — standalone module managers); richer surfaces upgrade it and are never
|
|
877
|
+
* downgraded back.
|
|
878
|
+
*/
|
|
879
|
+
function noteIntegrationSurface(integrationType) {
|
|
880
|
+
if (integrationType === "startOnboardingSection") return;
|
|
881
|
+
state.integrationType = integrationType;
|
|
882
|
+
}
|
|
883
|
+
function noteEnvironment(environment) {
|
|
884
|
+
state.browser = environment.browser ?? state.browser;
|
|
885
|
+
state.osVersion = environment.osVersion ?? state.osVersion;
|
|
886
|
+
state.osLanguage = environment.osLanguage ?? state.osLanguage;
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* WRITE-ONCE orchestrator identity (determinism guarantee for debugging):
|
|
890
|
+
* a session is a flow or a workflow from its first orchestrator observation
|
|
891
|
+
* and can never flip mid-session — a record labeled `flow` must always point
|
|
892
|
+
* at a real flow. First non-null value wins for each of flowType/flowId/
|
|
893
|
+
* workflowId; later calls are ignored (the service logs a self-health line
|
|
894
|
+
* when a CONFLICTING orchestrator kind shows up).
|
|
895
|
+
*/
|
|
896
|
+
function noteFlowContext(context) {
|
|
897
|
+
state.flowType = state.flowType ?? context.flowType;
|
|
898
|
+
state.flowId = state.flowId ?? context.flowId ?? null;
|
|
899
|
+
state.workflowId = state.workflowId ?? context.workflowId ?? null;
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* `testing` heuristic: devMode OR non-prod API host pattern. Always a boolean —
|
|
903
|
+
* the contract requires the field present on every record. Signals MERGE across
|
|
904
|
+
* calls (a later apiUrl-only call must not erase an earlier devMode signal);
|
|
905
|
+
* `testing` is recomputed from the merged pair.
|
|
906
|
+
*/
|
|
907
|
+
function noteTestingSignals(signals) {
|
|
908
|
+
state.devModeSignal = signals.devMode ?? state.devModeSignal;
|
|
909
|
+
state.apiUrlSignal = signals.apiUrl ?? state.apiUrlSignal;
|
|
910
|
+
state.testing = state.devModeSignal === true || state.apiUrlSignal !== void 0 && NON_PROD_HOST_PATTERN.test(state.apiUrlSignal);
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Live read of the merged testing signal (devMode OR non-prod host). Used to
|
|
914
|
+
* gate host-console self-health noise so production host pages stay quiet while
|
|
915
|
+
* staging/dev keeps the console signal (the record always captures it either
|
|
916
|
+
* way via `trueSightLog`). Same signal the overflow-flush staging gate uses.
|
|
917
|
+
*/
|
|
918
|
+
function isTrueSightTesting() {
|
|
919
|
+
return state.testing;
|
|
920
|
+
}
|
|
921
|
+
/**
|
|
922
|
+
* Tap for `initializeSession({ token })` with a host-minted token — records
|
|
923
|
+
* only the presence fact ("this token came from outside the SDK"), never the
|
|
924
|
+
* token itself.
|
|
925
|
+
*/
|
|
926
|
+
function noteExternalTokenProvided() {
|
|
927
|
+
state.hasExternalToken = true;
|
|
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
|
+
if (state.sessionId === null) noteExternalTokenProvided();
|
|
937
|
+
}
|
|
938
|
+
function configureTrueSightMetadataSources(next) {
|
|
939
|
+
sources = next;
|
|
940
|
+
}
|
|
941
|
+
/** Explicit literal — the metadata half handed to the record builder. */
|
|
942
|
+
function buildSessionMetadata() {
|
|
943
|
+
return {
|
|
944
|
+
sessionId: state.sessionId,
|
|
945
|
+
startedAtMs: state.startedAtMs,
|
|
946
|
+
browser: state.browser,
|
|
947
|
+
osVersion: state.osVersion,
|
|
948
|
+
osLanguage: state.osLanguage,
|
|
949
|
+
sdkLanguage: state.sdkLanguage,
|
|
950
|
+
integrationType: state.integrationType,
|
|
951
|
+
flowType: state.flowType,
|
|
952
|
+
flowId: state.flowId,
|
|
953
|
+
workflowId: state.workflowId,
|
|
954
|
+
testing: state.testing,
|
|
955
|
+
e2eEncryptionEnabled: readE2eEncryptionEnabled(),
|
|
956
|
+
hasConfigurationId: state.hasConfigurationId,
|
|
957
|
+
hasExternalCustomerId: state.hasExternalCustomerId,
|
|
958
|
+
hasProvidedSessionId: state.hasProvidedSessionId,
|
|
959
|
+
hasToken: readHasToken(),
|
|
960
|
+
hasExternalToken: state.hasExternalToken
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
/** Fail-open: diagnostics must never throw into the host flow. */
|
|
964
|
+
function readE2eEncryptionEnabled() {
|
|
965
|
+
try {
|
|
966
|
+
return sources.getE2eEncryptionEnabled?.() ?? false;
|
|
967
|
+
} catch {
|
|
968
|
+
return false;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
/** Fail-open, like readE2eEncryptionEnabled. */
|
|
972
|
+
function readHasToken() {
|
|
973
|
+
try {
|
|
974
|
+
return sources.getHasToken?.() ?? false;
|
|
975
|
+
} catch {
|
|
976
|
+
return false;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
function resetTrueSightMetadata() {
|
|
980
|
+
state = createInitialState();
|
|
981
|
+
sources = {};
|
|
982
|
+
}
|
|
983
|
+
//#endregion
|
|
984
|
+
//#region src/internal/trueSight/pendingEnvelopeStore.ts
|
|
985
|
+
/** Index slot listing sessionIds with pending entries (no enumeration API). */
|
|
986
|
+
const PENDING_INDEX_KEY = `${PENDING_STORAGE_KEY_PREFIX}index`;
|
|
987
|
+
function slotKey(sessionId) {
|
|
988
|
+
return `${PENDING_STORAGE_KEY_PREFIX}${sessionId}`;
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* Adds the session to the pending index. Called once at collection start —
|
|
992
|
+
* long before any page-hide — so the hide path never needs the index
|
|
993
|
+
* read-modify-write and stays a single synchronous-effective write.
|
|
994
|
+
*/
|
|
995
|
+
async function registerPendingSlot(sessionId, deps) {
|
|
996
|
+
try {
|
|
997
|
+
const index = await readIndex(deps.storage);
|
|
998
|
+
if (index.includes(sessionId)) return;
|
|
999
|
+
await deps.storage.set(PENDING_INDEX_KEY, [...index, sessionId]);
|
|
1000
|
+
} catch {}
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Writes the sealed snapshot into the session's slot. `BrowserStorageProvider`
|
|
1004
|
+
* executes the underlying `localStorage.setItem` synchronously in the first
|
|
1005
|
+
* slice of the async call, which is what makes this safe to fire (void) from
|
|
1006
|
+
* a page-hide handler.
|
|
1007
|
+
*/
|
|
1008
|
+
async function writePendingEnvelope(sessionId, entry, deps) {
|
|
1009
|
+
try {
|
|
1010
|
+
await deps.storage.set(slotKey(sessionId), entry);
|
|
1011
|
+
} catch {}
|
|
1012
|
+
}
|
|
1013
|
+
/** Removes the entry and its index membership (terminal upload dispatched). */
|
|
1014
|
+
async function clearPending(sessionId, deps) {
|
|
1015
|
+
try {
|
|
1016
|
+
await deps.storage.remove(slotKey(sessionId));
|
|
1017
|
+
const index = await readIndex(deps.storage);
|
|
1018
|
+
if (index.includes(sessionId)) await deps.storage.set(PENDING_INDEX_KEY, index.filter((candidate) => candidate !== sessionId));
|
|
1019
|
+
} catch {}
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* Next-load recovery, invoked from the first-token-observed hook (A1 — never
|
|
1023
|
+
* at `setup()`, which has no auth). For each foreign, old-enough entry: the
|
|
1024
|
+
* slot is cleared AT DISPATCH, then the envelope is posted fire-and-forget —
|
|
1025
|
+
* no 200-tracking, no retries (A2; a crash between clear and fire loses that
|
|
1026
|
+
* record, consistent with no-retry). Entries at/past the retention ceiling
|
|
1027
|
+
* are deleted unsent (A4). Never rejects; returns the A5 loss counters.
|
|
1028
|
+
*/
|
|
1029
|
+
async function recoverPendingEnvelopes(options) {
|
|
1030
|
+
const { storage, post, currentSessionId } = options;
|
|
1031
|
+
const now = options.now ?? getTimestamp;
|
|
1032
|
+
const counters = {
|
|
1033
|
+
recovered: 0,
|
|
1034
|
+
gcExpired: 0
|
|
1035
|
+
};
|
|
1036
|
+
try {
|
|
1037
|
+
const index = await readIndex(storage);
|
|
1038
|
+
if (index.length === 0) return counters;
|
|
1039
|
+
const keptInIndex = [];
|
|
1040
|
+
for (const sessionId of index) {
|
|
1041
|
+
if (sessionId === currentSessionId) {
|
|
1042
|
+
keptInIndex.push(sessionId);
|
|
1043
|
+
continue;
|
|
1044
|
+
}
|
|
1045
|
+
const entry = await readEntry(storage, sessionId);
|
|
1046
|
+
if (entry === "missing") continue;
|
|
1047
|
+
if (entry === "corrupt") {
|
|
1048
|
+
counters.gcExpired += 1;
|
|
1049
|
+
continue;
|
|
1050
|
+
}
|
|
1051
|
+
const age = now() - entry.persistedAt;
|
|
1052
|
+
if (age >= 6048e5) {
|
|
1053
|
+
counters.gcExpired += 1;
|
|
1054
|
+
await storage.remove(slotKey(sessionId));
|
|
1055
|
+
continue;
|
|
1056
|
+
}
|
|
1057
|
+
if (age < 12e4) {
|
|
1058
|
+
keptInIndex.push(sessionId);
|
|
1059
|
+
continue;
|
|
1060
|
+
}
|
|
1061
|
+
await storage.remove(slotKey(sessionId));
|
|
1062
|
+
counters.recovered += 1;
|
|
1063
|
+
post(endpoints.diagnosticsData, entry.envelope, {}).catch(() => {});
|
|
1064
|
+
}
|
|
1065
|
+
await storage.set(PENDING_INDEX_KEY, keptInIndex);
|
|
1066
|
+
} catch {}
|
|
1067
|
+
return counters;
|
|
1068
|
+
}
|
|
1069
|
+
async function readIndex(storage) {
|
|
1070
|
+
const index = await storage.get(PENDING_INDEX_KEY);
|
|
1071
|
+
if (!Array.isArray(index)) return [];
|
|
1072
|
+
return index.filter((value) => typeof value === "string");
|
|
1073
|
+
}
|
|
1074
|
+
/** Reads one entry; malformed slots are pruned and reported as corrupt. */
|
|
1075
|
+
async function readEntry(storage, sessionId) {
|
|
1076
|
+
try {
|
|
1077
|
+
const value = await storage.get(slotKey(sessionId));
|
|
1078
|
+
if (value === null) return "missing";
|
|
1079
|
+
if (typeof value === "object" && value.v === 1 && typeof value.persistedAt === "number" && typeof value.envelope === "object") return value;
|
|
1080
|
+
await storage.remove(slotKey(sessionId));
|
|
1081
|
+
return "corrupt";
|
|
1082
|
+
} catch {
|
|
1083
|
+
try {
|
|
1084
|
+
await storage.remove(slotKey(sessionId));
|
|
1085
|
+
} catch {}
|
|
1086
|
+
return "corrupt";
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
//#endregion
|
|
1090
|
+
//#region src/internal/featureConfig/featureConfigService.ts
|
|
1091
|
+
let cachedFeatures = null;
|
|
1092
|
+
/**
|
|
1093
|
+
* Checks if a feature is enabled in the feature config.
|
|
1094
|
+
*/
|
|
1095
|
+
function isFeatureEnabled(feature, features) {
|
|
1096
|
+
return features?.find((f) => f.feature === feature)?.enabled ?? false;
|
|
1097
|
+
}
|
|
1098
|
+
/**
|
|
1099
|
+
* Fetches feature configuration from the backend.
|
|
1100
|
+
* Results are cached for the session lifetime.
|
|
1101
|
+
*/
|
|
1102
|
+
async function fetchFeatureConfig(signal) {
|
|
1103
|
+
if (cachedFeatures) return cachedFeatures;
|
|
1104
|
+
const response = await api.get(endpoints.featureConfig, { signal });
|
|
1105
|
+
if (!response.ok) throw new Error(`Failed to fetch feature config: ${response.status} ${response.statusText}`);
|
|
1106
|
+
cachedFeatures = response.data;
|
|
1107
|
+
return cachedFeatures;
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Resets the cached feature config (useful for testing).
|
|
1111
|
+
*/
|
|
1112
|
+
function resetFeatureConfigCache() {
|
|
1113
|
+
cachedFeatures = null;
|
|
1114
|
+
}
|
|
1115
|
+
//#endregion
|
|
1116
|
+
//#region src/internal/trueSight/eventBridge.ts
|
|
1117
|
+
/**
|
|
1118
|
+
* Canonical subsystem registry (plan §Subsystem registry): one stable
|
|
1119
|
+
* lowercase dotted string per SDK area. The raw `eventModuleNames` wire
|
|
1120
|
+
* values are inconsistent (`SELFIE`, `datasharingconsent`, `AdSign`…), four
|
|
1121
|
+
* keys collapse into `ID`, and `workflow` doubles as a module name — this
|
|
1122
|
+
* table is the single normalization point, snapshot-frozen in tests so the
|
|
1123
|
+
* dashboard facet stays bounded (~70 strings) forever.
|
|
1124
|
+
*/
|
|
1125
|
+
const MODULE_SUBSYSTEMS = {
|
|
1126
|
+
[eventModuleNames.selfie]: "module.selfie",
|
|
1127
|
+
[eventModuleNames.faceCapture]: "module.face-capture",
|
|
1128
|
+
[eventModuleNames.authentication]: "module.authentication",
|
|
1129
|
+
[eventModuleNames.authFace]: "module.auth-face",
|
|
1130
|
+
[eventModuleNames.mlConsent]: "module.ml-consent",
|
|
1131
|
+
[eventModuleNames.combinedConsent]: "module.combined-consent",
|
|
1132
|
+
[eventModuleNames.curpValidation]: "module.curp",
|
|
1133
|
+
[eventModuleNames.faceMatch]: "module.face-match",
|
|
1134
|
+
[eventModuleNames.qr]: "module.qr",
|
|
1135
|
+
[eventModuleNames.videoSelfie]: "module.video-selfie",
|
|
1136
|
+
[eventModuleNames.id]: "module.id",
|
|
1137
|
+
[eventModuleNames.idCapture]: "module.id-capture",
|
|
1138
|
+
[eventModuleNames.idVerification]: "module.id-verification",
|
|
1139
|
+
[eventModuleNames.idOcr]: "module.id-ocr",
|
|
1140
|
+
[eventModuleNames.document]: "module.document-capture",
|
|
1141
|
+
[eventModuleNames.creditCard]: "module.credit-card-front",
|
|
1142
|
+
[eventModuleNames.creditCardBack]: "module.credit-card-back",
|
|
1143
|
+
[eventModuleNames.conference]: "module.conference",
|
|
1144
|
+
[eventModuleNames.otp]: "module.otp",
|
|
1145
|
+
[eventModuleNames.signature]: "module.e-sign",
|
|
1146
|
+
[eventModuleNames.ekyc]: "module.e-kyc",
|
|
1147
|
+
[eventModuleNames.watchlist]: "module.watchlist",
|
|
1148
|
+
[eventModuleNames.globalWatchList]: "module.global-watchlist",
|
|
1149
|
+
[eventModuleNames.customWatchList]: "module.custom-watchlist",
|
|
1150
|
+
[eventModuleNames.email]: "module.email",
|
|
1151
|
+
[eventModuleNames.phone]: "module.phone-number",
|
|
1152
|
+
[eventModuleNames.instantVerifyEmail]: "module.instant-verify-email",
|
|
1153
|
+
[eventModuleNames.instantVerifyConsent]: "module.instant-verify-consent",
|
|
1154
|
+
[eventModuleNames.forms]: "module.forms",
|
|
1155
|
+
[eventModuleNames.customModule]: "module.custom-module",
|
|
1156
|
+
[eventModuleNames.geolocation]: "module.geolocation",
|
|
1157
|
+
[eventModuleNames.ekyb]: "module.e-kyb",
|
|
1158
|
+
[eventModuleNames.identityReuse]: "module.identity-reuse",
|
|
1159
|
+
[eventModuleNames.antifraud]: "module.antifraud",
|
|
1160
|
+
[eventModuleNames.aeSignature]: "module.ae-signature",
|
|
1161
|
+
[eventModuleNames.qeSignature]: "module.qe-signature",
|
|
1162
|
+
[eventModuleNames.crossDocumentDataMatch]: "module.cross-document-data-match",
|
|
1163
|
+
[eventModuleNames.customFields]: "module.custom-fields",
|
|
1164
|
+
[eventModuleNames.fieldComparison]: "module.field-comparison",
|
|
1165
|
+
[eventModuleNames.personhood]: "module.personhood",
|
|
1166
|
+
[eventModuleNames.watchlistForBusiness]: "module.watchlist-for-business",
|
|
1167
|
+
[eventModuleNames.trustGraph]: "module.trust-graph",
|
|
1168
|
+
[eventModuleNames.certificateIssuance]: "module.certificate-issuance",
|
|
1169
|
+
[eventModuleNames.governmentValidation]: "module.government-validation",
|
|
1170
|
+
[eventModuleNames.documentUpload]: "module.document-upload",
|
|
1171
|
+
[eventModuleNames.home]: "module.home",
|
|
1172
|
+
[eventModuleNames.workflow]: "module.workflow",
|
|
1173
|
+
[eventModuleNames.fiscalQr]: "module.fiscal-qr"
|
|
1174
|
+
};
|
|
1175
|
+
const CUSTOM_SUBSYSTEM_MAX_CHARS = 40;
|
|
1176
|
+
/**
|
|
1177
|
+
* Canonical `module.<kebab>` for a raw wire module name. Unknown/integrator-
|
|
1178
|
+
* custom names get a sanitized lowercase fallback (capped) — custom SDK 2
|
|
1179
|
+
* integrations get real per-module detail, not a lumped `other`.
|
|
1180
|
+
*/
|
|
1181
|
+
function normalizeSubsystem(rawModule) {
|
|
1182
|
+
if (rawModule === void 0) return "module.unknown";
|
|
1183
|
+
const canonical = MODULE_SUBSYSTEMS[rawModule];
|
|
1184
|
+
if (canonical !== void 0) return canonical;
|
|
1185
|
+
const sanitized = rawModule.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, CUSTOM_SUBSYSTEM_MAX_CHARS).replace(/-+$/g, "");
|
|
1186
|
+
return `module.${sanitized === "" ? "unknown" : sanitized}`;
|
|
1187
|
+
}
|
|
1188
|
+
const ID_SCAN_MODULES = /* @__PURE__ */ new Set([
|
|
1189
|
+
eventModuleNames.id,
|
|
1190
|
+
eventModuleNames.idCapture,
|
|
1191
|
+
eventModuleNames.idVerification,
|
|
1192
|
+
eventModuleNames.idOcr,
|
|
1193
|
+
eventModuleNames.document,
|
|
1194
|
+
eventModuleNames.documentUpload,
|
|
1195
|
+
eventModuleNames.creditCard,
|
|
1196
|
+
eventModuleNames.creditCardBack,
|
|
1197
|
+
eventModuleNames.curpValidation
|
|
1198
|
+
]);
|
|
1199
|
+
const FACE_SCAN_MODULES = /* @__PURE__ */ new Set([
|
|
1200
|
+
eventModuleNames.selfie,
|
|
1201
|
+
eventModuleNames.faceCapture,
|
|
1202
|
+
eventModuleNames.authentication,
|
|
1203
|
+
eventModuleNames.authFace,
|
|
1204
|
+
eventModuleNames.faceMatch,
|
|
1205
|
+
eventModuleNames.videoSelfie,
|
|
1206
|
+
eventModuleNames.personhood
|
|
1207
|
+
]);
|
|
1208
|
+
const ORCHESTRATION_MODULES = /* @__PURE__ */ new Set([eventModuleNames.home, eventModuleNames.workflow]);
|
|
1209
|
+
/**
|
|
1210
|
+
* Coarse category for HTTP-failure entries, from the endpoint path (event
|
|
1211
|
+
* map row 23: "by endpoint"). A conservative token heuristic — the category
|
|
1212
|
+
* is coarse by contract, so near-misses fall to `other`, never to a wrong
|
|
1213
|
+
* scan bucket.
|
|
1214
|
+
*/
|
|
1215
|
+
function categoryForEndpoint(endpoint) {
|
|
1216
|
+
if (/face|selfie|video|speech|personhood|authenticate|recordings/.test(endpoint)) return "faceScan";
|
|
1217
|
+
if (/front-id|back-id|second-id|process\/id|images|barcode|ocr|document|curp|cfdi|address-statement/.test(endpoint)) return "idScan";
|
|
1218
|
+
if (/start|flow|workflow|feature-config|onboarding|finish-status/.test(endpoint)) return "orchestration";
|
|
1219
|
+
return "other";
|
|
1220
|
+
}
|
|
1221
|
+
/** Coarse contract category from the RAW `event.module` value (plan rule). */
|
|
1222
|
+
function categoryForModule(rawModule) {
|
|
1223
|
+
if (rawModule === void 0) return "other";
|
|
1224
|
+
if (ID_SCAN_MODULES.has(rawModule)) return "idScan";
|
|
1225
|
+
if (FACE_SCAN_MODULES.has(rawModule)) return "faceScan";
|
|
1226
|
+
if (ORCHESTRATION_MODULES.has(rawModule)) return "orchestration";
|
|
1227
|
+
return "other";
|
|
1228
|
+
}
|
|
1229
|
+
/** `verb key=value` line: undefined values drop their pair entirely. */
|
|
1230
|
+
function formatLine(verb, pairs = []) {
|
|
1231
|
+
const parts = [verb];
|
|
1232
|
+
for (const [key, value] of pairs) if (value !== void 0 && value !== null && value !== "") parts.push(`${key}=${String(value)}`);
|
|
1233
|
+
return parts.join(" ");
|
|
1234
|
+
}
|
|
1235
|
+
/**
|
|
1236
|
+
* Analytics event → contract log tuple, or `null` for codes the taxonomy
|
|
1237
|
+
* does not cover (deny-by-default: nothing rides into the record unreviewed).
|
|
1238
|
+
* Levels/subsystems/categories per the plan's event map rows 5–6 and 16–20.
|
|
1239
|
+
*/
|
|
1240
|
+
function mapAnalyticsEventToLog(event) {
|
|
1241
|
+
const payload = event.payload ?? {};
|
|
1242
|
+
const subsystem = normalizeSubsystem(event.module);
|
|
1243
|
+
const category = categoryForModule(event.module);
|
|
1244
|
+
switch (event.code) {
|
|
1245
|
+
case "moduleOpened":
|
|
1246
|
+
case "moduleClosed": return {
|
|
1247
|
+
level: "info",
|
|
1248
|
+
subsystem,
|
|
1249
|
+
category,
|
|
1250
|
+
message: formatLine(event.code === "moduleOpened" ? "module opened" : "module closed", [["screen", event.screen]])
|
|
1251
|
+
};
|
|
1252
|
+
case "screenOpened":
|
|
1253
|
+
case "screenClosed": return {
|
|
1254
|
+
level: "debug",
|
|
1255
|
+
subsystem,
|
|
1256
|
+
category,
|
|
1257
|
+
message: formatLine(event.code === "screenOpened" ? "screen opened" : "screen closed", [["screen", event.screen]])
|
|
1258
|
+
};
|
|
1259
|
+
case "errorTriggered": return {
|
|
1260
|
+
level: "error",
|
|
1261
|
+
subsystem,
|
|
1262
|
+
category,
|
|
1263
|
+
message: formatLine("errorTriggered", [
|
|
1264
|
+
["errorName", stringOrUndefined(payload.errorName) ?? "unknown"],
|
|
1265
|
+
["errorCode", stringOrUndefined(payload.errorCode)],
|
|
1266
|
+
["reason", stringOrUndefined(payload.reason)]
|
|
1267
|
+
])
|
|
1268
|
+
};
|
|
1269
|
+
case "captureAttemptFinished": return {
|
|
1270
|
+
level: "debug",
|
|
1271
|
+
subsystem,
|
|
1272
|
+
category,
|
|
1273
|
+
message: formatLine("capture attempt finished", [["logs", stringOrUndefined(payload.logs)]])
|
|
1274
|
+
};
|
|
1275
|
+
case "background":
|
|
1276
|
+
case "foreground": return {
|
|
1277
|
+
level: "debug",
|
|
1278
|
+
subsystem,
|
|
1279
|
+
category,
|
|
1280
|
+
message: `visibility ${event.code}`
|
|
1281
|
+
};
|
|
1282
|
+
case "elementClicked": return {
|
|
1283
|
+
level: "debug",
|
|
1284
|
+
subsystem,
|
|
1285
|
+
category,
|
|
1286
|
+
message: formatLine("element clicked", [["element", stringOrUndefined(payload.element)], ["action", stringOrUndefined(payload.action)]])
|
|
1287
|
+
};
|
|
1288
|
+
case "browser": {
|
|
1289
|
+
const browser = nameVersion(payload.browser);
|
|
1290
|
+
const os = nameVersion(payload.os);
|
|
1291
|
+
const device = typeof payload.device === "object" && payload.device !== null ? stringOrUndefined(payload.device.type) : void 0;
|
|
1292
|
+
return {
|
|
1293
|
+
level: "info",
|
|
1294
|
+
subsystem: "session",
|
|
1295
|
+
category: "other",
|
|
1296
|
+
message: formatLine("browser info", [
|
|
1297
|
+
["browser", browser],
|
|
1298
|
+
["os", os],
|
|
1299
|
+
["device", device],
|
|
1300
|
+
["webrtc", typeof payload.isWebRtcSupported === "boolean" ? payload.isWebRtcSupported : void 0]
|
|
1301
|
+
])
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
default: return null;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
function stringOrUndefined(value) {
|
|
1308
|
+
return typeof value === "string" ? value : void 0;
|
|
1309
|
+
}
|
|
1310
|
+
function nameVersion(value) {
|
|
1311
|
+
if (typeof value !== "object" || value === null) return;
|
|
1312
|
+
const { name, version } = value;
|
|
1313
|
+
const joined = [name, version].filter((part) => typeof part === "string" && part !== "").join(" ");
|
|
1314
|
+
return joined === "" ? void 0 : joined;
|
|
1315
|
+
}
|
|
1316
|
+
//#endregion
|
|
1317
|
+
//#region src/internal/trueSight/uploader.ts
|
|
1318
|
+
let cryptoProviderPromise = null;
|
|
1319
|
+
/**
|
|
1320
|
+
* Loads the browser sealer as a LAZY chunk, once — crypto stays off the host
|
|
1321
|
+
* page's critical path until diagnostics actually need it (first upload or
|
|
1322
|
+
* the service's prewarm).
|
|
1323
|
+
*/
|
|
1324
|
+
function loadDiagnosticsCryptoProvider() {
|
|
1325
|
+
cryptoProviderPromise ??= import("./BrowserDiagnosticsCryptoProvider-CriIh1Gt.esm.js").then((module) => new module.BrowserDiagnosticsCryptoProvider());
|
|
1326
|
+
return cryptoProviderPromise;
|
|
1327
|
+
}
|
|
1328
|
+
/**
|
|
1329
|
+
* Seals and posts one diagnostics record. Never rejects (fail-open). Size
|
|
1330
|
+
* guards per contract: warn approaching the 1 MB envelope cap; over the cap,
|
|
1331
|
+
* rebuild ONCE with the oldest half of the logs dropped; still over → drop
|
|
1332
|
+
* the upload entirely rather than send an invalid envelope.
|
|
1333
|
+
*/
|
|
1334
|
+
async function uploadDiagnostics(record, options) {
|
|
1335
|
+
const warn = options.warn ?? defaultWarn;
|
|
1336
|
+
try {
|
|
1337
|
+
const sealer = await (options.loadCrypto ?? loadDiagnosticsCryptoProvider)();
|
|
1338
|
+
let envelope = await sealer.seal(JSON.stringify(record));
|
|
1339
|
+
let envelopeBytes = utf8ByteLength(JSON.stringify(envelope));
|
|
1340
|
+
if (envelopeBytes > 1e6) {
|
|
1341
|
+
const trimmed = {
|
|
1342
|
+
...record,
|
|
1343
|
+
logs: record.logs.slice(Math.floor(record.logs.length / 2))
|
|
1344
|
+
};
|
|
1345
|
+
warn(`[TrueSight] envelope ${envelopeBytes}B over the 1MB cap — rebuilt with the oldest ${record.logs.length - trimmed.logs.length} logs dropped`);
|
|
1346
|
+
envelope = await sealer.seal(JSON.stringify(trimmed));
|
|
1347
|
+
envelopeBytes = utf8ByteLength(JSON.stringify(envelope));
|
|
1348
|
+
if (envelopeBytes > 1e6) {
|
|
1349
|
+
warn("[TrueSight] envelope still over the cap after trim — upload dropped");
|
|
1350
|
+
return;
|
|
1351
|
+
}
|
|
1352
|
+
} else if (envelopeBytes > 9e5) warn(`[TrueSight] envelope ${envelopeBytes}B is approaching the 1MB cap`);
|
|
1353
|
+
const keepalive = options.keepalive === true && envelopeBytes <= 6e4;
|
|
1354
|
+
if (isForwardedFalse((await options.post(endpoints.diagnosticsData, envelope, keepalive ? { keepalive: true } : {})).data)) warn("[TrueSight] proxy accepted the record but did not forward it (forwarded:false)");
|
|
1355
|
+
} catch (error) {
|
|
1356
|
+
warn(`[TrueSight] diagnostics upload failed (no retry): ${String(error)}`);
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
function isForwardedFalse(data) {
|
|
1360
|
+
return typeof data === "object" && data !== null && "forwarded" in data && data.forwarded === false;
|
|
1361
|
+
}
|
|
1362
|
+
function defaultWarn() {}
|
|
1363
|
+
//#endregion
|
|
1364
|
+
//#region src/internal/trueSight/trueSightService.ts
|
|
1365
|
+
let active = false;
|
|
1366
|
+
let remoteKilled = false;
|
|
1367
|
+
let finalized = false;
|
|
1368
|
+
let cryptoUnsupported = false;
|
|
1369
|
+
let collectionStarted = false;
|
|
1370
|
+
let flagResolutionStarted = false;
|
|
1371
|
+
let lastError = null;
|
|
1372
|
+
let buffer = null;
|
|
1373
|
+
let unsubscribeEvents = null;
|
|
1374
|
+
let options = defaultOptions();
|
|
1375
|
+
/** First orchestrator kind observed — LOCKS the session identity (see stampOrchestratorIdentity). */
|
|
1376
|
+
let observedManagerKind = null;
|
|
1377
|
+
let orchestratorConflictLogged = false;
|
|
1378
|
+
let snapshotRecordId = null;
|
|
1379
|
+
let cachedPendingEnvelope = null;
|
|
1380
|
+
let snapshotDirty = false;
|
|
1381
|
+
let captureActive = false;
|
|
1382
|
+
let rebuildInFlight = false;
|
|
1383
|
+
let sealFailureLogged = false;
|
|
1384
|
+
let pendingSlotRegistered = false;
|
|
1385
|
+
let recoveryStarted = false;
|
|
1386
|
+
let bridgeFailureCount = 0;
|
|
1387
|
+
let envSnapshotLogged = false;
|
|
1388
|
+
let hintTransitionCount = 0;
|
|
1389
|
+
let hintSuppressedCount = 0;
|
|
1390
|
+
let lastHintStatus = null;
|
|
1391
|
+
let overflowBatchCount = 0;
|
|
1392
|
+
let lastFlushRecordId = null;
|
|
1393
|
+
let overflowDormant = false;
|
|
1394
|
+
let overflowFlushInFlightUpTo = null;
|
|
1395
|
+
let dirtyTimerHandle = null;
|
|
1396
|
+
let unsubscribePageHide = null;
|
|
1397
|
+
function defaultOptions() {
|
|
1398
|
+
return {
|
|
1399
|
+
fetchFeatures: fetchFeatureConfig,
|
|
1400
|
+
captureTransport: captureLiveTransport,
|
|
1401
|
+
upload: uploadDiagnostics,
|
|
1402
|
+
loadCrypto: loadDiagnosticsCryptoProvider
|
|
1403
|
+
};
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* Boot-time entry, called from `setup()`. Idempotent — the first activating
|
|
1407
|
+
* call wins for the SDK lifecycle (like the analytics batcher and the
|
|
1408
|
+
* encryption lock); `reset()` → `resetTrueSight()` starts a new one.
|
|
1409
|
+
* `enabled:false` is a no-op by design: zero subscriptions, zero state.
|
|
1410
|
+
*/
|
|
1411
|
+
function initializeTrueSightDiagnostics(serviceOptions) {
|
|
1412
|
+
if (!serviceOptions.enabled || active) return;
|
|
1413
|
+
active = true;
|
|
1414
|
+
options = {
|
|
1415
|
+
...defaultOptions(),
|
|
1416
|
+
...pickDefined(serviceOptions)
|
|
1417
|
+
};
|
|
1418
|
+
buffer = createLogBuffer({ onOverflow: handleBufferOverflow });
|
|
1419
|
+
configureTrueSightMetadataSources({
|
|
1420
|
+
getHasToken: () => getToken() !== null,
|
|
1421
|
+
getE2eEncryptionEnabled: isHttpEncrypted
|
|
1422
|
+
});
|
|
1423
|
+
unsubscribeEvents = subscribeEvent(handleAnalyticsEvent);
|
|
1424
|
+
trueSightLog("debug", "diagnostics", "other", "diagnostics initialized");
|
|
1425
|
+
if (options.pageLifecycle && options.storage) unsubscribePageHide = options.pageLifecycle.onPageHide(handlePageHide);
|
|
1426
|
+
if (options.timer && options.storage) dirtyTimerHandle = options.timer.setInterval(() => {
|
|
1427
|
+
maybeRebuildSnapshot();
|
|
1428
|
+
}, SNAPSHOT_DIRTY_INTERVAL_MS);
|
|
1429
|
+
}
|
|
1430
|
+
/**
|
|
1431
|
+
* Session-time entry, called from `initializeSession` once feature config is
|
|
1432
|
+
* known. Collection is already running by then (buffering starts at
|
|
1433
|
+
* initialize); this resolves the remote flag and prewarms the crypto chunk.
|
|
1434
|
+
* When the host's fetch failed, call with no argument — the service resolves
|
|
1435
|
+
* the cached `fetchFeatureConfig()` itself (a token is present at this point).
|
|
1436
|
+
*/
|
|
1437
|
+
function startTrueSightCollection(features) {
|
|
1438
|
+
if (!active || remoteKilled || finalized) return;
|
|
1439
|
+
if (!collectionStarted) {
|
|
1440
|
+
collectionStarted = true;
|
|
1441
|
+
prewarmCrypto();
|
|
1442
|
+
}
|
|
1443
|
+
if (features) {
|
|
1444
|
+
noteFeatureConfig(features);
|
|
1445
|
+
if (!flagResolutionStarted) {
|
|
1446
|
+
flagResolutionStarted = true;
|
|
1447
|
+
applyFeatureResolution(features, false);
|
|
1448
|
+
}
|
|
1449
|
+
} else if (!flagResolutionStarted) {
|
|
1450
|
+
flagResolutionStarted = true;
|
|
1451
|
+
options.fetchFeatures().then((fetched) => {
|
|
1452
|
+
noteFeatureConfig(fetched);
|
|
1453
|
+
applyFeatureResolution(fetched, false);
|
|
1454
|
+
}, () => {
|
|
1455
|
+
applyFeatureResolution(null, true);
|
|
1456
|
+
});
|
|
1457
|
+
}
|
|
1458
|
+
kickRecoveryOnce();
|
|
1459
|
+
}
|
|
1460
|
+
/**
|
|
1461
|
+
* P1-E capture taps call this around detection loops (C7): while active,
|
|
1462
|
+
* snapshot rebuilds are suppressed — the collector must never compete with
|
|
1463
|
+
* 30 fps capture. Deactivation flushes the deferred rebuild.
|
|
1464
|
+
*/
|
|
1465
|
+
function noteTrueSightCaptureActivity(activityActive) {
|
|
1466
|
+
captureActive = activityActive;
|
|
1467
|
+
if (!activityActive) maybeRebuildSnapshot();
|
|
1468
|
+
}
|
|
1469
|
+
/**
|
|
1470
|
+
* Seals and uploads the one final record per session. The upload-relevant
|
|
1471
|
+
* state — transport, metadata (live token/E2EE getters read NOW), buffered
|
|
1472
|
+
* logs — is captured SYNCHRONOUSLY before the first await, because `reset()`
|
|
1473
|
+
* calls `resetApi()` immediately after this returns. Finalize-once: later
|
|
1474
|
+
* terminals and late events are no-ops. Never rejects.
|
|
1475
|
+
*/
|
|
1476
|
+
function finalizeTrueSight(outcome, failureReason) {
|
|
1477
|
+
if (!active || remoteKilled || finalized) return Promise.resolve();
|
|
1478
|
+
finalized = true;
|
|
1479
|
+
trueSightLog("info", "session", "orchestration", `finalizing outcome=${outcome}${failureReason !== void 0 ? ` reason=${failureReason}` : ""}`);
|
|
1480
|
+
const metadata = buildSessionMetadata();
|
|
1481
|
+
const logs = (buffer?.snapshot() ?? []).filter((entry) => overflowFlushInFlightUpTo === null || entry.index > overflowFlushInFlightUpTo);
|
|
1482
|
+
const transport = safeCaptureTransport();
|
|
1483
|
+
if (transport === null || cryptoUnsupported) return Promise.resolve();
|
|
1484
|
+
const record = buildDiagnosticsRecord(metadata, logs, outcome, failureReason);
|
|
1485
|
+
if (record === null) return Promise.resolve();
|
|
1486
|
+
cachedPendingEnvelope = null;
|
|
1487
|
+
if (options.storage && metadata.sessionId) clearPending(metadata.sessionId, { storage: options.storage });
|
|
1488
|
+
return options.upload(record, {
|
|
1489
|
+
post: transport,
|
|
1490
|
+
keepalive: true,
|
|
1491
|
+
loadCrypto: options.loadCrypto,
|
|
1492
|
+
warn: selfHealthWarn
|
|
1493
|
+
});
|
|
1494
|
+
}
|
|
1495
|
+
/**
|
|
1496
|
+
* Capture guidance-hint transition tap (event map 19b/19c): the moment the
|
|
1497
|
+
* hint the user sees CHANGES, as the status CODE — never the localized text.
|
|
1498
|
+
* Consecutive dedupe on top of the source dedupe, plus a per-attempt budget
|
|
1499
|
+
* (~60, then suppress-with-counter) so a struggling capture can never flood
|
|
1500
|
+
* the buffer. The budget resets when a capture attempt finishes. Level is
|
|
1501
|
+
* debug so the eviction fallback drops hints before warnings/errors.
|
|
1502
|
+
*/
|
|
1503
|
+
function trueSightHintTransition(subsystem, category, status) {
|
|
1504
|
+
if (buffer === null || finalized) return;
|
|
1505
|
+
if (status === lastHintStatus) return;
|
|
1506
|
+
lastHintStatus = status;
|
|
1507
|
+
hintTransitionCount += 1;
|
|
1508
|
+
if (hintTransitionCount > 60) {
|
|
1509
|
+
hintSuppressedCount += 1;
|
|
1510
|
+
return;
|
|
1511
|
+
}
|
|
1512
|
+
if (hintTransitionCount === 60) {
|
|
1513
|
+
trueSightLog("debug", subsystem, category, "hint transition budget reached suppressing=true");
|
|
1514
|
+
return;
|
|
1515
|
+
}
|
|
1516
|
+
trueSightLog("debug", subsystem, category, `hint changed status=${status}`);
|
|
1517
|
+
}
|
|
1518
|
+
function resetHintBudget() {
|
|
1519
|
+
if (hintSuppressedCount > 0) trueSightLog("debug", "diagnostics", "other", `hint transitions suppressed count=${hintSuppressedCount}`);
|
|
1520
|
+
hintTransitionCount = 0;
|
|
1521
|
+
hintSuppressedCount = 0;
|
|
1522
|
+
lastHintStatus = null;
|
|
1523
|
+
}
|
|
1524
|
+
/** Buffer tap for wiring points and self-health lines. No-op when inactive. */
|
|
1525
|
+
function trueSightLog(level, subsystem, category, message) {
|
|
1526
|
+
if (buffer === null) return;
|
|
1527
|
+
buffer.append(level, subsystem, category, message);
|
|
1528
|
+
snapshotDirty = true;
|
|
1529
|
+
}
|
|
1530
|
+
/**
|
|
1531
|
+
* Minimal P1-B bridge, invoked by `attachFlowEventEmitter` for every curated
|
|
1532
|
+
* flow event. Terminal mapping (repo conventions): `flow.completed` →
|
|
1533
|
+
* success, `flow.closed` → cancelled, `flow.error` → records `lastError`
|
|
1534
|
+
* only — error state is recoverable, not terminal. Fail-open.
|
|
1535
|
+
*/
|
|
1536
|
+
function notifyTrueSightFlowEvent(event, managerKind) {
|
|
1537
|
+
if (!active || remoteKilled) return;
|
|
1538
|
+
try {
|
|
1539
|
+
const identityAccepted = stampOrchestratorIdentity(managerKind);
|
|
1540
|
+
snapshotDirty = true;
|
|
1541
|
+
switch (event.type) {
|
|
1542
|
+
case "flow.started":
|
|
1543
|
+
trueSightLog("info", managerKind, "orchestration", "flow.started");
|
|
1544
|
+
break;
|
|
1545
|
+
case "flow.ready":
|
|
1546
|
+
if (identityAccepted) noteFlowContext({
|
|
1547
|
+
flowType: managerKind,
|
|
1548
|
+
flowId: managerKind === "flow" ? event.flowId ?? null : null,
|
|
1549
|
+
workflowId: managerKind === "workflow" ? event.flowId ?? null : null
|
|
1550
|
+
});
|
|
1551
|
+
trueSightLog("info", managerKind, "orchestration", `flow.ready ${managerKind === "workflow" ? "workflowId" : "flowId"}=${event.flowId ?? "unknown"}`);
|
|
1552
|
+
break;
|
|
1553
|
+
case "flow.module.started":
|
|
1554
|
+
case "flow.module.completed": {
|
|
1555
|
+
const position = modulePosition(event.payload);
|
|
1556
|
+
trueSightLog("info", managerKind, "orchestration", `module ${event.type === "flow.module.started" ? "started" : "completed"} module=${event.module ?? "unknown"}${position}`);
|
|
1557
|
+
maybeRebuildSnapshot();
|
|
1558
|
+
break;
|
|
1559
|
+
}
|
|
1560
|
+
case "flow.error":
|
|
1561
|
+
lastError = sanitizeMessage(event.error ?? "unknown");
|
|
1562
|
+
trueSightLog("error", managerKind, "orchestration", `flow.error message=${event.error ?? "unknown"}`);
|
|
1563
|
+
break;
|
|
1564
|
+
case "flow.completed":
|
|
1565
|
+
trueSightLog("info", managerKind, "orchestration", "flow.completed");
|
|
1566
|
+
finalizeTrueSight("success");
|
|
1567
|
+
break;
|
|
1568
|
+
case "flow.closed":
|
|
1569
|
+
trueSightLog("info", managerKind, "orchestration", "flow.closed");
|
|
1570
|
+
finalizeTrueSight("cancelled");
|
|
1571
|
+
break;
|
|
1572
|
+
default: break;
|
|
1573
|
+
}
|
|
1574
|
+
} catch {}
|
|
1575
|
+
}
|
|
1576
|
+
/**
|
|
1577
|
+
* `manager.stop()` while unfinalized = the session ended without a terminal —
|
|
1578
|
+
* the sanctioned interrupted marker until BE ships `inProgress`.
|
|
1579
|
+
*/
|
|
1580
|
+
function notifyTrueSightManagerStopped(managerKind) {
|
|
1581
|
+
if (!active || remoteKilled || finalized) return;
|
|
1582
|
+
try {
|
|
1583
|
+
stampOrchestratorIdentity(managerKind);
|
|
1584
|
+
finalizeTrueSight("failure", lastError ?? "stopped_before_completion");
|
|
1585
|
+
} catch {}
|
|
1586
|
+
}
|
|
1587
|
+
/**
|
|
1588
|
+
* DETERMINISTIC session identity: the FIRST orchestrator kind observed locks
|
|
1589
|
+
* `flowType`/`integrationType` for the whole session — a record labeled
|
|
1590
|
+
* `flow` must always point at a real flow, never flip mid-session and send
|
|
1591
|
+
* the debugger to the wrong dashboard. A conflicting kind (host misuse: two
|
|
1592
|
+
* orchestrators on one session) is ignored for identity purposes and leaves
|
|
1593
|
+
* exactly one self-health breadcrumb; its terminals still finalize
|
|
1594
|
+
* (finalize-once — session closure with a caveat beats no record).
|
|
1595
|
+
*
|
|
1596
|
+
* @returns whether this kind owns the session identity (callers gate
|
|
1597
|
+
* identity-derived writes like flowId/workflowId on it).
|
|
1598
|
+
*/
|
|
1599
|
+
function stampOrchestratorIdentity(managerKind) {
|
|
1600
|
+
if (observedManagerKind === null) observedManagerKind = managerKind;
|
|
1601
|
+
else if (observedManagerKind !== managerKind) {
|
|
1602
|
+
if (!orchestratorConflictLogged) {
|
|
1603
|
+
orchestratorConflictLogged = true;
|
|
1604
|
+
trueSightLog("warning", "diagnostics", "other", `orchestratorConflict ignored=${managerKind} locked=${observedManagerKind}`);
|
|
1605
|
+
}
|
|
1606
|
+
return false;
|
|
1607
|
+
}
|
|
1608
|
+
noteIntegrationSurface(managerKind === "workflow" ? "startWorkflow" : "startFlow");
|
|
1609
|
+
noteFlowContext({ flowType: managerKind });
|
|
1610
|
+
return true;
|
|
1611
|
+
}
|
|
1612
|
+
/** Full teardown, called from `reset()` AFTER finalize captured its snapshot. */
|
|
1613
|
+
function resetTrueSight() {
|
|
1614
|
+
unsubscribeEvents?.();
|
|
1615
|
+
unsubscribeEvents = null;
|
|
1616
|
+
unsubscribePageHide?.();
|
|
1617
|
+
unsubscribePageHide = null;
|
|
1618
|
+
if (dirtyTimerHandle !== null) {
|
|
1619
|
+
options.timer?.clearInterval(dirtyTimerHandle);
|
|
1620
|
+
dirtyTimerHandle = null;
|
|
1621
|
+
}
|
|
1622
|
+
buffer = null;
|
|
1623
|
+
active = false;
|
|
1624
|
+
remoteKilled = false;
|
|
1625
|
+
finalized = false;
|
|
1626
|
+
cryptoUnsupported = false;
|
|
1627
|
+
collectionStarted = false;
|
|
1628
|
+
flagResolutionStarted = false;
|
|
1629
|
+
lastError = null;
|
|
1630
|
+
observedManagerKind = null;
|
|
1631
|
+
orchestratorConflictLogged = false;
|
|
1632
|
+
snapshotRecordId = null;
|
|
1633
|
+
cachedPendingEnvelope = null;
|
|
1634
|
+
snapshotDirty = false;
|
|
1635
|
+
captureActive = false;
|
|
1636
|
+
rebuildInFlight = false;
|
|
1637
|
+
sealFailureLogged = false;
|
|
1638
|
+
pendingSlotRegistered = false;
|
|
1639
|
+
recoveryStarted = false;
|
|
1640
|
+
bridgeFailureCount = 0;
|
|
1641
|
+
envSnapshotLogged = false;
|
|
1642
|
+
hintTransitionCount = 0;
|
|
1643
|
+
hintSuppressedCount = 0;
|
|
1644
|
+
lastHintStatus = null;
|
|
1645
|
+
overflowBatchCount = 0;
|
|
1646
|
+
lastFlushRecordId = null;
|
|
1647
|
+
overflowDormant = false;
|
|
1648
|
+
overflowFlushInFlightUpTo = null;
|
|
1649
|
+
options = defaultOptions();
|
|
1650
|
+
resetTrueSightMetadata();
|
|
1651
|
+
}
|
|
1652
|
+
function handleAnalyticsEvent(event) {
|
|
1653
|
+
if (finalized) return;
|
|
1654
|
+
try {
|
|
1655
|
+
const mapped = mapAnalyticsEventToLog(event);
|
|
1656
|
+
if (mapped === null) return;
|
|
1657
|
+
trueSightLog(mapped.level, mapped.subsystem, mapped.category, mapped.message);
|
|
1658
|
+
if (mapped.level === "error" || mapped.level === "severe") logEnvironmentSnapshotOnce();
|
|
1659
|
+
if (event.code === "captureAttemptFinished") resetHintBudget();
|
|
1660
|
+
} catch {
|
|
1661
|
+
bridgeFailureCount += 1;
|
|
1662
|
+
if (bridgeFailureCount === 1) trueSightLog("warning", "diagnostics", "other", "bridge mapping failed");
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
/**
|
|
1666
|
+
* Environment-snapshot-on-first-error (event map 19d): the "conditions at
|
|
1667
|
+
* the moment of failure" line — logged once per session, right after the
|
|
1668
|
+
* first error-level entry. The snapshot closure is injected (navigator
|
|
1669
|
+
* facts live behind the L0 environment provider).
|
|
1670
|
+
*/
|
|
1671
|
+
function logEnvironmentSnapshotOnce() {
|
|
1672
|
+
if (envSnapshotLogged || options.getEnvironmentSnapshot === void 0) return;
|
|
1673
|
+
envSnapshotLogged = true;
|
|
1674
|
+
try {
|
|
1675
|
+
trueSightLog("info", "session", "other", `environment at first error ${options.getEnvironmentSnapshot()}`);
|
|
1676
|
+
} catch {}
|
|
1677
|
+
}
|
|
1678
|
+
function applyFeatureResolution(features, unresolvable) {
|
|
1679
|
+
if (!active || remoteKilled || finalized) return;
|
|
1680
|
+
const entry = features?.features?.find((candidate) => candidate.feature === "TRUESIGHT_DIAGNOSTICS");
|
|
1681
|
+
if (entry?.enabled === false) {
|
|
1682
|
+
remoteKill();
|
|
1683
|
+
return;
|
|
1684
|
+
}
|
|
1685
|
+
trueSightLog("info", "diagnostics", "other", `featureFlag resolution=${unresolvable ? "unresolvable" : entry ? "true" : "absent"}`);
|
|
1686
|
+
}
|
|
1687
|
+
function remoteKill() {
|
|
1688
|
+
remoteKilled = true;
|
|
1689
|
+
buffer = null;
|
|
1690
|
+
unsubscribeEvents?.();
|
|
1691
|
+
unsubscribeEvents = null;
|
|
1692
|
+
}
|
|
1693
|
+
/**
|
|
1694
|
+
* Size-limit overflow flush (plan §1.3, event map 10b): the buffer crossed
|
|
1695
|
+
* ~600 KB mid-session — ship the slice as its OWN contract-valid record
|
|
1696
|
+
* (fresh id, same sessionId, index continuity ties the records together)
|
|
1697
|
+
* and keep logging. **STAGING-ONLY until BE ships `inProgress`/`flushReason`
|
|
1698
|
+
* (hard gate B2)**: outside staging (`testing !== true`) the machinery goes
|
|
1699
|
+
* dormant and the buffer falls back to eviction. Interim outcome marker is
|
|
1700
|
+
* the sanctioned `failure/interrupted` pair; the terminal record supersedes.
|
|
1701
|
+
*/
|
|
1702
|
+
function handleBufferOverflow(slice) {
|
|
1703
|
+
dispatchOverflowSlice(slice);
|
|
1704
|
+
}
|
|
1705
|
+
async function dispatchOverflowSlice(slice) {
|
|
1706
|
+
if (!active || remoteKilled || finalized || overflowDormant || slice.length === 0) return;
|
|
1707
|
+
const metadata = buildSessionMetadata();
|
|
1708
|
+
if (metadata.testing !== true) {
|
|
1709
|
+
goOverflowDormant("overflowFlush dormant reason=prod");
|
|
1710
|
+
return;
|
|
1711
|
+
}
|
|
1712
|
+
if (cryptoUnsupported) {
|
|
1713
|
+
goOverflowDormant("overflowFlush dormant reason=cryptoUnsupported");
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1716
|
+
const transport = safeCaptureTransport();
|
|
1717
|
+
if (transport === null) {
|
|
1718
|
+
goOverflowDormant("overflowFlush dormant reason=noTransport");
|
|
1719
|
+
return;
|
|
1720
|
+
}
|
|
1721
|
+
overflowBatchCount += 1;
|
|
1722
|
+
const record = buildDiagnosticsRecord(metadata, [{
|
|
1723
|
+
index: slice[0].index,
|
|
1724
|
+
timestampMs: getTimestamp(),
|
|
1725
|
+
level: "info",
|
|
1726
|
+
subsystem: "diagnostics",
|
|
1727
|
+
category: "other",
|
|
1728
|
+
message: `sizeLimitFlush batch=${overflowBatchCount} prevRecordId=${lastFlushRecordId ?? "none"}`
|
|
1729
|
+
}, ...slice], "failure", "interrupted");
|
|
1730
|
+
if (record === null) {
|
|
1731
|
+
goOverflowDormant("overflowFlush dormant reason=unbuildable");
|
|
1732
|
+
return;
|
|
1733
|
+
}
|
|
1734
|
+
lastFlushRecordId = record.id;
|
|
1735
|
+
const upToIndex = slice[slice.length - 1].index;
|
|
1736
|
+
overflowFlushInFlightUpTo = upToIndex;
|
|
1737
|
+
await options.upload(record, {
|
|
1738
|
+
post: transport,
|
|
1739
|
+
loadCrypto: options.loadCrypto,
|
|
1740
|
+
warn: selfHealthWarn
|
|
1741
|
+
});
|
|
1742
|
+
buffer?.markFlushed(upToIndex);
|
|
1743
|
+
overflowFlushInFlightUpTo = null;
|
|
1744
|
+
snapshotDirty = true;
|
|
1745
|
+
trueSightLog("info", "diagnostics", "other", `sizeLimitFlush dispatched batch=${overflowBatchCount} recordId=${record.id} entries=${slice.length}`);
|
|
1746
|
+
}
|
|
1747
|
+
/** B2 fallback: machinery dormant, eviction takes over — logged exactly once. */
|
|
1748
|
+
function goOverflowDormant(message) {
|
|
1749
|
+
if (overflowDormant) return;
|
|
1750
|
+
overflowDormant = true;
|
|
1751
|
+
trueSightLog("warning", "diagnostics", "other", message);
|
|
1752
|
+
buffer?.setOverflowMode("evict");
|
|
1753
|
+
}
|
|
1754
|
+
/**
|
|
1755
|
+
* Debounced interrupted-snapshot rebuild (plan §1.8): triggered by module
|
|
1756
|
+
* boundaries and the dirty-interval tick, suppressed while a capture loop is
|
|
1757
|
+
* active (C7). Seals the CURRENT state as a `failure/interrupted` record
|
|
1758
|
+
* under the session's stable snapshot id, caches the envelope (the page-hide
|
|
1759
|
+
* handler writes only the cache — it never builds), and persists it.
|
|
1760
|
+
*/
|
|
1761
|
+
function maybeRebuildSnapshot() {
|
|
1762
|
+
if (!active || remoteKilled || finalized || cryptoUnsupported || captureActive || rebuildInFlight || !snapshotDirty || options.storage === void 0) return;
|
|
1763
|
+
const metadata = buildSessionMetadata();
|
|
1764
|
+
if (!metadata.sessionId) return;
|
|
1765
|
+
const storage = options.storage;
|
|
1766
|
+
const sessionId = metadata.sessionId;
|
|
1767
|
+
snapshotRecordId ??= randomUUID();
|
|
1768
|
+
const record = buildDiagnosticsRecord(metadata, buffer?.snapshot() ?? [], "failure", "interrupted", snapshotRecordId);
|
|
1769
|
+
if (record === null) return;
|
|
1770
|
+
snapshotDirty = false;
|
|
1771
|
+
rebuildInFlight = true;
|
|
1772
|
+
options.loadCrypto().then((sealer) => sealer.seal(JSON.stringify(record))).then(async (envelope) => {
|
|
1773
|
+
cachedPendingEnvelope = envelope;
|
|
1774
|
+
if (!pendingSlotRegistered) {
|
|
1775
|
+
pendingSlotRegistered = true;
|
|
1776
|
+
await registerPendingSlot(sessionId, { storage });
|
|
1777
|
+
}
|
|
1778
|
+
await writePendingEnvelope(sessionId, {
|
|
1779
|
+
v: 1,
|
|
1780
|
+
persistedAt: getTimestamp(),
|
|
1781
|
+
envelope
|
|
1782
|
+
}, { storage });
|
|
1783
|
+
}).catch(() => {
|
|
1784
|
+
snapshotDirty = true;
|
|
1785
|
+
if (!sealFailureLogged) {
|
|
1786
|
+
sealFailureLogged = true;
|
|
1787
|
+
trueSightLog("warning", "diagnostics", "other", "snapshot seal failed persistDisabled=false");
|
|
1788
|
+
}
|
|
1789
|
+
}).finally(() => {
|
|
1790
|
+
rebuildInFlight = false;
|
|
1791
|
+
});
|
|
1792
|
+
}
|
|
1793
|
+
/**
|
|
1794
|
+
* Page-hide = persist only, NEVER send (locked decision): one synchronous-
|
|
1795
|
+
* effective write of the freshest pre-sealed snapshot. Building or posting
|
|
1796
|
+
* here is forbidden — a hidden tab is frequently a user who returns.
|
|
1797
|
+
*/
|
|
1798
|
+
function handlePageHide() {
|
|
1799
|
+
if (!active || remoteKilled || finalized || cachedPendingEnvelope === null || options.storage === void 0) return;
|
|
1800
|
+
const sessionId = buildSessionMetadata().sessionId;
|
|
1801
|
+
if (!sessionId) return;
|
|
1802
|
+
writePendingEnvelope(sessionId, {
|
|
1803
|
+
v: 1,
|
|
1804
|
+
persistedAt: getTimestamp(),
|
|
1805
|
+
envelope: cachedPendingEnvelope
|
|
1806
|
+
}, { storage: options.storage });
|
|
1807
|
+
trueSightLog("debug", "diagnostics", "other", "snapshot persisted on pagehide");
|
|
1808
|
+
}
|
|
1809
|
+
/**
|
|
1810
|
+
* Next-load recovery off the first-token-observed hook (A1) — runs once per
|
|
1811
|
+
* lifecycle, fire-and-forget, and reports the A5 loss counters as a
|
|
1812
|
+
* self-health line when there was anything to report.
|
|
1813
|
+
*/
|
|
1814
|
+
function kickRecoveryOnce() {
|
|
1815
|
+
if (recoveryStarted || options.storage === void 0) return;
|
|
1816
|
+
recoveryStarted = true;
|
|
1817
|
+
const transport = safeCaptureTransport();
|
|
1818
|
+
if (transport === null) return;
|
|
1819
|
+
recoverPendingEnvelopes({
|
|
1820
|
+
storage: options.storage,
|
|
1821
|
+
post: transport,
|
|
1822
|
+
currentSessionId: buildSessionMetadata().sessionId
|
|
1823
|
+
}).then((counters) => {
|
|
1824
|
+
if (counters.recovered > 0 || counters.gcExpired > 0) trueSightLog("info", "diagnostics", "other", `recovery recovered=${counters.recovered} gcExpired=${counters.gcExpired}`);
|
|
1825
|
+
});
|
|
1826
|
+
}
|
|
1827
|
+
/**
|
|
1828
|
+
* Resolves crypto support ahead of finalize (and warms the lazy chunk so the
|
|
1829
|
+
* terminal path never pays the import). Unsupported → collect-only mode with
|
|
1830
|
+
* exactly one self-health warning.
|
|
1831
|
+
*/
|
|
1832
|
+
function prewarmCrypto() {
|
|
1833
|
+
options.loadCrypto().then((provider) => {
|
|
1834
|
+
if (!provider.isSupported()) markCryptoUnsupported();
|
|
1835
|
+
}, () => {
|
|
1836
|
+
markCryptoUnsupported();
|
|
1837
|
+
});
|
|
1838
|
+
}
|
|
1839
|
+
function markCryptoUnsupported() {
|
|
1840
|
+
if (cryptoUnsupported) return;
|
|
1841
|
+
cryptoUnsupported = true;
|
|
1842
|
+
trueSightLog("warning", "diagnostics", "other", "crypto unsupported collectOnly=true");
|
|
1843
|
+
}
|
|
1844
|
+
/**
|
|
1845
|
+
* Default transport capture: a closure over the live client + token AS OF
|
|
1846
|
+
* NOW. `reset()` may null the singletons immediately after — the returned
|
|
1847
|
+
* closure keeps working against the captured references.
|
|
1848
|
+
*/
|
|
1849
|
+
function captureLiveTransport() {
|
|
1850
|
+
try {
|
|
1851
|
+
if (!isApiConfigured()) return null;
|
|
1852
|
+
const client = getApi();
|
|
1853
|
+
const token = getToken();
|
|
1854
|
+
if (token === null) return null;
|
|
1855
|
+
return (url, body, config) => client.post(url, body, {
|
|
1856
|
+
...config,
|
|
1857
|
+
headers: { "X-Incode-Hardware-Id": token }
|
|
1858
|
+
});
|
|
1859
|
+
} catch {
|
|
1860
|
+
return null;
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
function safeCaptureTransport() {
|
|
1864
|
+
try {
|
|
1865
|
+
return options.captureTransport();
|
|
1866
|
+
} catch {
|
|
1867
|
+
return null;
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
function selfHealthWarn(message) {
|
|
1871
|
+
if (isTrueSightTesting()) console.warn(message);
|
|
1872
|
+
trueSightLog("warning", "diagnostics", "other", message);
|
|
1873
|
+
}
|
|
1874
|
+
/** Spread-safe subset: injected seams only, `undefined` values dropped. */
|
|
1875
|
+
function pickDefined(serviceOptions) {
|
|
1876
|
+
const picked = {};
|
|
1877
|
+
if (serviceOptions.fetchFeatures) picked.fetchFeatures = serviceOptions.fetchFeatures;
|
|
1878
|
+
if (serviceOptions.captureTransport) picked.captureTransport = serviceOptions.captureTransport;
|
|
1879
|
+
if (serviceOptions.upload) picked.upload = serviceOptions.upload;
|
|
1880
|
+
if (serviceOptions.loadCrypto) picked.loadCrypto = serviceOptions.loadCrypto;
|
|
1881
|
+
if (serviceOptions.pageLifecycle) picked.pageLifecycle = serviceOptions.pageLifecycle;
|
|
1882
|
+
if (serviceOptions.timer) picked.timer = serviceOptions.timer;
|
|
1883
|
+
if (serviceOptions.storage) picked.storage = serviceOptions.storage;
|
|
1884
|
+
if (serviceOptions.getEnvironmentSnapshot) picked.getEnvironmentSnapshot = serviceOptions.getEnvironmentSnapshot;
|
|
1885
|
+
return picked;
|
|
1886
|
+
}
|
|
1887
|
+
/** ` index=i total=n` suffix when the flow event carries module positioning. */
|
|
1888
|
+
function modulePosition(payload) {
|
|
1889
|
+
if (typeof payload !== "object" || payload === null) return "";
|
|
1890
|
+
const { moduleIndex, totalModules } = payload;
|
|
1891
|
+
return `${typeof moduleIndex === "number" ? ` index=${moduleIndex}` : ""}${typeof totalModules === "number" ? ` total=${totalModules}` : ""}`;
|
|
1892
|
+
}
|
|
1893
|
+
//#endregion
|
|
1894
|
+
export { upgradeToWasmHttpClient as C, resetHttpClientState as S, noteTokenActivated as _, notifyTrueSightManagerStopped as a, getStoredHttpConfig as b, trueSightHintTransition as c, fetchFeatureConfig as d, isFeatureEnabled as f, noteTestingSignals as g, noteSessionCreated as h, notifyTrueSightFlowEvent as i, trueSightLog as l, noteEnvironment as m, initializeTrueSightDiagnostics as n, resetTrueSight as o, resetFeatureConfigCache as p, noteTrueSightCaptureActivity as r, startTrueSightCollection as s, finalizeTrueSight as t, categoryForEndpoint as u, SDK_VERSION as v, createApi as w, installFreshHttpClient as x, randomUUID as y };
|