@incodetech/core 0.0.0-dev-20260820-e7c67ad4 → 0.0.0-dev-20260821-af317971
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/{BrowserDiagnosticsCryptoProvider-pKKLCGRk.esm.js → BrowserDiagnosticsCryptoProvider-C0MCKC1X.esm.js} +1 -1
- package/dist/{addressSearch-DQyrvDQj.esm.js → addressSearch-D1XpBdUS.esm.js} +1 -1
- package/dist/ae-signature.esm.js +1 -1
- package/dist/antifraud.esm.js +2 -2
- package/dist/{antifraudManager-BMZvuxv0.esm.js → antifraudManager-CQFNgSPt.esm.js} +2 -2
- package/dist/{antifraudStateMachine-r4VxSBS4.esm.js → antifraudStateMachine-Bf_JVNwn.esm.js} +2 -2
- package/dist/{apiError-DyXOc0Ha.esm.js → apiError-DINhZF1k.esm.js} +1 -1
- package/dist/authentication.esm.js +2 -2
- package/dist/{authenticationManager-C_DUIrb5.esm.js → authenticationManager-Ckwq7pZi.esm.js} +3 -3
- package/dist/{authenticationStateMachine-N-u23M0G.esm.js → authenticationStateMachine-CScvURND.esm.js} +4 -4
- package/dist/certificate-issuance.esm.js +2 -2
- package/dist/{certificateIssuanceManager-buCaNcxx.esm.js → certificateIssuanceManager-DFTukqtI.esm.js} +2 -2
- package/dist/{certificateIssuanceStateMachine-COd7_l2T.esm.js → certificateIssuanceStateMachine-D_R92TYu.esm.js} +2 -2
- package/dist/consent.d.ts +1 -1
- package/dist/consent.esm.js +2 -2
- package/dist/{consentManager-uhDPdU6i.d.ts → consentManager-BhYFeKiG.d.ts} +8 -8
- package/dist/{consentManager-DyBXdkFn.esm.js → consentManager-BxjpLZAG.esm.js} +2 -2
- package/dist/{consentStateMachine-WD-S-Yhs.esm.js → consentStateMachine-D9D4ON8Z.esm.js} +2 -2
- package/dist/cross-document-data-match.esm.js +1 -1
- package/dist/{crossDocumentDataMatchManager-pNkutndd.esm.js → crossDocumentDataMatchManager-CGT0V6RV.esm.js} +2 -2
- package/dist/curp-validation.esm.js +2 -2
- package/dist/{curpValidationManager-DEesnLee.esm.js → curpValidationManager-6Nmkn5u1.esm.js} +2 -2
- package/dist/{curpValidationStateMachine-9KwnqeoB.esm.js → curpValidationStateMachine-Ds7KMacK.esm.js} +2 -2
- package/dist/custom-fields.esm.js +1 -1
- package/dist/custom-watchlist.esm.js +2 -2
- package/dist/{customFieldsManager-Dgy3Hi0q.esm.js → customFieldsManager-BjTF6dRi.esm.js} +2 -2
- package/dist/{customWatchlistManager-BlJTcPKK.esm.js → customWatchlistManager-SFTkKkcs.esm.js} +2 -2
- package/dist/{customWatchlistStateMachine-B_ey3TFj.esm.js → customWatchlistStateMachine-YWSgKLbF.esm.js} +2 -2
- package/dist/{deepsightLoader-CJ-pplPZ.esm.js → deepsightLoader-B97yrkGH.esm.js} +3 -3
- package/dist/document-capture.esm.js +2 -2
- package/dist/{documentCaptureManager-C1UC1WYh.esm.js → documentCaptureManager-CV-B3ttS.esm.js} +2 -2
- package/dist/{documentCaptureStateMachine-CBHmgyM7.esm.js → documentCaptureStateMachine-DyNnjqKZ.esm.js} +2 -2
- package/dist/dynamic-forms.esm.js +2 -2
- package/dist/{dynamicFormsManager-DZmrn3Gs.esm.js → dynamicFormsManager-DhL8CAti.esm.js} +2 -2
- package/dist/{dynamicFormsStateMachine-DJGGCw-_.esm.js → dynamicFormsStateMachine-C58R6XYG.esm.js} +3 -3
- package/dist/ekyb.esm.js +3 -3
- package/dist/{ekybManager-DvNzYUtw.esm.js → ekybManager-DhFCnPQH.esm.js} +2 -2
- package/dist/{ekybStateMachine-C4F-25c-.esm.js → ekybStateMachine-DLGDsiyt.esm.js} +4 -4
- package/dist/ekyc.esm.js +2 -2
- package/dist/{ekycManager-CasdX1Ou.esm.js → ekycManager-DgT48ky6.esm.js} +2 -2
- package/dist/{ekycStateMachine-DHvksnrr.esm.js → ekycStateMachine-CQwqiR-R.esm.js} +3 -3
- package/dist/electronic-signature.esm.js +1 -1
- package/dist/{electronicSignatureManager-B8ewPeEV.esm.js → electronicSignatureManager-BNR6fi3d.esm.js} +3 -3
- package/dist/email.esm.js +2 -2
- package/dist/{emailManager-NLzaP12q.esm.js → emailManager-BY0jeYwR.esm.js} +2 -2
- package/dist/{emailStateMachine-Bm894MHB.esm.js → emailStateMachine-Crw8QVmc.esm.js} +2 -2
- package/dist/extensibility.d.ts +5 -5
- package/dist/extensibility.esm.js +34 -34
- package/dist/face-match.esm.js +2 -2
- package/dist/{faceCaptureManagerFactory-BltEV2Xt.esm.js → faceCaptureManagerFactory-BfuYyPH6.esm.js} +2 -2
- package/dist/{faceCaptureSetup-BGG17dLI.esm.js → faceCaptureSetup-DVMnvRbV.esm.js} +4 -4
- package/dist/{faceMatchManager-DEVhhdf4.esm.js → faceMatchManager-Ri4UbNz0.esm.js} +2 -2
- package/dist/{faceMatchStateMachine-CJiO2yLO.esm.js → faceMatchStateMachine-20DdZ3jg.esm.js} +2 -2
- package/dist/{feature-management-ZXt938Hq.esm.js → feature-management-DBuXnUWY.esm.js} +1 -1
- package/dist/feature-management.esm.js +1 -1
- package/dist/field-comparison.esm.js +1 -1
- package/dist/{fieldComparisonManager-BRYsIi34.esm.js → fieldComparisonManager-Cg6kPQQx.esm.js} +2 -2
- package/dist/fiscal-qr.esm.js +1 -1
- package/dist/{fiscalQrManager-7UH-ZMea.esm.js → fiscalQrManager-C_mDF2xK.esm.js} +2 -2
- package/dist/flow.d.ts +1 -1
- package/dist/flow.esm.js +5 -5
- package/dist/{flowCompletionService-BGairB36.esm.js → flowCompletionService-DthD-ObU.esm.js} +1 -1
- package/dist/{flowServices-DifI1jyA.esm.js → flowServices-BARG219v.esm.js} +4 -4
- package/dist/geolocation.esm.js +2 -2
- package/dist/{geolocationManager-BnB4QqVU.esm.js → geolocationManager-CHxv2c-F.esm.js} +2 -2
- package/dist/{geolocationStateMachine-CfI-8eaD.esm.js → geolocationStateMachine-C9dzQ0YZ.esm.js} +3 -3
- package/dist/government-validation.esm.js +2 -2
- package/dist/{governmentValidationManager-DnVUyppQ.esm.js → governmentValidationManager-CQBcGMBa.esm.js} +2 -2
- package/dist/{governmentValidationStateMachine-CNzJ5UQb.esm.js → governmentValidationStateMachine-DgxxQTbM.esm.js} +2 -2
- package/dist/home.esm.js +1 -1
- package/dist/id-ocr.esm.js +2 -2
- package/dist/id-selfie-flow.esm.js +8 -8
- package/dist/id-verification.esm.js +2 -2
- package/dist/id.d.ts +2 -2
- package/dist/id.esm.js +5 -5
- package/dist/{idCaptureManager-DQEUuleg.d.ts → idCaptureManager-DR0ra4Us.d.ts} +20 -10
- package/dist/{idCaptureManager-5p43Mmyv.esm.js → idCaptureManager-Ji6vFlsJ.esm.js} +12 -16
- package/dist/{idCaptureServices-D5TXcSQQ.esm.js → idCaptureServices-0lE7kEdA.esm.js} +143 -17
- package/dist/{idCaptureStateMachine-DF1WRVP9.esm.js → idCaptureStateMachine-DG7t_39B.esm.js} +445 -54
- package/dist/{idOcrManager-D_2k-6Vv.esm.js → idOcrManager-BIQYQXXj.esm.js} +2 -2
- package/dist/{idOcrStateMachine-Bq_e3l4E.esm.js → idOcrStateMachine-cSxzHpHt.esm.js} +2 -2
- package/dist/{idVerificationManager-DdlrWSSB.esm.js → idVerificationManager-JpV_SAsl.esm.js} +2 -2
- package/dist/{idVerificationStateMachine-GEQWUPU2.esm.js → idVerificationStateMachine-nPeUNyFq.esm.js} +2 -2
- package/dist/identity-reuse.d.ts +1 -1
- package/dist/identity-reuse.esm.js +2 -2
- package/dist/{identityReuseManager-CzLZNgdh.esm.js → identityReuseManager-kNCg9AbD.esm.js} +2 -2
- package/dist/{identityReuseManager-BFDI7iFK.d.ts → identityReuseManager-v2TH5g7e.d.ts} +4 -4
- package/dist/{identityReuseStateMachine-AubRPhIi.esm.js → identityReuseStateMachine-DyulxDjP.esm.js} +2 -2
- package/dist/index.esm.js +1 -1
- package/dist/mandatory-consent.d.ts +1 -1
- package/dist/mandatory-consent.esm.js +2 -2
- package/dist/{mandatoryConsentManager-CEIkNukS.esm.js → mandatoryConsentManager-B4Niyg_u.esm.js} +2 -2
- package/dist/{mandatoryConsentManager-DvR2XzUH.d.ts → mandatoryConsentManager-CaTcQLK6.d.ts} +4 -4
- package/dist/{mandatoryConsentStateMachine-zroQGzwb.esm.js → mandatoryConsentStateMachine-B4-1u-L8.esm.js} +2 -2
- package/dist/{onDeviceFaceResults-BeHb0Zet.esm.js → onDeviceFaceResults-BqLGnM8A.esm.js} +3 -3
- package/dist/personhood.esm.js +5 -5
- package/dist/phone.esm.js +2 -2
- package/dist/{phoneManager-B_03mKyi.esm.js → phoneManager-FsJ0W2Ei.esm.js} +2 -2
- package/dist/{phoneStateMachine-E1fUUcNM.esm.js → phoneStateMachine-Ba0wKHyX.esm.js} +2 -2
- package/dist/qe-signature.esm.js +1 -1
- package/dist/{recordingService-DKb3A23J.esm.js → recordingService-BNUTYip6.esm.js} +1 -1
- package/dist/redirect-to-mobile.esm.js +2 -2
- package/dist/{redirectToMobileManager-Bgo6eqri.esm.js → redirectToMobileManager-y4VQB11M.esm.js} +3 -3
- package/dist/{redirectToMobileStateMachine-C9SYCJcH.esm.js → redirectToMobileStateMachine-Cyv2x0PP.esm.js} +2 -2
- package/dist/{runChildModule-DsFARqqY.esm.js → runChildModule-CyrA4IkE.esm.js} +3 -3
- package/dist/{sdkVersion-C5UD9rLq.esm.js → sdkVersion-C2N5d9MD.esm.js} +1 -1
- package/dist/selfie.esm.js +6 -6
- package/dist/{selfieManager-B-wIgrPB.esm.js → selfieManager-CCl2CgNV.esm.js} +3 -3
- package/dist/{selfieStateMachine-DXwqWYTH.esm.js → selfieStateMachine-OD6m5Pnh.esm.js} +4 -4
- package/dist/{session-khwoLlR8.esm.js → session-CK-eOrL7.esm.js} +4 -4
- package/dist/session.esm.js +4 -4
- package/dist/{sessionInitializer-BVjQZWxu.esm.js → sessionInitializer-CVrazqxw.esm.js} +4 -4
- package/dist/{setup-CSYGLqEQ.esm.js → setup-Cl3qY4N6.esm.js} +5 -5
- package/dist/signature.esm.js +2 -2
- package/dist/{signatureManager-DoACIR02.esm.js → signatureManager-Ca43yhwk.esm.js} +2 -2
- package/dist/{signatureStateMachine-Cf73DGWO.esm.js → signatureStateMachine-K1LMRrxG.esm.js} +2 -2
- package/dist/trueSight-ClQ2RLmN.esm.js +1 -0
- package/dist/{trueSightService-cimVc012.esm.js → trueSightService-CTM6xlHG.esm.js} +2 -2
- package/dist/trust-graph.esm.js +1 -1
- package/dist/{types-B_PW_0Wq2.d.ts → types-DQtm9Esn2.d.ts} +69 -13
- package/dist/video-selfie.esm.js +5 -5
- package/dist/{videoSelfieCameraWarmer-fvzaTVJ4.esm.js → videoSelfieCameraWarmer-DVzRMMaV.esm.js} +2 -2
- package/dist/wasm.esm.js +1 -1
- package/dist/watchlist-for-business.esm.js +2 -2
- package/dist/watchlist.esm.js +2 -2
- package/dist/{watchlistForBusinessManager-Bo08PkKo.esm.js → watchlistForBusinessManager-MEWKeR3h.esm.js} +2 -2
- package/dist/{watchlistForBusinessStateMachine-BAg1B4HF.esm.js → watchlistForBusinessStateMachine-Dszp35m2.esm.js} +2 -2
- package/dist/{watchlistManager-CPBZnFYj.esm.js → watchlistManager-LoNZH9qm.esm.js} +2 -2
- package/dist/{watchlistStateMachine-Bl7Wy9Cm.esm.js → watchlistStateMachine-DIKQDoUT.esm.js} +2 -2
- package/dist/workflow.esm.js +36 -36
- package/dist/{xstate-actors.esm-CtI5S0f4.esm.js → xstate-actors.esm-BXeQ-Ucz.esm.js} +1 -1
- package/dist/{xstate.esm-Cf4e0Cfd.esm.js → xstate.esm-BuFLFuzz.esm.js} +1 -1
- package/package.json +1 -1
- package/dist/trueSight-DZJ12lrB.esm.js +0 -1
package/dist/{idCaptureStateMachine-DF1WRVP9.esm.js → idCaptureStateMachine-DG7t_39B.esm.js}
RENAMED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { t as BrowserTimerProvider } from "./BrowserTimerProvider-BXhgNxLt.esm.js";
|
|
2
|
-
import { s as exposeExperimentOnce } from "./feature-management-
|
|
2
|
+
import { s as exposeExperimentOnce } from "./feature-management-DBuXnUWY.esm.js";
|
|
3
3
|
import { n as revokeObjectURL } from "./IBrowserEnvironmentCapability-DEaRRk-R.esm.js";
|
|
4
4
|
import { r as getToken, t as api } from "./api-Bx3gKW_y.esm.js";
|
|
5
|
-
import { c as trueSightHintTransition, l as trueSightLog, r as noteTrueSightCaptureActivity } from "./trueSightService-
|
|
5
|
+
import { c as trueSightHintTransition, l as trueSightLog, r as noteTrueSightCaptureActivity } from "./trueSightService-CTM6xlHG.esm.js";
|
|
6
6
|
import { n as eventModuleNames, s as recordExperimentAssignmentOnce } from "./events-DYiyoSlx.esm.js";
|
|
7
|
-
import { t as getDisableIpify } from "./sessionInitializer-
|
|
8
|
-
import "./trueSight-
|
|
7
|
+
import { t as getDisableIpify } from "./sessionInitializer-CVrazqxw.esm.js";
|
|
8
|
+
import "./trueSight-ClQ2RLmN.esm.js";
|
|
9
9
|
import { t as addDeviceStats } from "./stats-B0nFKawG.esm.js";
|
|
10
10
|
import { t as isAndroid } from "./platform-Q4r1nvWX.esm.js";
|
|
11
|
-
import "./session-
|
|
12
|
-
import {
|
|
13
|
-
import { n as fromPromise, t as fromCallback } from "./xstate-actors.esm-
|
|
11
|
+
import "./session-CK-eOrL7.esm.js";
|
|
12
|
+
import { c as not, i as assign, l as raise, n as enqueueActions, o as and, r as sendTo, t as setup } from "./xstate.esm-BuFLFuzz.esm.js";
|
|
13
|
+
import { n as fromPromise, t as fromCallback } from "./xstate-actors.esm-BXeQ-Ucz.esm.js";
|
|
14
14
|
import { n as invokeRequestPermissionActor, t as checkPermission } from "./permissionServices-Dgtg_4Lv.esm.js";
|
|
15
|
-
import { _ as StreamCanvasProcessingSession } from "./onDeviceFaceResults-
|
|
15
|
+
import { _ as StreamCanvasProcessingSession } from "./onDeviceFaceResults-BqLGnM8A.esm.js";
|
|
16
16
|
import { t as sleep } from "./ITimerCapability-DgdDzp8G.esm.js";
|
|
17
17
|
import { t as IncodeCanvas } from "./canvas-E1zGkel4.esm.js";
|
|
18
18
|
import { t as getBrowser } from "./getBrowser-DmNprTMV.esm.js";
|
|
@@ -20,7 +20,7 @@ import { n as getWindowDimensions } from "./getDeviceClass-CeBiEayS.esm.js";
|
|
|
20
20
|
import { t as StreamCanvasCapture } from "./StreamCanvasCapture-D2XcXCZ4.esm.js";
|
|
21
21
|
import { n as needsMotionPrimeOnlyFromPermission, r as resolveStoredPermissionResult, t as isReadyForCaptureFromPermission } from "./permissionGuards-DJNYwEOq.esm.js";
|
|
22
22
|
import { r as flagIdManualReview, t as imageFileToDataUrl } from "./imageFile-DutiOU7n.esm.js";
|
|
23
|
-
import { a as processId, c as stopStream, d as validateUploadResponse, f as ID_ERROR_CODES, g as
|
|
23
|
+
import { _ as getIdCameraStream, a as processId, c as stopStream, d as validateUploadResponse, f as ID_ERROR_CODES, g as OPTIMIZING_WATCHDOG_MARGIN_MS, h as CAPTURE_OPTIMIZING, i as preloadIdRecordingProvider, l as uploadIdImage, m as resolveIdCaptureThresholds, o as startRecordingSession, r as initializeIdCapture, s as stopRecording, t as addBarcode, u as uploadManualIdFile } from "./idCaptureServices-0lE7kEdA.esm.js";
|
|
24
24
|
//#region src/modules/id/digitalUpload/digitalUploadErrors.ts
|
|
25
25
|
const TERMINAL_FAIL_REASONS = /* @__PURE__ */ new Set(["DIGITAL_ID_REQUESTED_BUT_OTHER_PROVIDED", "ID_TYPE_UNACCEPTABLE"]);
|
|
26
26
|
function isKnownFailReason(reason) {
|
|
@@ -737,6 +737,20 @@ const hasAttemptsRemainingGuard = ({ context }) => context.attemptsRemaining > 0
|
|
|
737
737
|
const hasCapturedImageGuard = ({ context }) => {
|
|
738
738
|
return context.provider?.getCapturedCanvas() !== null;
|
|
739
739
|
};
|
|
740
|
+
const hasCandidateFrameGuard = ({ event }) => {
|
|
741
|
+
return event.type === "DETECTION_OPTIMIZING" && Boolean(event.candidateCanvas);
|
|
742
|
+
};
|
|
743
|
+
/**
|
|
744
|
+
* IDC-05: whether WASM's commit arrived while the optimizing phase was still
|
|
745
|
+
* spending its dwell, and is therefore parked in `optimizing.holding` waiting
|
|
746
|
+
* for the release.
|
|
747
|
+
*
|
|
748
|
+
* Gates the phase's own `SWITCH_TO_MANUAL_CAPTURE` / `MANUAL_CAPTURE` handlers:
|
|
749
|
+
* while a commit is parked those escapes end the dwell early instead of leaving
|
|
750
|
+
* the phase, so WASM's committed frame is honored rather than dropped on the way
|
|
751
|
+
* out. False leaves both events to the arm parent, the documented escape hatch.
|
|
752
|
+
*/
|
|
753
|
+
const hasStashedCommitGuard = ({ context }) => context.stashedCommit !== void 0;
|
|
740
754
|
const hasUploadValidationErrorGuard = ({ context }) => {
|
|
741
755
|
if (!context.uploadResponse) return false;
|
|
742
756
|
return validateUploadResponse(context.uploadResponse, {
|
|
@@ -781,16 +795,31 @@ const shouldContinueToBackGuard = ({ context }) => {
|
|
|
781
795
|
const shouldContinueToFrontGuard = ({ context }) => context.config.usSmartCapture === true && context.currentMode === "back" && context.uploadResponse?.forceFrontIdCapture === true;
|
|
782
796
|
const hasMandatoryConsentGuard = ({ context }) => context.uploadResponse?.showMandatoryConsent === true;
|
|
783
797
|
/**
|
|
784
|
-
*
|
|
785
|
-
* `
|
|
798
|
+
* IDC-05 arm, as resolved once per session by
|
|
799
|
+
* `resolveCaptureOptimizingTreatment` at actor creation.
|
|
786
800
|
*/
|
|
787
|
-
const
|
|
801
|
+
const isCaptureOptimizingModeGuard = ({ context }) => context.captureFeedbackMode === "optimizing";
|
|
788
802
|
/**
|
|
789
|
-
*
|
|
790
|
-
*
|
|
791
|
-
*
|
|
803
|
+
* IDC-05 rendering-layer capability: whether the consumer opted into rendering
|
|
804
|
+
* `captureStatus === 'optimizing'`. Consumers that omit it retain the direct
|
|
805
|
+
* capture-to-upload path. Nothing is advanced by the host — core owns the phase's
|
|
806
|
+
* timing on both paths (WASM's commit on auto capture, `optimizingDwell` on
|
|
807
|
+
* manual), so there is no acknowledgement call.
|
|
808
|
+
*
|
|
809
|
+
* Paired with `isCaptureOptimizingModeGuard` at both branch sites
|
|
810
|
+
* (`choosingDetectionStrategy`, `capturingManual`). Through
|
|
811
|
+
* `createIdCaptureActor` the two can never disagree — that path derives
|
|
812
|
+
* `captureFeedbackMode` from `resolveCaptureOptimizingTreatment`, which
|
|
813
|
+
* already requires this capability — so the pairing looks redundant, and for
|
|
814
|
+
* SDK-built sessions it is.
|
|
815
|
+
*
|
|
816
|
+
* It is NOT redundant on the public surface: `idCaptureMachine` is exported from
|
|
817
|
+
* `@incodetech/core/id` and its `input.captureFeedbackMode` is settable, so a
|
|
818
|
+
* host wiring the machine up directly could otherwise reach the phase without
|
|
819
|
+
* declaring the capability. This guard is what makes the documented opt-in true
|
|
820
|
+
* for every route into the machine, not just the factory.
|
|
792
821
|
*/
|
|
793
|
-
const
|
|
822
|
+
const supportsOptimizingStatusGuard = ({ context }) => context.config.supportsOptimizingStatus === true;
|
|
794
823
|
const isDeepsightEnabledGuard = ({ context }) => context.dependencies !== void 0;
|
|
795
824
|
const isDeepsightReadyGuard = ({ context }) => context.deepsightService !== void 0;
|
|
796
825
|
const needsDeepsightInitGuard = ({ context }) => context.dependencies !== void 0 && context.deepsightService === void 0 && !context.deepsightInitAttempted;
|
|
@@ -879,6 +908,7 @@ const isBackModeInMultiSideFlowGuard = ({ context }) => context.currentMode ===
|
|
|
879
908
|
* max-attempts/OCR cap (ENG-46592 / re-respects ENG-45666).
|
|
880
909
|
*/
|
|
881
910
|
const wasExpiredRedirectedGuard = ({ context }) => context.expiredRedirected === true;
|
|
911
|
+
const hasManualCaptureTriggeredGuard = ({ context }) => context.manualCaptureTriggered;
|
|
882
912
|
//#endregion
|
|
883
913
|
//#region src/modules/id/idCaptureHelpers.ts
|
|
884
914
|
/**
|
|
@@ -987,6 +1017,13 @@ const runDetectionActor = fromCallback(({ input, sendBack }) => {
|
|
|
987
1017
|
let isCapturing = false;
|
|
988
1018
|
const timer = BrowserTimerProvider.getInstance();
|
|
989
1019
|
let notificationTimeout = null;
|
|
1020
|
+
let optimizingBoundaryTimeout = null;
|
|
1021
|
+
/**
|
|
1022
|
+
* IDC-05 latch for the boundary clock: whether a boundary is currently
|
|
1023
|
+
* pending. `onCapturing` is WASM's "aggregation window opened" callback and is
|
|
1024
|
+
* the clock's only T0; nothing in WASM enforces that it fires once per window.
|
|
1025
|
+
*/
|
|
1026
|
+
let isOptimizingBoundaryArmed = false;
|
|
990
1027
|
let currentNotificationStatus = null;
|
|
991
1028
|
let lastReportedSide = null;
|
|
992
1029
|
const NOTIFICATION_DURATION_MS = 500;
|
|
@@ -1005,6 +1042,50 @@ const runDetectionActor = fromCallback(({ input, sendBack }) => {
|
|
|
1005
1042
|
currentNotificationStatus = null;
|
|
1006
1043
|
}
|
|
1007
1044
|
};
|
|
1045
|
+
const clearOptimizingBoundary = () => {
|
|
1046
|
+
if (optimizingBoundaryTimeout) {
|
|
1047
|
+
timer.clearTimeout(optimizingBoundaryTimeout);
|
|
1048
|
+
optimizingBoundaryTimeout = null;
|
|
1049
|
+
}
|
|
1050
|
+
isOptimizingBoundaryArmed = false;
|
|
1051
|
+
};
|
|
1052
|
+
/**
|
|
1053
|
+
* IDC-05 boundary clock — the actor's *only* timer, and the only piece of the
|
|
1054
|
+
* optimizing phase it owns. WASM's `CapturingManager` opens the
|
|
1055
|
+
* frames-aggregation window at `onCapturing` and closes it with `onCapture` at
|
|
1056
|
+
* `T0 + framesAggregationInterval` (already resolved to
|
|
1057
|
+
* `captureWindowMs + optimizingDwellMs`). The phase begins at
|
|
1058
|
+
* `T0 + captureWindowMs`, so it is timed from the very callback that defines
|
|
1059
|
+
* T0; how long it then lasts is the machine's business.
|
|
1060
|
+
*
|
|
1061
|
+
* No best frame yet at that point means the session simply behaves like the
|
|
1062
|
+
* countdown arm — no event, no phase — which mirrors iOS's "auto capture with
|
|
1063
|
+
* no best crop yet" fallback.
|
|
1064
|
+
*
|
|
1065
|
+
* At most one boundary pending at a time — see `isOptimizingBoundaryArmed`.
|
|
1066
|
+
*/
|
|
1067
|
+
const scheduleOptimizingBoundary = () => {
|
|
1068
|
+
if (input.optimizingAfterMs == null || isOptimizingBoundaryArmed) return;
|
|
1069
|
+
isOptimizingBoundaryArmed = true;
|
|
1070
|
+
optimizingBoundaryTimeout = timer.setTimeout(() => {
|
|
1071
|
+
optimizingBoundaryTimeout = null;
|
|
1072
|
+
isOptimizingBoundaryArmed = false;
|
|
1073
|
+
enterOptimizing();
|
|
1074
|
+
}, input.optimizingAfterMs);
|
|
1075
|
+
};
|
|
1076
|
+
/**
|
|
1077
|
+
* Reports the boundary with the candidate frame to freeze. Silent when there
|
|
1078
|
+
* is no candidate — no event means no phase, and the session behaves like the
|
|
1079
|
+
* countdown arm (see `scheduleOptimizingBoundary`).
|
|
1080
|
+
*/
|
|
1081
|
+
const enterOptimizing = () => {
|
|
1082
|
+
const candidateCanvas = bestCanvas?.clone();
|
|
1083
|
+
if (!candidateCanvas) return;
|
|
1084
|
+
sendBack({
|
|
1085
|
+
type: "DETECTION_OPTIMIZING",
|
|
1086
|
+
candidateCanvas
|
|
1087
|
+
});
|
|
1088
|
+
};
|
|
1008
1089
|
const sendNotification = (status) => {
|
|
1009
1090
|
if (isReportedSideWrong()) return;
|
|
1010
1091
|
if (notificationTimeout && currentNotificationStatus !== status) return;
|
|
@@ -1092,6 +1173,7 @@ const runDetectionActor = fromCallback(({ input, sendBack }) => {
|
|
|
1092
1173
|
},
|
|
1093
1174
|
onSwitchToManualCapture: () => {
|
|
1094
1175
|
isCapturing = false;
|
|
1176
|
+
clearOptimizingBoundary();
|
|
1095
1177
|
sendBack({ type: "SWITCH_TO_MANUAL_CAPTURE" });
|
|
1096
1178
|
},
|
|
1097
1179
|
onCapturing: () => {
|
|
@@ -1103,6 +1185,7 @@ const runDetectionActor = fromCallback(({ input, sendBack }) => {
|
|
|
1103
1185
|
type: "DETECTION_UPDATE",
|
|
1104
1186
|
status: "capturing"
|
|
1105
1187
|
});
|
|
1188
|
+
scheduleOptimizingBoundary();
|
|
1106
1189
|
},
|
|
1107
1190
|
onBestFrame: (blur, glare, orientation) => {
|
|
1108
1191
|
if (currentCanvas) {
|
|
@@ -1119,16 +1202,24 @@ const runDetectionActor = fromCallback(({ input, sendBack }) => {
|
|
|
1119
1202
|
},
|
|
1120
1203
|
onCapture: () => {
|
|
1121
1204
|
isCapturing = false;
|
|
1122
|
-
if (
|
|
1205
|
+
if (isOptimizingBoundaryArmed) {
|
|
1206
|
+
clearOptimizingBoundary();
|
|
1207
|
+
enterOptimizing();
|
|
1208
|
+
}
|
|
1209
|
+
if (!bestCanvas) {
|
|
1210
|
+
const clonedCanvas = currentCanvas?.clone();
|
|
1211
|
+
if (clonedCanvas) sendBack({
|
|
1212
|
+
type: "DETECTION_SUCCESS",
|
|
1213
|
+
canvas: clonedCanvas,
|
|
1214
|
+
qualityElements: {}
|
|
1215
|
+
});
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
sendBack({
|
|
1123
1219
|
type: "DETECTION_SUCCESS",
|
|
1124
1220
|
canvas: bestCanvas,
|
|
1125
1221
|
qualityElements: storedQualityElements
|
|
1126
1222
|
});
|
|
1127
|
-
else if (currentCanvas) sendBack({
|
|
1128
|
-
type: "DETECTION_SUCCESS",
|
|
1129
|
-
canvas: currentCanvas.clone(),
|
|
1130
|
-
qualityElements: {}
|
|
1131
|
-
});
|
|
1132
1223
|
},
|
|
1133
1224
|
onIdTypeChange: (idType) => {
|
|
1134
1225
|
sendBack({
|
|
@@ -1179,6 +1270,7 @@ const runDetectionActor = fromCallback(({ input, sendBack }) => {
|
|
|
1179
1270
|
notificationTimeout = null;
|
|
1180
1271
|
currentNotificationStatus = null;
|
|
1181
1272
|
}
|
|
1273
|
+
clearOptimizingBoundary();
|
|
1182
1274
|
currentCanvas = null;
|
|
1183
1275
|
bestCanvas = null;
|
|
1184
1276
|
storedQualityElements = {};
|
|
@@ -1197,6 +1289,7 @@ const runDetectionActor = fromCallback(({ input, sendBack }) => {
|
|
|
1197
1289
|
});
|
|
1198
1290
|
return () => {
|
|
1199
1291
|
clearNotificationTimeout();
|
|
1292
|
+
clearOptimizingBoundary();
|
|
1200
1293
|
session?.dispose();
|
|
1201
1294
|
noteTrueSightCaptureActivity(false);
|
|
1202
1295
|
};
|
|
@@ -1284,7 +1377,7 @@ const startRecordingActor = fromPromise(async ({ input }) => {
|
|
|
1284
1377
|
});
|
|
1285
1378
|
const initializeDeepsightSessionActor = fromPromise(async ({ input }) => {
|
|
1286
1379
|
if (!input.dependencies) return;
|
|
1287
|
-
const { loadDeepsightSession } = await import("./deepsightLoader-
|
|
1380
|
+
const { loadDeepsightSession } = await import("./deepsightLoader-B97yrkGH.esm.js");
|
|
1288
1381
|
return loadDeepsightSession({
|
|
1289
1382
|
ds: input.ds,
|
|
1290
1383
|
storage: input.dependencies.storage,
|
|
@@ -1322,11 +1415,11 @@ function performResetForFrontCapture(context) {
|
|
|
1322
1415
|
function performResetDetection(context) {
|
|
1323
1416
|
context.resetDetection?.();
|
|
1324
1417
|
}
|
|
1325
|
-
function
|
|
1326
|
-
if (context.config.
|
|
1327
|
-
const assignment = exposeExperimentOnce(
|
|
1418
|
+
function performReportCaptureOptimizingAssignment(context) {
|
|
1419
|
+
if (context.config.supportsOptimizingStatus !== true) return;
|
|
1420
|
+
const assignment = exposeExperimentOnce(CAPTURE_OPTIMIZING);
|
|
1328
1421
|
if (!assignment) return;
|
|
1329
|
-
recordExperimentAssignmentOnce(eventModuleNames.idCapture,
|
|
1422
|
+
recordExperimentAssignmentOnce(eventModuleNames.idCapture, CAPTURE_OPTIMIZING.storeParam, assignment);
|
|
1330
1423
|
}
|
|
1331
1424
|
function performStopMediaRecording(context) {
|
|
1332
1425
|
if (context.recordingSession) stopRecording(context.recordingSession);
|
|
@@ -1392,6 +1485,7 @@ function getResetContextValues(context) {
|
|
|
1392
1485
|
idType: void 0,
|
|
1393
1486
|
qualityElements: void 0,
|
|
1394
1487
|
previewImageUrl: void 0,
|
|
1488
|
+
...getClearOptimizingValues(context),
|
|
1395
1489
|
uploadProgress: void 0,
|
|
1396
1490
|
currentMode,
|
|
1397
1491
|
selectedDocumentType: void 0,
|
|
@@ -1407,6 +1501,7 @@ function getClearUploadFailureValues(context) {
|
|
|
1407
1501
|
uploadError: void 0,
|
|
1408
1502
|
detectionStatus: "idle",
|
|
1409
1503
|
previewImageUrl: void 0,
|
|
1504
|
+
...getClearOptimizingValues(context),
|
|
1410
1505
|
uploadProgress: void 0
|
|
1411
1506
|
};
|
|
1412
1507
|
}
|
|
@@ -1426,6 +1521,39 @@ function storeCapturedCanvasInProviderLogic(context, event) {
|
|
|
1426
1521
|
const canvasHeight = canvas.height();
|
|
1427
1522
|
if (!canvasWidth || !canvasHeight) return;
|
|
1428
1523
|
const originalCanvas = canvas;
|
|
1524
|
+
const frameRect = resolveCaptureFrameRect(context, canvasWidth, canvasHeight);
|
|
1525
|
+
const transformedCanvas = context.provider.transformPerspective(originalCanvas, frameRect);
|
|
1526
|
+
context.provider.setCapturedCanvases(originalCanvas, transformedCanvas);
|
|
1527
|
+
}
|
|
1528
|
+
/**
|
|
1529
|
+
* JPEG quality for the IDC-05 optimizing phase's display-only still.
|
|
1530
|
+
*
|
|
1531
|
+
* `updateBlob()` is synchronous and expensive: `toDataURL` → `atob` → a per-byte
|
|
1532
|
+
* loop building the blob (`IncodeCanvas.base64ToBlob`). At the default quality of
|
|
1533
|
+
* 1.0 on a 1080p frame that is tens of milliseconds of main-thread work — and on
|
|
1534
|
+
* this path it runs inside an `assign`, in the same tick that starts the phase
|
|
1535
|
+
* animation, with the 30fps WASM detection loop still live. Both halves of the
|
|
1536
|
+
* cost scale with the encoded byte count, so dropping quality cuts the encode and
|
|
1537
|
+
* the byte loop together.
|
|
1538
|
+
*
|
|
1539
|
+
* Treatment-arm only, deliberately: the committed frame keeps quality 1.0, since
|
|
1540
|
+
* it is what uploads (`getStoreCapturedImageValues` → `getBase64Image(1.0)`) and
|
|
1541
|
+
* its encode happens on the analyzing screen with no animation to jank. This
|
|
1542
|
+
* still is on screen for one dwell at roughly card size and never leaves the
|
|
1543
|
+
* device.
|
|
1544
|
+
*/
|
|
1545
|
+
const CANDIDATE_FRAME_JPEG_QUALITY = .8;
|
|
1546
|
+
/**
|
|
1547
|
+
* The document's rectangle within a camera frame, in canvas coordinates —
|
|
1548
|
+
* the input to `transformPerspective`.
|
|
1549
|
+
*
|
|
1550
|
+
* Shared by the commit path (`storeCapturedCanvasInProviderLogic`) and the
|
|
1551
|
+
* IDC-05 optimizing phase (`getCandidateFrameValues`) so the still shown
|
|
1552
|
+
* mid-capture is cropped and warped exactly like the frame that later uploads.
|
|
1553
|
+
* Deriving it twice is what made the phase show an uncropped full frame that then
|
|
1554
|
+
* visibly jumped to a cropped one on the analyzing screen.
|
|
1555
|
+
*/
|
|
1556
|
+
function resolveCaptureFrameRect(context, canvasWidth, canvasHeight) {
|
|
1429
1557
|
let frameRect;
|
|
1430
1558
|
const { innerWidth: viewportWidth, innerHeight: viewportHeight } = getWindowDimensions();
|
|
1431
1559
|
if (context.detectionArea) {
|
|
@@ -1457,7 +1585,7 @@ function storeCapturedCanvasInProviderLogic(context, event) {
|
|
|
1457
1585
|
h: context.frameRect.h / scale
|
|
1458
1586
|
};
|
|
1459
1587
|
} else {
|
|
1460
|
-
const quadValue = (context.provider
|
|
1588
|
+
const quadValue = (context.provider?.getLastProcessResult?.())?.quad;
|
|
1461
1589
|
const hasQuad = !!quadValue;
|
|
1462
1590
|
const quadSize = quadValue?.size ? quadValue.size() : quadValue?.length ?? 0;
|
|
1463
1591
|
if (hasQuad && quadSize >= 4 && quadValue.get) {
|
|
@@ -1488,8 +1616,7 @@ function storeCapturedCanvasInProviderLogic(context, event) {
|
|
|
1488
1616
|
};
|
|
1489
1617
|
}
|
|
1490
1618
|
}
|
|
1491
|
-
|
|
1492
|
-
context.provider.setCapturedCanvases(originalCanvas, transformedCanvas);
|
|
1619
|
+
return frameRect;
|
|
1493
1620
|
}
|
|
1494
1621
|
function getStoreCapturedImageValues(context, event) {
|
|
1495
1622
|
if (!context.currentMode) return {
|
|
@@ -1523,7 +1650,79 @@ function getStoreCapturedImageValues(context, event) {
|
|
|
1523
1650
|
}
|
|
1524
1651
|
return {
|
|
1525
1652
|
capturedImages,
|
|
1526
|
-
previewImageUrl
|
|
1653
|
+
previewImageUrl,
|
|
1654
|
+
...getClearOptimizingValues(context)
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
|
+
/**
|
|
1658
|
+
* IDC-05: freezes WASM's best-scoring frame *so far* for the optimizing phase.
|
|
1659
|
+
* Display-only — the committed frame arrives later, from `onCapture`, and
|
|
1660
|
+
* `storeCapturedImage` puts that one on `previewImageUrl` while clearing this
|
|
1661
|
+
* one in the same assign, so the rendering layer's
|
|
1662
|
+
* `candidateImageUrl ?? previewImageUrl` falls through to the frame that
|
|
1663
|
+
* actually uploads for the crossfade.
|
|
1664
|
+
*
|
|
1665
|
+
* Revokes any previous URL rather than leaking one per retry.
|
|
1666
|
+
*/
|
|
1667
|
+
function getCandidateFrameValues(context, event) {
|
|
1668
|
+
if (event.type !== "DETECTION_OPTIMIZING" || !event.candidateCanvas) return { candidateImageUrl: context.candidateImageUrl };
|
|
1669
|
+
const candidateCanvas = event.candidateCanvas;
|
|
1670
|
+
const canvas = cropCanvasForPreview(context, candidateCanvas);
|
|
1671
|
+
canvas.updateBlob(CANDIDATE_FRAME_JPEG_QUALITY);
|
|
1672
|
+
const url = canvas.getBlobData()?.url;
|
|
1673
|
+
if (!url) {
|
|
1674
|
+
releasePreviewCanvases(candidateCanvas, canvas, { shouldReleasePreview: true });
|
|
1675
|
+
return { candidateImageUrl: context.candidateImageUrl };
|
|
1676
|
+
}
|
|
1677
|
+
releasePreviewCanvases(candidateCanvas, canvas, { shouldReleasePreview: false });
|
|
1678
|
+
if (context.candidateImageUrl) revokeObjectURL(context.candidateImageUrl);
|
|
1679
|
+
return { candidateImageUrl: url };
|
|
1680
|
+
}
|
|
1681
|
+
/**
|
|
1682
|
+
* Reclaims the full-frame canvases the phase allocated. At 1080p each is ~8MB of
|
|
1683
|
+
* backing store, and `release()` frees it now instead of at the next GC — which
|
|
1684
|
+
* is what matters on iOS Safari, where canvas memory is its own budget.
|
|
1685
|
+
*
|
|
1686
|
+
* `source` — the clone the detection actor snapshotted — is always dead by the
|
|
1687
|
+
* time this runs: its pixels live on in `preview`'s blob.
|
|
1688
|
+
*
|
|
1689
|
+
* `preview` is the caller's decision, because `release()` also revokes
|
|
1690
|
+
* `blobData.url`. On the success path that URL is the very thing being handed to
|
|
1691
|
+
* the machine as `candidateImageUrl`, so releasing it would blank the phase's
|
|
1692
|
+
* own still; pass `shouldReleasePreview: true` only where no URL survives. Either way
|
|
1693
|
+
* the identity guard covers `transformPerspective` returning the canvas it was
|
|
1694
|
+
* given (no provider, or a WASM failure), so the aliased canvas is never
|
|
1695
|
+
* released twice or released out from under a live URL.
|
|
1696
|
+
*/
|
|
1697
|
+
function releasePreviewCanvases(source, preview, { shouldReleasePreview }) {
|
|
1698
|
+
if (preview === source) {
|
|
1699
|
+
if (shouldReleasePreview) source.release();
|
|
1700
|
+
return;
|
|
1701
|
+
}
|
|
1702
|
+
if (shouldReleasePreview) preview.release();
|
|
1703
|
+
source.release();
|
|
1704
|
+
}
|
|
1705
|
+
function cropCanvasForPreview(context, canvas) {
|
|
1706
|
+
const canvasWidth = canvas.width();
|
|
1707
|
+
const canvasHeight = canvas.height();
|
|
1708
|
+
if (!context.provider || !canvasWidth || !canvasHeight) return canvas;
|
|
1709
|
+
const frameRect = resolveCaptureFrameRect(context, canvasWidth, canvasHeight);
|
|
1710
|
+
return context.provider.transformPerspective(canvas, frameRect);
|
|
1711
|
+
}
|
|
1712
|
+
/**
|
|
1713
|
+
* Drops the IDC-05 best-so-far still at every attempt/side boundary. Unlike
|
|
1714
|
+
* `previewImageUrl` it is never preserved into `flipPreview` (it was never a
|
|
1715
|
+
* committed frame), so it can always be revoked outright.
|
|
1716
|
+
*
|
|
1717
|
+
* Clears `stashedCommit` alongside it: a commit parked for the phase's dwell is
|
|
1718
|
+
* only meaningful inside that phase, and holding the canvas reference past it
|
|
1719
|
+
* would keep a full-res frame alive for the rest of the attempt.
|
|
1720
|
+
*/
|
|
1721
|
+
function getClearOptimizingValues(context) {
|
|
1722
|
+
if (context.candidateImageUrl) revokeObjectURL(context.candidateImageUrl);
|
|
1723
|
+
return {
|
|
1724
|
+
candidateImageUrl: void 0,
|
|
1725
|
+
stashedCommit: void 0
|
|
1527
1726
|
};
|
|
1528
1727
|
}
|
|
1529
1728
|
function getDetectionStatusFromUpdate(context, event) {
|
|
@@ -1658,6 +1857,7 @@ const idCaptureMachine = setup({
|
|
|
1658
1857
|
qualityElements: void 0,
|
|
1659
1858
|
frameRect: void 0,
|
|
1660
1859
|
previewImageUrl: void 0,
|
|
1860
|
+
...getClearOptimizingValues(context),
|
|
1661
1861
|
flipPreview: context.previewImageUrl ? {
|
|
1662
1862
|
url: context.previewImageUrl,
|
|
1663
1863
|
orientation: context.orientation,
|
|
@@ -1688,6 +1888,7 @@ const idCaptureMachine = setup({
|
|
|
1688
1888
|
qualityElements: void 0,
|
|
1689
1889
|
frameRect: void 0,
|
|
1690
1890
|
previewImageUrl: void 0,
|
|
1891
|
+
...getClearOptimizingValues(context),
|
|
1691
1892
|
flipPreview: context.previewImageUrl ? {
|
|
1692
1893
|
url: context.previewImageUrl,
|
|
1693
1894
|
orientation: context.orientation,
|
|
@@ -1717,6 +1918,7 @@ const idCaptureMachine = setup({
|
|
|
1717
1918
|
qualityElements: void 0,
|
|
1718
1919
|
frameRect: void 0,
|
|
1719
1920
|
previewImageUrl: void 0,
|
|
1921
|
+
...getClearOptimizingValues(context),
|
|
1720
1922
|
uploadProgress: void 0,
|
|
1721
1923
|
manualCaptureTriggered: false,
|
|
1722
1924
|
attemptsRemaining: context.config.captureAttempts
|
|
@@ -1739,8 +1941,8 @@ const idCaptureMachine = setup({
|
|
|
1739
1941
|
trackTutorialId: () => {},
|
|
1740
1942
|
trackContinue: () => {},
|
|
1741
1943
|
trackCameraId: ({ context }) => {},
|
|
1742
|
-
|
|
1743
|
-
|
|
1944
|
+
reportCaptureOptimizingAssignment: ({ context }) => {
|
|
1945
|
+
performReportCaptureOptimizingAssignment(context);
|
|
1744
1946
|
},
|
|
1745
1947
|
preloadRecordingProvider: ({ context }) => {
|
|
1746
1948
|
preloadIdRecordingProvider(context.config);
|
|
@@ -1782,6 +1984,53 @@ const idCaptureMachine = setup({
|
|
|
1782
1984
|
} }),
|
|
1783
1985
|
setCurrentMode: assign({ currentMode: ({ event, context }) => getCurrentModeFromEvent(context, event) }),
|
|
1784
1986
|
storeCapturedImage: assign(({ context, event }) => getStoreCapturedImageValues(context, event)),
|
|
1987
|
+
setCandidateFrame: assign(({ context, event }) => getCandidateFrameValues(context, event)),
|
|
1988
|
+
/**
|
|
1989
|
+
* IDC-05: parks WASM's commit while the optimizing phase spends the rest of
|
|
1990
|
+
* its dwell. The frame travels in context only for that stretch —
|
|
1991
|
+
* `releaseStashedCommit` re-raises it and `getClearOptimizingValues` drops it
|
|
1992
|
+
* on every other exit from the phase.
|
|
1993
|
+
*/
|
|
1994
|
+
stashCommittedFrame: assign({ stashedCommit: ({ event }) => {
|
|
1995
|
+
const commit = event;
|
|
1996
|
+
return {
|
|
1997
|
+
canvas: commit.canvas,
|
|
1998
|
+
qualityElements: commit.qualityElements
|
|
1999
|
+
};
|
|
2000
|
+
} }),
|
|
2001
|
+
/**
|
|
2002
|
+
* IDC-05: hands a parked commit back to the machine as the very event that
|
|
2003
|
+
* would have carried it, so `capturing`'s entry actions stay event-driven.
|
|
2004
|
+
* Re-raised rather than read from context by `capturing` because
|
|
2005
|
+
* `storeCapturedCanvasInProvider` falls back to the *live* frame when the
|
|
2006
|
+
* entering event has no canvas — a timer transition into `capturing` would
|
|
2007
|
+
* stage a live frame for upload instead of the one WASM committed.
|
|
2008
|
+
*/
|
|
2009
|
+
releaseStashedCommit: enqueueActions(({ context, enqueue }) => {
|
|
2010
|
+
const stashed = context.stashedCommit;
|
|
2011
|
+
if (!stashed) return;
|
|
2012
|
+
enqueue(raise({
|
|
2013
|
+
type: "DETECTION_SUCCESS",
|
|
2014
|
+
canvas: stashed.canvas,
|
|
2015
|
+
qualityElements: stashed.qualityElements
|
|
2016
|
+
}));
|
|
2017
|
+
}),
|
|
2018
|
+
/**
|
|
2019
|
+
* IDC-05: releases everything the optimizing phase allocated — the parked
|
|
2020
|
+
* commit AND the frozen still's blob URL. Bound to `optimizing.exit`, so it
|
|
2021
|
+
* covers every route out of the phase, not just the two that already clear
|
|
2022
|
+
* up after themselves (`getStoreCapturedImageValues` on the commit,
|
|
2023
|
+
* `optimizingGrace`'s own action on the abandon path). Before this it
|
|
2024
|
+
* cleared only `stashedCommit`, and an exit through the manual-capture
|
|
2025
|
+
* escape leaked the URL until the next attempt/side boundary.
|
|
2026
|
+
*
|
|
2027
|
+
* Safe to revoke here on the commit path: exit and `capturing`'s entry run
|
|
2028
|
+
* in the same macrostep, and `capturing`'s eventless `always` means the UI
|
|
2029
|
+
* only ever observes the resulting `uploading` snapshot — by which point
|
|
2030
|
+
* `previewImageUrl` is set, so `candidateImageUrl ?? previewImageUrl` never
|
|
2031
|
+
* resolves to nothing (see `getStoreCapturedImageValues`).
|
|
2032
|
+
*/
|
|
2033
|
+
clearOptimizingPhase: assign(({ context }) => getClearOptimizingValues(context)),
|
|
1785
2034
|
storeBarcodeResponse: assign(({ context, event }) => getBarcodeResponseValues(context, event)),
|
|
1786
2035
|
storeDecodedBarcode: assign({ decodedBarcode: ({ event }) => event.decoded }),
|
|
1787
2036
|
setBarcodeFastPathAttempted: assign({ barcodeFastPathAttempted: true }),
|
|
@@ -1849,13 +2098,15 @@ const idCaptureMachine = setup({
|
|
|
1849
2098
|
hasInitializedCamera: hasInitializedCameraGuard,
|
|
1850
2099
|
hasAttemptsRemaining: hasAttemptsRemainingGuard,
|
|
1851
2100
|
hasCapturedImage: hasCapturedImageGuard,
|
|
2101
|
+
hasCandidateFrame: hasCandidateFrameGuard,
|
|
2102
|
+
hasStashedCommit: hasStashedCommitGuard,
|
|
1852
2103
|
hasUploadValidationError: hasUploadValidationErrorGuard,
|
|
1853
2104
|
isFrontMode: isFrontModeGuard,
|
|
1854
2105
|
shouldContinueToBack: shouldContinueToBackGuard,
|
|
1855
2106
|
shouldContinueToFront: shouldContinueToFrontGuard,
|
|
1856
2107
|
hasMandatoryConsent: hasMandatoryConsentGuard,
|
|
1857
|
-
|
|
1858
|
-
|
|
2108
|
+
isCaptureOptimizingMode: isCaptureOptimizingModeGuard,
|
|
2109
|
+
supportsOptimizingStatus: supportsOptimizingStatusGuard,
|
|
1859
2110
|
isDeepsightEnabled: isDeepsightEnabledGuard,
|
|
1860
2111
|
isDeepsightReady: isDeepsightReadyGuard,
|
|
1861
2112
|
needsDeepsightInit: needsDeepsightInitGuard,
|
|
@@ -1871,6 +2122,7 @@ const idCaptureMachine = setup({
|
|
|
1871
2122
|
shouldSkipProcessId: shouldSkipProcessIdGuard,
|
|
1872
2123
|
shouldSubmitBarcode: shouldSubmitBarcodeGuard,
|
|
1873
2124
|
canRunBarcodeFastPath: canRunBarcodeFastPathGuard,
|
|
2125
|
+
hasManualCaptureTriggered: hasManualCaptureTriggeredGuard,
|
|
1874
2126
|
isProcessingExpiredExhausted: isProcessingExpiredExhaustedGuard,
|
|
1875
2127
|
shouldProcessAfterExhaustion: shouldProcessAfterExhaustionGuard,
|
|
1876
2128
|
forceFinishAfterProcessing: forceFinishAfterProcessingGuard,
|
|
@@ -1879,6 +2131,36 @@ const idCaptureMachine = setup({
|
|
|
1879
2131
|
isManualUploadExhausted: ({ event }) => event.output?.result === "exhausted",
|
|
1880
2132
|
isDigitalUploadExhausted: ({ event }) => event.output?.result === "exhausted",
|
|
1881
2133
|
isDigitalUploadSuccessful: ({ event }) => event.output?.result === "success"
|
|
2134
|
+
},
|
|
2135
|
+
delays: {
|
|
2136
|
+
/**
|
|
2137
|
+
* IDC-05: how long the optimizing phase lasts, on BOTH paths — the auto
|
|
2138
|
+
* path's `optimizing.holding` and the manual path's `optimizingHold`. One
|
|
2139
|
+
* value, read from context rather than hardcoded, so the experiment payload
|
|
2140
|
+
* governs the phase wherever it is played.
|
|
2141
|
+
*
|
|
2142
|
+
* `?? 0` rather than the default dwell, deliberately: neither state is
|
|
2143
|
+
* reachable outside the treatment arm, and the treatment arm is the only
|
|
2144
|
+
* thing that populates `optimizingDwellMs`
|
|
2145
|
+
* (`resolveCaptureOptimizingTreatment` always sets it on its `optimizing`
|
|
2146
|
+
* branch). An absent value here therefore means the wiring between the two
|
|
2147
|
+
* broke, and falling back to the default would silently add a dwell to a
|
|
2148
|
+
* capture that was never supposed to have one. Zero makes that failure a
|
|
2149
|
+
* pass-through instead of a 1.5s regression.
|
|
2150
|
+
*/
|
|
2151
|
+
optimizingDwell: ({ context }) => context.optimizingDwellMs ?? 0,
|
|
2152
|
+
/**
|
|
2153
|
+
* IDC-05: how much longer the machine waits for WASM's commit once the phase
|
|
2154
|
+
* has had its full dwell (`optimizing.released`). Past this, `onCapture` —
|
|
2155
|
+
* the phase's normal exit — is not coming for the window this still belongs
|
|
2156
|
+
* to, and the phase is abandoned.
|
|
2157
|
+
*
|
|
2158
|
+
* A constant, not `dwell + margin`: the dwell has already been spent in
|
|
2159
|
+
* `holding` by the time this arms, so the total from phase entry is
|
|
2160
|
+
* unchanged. It also means the timer stays armed on a partially-resolved
|
|
2161
|
+
* payload, where `optimizingDwell` above collapses to zero.
|
|
2162
|
+
*/
|
|
2163
|
+
optimizingGrace: OPTIMIZING_WATCHDOG_MARGIN_MS
|
|
1882
2164
|
}
|
|
1883
2165
|
}).createMachine({
|
|
1884
2166
|
id: "idCapture",
|
|
@@ -1889,6 +2171,8 @@ const idCaptureMachine = setup({
|
|
|
1889
2171
|
return {
|
|
1890
2172
|
config: input.config,
|
|
1891
2173
|
captureFeedbackMode: input.captureFeedbackMode ?? "countdown",
|
|
2174
|
+
captureWindowMs: input.captureWindowMs,
|
|
2175
|
+
optimizingDwellMs: input.optimizingDwellMs,
|
|
1892
2176
|
currentMode,
|
|
1893
2177
|
selectedDocumentType: void 0,
|
|
1894
2178
|
stream: void 0,
|
|
@@ -1922,6 +2206,7 @@ const idCaptureMachine = setup({
|
|
|
1922
2206
|
frameRect: void 0,
|
|
1923
2207
|
detectionArea: void 0,
|
|
1924
2208
|
previewImageUrl: void 0,
|
|
2209
|
+
candidateImageUrl: void 0,
|
|
1925
2210
|
uploadProgress: void 0,
|
|
1926
2211
|
manualCaptureTriggered: false,
|
|
1927
2212
|
deepsightService: void 0,
|
|
@@ -2252,7 +2537,7 @@ const idCaptureMachine = setup({
|
|
|
2252
2537
|
guard: "needsDeepsightInit"
|
|
2253
2538
|
},
|
|
2254
2539
|
{
|
|
2255
|
-
target: "
|
|
2540
|
+
target: "choosingDetectionStrategy",
|
|
2256
2541
|
guard: "hasInitializedCamera"
|
|
2257
2542
|
},
|
|
2258
2543
|
{ target: "initializing" }
|
|
@@ -2287,7 +2572,7 @@ const idCaptureMachine = setup({
|
|
|
2287
2572
|
cameraFallbackLevel: context.cameraFallbackLevel
|
|
2288
2573
|
}),
|
|
2289
2574
|
onDone: {
|
|
2290
|
-
target: "
|
|
2575
|
+
target: "choosingDetectionStrategy",
|
|
2291
2576
|
actions: "setStreamAndCapturer"
|
|
2292
2577
|
},
|
|
2293
2578
|
onError: [{
|
|
@@ -2299,13 +2584,20 @@ const idCaptureMachine = setup({
|
|
|
2299
2584
|
actions: assign({ error: ({ event }) => String(event.error) })
|
|
2300
2585
|
}]
|
|
2301
2586
|
} },
|
|
2587
|
+
choosingDetectionStrategy: {
|
|
2588
|
+
entry: ["reportCaptureOptimizingAssignment"],
|
|
2589
|
+
always: [{
|
|
2590
|
+
target: "detectingWithOptimization",
|
|
2591
|
+
guard: and(["isCaptureOptimizingMode", "supportsOptimizingStatus"])
|
|
2592
|
+
}, { target: "detecting" }]
|
|
2593
|
+
},
|
|
2302
2594
|
detecting: {
|
|
2303
2595
|
always: [{
|
|
2304
2596
|
target: "manualCaptureWaiting",
|
|
2305
|
-
guard:
|
|
2597
|
+
guard: "hasManualCaptureTriggered",
|
|
2306
2598
|
actions: assign({ detectionStatus: () => "manualCapture" })
|
|
2307
2599
|
}],
|
|
2308
|
-
entry: [assign({ detectionStatus: () => "detecting" })
|
|
2600
|
+
entry: [assign({ detectionStatus: () => "detecting" })],
|
|
2309
2601
|
invoke: [{
|
|
2310
2602
|
id: "startRecording",
|
|
2311
2603
|
src: "startRecording",
|
|
@@ -2356,6 +2648,113 @@ const idCaptureMachine = setup({
|
|
|
2356
2648
|
ORIENTATION_CHANGE: { actions: "setOrientation" }
|
|
2357
2649
|
}
|
|
2358
2650
|
},
|
|
2651
|
+
/**
|
|
2652
|
+
* IDC-05 treatment arm: same detection as `detecting` above (kept in sync by
|
|
2653
|
+
* hand — see the comment there), plus the two-phase searching -> optimizing
|
|
2654
|
+
* phase.
|
|
2655
|
+
*
|
|
2656
|
+
* Two *distinct* state nodes (this one and `detecting`) rather than one
|
|
2657
|
+
* compound state, deliberately: `snapshot.matches({ capture: 'detecting' })`
|
|
2658
|
+
* keeps meaning exactly what it always meant. Folding the phase into
|
|
2659
|
+
* `detecting` as a substate would make every such selector silently true
|
|
2660
|
+
* while the user is being told the capture succeeded — a hazard no type or
|
|
2661
|
+
* test would catch.
|
|
2662
|
+
*/
|
|
2663
|
+
detectingWithOptimization: {
|
|
2664
|
+
entry: assign({ detectionStatus: () => "detecting" }),
|
|
2665
|
+
always: [{
|
|
2666
|
+
target: "manualCaptureWaiting",
|
|
2667
|
+
guard: "hasManualCaptureTriggered",
|
|
2668
|
+
actions: assign({ detectionStatus: () => "manualCapture" })
|
|
2669
|
+
}],
|
|
2670
|
+
invoke: [{
|
|
2671
|
+
id: "startRecording",
|
|
2672
|
+
src: "startRecording",
|
|
2673
|
+
input: ({ context }) => ({
|
|
2674
|
+
config: context.config,
|
|
2675
|
+
stream: context.stream,
|
|
2676
|
+
existing: context.recordingSession,
|
|
2677
|
+
currentMode: context.currentMode
|
|
2678
|
+
}),
|
|
2679
|
+
onDone: { actions: assign({ recordingSession: ({ context, event }) => {
|
|
2680
|
+
return event.output ?? context.recordingSession;
|
|
2681
|
+
} }) },
|
|
2682
|
+
onError: { actions: () => void 0 }
|
|
2683
|
+
}, {
|
|
2684
|
+
id: "runDetection",
|
|
2685
|
+
src: "runDetection",
|
|
2686
|
+
input: ({ context }) => ({
|
|
2687
|
+
frameCapturer: context.frameCapturer,
|
|
2688
|
+
provider: context.provider,
|
|
2689
|
+
config: context.config,
|
|
2690
|
+
currentMode: context.currentMode,
|
|
2691
|
+
detectionArea: context.detectionArea ?? context.config.detectionArea,
|
|
2692
|
+
optimizingAfterMs: context.captureWindowMs
|
|
2693
|
+
})
|
|
2694
|
+
}],
|
|
2695
|
+
on: {
|
|
2696
|
+
DETECTION_SUCCESS: {
|
|
2697
|
+
target: "capturing",
|
|
2698
|
+
actions: assign({ qualityElements: ({ event }) => event.qualityElements })
|
|
2699
|
+
},
|
|
2700
|
+
DETECTION_RESET_READY: { actions: assign({ resetDetection: ({ event }) => event.reset }) },
|
|
2701
|
+
ID_TYPE_CHANGE: { actions: "setIdType" },
|
|
2702
|
+
ORIENTATION_CHANGE: { actions: "setOrientation" },
|
|
2703
|
+
MANUAL_CAPTURE: { target: "#idCapture.capture.capturingManual" },
|
|
2704
|
+
SWITCH_TO_MANUAL_CAPTURE: {
|
|
2705
|
+
target: "#idCapture.capture.manualCaptureWaiting",
|
|
2706
|
+
actions: assign({
|
|
2707
|
+
detectionStatus: () => "manualCapture",
|
|
2708
|
+
manualCaptureTriggered: () => true
|
|
2709
|
+
})
|
|
2710
|
+
}
|
|
2711
|
+
},
|
|
2712
|
+
initial: "searching",
|
|
2713
|
+
states: {
|
|
2714
|
+
searching: { on: {
|
|
2715
|
+
DETECTION_UPDATE: { actions: "setDetectionStatus" },
|
|
2716
|
+
ID_SIDE_CHANGE: { actions: assign({ detectionStatus: ({ context, event }) => getDetectionStatusFromSideChange(context, event.side) }) },
|
|
2717
|
+
BARCODE_DECODED: [{
|
|
2718
|
+
target: "#idCapture.capture.capturingBarcode",
|
|
2719
|
+
guard: "canRunBarcodeFastPath",
|
|
2720
|
+
actions: ["storeDecodedBarcode", "setBarcodeFastPathAttempted"]
|
|
2721
|
+
}, { actions: "storeDecodedBarcode" }],
|
|
2722
|
+
DETECTION_OPTIMIZING: {
|
|
2723
|
+
target: "optimizing",
|
|
2724
|
+
guard: "hasCandidateFrame",
|
|
2725
|
+
actions: "setCandidateFrame"
|
|
2726
|
+
}
|
|
2727
|
+
} },
|
|
2728
|
+
optimizing: {
|
|
2729
|
+
exit: "clearOptimizingPhase",
|
|
2730
|
+
on: {
|
|
2731
|
+
BARCODE_DECODED: { actions: "storeDecodedBarcode" },
|
|
2732
|
+
SWITCH_TO_MANUAL_CAPTURE: {
|
|
2733
|
+
guard: "hasStashedCommit",
|
|
2734
|
+
target: "#idCapture.capture.detectingWithOptimization.optimizing.released"
|
|
2735
|
+
},
|
|
2736
|
+
MANUAL_CAPTURE: {
|
|
2737
|
+
guard: "hasStashedCommit",
|
|
2738
|
+
target: "#idCapture.capture.detectingWithOptimization.optimizing.released"
|
|
2739
|
+
}
|
|
2740
|
+
},
|
|
2741
|
+
initial: "holding",
|
|
2742
|
+
states: {
|
|
2743
|
+
holding: {
|
|
2744
|
+
after: { optimizingDwell: { target: "released" } },
|
|
2745
|
+
on: { DETECTION_SUCCESS: { actions: "stashCommittedFrame" } }
|
|
2746
|
+
},
|
|
2747
|
+
released: {
|
|
2748
|
+
entry: "releaseStashedCommit",
|
|
2749
|
+
after: { optimizingGrace: {
|
|
2750
|
+
target: "#idCapture.capture.detectingWithOptimization.searching",
|
|
2751
|
+
actions: assign({ detectionStatus: () => "detecting" })
|
|
2752
|
+
} }
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
}
|
|
2757
|
+
},
|
|
2359
2758
|
manualCaptureWaiting: { on: { MANUAL_CAPTURE: { target: "capturingManual" } } },
|
|
2360
2759
|
capturing: {
|
|
2361
2760
|
entry: [
|
|
@@ -2368,14 +2767,6 @@ const idCaptureMachine = setup({
|
|
|
2368
2767
|
target: "submittingBarcode",
|
|
2369
2768
|
guard: and(["hasCapturedImage", "shouldSubmitBarcode"])
|
|
2370
2769
|
},
|
|
2371
|
-
{
|
|
2372
|
-
target: "resultPreview",
|
|
2373
|
-
guard: and([
|
|
2374
|
-
"hasCapturedImage",
|
|
2375
|
-
"isCaptureResultPreviewMode",
|
|
2376
|
-
"supportsCaptureResultPreview"
|
|
2377
|
-
])
|
|
2378
|
-
},
|
|
2379
2770
|
{
|
|
2380
2771
|
target: "uploading",
|
|
2381
2772
|
guard: "hasCapturedImage"
|
|
@@ -2389,7 +2780,6 @@ const idCaptureMachine = setup({
|
|
|
2389
2780
|
}
|
|
2390
2781
|
]
|
|
2391
2782
|
},
|
|
2392
|
-
resultPreview: { on: { RESULT_PREVIEW_COMPLETE: { target: "uploading" } } },
|
|
2393
2783
|
submittingBarcode: { invoke: {
|
|
2394
2784
|
id: "submitBarcode",
|
|
2395
2785
|
src: "submitBarcode",
|
|
@@ -2425,7 +2815,7 @@ const idCaptureMachine = setup({
|
|
|
2425
2815
|
target: "success",
|
|
2426
2816
|
actions: ["storeBarcodeResponse", "markBarcodeFastPathCaptured"]
|
|
2427
2817
|
},
|
|
2428
|
-
onError: { target: "
|
|
2818
|
+
onError: { target: "choosingDetectionStrategy" }
|
|
2429
2819
|
} },
|
|
2430
2820
|
capturingManual: {
|
|
2431
2821
|
entry: [
|
|
@@ -2435,11 +2825,11 @@ const idCaptureMachine = setup({
|
|
|
2435
2825
|
],
|
|
2436
2826
|
always: [
|
|
2437
2827
|
{
|
|
2438
|
-
target: "
|
|
2828
|
+
target: "optimizingHold",
|
|
2439
2829
|
guard: and([
|
|
2440
2830
|
"hasCapturedImage",
|
|
2441
|
-
"
|
|
2442
|
-
"
|
|
2831
|
+
"isCaptureOptimizingMode",
|
|
2832
|
+
"supportsOptimizingStatus"
|
|
2443
2833
|
])
|
|
2444
2834
|
},
|
|
2445
2835
|
{
|
|
@@ -2455,6 +2845,7 @@ const idCaptureMachine = setup({
|
|
|
2455
2845
|
}
|
|
2456
2846
|
]
|
|
2457
2847
|
},
|
|
2848
|
+
optimizingHold: { after: { optimizingDwell: { target: "uploading" } } },
|
|
2458
2849
|
uploading: {
|
|
2459
2850
|
entry: assign({ uploadProgress: () => 0 }),
|
|
2460
2851
|
invoke: [{
|
|
@@ -2656,7 +3047,7 @@ const idCaptureMachine = setup({
|
|
|
2656
3047
|
}
|
|
2657
3048
|
},
|
|
2658
3049
|
onDone: [{
|
|
2659
|
-
target: "#idCapture.capture.
|
|
3050
|
+
target: "#idCapture.capture.choosingDetectionStrategy",
|
|
2660
3051
|
guard: "hasStream",
|
|
2661
3052
|
actions: "clearFlipPreview"
|
|
2662
3053
|
}, {
|
|
@@ -2708,7 +3099,7 @@ const idCaptureMachine = setup({
|
|
|
2708
3099
|
}
|
|
2709
3100
|
},
|
|
2710
3101
|
onDone: [{
|
|
2711
|
-
target: "#idCapture.capture.
|
|
3102
|
+
target: "#idCapture.capture.choosingDetectionStrategy",
|
|
2712
3103
|
guard: "hasStream",
|
|
2713
3104
|
actions: "clearFlipPreview"
|
|
2714
3105
|
}, {
|