@incodetech/core 0.0.0-dev-20260508-a05aa65 → 0.0.0-dev-20260508-da43840

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/dist/{addressSearch-DGVL5bWp.esm.js → addressSearch-DayrVNF_.esm.js} +1 -1
  2. package/dist/{ae-signature-CW0Y3VGK.esm.js → ae-signature-DsoDilvy.esm.js} +1 -1
  3. package/dist/ae-signature.d.ts +1 -1
  4. package/dist/ae-signature.esm.js +3 -3
  5. package/dist/antifraud.esm.js +2 -2
  6. package/dist/{antifraudStateMachine-D4G28SI4.esm.js → antifraudStateMachine-Dcg1T07S.esm.js} +1 -1
  7. package/dist/authentication.esm.js +5 -5
  8. package/dist/{authenticationManager-CO8WhECt.esm.js → authenticationManager-CVoZsbJX.esm.js} +3 -3
  9. package/dist/{authenticationStateMachine-BNH4XOow.esm.js → authenticationStateMachine-DyimpeBS.esm.js} +2 -2
  10. package/dist/consent.d.ts +47 -47
  11. package/dist/consent.esm.js +2 -2
  12. package/dist/{consentStateMachine-Bda2QqSh.esm.js → consentStateMachine-arnGM2iE.esm.js} +1 -1
  13. package/dist/cpf-ocr.d.ts +23 -23
  14. package/dist/cpf-ocr.esm.js +1 -1
  15. package/dist/cross-document-data-match.esm.js +1 -1
  16. package/dist/curp-validation.esm.js +2 -2
  17. package/dist/{curpValidationStateMachine-CYXt-Why.esm.js → curpValidationStateMachine-B0Yhzej1.esm.js} +1 -1
  18. package/dist/custom-fields.esm.js +1 -1
  19. package/dist/custom-watchlist.esm.js +1 -1
  20. package/dist/document-capture.d.ts +71 -71
  21. package/dist/document-capture.esm.js +2 -2
  22. package/dist/document-upload.d.ts +43 -43
  23. package/dist/document-upload.esm.js +1 -1
  24. package/dist/{documentCaptureStateMachine-SQ3AsME6.esm.js → documentCaptureStateMachine-fpqYHdZV.esm.js} +1 -1
  25. package/dist/dynamic-forms.esm.js +1 -1
  26. package/dist/ekyb.esm.js +5 -5
  27. package/dist/{ekybStateMachine-FXI54YYY.esm.js → ekybStateMachine-Dnjggy7x.esm.js} +3 -3
  28. package/dist/ekyc.esm.js +3 -3
  29. package/dist/{ekycStateMachine-B-R_nMk9.esm.js → ekycStateMachine-6OaK23Ab.esm.js} +2 -2
  30. package/dist/electronic-signature.d.ts +1 -1
  31. package/dist/electronic-signature.esm.js +2 -2
  32. package/dist/{electronicSignatureManager-W3dYg32m.esm.js → electronicSignatureManager-DYooXM8e.esm.js} +1 -1
  33. package/dist/email.esm.js +3 -3
  34. package/dist/{emailManager-Dcdv3r8N.esm.js → emailManager-CJAgi4be.esm.js} +2 -2
  35. package/dist/{emailStateMachine-CfL8um8y.esm.js → emailStateMachine-BW4tiYqt.esm.js} +1 -1
  36. package/dist/extensibility.d.ts +1 -1
  37. package/dist/extensibility.esm.js +14 -14
  38. package/dist/face-match.esm.js +2 -2
  39. package/dist/{faceCaptureManagerFactory-bM8uVQhs.esm.js → faceCaptureManagerFactory-ByAGjOLF.esm.js} +1 -1
  40. package/dist/{faceCaptureSetup-DPJ8f1ce.esm.js → faceCaptureSetup-D3dirkMC.esm.js} +1 -1
  41. package/dist/{faceMatchStateMachine-o_4FAl-g.esm.js → faceMatchStateMachine-Fwkg2Q37.esm.js} +1 -1
  42. package/dist/flow.d.ts +2 -2
  43. package/dist/flow.esm.js +4 -4
  44. package/dist/{flowServices-B41pWry3.esm.js → flowServices-1z6Qnipt.esm.js} +1 -1
  45. package/dist/geolocation.esm.js +2 -2
  46. package/dist/{geolocationStateMachine-Oj4giZl6.esm.js → geolocationStateMachine-15aagr2_.esm.js} +1 -1
  47. package/dist/government-validation.esm.js +2 -2
  48. package/dist/{governmentValidationStateMachine-DwZUuGG9.esm.js → governmentValidationStateMachine-Bg4F9j-0.esm.js} +1 -1
  49. package/dist/home.d.ts +10 -10
  50. package/dist/home.esm.js +1 -1
  51. package/dist/id-ocr.d.ts +52 -52
  52. package/dist/id-ocr.esm.js +2 -2
  53. package/dist/id.d.ts +1 -1
  54. package/dist/id.esm.js +4 -4
  55. package/dist/{idCaptureManager-xbLvlmaw.d.ts → idCaptureManager-C4xBRJNt.d.ts} +25 -27
  56. package/dist/{idCaptureManager-6AfsPFbT.esm.js → idCaptureManager-Dl7KHLJ5.esm.js} +21 -18
  57. package/dist/{idCaptureStateMachine-CjhFzer8.esm.js → idCaptureStateMachine-C8Ey-cuR.esm.js} +365 -356
  58. package/dist/{idOcrStateMachine-Bh_LFdKk.esm.js → idOcrStateMachine-Dw4i2Yyo.esm.js} +1 -1
  59. package/dist/identity-reuse.d.ts +40 -40
  60. package/dist/identity-reuse.esm.js +1 -1
  61. package/dist/{index-CorEGzgE.d.ts → index-BQYMQp-F.d.ts} +119 -119
  62. package/dist/index.esm.js +2 -2
  63. package/dist/mandatory-consent.d.ts +47 -47
  64. package/dist/mandatory-consent.esm.js +2 -2
  65. package/dist/{mandatoryConsentStateMachine-b5d37Xvb.esm.js → mandatoryConsentStateMachine-D0CiwKkK.esm.js} +1 -1
  66. package/dist/phone.esm.js +3 -3
  67. package/dist/{phoneManager-CBupL3Zp.esm.js → phoneManager-BgAfR0DQ.esm.js} +2 -2
  68. package/dist/{phoneStateMachine-B0KqPCut.esm.js → phoneStateMachine-dDqWuk_Q.esm.js} +1 -1
  69. package/dist/{qe-signature-CLobj5mQ.esm.js → qe-signature-CaxK1LMD.esm.js} +1 -1
  70. package/dist/qe-signature.d.ts +1 -1
  71. package/dist/qe-signature.esm.js +3 -3
  72. package/dist/redirect-to-mobile.esm.js +2 -2
  73. package/dist/{redirectToMobileStateMachine-Dvias_ax.esm.js → redirectToMobileStateMachine-7bW5wC2f.esm.js} +1 -1
  74. package/dist/{runChildModule-BpsyjQ6x.esm.js → runChildModule-B16ocpd4.esm.js} +1 -1
  75. package/dist/selfie.esm.js +5 -5
  76. package/dist/{selfieManager-CNus5KCH.esm.js → selfieManager-C55Fsp9Q.esm.js} +3 -3
  77. package/dist/{selfieStateMachine-DCwYz6V1.esm.js → selfieStateMachine-CLqNjiIq.esm.js} +2 -2
  78. package/dist/{session-f758tX1l.esm.js → session-CfB7Ki6h.esm.js} +1 -1
  79. package/dist/session.esm.js +1 -1
  80. package/dist/{setup-BOSxfmSM.esm.js → setup-BzXmAo0M.esm.js} +1 -1
  81. package/dist/signature.esm.js +2 -2
  82. package/dist/{signatureStateMachine-PoXfqqBQ.esm.js → signatureStateMachine-CB7XiLfo.esm.js} +1 -1
  83. package/dist/wasm.esm.js +2 -2
  84. package/dist/watchlist-for-business.esm.js +1 -1
  85. package/dist/watchlist.esm.js +1 -1
  86. package/dist/workflow.d.ts +87 -87
  87. package/dist/workflow.esm.js +27 -27
  88. package/dist/{xstate.esm-C19_S3_9.esm.js → xstate.esm-7GmmAwg6.esm.js} +1 -1
  89. package/package.json +1 -1
@@ -3,8 +3,8 @@ import { t as BrowserTimerProvider } from "./BrowserTimerProvider-BZGH3sYJ.esm.j
3
3
  import { r as getToken, t as api } from "./api-eqRXuVG-.esm.js";
4
4
  import { S as revokeObjectURL } from "./events-Bt1azl2B.esm.js";
5
5
  import { t as endpoints } from "./endpoints-B3V1U9Dg.esm.js";
6
- import { t as getDisableIpify } from "./session-f758tX1l.esm.js";
7
- import { i as fromPromise, n as assign, r as fromCallback, t as setup } from "./xstate.esm-C19_S3_9.esm.js";
6
+ import { t as getDisableIpify } from "./session-CfB7Ki6h.esm.js";
7
+ import { a as fromPromise, i as fromCallback, n as sendTo, r as assign, t as setup } from "./xstate.esm-7GmmAwg6.esm.js";
8
8
  import { _ as StreamCanvasCapture, d as createRecordingSession, f as startRecording, g as flagIdManualReview, m as StreamCanvasProcessingSession, n as preloadOpenViduProvider, p as stopRecording$1 } from "./recordingService-Dc8qrd2u.esm.js";
9
9
  import { n as IncodeCanvas } from "./deepsightService-gNTXZu7Y.esm.js";
10
10
  import { n as requestPermission, r as clearCameraPermissionCache, t as checkPermission } from "./permissionServices-DIxFacTA.esm.js";
@@ -197,6 +197,12 @@ async function getIdCameraStream(deviceId) {
197
197
  return getBackCameraStream(deviceId);
198
198
  }
199
199
 
200
+ //#endregion
201
+ //#region src/modules/id/manualUpload/types.ts
202
+ const MANUAL_UPLOAD_MAX_RETRIES = 3;
203
+ const MANUAL_UPLOAD_MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;
204
+ const MANUAL_UPLOAD_EXHAUSTION_FORWARD_MS = 5e3;
205
+
200
206
  //#endregion
201
207
  //#region src/modules/id/types.ts
202
208
  const ID_ERROR_CODES = {
@@ -216,9 +222,6 @@ const ID_ERROR_CODES = {
216
222
  USER_CANCELLED: "USER_CANCELLED",
217
223
  SERVER: "SERVER_ERROR"
218
224
  };
219
- const MANUAL_UPLOAD_MAX_RETRIES = 3;
220
- const MANUAL_UPLOAD_MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;
221
- const MANUAL_UPLOAD_EXHAUSTION_FORWARD_MS = 5e3;
222
225
 
223
226
  //#endregion
224
227
  //#region src/modules/id/idCaptureServices.ts
@@ -501,6 +504,337 @@ async function uploadManualIdFile(params) {
501
504
  return res.data;
502
505
  }
503
506
 
507
+ //#endregion
508
+ //#region src/modules/id/manualUpload/manualUploadErrors.ts
509
+ /**
510
+ * i18n keys for manual-upload user-facing error copy.
511
+ * Keep in sync with `packages/ui/src/i18n/**.json` under the `manualIdUpload.*` namespace.
512
+ */
513
+ const MANUAL_UPLOAD_ERROR_KEYS = {
514
+ wrongSide: "manualIdUpload.wrongSide",
515
+ wrongDocument: "manualIdUpload.wrongDocument",
516
+ fileTooBig: "manualIdUpload.fileTooBig",
517
+ generic: "manualIdUpload.generic",
518
+ lowSharpness: "manualIdUpload.lowSharpness",
519
+ glareDetected: "manualIdUpload.glareDetected",
520
+ readabilityIssue: "manualIdUpload.readabilityIssue",
521
+ qualityRejected: "manualIdUpload.qualityRejected"
522
+ };
523
+ /**
524
+ * Map the server's `failReason` (plus client-side passport/ID tab mismatch and
525
+ * per-image quality flags) onto an i18n key. Mirrors v1's `shouldUploadAgain`
526
+ * branch logic in
527
+ * `ms-incodesmile-web/packages/incode-welcome/src/manualIdUpload/manuaIdUpload.tsx`,
528
+ * extended to also reject responses where the backend flagged a per-image
529
+ * quality issue (`correctSharpness`, `correctGlare`, `readability`, or
530
+ * `idQualityAttemptApproved` set to `false`).
531
+ *
532
+ * Quality flags are checked with `=== false` so missing/undefined values
533
+ * (older backends, partial payloads) keep the legacy "trust the server"
534
+ * behaviour and do not produce false positives.
535
+ *
536
+ * Returns `null` when the response represents a successful upload — the caller
537
+ * should treat `null` as "no error, advance to next slot".
538
+ */
539
+ function mapFailReasonToErrorKey(response, expectedTab) {
540
+ const failReason = response.failReason;
541
+ if (failReason === "WRONG_DOCUMENT_SIDE") return MANUAL_UPLOAD_ERROR_KEYS.wrongSide;
542
+ if (failReason === "WRONG_ONE_SIDED_DOCUMENT" || failReason === "UNKNOWN_DOCUMENT_TYPE") return MANUAL_UPLOAD_ERROR_KEYS.wrongDocument;
543
+ if (failReason === "ID_TYPE_UNACCEPTABLE") return MANUAL_UPLOAD_ERROR_KEYS.wrongDocument;
544
+ if (expectedTab === "passport" && response.typeOfId && response.typeOfId.toLowerCase() !== "passport") return MANUAL_UPLOAD_ERROR_KEYS.wrongDocument;
545
+ if (expectedTab === "id" && response.typeOfId?.toLowerCase() === "passport") return MANUAL_UPLOAD_ERROR_KEYS.wrongDocument;
546
+ if (response.correctSharpness === false) return MANUAL_UPLOAD_ERROR_KEYS.lowSharpness;
547
+ if (response.correctGlare === false) return MANUAL_UPLOAD_ERROR_KEYS.glareDetected;
548
+ if (response.readability === false) return MANUAL_UPLOAD_ERROR_KEYS.readabilityIssue;
549
+ if (response.idQualityAttemptApproved === false) return MANUAL_UPLOAD_ERROR_KEYS.qualityRejected;
550
+ return null;
551
+ }
552
+
553
+ //#endregion
554
+ //#region src/modules/id/manualUpload/manualUploadServices.ts
555
+ /**
556
+ * Read a File's bytes and return the raw base64 payload (the portion after
557
+ * `data:<mime>;base64,`). The backend's `/omni/add/*-id/v2` endpoints reject
558
+ * full data-URLs with `IllegalArgumentException: Illegal base64 character 3a`,
559
+ * so the prefix must be stripped before posting. Mirrors the live-camera
560
+ * path in `packages/infra/src/media/canvas.ts:getBase64Image()`.
561
+ */
562
+ function fileToBase64Payload(file) {
563
+ return new Promise((resolve, reject) => {
564
+ const reader = new FileReader();
565
+ reader.onload = () => {
566
+ const result = reader.result;
567
+ if (typeof result !== "string") {
568
+ reject(/* @__PURE__ */ new Error("FileReader produced non-string result"));
569
+ return;
570
+ }
571
+ const commaIndex = result.indexOf(",");
572
+ resolve(commaIndex === -1 ? result : result.slice(commaIndex + 1));
573
+ };
574
+ reader.onerror = () => {
575
+ reject(reader.error ?? /* @__PURE__ */ new Error("FileReader failed"));
576
+ };
577
+ reader.readAsDataURL(file);
578
+ });
579
+ }
580
+
581
+ //#endregion
582
+ //#region src/modules/id/manualUpload/manualUploadStateMachine.ts
583
+ const uploadManualFileActor = fromPromise(async ({ input, signal }) => {
584
+ const base64Image = await fileToBase64Payload(input.file);
585
+ return uploadManualIdFile({
586
+ side: input.side,
587
+ base64Image,
588
+ retry: input.retry,
589
+ onlyFront: input.onlyFront,
590
+ isSecondId: input.isSecondId,
591
+ signal
592
+ });
593
+ });
594
+ const getUploadResponseFromEvent = (event) => {
595
+ if ("output" in event) return event.output;
596
+ };
597
+ const _manualUploadMachine = setup({
598
+ types: {
599
+ context: {},
600
+ events: {},
601
+ input: {},
602
+ output: {}
603
+ },
604
+ actors: { uploadManualFile: uploadManualFileActor },
605
+ actions: {
606
+ setManualUploadActiveTab: assign(({ event }) => {
607
+ if (event.type !== "MANUAL_UPLOAD_TAB_CHANGED") return {};
608
+ return {
609
+ activeTab: event.tab,
610
+ frontFile: null,
611
+ backFile: null,
612
+ passportFile: null,
613
+ frontUploaded: false,
614
+ backUploaded: false,
615
+ passportUploaded: false,
616
+ skipBackFromServer: false,
617
+ errorMessage: null,
618
+ retriesLeft: MANUAL_UPLOAD_MAX_RETRIES
619
+ };
620
+ }),
621
+ resetManualUpload: assign(() => ({
622
+ frontFile: null,
623
+ backFile: null,
624
+ passportFile: null,
625
+ frontUploaded: false,
626
+ backUploaded: false,
627
+ passportUploaded: false,
628
+ skipBackFromServer: false,
629
+ errorMessage: null,
630
+ retriesLeft: MANUAL_UPLOAD_MAX_RETRIES
631
+ })),
632
+ storeSelectedFile: assign(({ event }) => {
633
+ if (event.type !== "MANUAL_UPLOAD_FILE_SELECTED") return {};
634
+ const updated = { errorMessage: null };
635
+ if (event.side === "front") updated.frontFile = event.file;
636
+ else if (event.side === "back") updated.backFile = event.file;
637
+ else updated.passportFile = event.file;
638
+ return updated;
639
+ }),
640
+ markFrontUploaded: assign(() => ({
641
+ frontUploaded: true,
642
+ errorMessage: null
643
+ })),
644
+ markBackUploaded: assign(() => ({
645
+ backUploaded: true,
646
+ errorMessage: null
647
+ })),
648
+ markPassportUploaded: assign(() => ({
649
+ passportUploaded: true,
650
+ errorMessage: null
651
+ })),
652
+ recordSkipBackFromResponse: assign(({ event }) => {
653
+ if (!("output" in event)) return {};
654
+ if (!event.output.skipBackIdCapture) return {};
655
+ return { skipBackFromServer: true };
656
+ }),
657
+ decrementManualUploadRetries: assign(({ context }) => ({ retriesLeft: Math.max(0, context.retriesLeft - 1) })),
658
+ setManualUploadErrorFromResponse: assign(({ context, event }) => {
659
+ if (!("output" in event)) return {};
660
+ const response = event.output;
661
+ return { errorMessage: mapFailReasonToErrorKey(response, context.activeTab) ?? "manualIdUpload.generic" };
662
+ }),
663
+ setManualUploadGenericError: assign(() => ({ errorMessage: "manualIdUpload.generic" })),
664
+ setManualUploadFileTooLargeError: assign(() => ({ errorMessage: "manualIdUpload.fileTooBig" })),
665
+ clearManualUploadError: assign(() => ({ errorMessage: null }))
666
+ },
667
+ guards: {
668
+ isSelectedFileTooLarge: ({ event }) => {
669
+ if (event.type !== "MANUAL_UPLOAD_FILE_SELECTED") return false;
670
+ return event.file.size > MANUAL_UPLOAD_MAX_FILE_SIZE_BYTES;
671
+ },
672
+ isFrontFileSelection: ({ event }) => event.type === "MANUAL_UPLOAD_FILE_SELECTED" && event.side === "front",
673
+ isBackFileSelection: ({ event }) => event.type === "MANUAL_UPLOAD_FILE_SELECTED" && event.side === "back",
674
+ isPassportFileSelection: ({ event }) => event.type === "MANUAL_UPLOAD_FILE_SELECTED" && event.side === "passport",
675
+ manualUploadRetriesExhausted: ({ context }) => context.retriesLeft <= 0,
676
+ canContinueFromIdTab: ({ context }) => {
677
+ if (context.activeTab !== "id") return false;
678
+ if (!context.frontUploaded) return false;
679
+ if (context.onlyFront) return true;
680
+ if (context.skipBackFromServer) return true;
681
+ return context.backUploaded;
682
+ },
683
+ canContinueFromPassportTab: ({ context }) => context.activeTab === "passport" && context.passportUploaded,
684
+ manualUploadResponseHasError: ({ context, event }) => {
685
+ const response = getUploadResponseFromEvent(event);
686
+ if (!response) return false;
687
+ return mapFailReasonToErrorKey(response, context.activeTab) !== null;
688
+ }
689
+ }
690
+ }).createMachine({
691
+ id: "manualUpload",
692
+ initial: "selecting",
693
+ context: ({ input }) => ({
694
+ onlyFront: input.onlyFront,
695
+ isSecondId: input.isSecondId,
696
+ frontFile: null,
697
+ backFile: null,
698
+ passportFile: null,
699
+ activeTab: "id",
700
+ retriesLeft: MANUAL_UPLOAD_MAX_RETRIES,
701
+ errorMessage: null,
702
+ skipBackFromServer: false,
703
+ frontUploaded: false,
704
+ backUploaded: false,
705
+ passportUploaded: false
706
+ }),
707
+ on: {
708
+ MANUAL_UPLOAD_TAB_CHANGED: {
709
+ target: ".selecting",
710
+ actions: ["setManualUploadActiveTab"]
711
+ },
712
+ MANUAL_UPLOAD_RESET: {
713
+ target: ".selecting",
714
+ actions: ["resetManualUpload"]
715
+ }
716
+ },
717
+ states: {
718
+ selecting: { on: {
719
+ MANUAL_UPLOAD_FILE_SELECTED: [
720
+ {
721
+ guard: "isSelectedFileTooLarge",
722
+ actions: ["setManualUploadFileTooLargeError"]
723
+ },
724
+ {
725
+ guard: "isFrontFileSelection",
726
+ target: "uploadingFront",
727
+ actions: ["storeSelectedFile"]
728
+ },
729
+ {
730
+ guard: "isBackFileSelection",
731
+ target: "uploadingBack",
732
+ actions: ["storeSelectedFile"]
733
+ },
734
+ {
735
+ guard: "isPassportFileSelection",
736
+ target: "uploadingPassport",
737
+ actions: ["storeSelectedFile"]
738
+ }
739
+ ],
740
+ MANUAL_UPLOAD_CONTINUE: [{
741
+ guard: "canContinueFromIdTab",
742
+ target: "finished"
743
+ }, {
744
+ guard: "canContinueFromPassportTab",
745
+ target: "finished"
746
+ }]
747
+ } },
748
+ uploadingFront: { invoke: {
749
+ id: "uploadManualFile",
750
+ src: "uploadManualFile",
751
+ input: ({ context }) => ({
752
+ side: "front",
753
+ file: context.frontFile,
754
+ retry: context.retriesLeft < MANUAL_UPLOAD_MAX_RETRIES,
755
+ onlyFront: context.onlyFront,
756
+ isSecondId: context.isSecondId
757
+ }),
758
+ onDone: [{
759
+ guard: "manualUploadResponseHasError",
760
+ target: "checkRetries",
761
+ actions: ["decrementManualUploadRetries", "setManualUploadErrorFromResponse"]
762
+ }, {
763
+ target: "selecting",
764
+ actions: [
765
+ "markFrontUploaded",
766
+ "recordSkipBackFromResponse",
767
+ "clearManualUploadError"
768
+ ]
769
+ }],
770
+ onError: {
771
+ target: "checkRetries",
772
+ actions: ["decrementManualUploadRetries", "setManualUploadGenericError"]
773
+ }
774
+ } },
775
+ uploadingBack: { invoke: {
776
+ id: "uploadManualFile",
777
+ src: "uploadManualFile",
778
+ input: ({ context }) => ({
779
+ side: "back",
780
+ file: context.backFile,
781
+ retry: context.retriesLeft < MANUAL_UPLOAD_MAX_RETRIES,
782
+ onlyFront: false,
783
+ isSecondId: context.isSecondId
784
+ }),
785
+ onDone: [{
786
+ guard: "manualUploadResponseHasError",
787
+ target: "checkRetries",
788
+ actions: ["decrementManualUploadRetries", "setManualUploadErrorFromResponse"]
789
+ }, {
790
+ target: "selecting",
791
+ actions: ["markBackUploaded", "clearManualUploadError"]
792
+ }],
793
+ onError: {
794
+ target: "checkRetries",
795
+ actions: ["decrementManualUploadRetries", "setManualUploadGenericError"]
796
+ }
797
+ } },
798
+ uploadingPassport: { invoke: {
799
+ id: "uploadManualFile",
800
+ src: "uploadManualFile",
801
+ input: ({ context }) => ({
802
+ side: "passport",
803
+ file: context.passportFile,
804
+ retry: context.retriesLeft < MANUAL_UPLOAD_MAX_RETRIES,
805
+ onlyFront: false,
806
+ isSecondId: context.isSecondId
807
+ }),
808
+ onDone: [{
809
+ guard: "manualUploadResponseHasError",
810
+ target: "checkRetries",
811
+ actions: ["decrementManualUploadRetries", "setManualUploadErrorFromResponse"]
812
+ }, {
813
+ target: "selecting",
814
+ actions: ["markPassportUploaded", "clearManualUploadError"]
815
+ }],
816
+ onError: {
817
+ target: "checkRetries",
818
+ actions: ["decrementManualUploadRetries", "setManualUploadGenericError"]
819
+ }
820
+ } },
821
+ checkRetries: { always: [{
822
+ guard: "manualUploadRetriesExhausted",
823
+ target: "retriesExhausted"
824
+ }, { target: "selecting" }] },
825
+ retriesExhausted: { after: { [MANUAL_UPLOAD_EXHAUSTION_FORWARD_MS]: { target: "exhausted" } } },
826
+ exhausted: {
827
+ type: "final",
828
+ output: { result: "exhausted" }
829
+ },
830
+ finished: {
831
+ type: "final",
832
+ output: { result: "success" }
833
+ }
834
+ }
835
+ });
836
+ const manualUploadMachine = _manualUploadMachine;
837
+
504
838
  //#endregion
505
839
  //#region ../infra/src/wasm/idCaptureDefaults.ts
506
840
  /**
@@ -854,88 +1188,6 @@ const checkVirtualCameraActor = fromPromise(async ({ input }) => {
854
1188
  if (!videoTrack) return false;
855
1189
  return input.deepsightService.checkVirtualCamera(videoTrack);
856
1190
  });
857
- /**
858
- * Read a File's bytes and return the raw base64 payload (the portion after
859
- * `data:<mime>;base64,`). The backend's `/omni/add/*-id/v2` endpoints reject
860
- * full data-URLs with `IllegalArgumentException: Illegal base64 character 3a`,
861
- * so the prefix must be stripped before posting. Mirrors the live-camera
862
- * path in `packages/infra/src/media/canvas.ts:getBase64Image()`.
863
- */
864
- function fileToBase64Payload(file) {
865
- return new Promise((resolve, reject) => {
866
- const reader = new FileReader();
867
- reader.onload = () => {
868
- const result = reader.result;
869
- if (typeof result !== "string") {
870
- reject(/* @__PURE__ */ new Error("FileReader produced non-string result"));
871
- return;
872
- }
873
- const commaIndex = result.indexOf(",");
874
- resolve(commaIndex === -1 ? result : result.slice(commaIndex + 1));
875
- };
876
- reader.onerror = () => {
877
- reject(reader.error ?? /* @__PURE__ */ new Error("FileReader failed"));
878
- };
879
- reader.readAsDataURL(file);
880
- });
881
- }
882
- const uploadManualFileActor = fromPromise(async ({ input, signal }) => {
883
- const base64Image = await fileToBase64Payload(input.file);
884
- return uploadManualIdFile({
885
- side: input.side,
886
- base64Image,
887
- retry: input.retry,
888
- onlyFront: input.onlyFront,
889
- isSecondId: input.isSecondId,
890
- signal
891
- });
892
- });
893
-
894
- //#endregion
895
- //#region src/modules/id/manualUploadErrors.ts
896
- /**
897
- * i18n keys for manual-upload user-facing error copy.
898
- * Keep in sync with `packages/ui/src/i18n/**.json` under the `manualIdUpload.*` namespace.
899
- */
900
- const MANUAL_UPLOAD_ERROR_KEYS = {
901
- wrongSide: "manualIdUpload.wrongSide",
902
- wrongDocument: "manualIdUpload.wrongDocument",
903
- fileTooBig: "manualIdUpload.fileTooBig",
904
- generic: "manualIdUpload.generic",
905
- lowSharpness: "manualIdUpload.lowSharpness",
906
- glareDetected: "manualIdUpload.glareDetected",
907
- readabilityIssue: "manualIdUpload.readabilityIssue",
908
- qualityRejected: "manualIdUpload.qualityRejected"
909
- };
910
- /**
911
- * Map the server's `failReason` (plus client-side passport/ID tab mismatch and
912
- * per-image quality flags) onto an i18n key. Mirrors v1's `shouldUploadAgain`
913
- * branch logic in
914
- * `ms-incodesmile-web/packages/incode-welcome/src/manualIdUpload/manuaIdUpload.tsx`,
915
- * extended to also reject responses where the backend flagged a per-image
916
- * quality issue (`correctSharpness`, `correctGlare`, `readability`, or
917
- * `idQualityAttemptApproved` set to `false`).
918
- *
919
- * Quality flags are checked with `=== false` so missing/undefined values
920
- * (older backends, partial payloads) keep the legacy "trust the server"
921
- * behaviour and do not produce false positives.
922
- *
923
- * Returns `null` when the response represents a successful upload — the caller
924
- * should treat `null` as "no error, advance to next slot".
925
- */
926
- function mapFailReasonToErrorKey(response, expectedTab) {
927
- const failReason = response.failReason;
928
- if (failReason === "WRONG_DOCUMENT_SIDE") return MANUAL_UPLOAD_ERROR_KEYS.wrongSide;
929
- if (failReason === "WRONG_ONE_SIDED_DOCUMENT" || failReason === "UNKNOWN_DOCUMENT_TYPE") return MANUAL_UPLOAD_ERROR_KEYS.wrongDocument;
930
- if (failReason === "ID_TYPE_UNACCEPTABLE") return MANUAL_UPLOAD_ERROR_KEYS.wrongDocument;
931
- if (expectedTab === "passport" && response.typeOfId && response.typeOfId.toLowerCase() !== "passport") return MANUAL_UPLOAD_ERROR_KEYS.wrongDocument;
932
- if (expectedTab === "id" && response.typeOfId?.toLowerCase() === "passport") return MANUAL_UPLOAD_ERROR_KEYS.wrongDocument;
933
- if (response.correctSharpness === false) return MANUAL_UPLOAD_ERROR_KEYS.lowSharpness;
934
- if (response.correctGlare === false) return MANUAL_UPLOAD_ERROR_KEYS.glareDetected;
935
- if (response.readability === false) return MANUAL_UPLOAD_ERROR_KEYS.readabilityIssue;
936
- if (response.idQualityAttemptApproved === false) return MANUAL_UPLOAD_ERROR_KEYS.qualityRejected;
937
- return null;
938
- }
939
1191
 
940
1192
  //#endregion
941
1193
  //#region src/modules/id/idCaptureActions.ts
@@ -1218,45 +1470,6 @@ const hasMandatoryConsentGuard = ({ context }) => context.uploadResponse?.showMa
1218
1470
  const isDeepsightEnabledGuard = ({ context }) => context.dependencies !== void 0;
1219
1471
  const isDeepsightReadyGuard = ({ context }) => context.deepsightService !== void 0;
1220
1472
  const needsDeepsightInitGuard = ({ context }) => context.dependencies !== void 0 && context.deepsightService === void 0 && !context.deepsightInitAttempted;
1221
- const getFileFromEvent = (event) => {
1222
- if (event.type === "MANUAL_UPLOAD_FILE_SELECTED") return event.file;
1223
- };
1224
- const getSideFromEvent = (event) => {
1225
- if (event.type === "MANUAL_UPLOAD_FILE_SELECTED") return event.side;
1226
- };
1227
- const isSelectedFileTooLargeGuard = ({ event }) => {
1228
- const file = getFileFromEvent(event);
1229
- return file ? file.size > MANUAL_UPLOAD_MAX_FILE_SIZE_BYTES : false;
1230
- };
1231
- const isFrontFileSelectionGuard = ({ event }) => getSideFromEvent(event) === "front";
1232
- const isBackFileSelectionGuard = ({ event }) => getSideFromEvent(event) === "back";
1233
- const isPassportFileSelectionGuard = ({ event }) => getSideFromEvent(event) === "passport";
1234
- /**
1235
- * True once `retriesLeft` has been decremented to 0 — evaluated from the
1236
- * `checkRetries` state after the decrement action runs.
1237
- */
1238
- const manualUploadRetriesExhaustedGuard = ({ context }) => context.manualUpload.retriesLeft <= 0;
1239
- const canContinueFromIdTabGuard = ({ context }) => {
1240
- if (context.manualUpload.activeTab !== "id") return false;
1241
- if (!context.manualUpload.frontUploaded) return false;
1242
- if (context.config.onlyFront) return true;
1243
- if (context.manualUpload.skipBackFromServer) return true;
1244
- return context.manualUpload.backUploaded;
1245
- };
1246
- const canContinueFromPassportTabGuard = ({ context }) => context.manualUpload.activeTab === "passport" && context.manualUpload.passportUploaded;
1247
- const getUploadResponseFromEvent = (event) => {
1248
- if ("output" in event) return event.output;
1249
- };
1250
- /**
1251
- * True when the server-side upload response contains a failReason or type
1252
- * mismatch that should be surfaced to the user and counted against retries.
1253
- * Evaluated by the actor's `onDone`, so the response lives on `event.output`.
1254
- */
1255
- const manualUploadResponseHasErrorGuard = ({ context, event }) => {
1256
- const response = getUploadResponseFromEvent(event);
1257
- if (!response) return false;
1258
- return mapFailReasonToErrorKey(response, context.manualUpload.activeTab) !== null;
1259
- };
1260
1473
  const hasOnlyManualUploadAvailableGuard = ({ context }) => context.availableDocumentTypes.length === 1 && context.availableDocumentTypes[0] === "manualIdUpload";
1261
1474
  const isManualIdUploadSelectedGuard = ({ event }) => event.type === "SELECT_DOCUMENT" && event.documentType === "manualIdUpload";
1262
1475
 
@@ -1285,7 +1498,7 @@ const _idCaptureMachine = setup({
1285
1498
  checkMotionSensor: checkMotionSensorActor,
1286
1499
  initializeDeepsightSession: initializeDeepsightSessionActor,
1287
1500
  checkVirtualCamera: checkVirtualCameraActor,
1288
- uploadManualFile: uploadManualFileActor
1501
+ manualUploadMachine
1289
1502
  },
1290
1503
  actions: {
1291
1504
  stopMediaStream: assign(({ context }) => {
@@ -1437,94 +1650,7 @@ const _idCaptureMachine = setup({
1437
1650
  } }),
1438
1651
  setMotionStatus: assign({ motionStatus: ({ event }) => {
1439
1652
  if ("status" in event && event.type === "MOTION_STATUS") return event.status;
1440
- } }),
1441
- setManualUploadActiveTab: assign(({ context, event }) => {
1442
- if (event.type !== "MANUAL_UPLOAD_TAB_CHANGED") return {};
1443
- return { manualUpload: {
1444
- ...context.manualUpload,
1445
- activeTab: event.tab,
1446
- frontFile: null,
1447
- backFile: null,
1448
- passportFile: null,
1449
- frontUploaded: false,
1450
- backUploaded: false,
1451
- passportUploaded: false,
1452
- skipBackFromServer: false,
1453
- errorMessage: null,
1454
- retriesLeft: MANUAL_UPLOAD_MAX_RETRIES
1455
- } };
1456
- }),
1457
- resetManualUpload: assign(({ context }) => ({ manualUpload: {
1458
- ...context.manualUpload,
1459
- frontFile: null,
1460
- backFile: null,
1461
- passportFile: null,
1462
- frontUploaded: false,
1463
- backUploaded: false,
1464
- passportUploaded: false,
1465
- skipBackFromServer: false,
1466
- errorMessage: null,
1467
- retriesLeft: MANUAL_UPLOAD_MAX_RETRIES
1468
- } })),
1469
- storeSelectedFile: assign(({ context, event }) => {
1470
- if (event.type !== "MANUAL_UPLOAD_FILE_SELECTED") return {};
1471
- const updated = {
1472
- ...context.manualUpload,
1473
- errorMessage: null
1474
- };
1475
- if (event.side === "front") updated.frontFile = event.file;
1476
- else if (event.side === "back") updated.backFile = event.file;
1477
- else updated.passportFile = event.file;
1478
- return { manualUpload: updated };
1479
- }),
1480
- markFrontUploaded: assign(({ context }) => ({ manualUpload: {
1481
- ...context.manualUpload,
1482
- frontUploaded: true,
1483
- errorMessage: null
1484
- } })),
1485
- markBackUploaded: assign(({ context }) => ({ manualUpload: {
1486
- ...context.manualUpload,
1487
- backUploaded: true,
1488
- errorMessage: null
1489
- } })),
1490
- markPassportUploaded: assign(({ context }) => ({ manualUpload: {
1491
- ...context.manualUpload,
1492
- passportUploaded: true,
1493
- errorMessage: null
1494
- } })),
1495
- recordSkipBackFromResponse: assign(({ context, event }) => {
1496
- if (!("output" in event)) return {};
1497
- if (!event.output.skipBackIdCapture) return {};
1498
- return { manualUpload: {
1499
- ...context.manualUpload,
1500
- skipBackFromServer: true
1501
- } };
1502
- }),
1503
- decrementManualUploadRetries: assign(({ context }) => ({ manualUpload: {
1504
- ...context.manualUpload,
1505
- retriesLeft: Math.max(0, context.manualUpload.retriesLeft - 1)
1506
- } })),
1507
- setManualUploadErrorFromResponse: assign(({ context, event }) => {
1508
- if (!("output" in event)) return {};
1509
- const response = event.output;
1510
- const errorKey = mapFailReasonToErrorKey(response, context.manualUpload.activeTab);
1511
- return { manualUpload: {
1512
- ...context.manualUpload,
1513
- errorMessage: errorKey ?? "manualIdUpload.generic"
1514
- } };
1515
- }),
1516
- setManualUploadGenericError: assign(({ context }) => ({ manualUpload: {
1517
- ...context.manualUpload,
1518
- errorMessage: "manualIdUpload.generic"
1519
- } })),
1520
- setManualUploadFileTooLargeError: assign(({ context }) => ({ manualUpload: {
1521
- ...context.manualUpload,
1522
- errorMessage: "manualIdUpload.fileTooBig"
1523
- } })),
1524
- clearManualUploadError: assign(({ context }) => ({ manualUpload: {
1525
- ...context.manualUpload,
1526
- errorMessage: null
1527
- } }))
1653
+ } })
1528
1654
  },
1529
1655
  guards: {
1530
1656
  hasShowTutorial: hasShowTutorialGuard,
@@ -1544,16 +1670,9 @@ const _idCaptureMachine = setup({
1544
1670
  isDeepsightEnabled: isDeepsightEnabledGuard,
1545
1671
  isDeepsightReady: isDeepsightReadyGuard,
1546
1672
  needsDeepsightInit: needsDeepsightInitGuard,
1547
- isSelectedFileTooLarge: isSelectedFileTooLargeGuard,
1548
- isFrontFileSelection: isFrontFileSelectionGuard,
1549
- isBackFileSelection: isBackFileSelectionGuard,
1550
- isPassportFileSelection: isPassportFileSelectionGuard,
1551
- manualUploadRetriesExhausted: manualUploadRetriesExhaustedGuard,
1552
- canContinueFromIdTab: canContinueFromIdTabGuard,
1553
- canContinueFromPassportTab: canContinueFromPassportTabGuard,
1554
- manualUploadResponseHasError: manualUploadResponseHasErrorGuard,
1555
1673
  hasOnlyManualUploadAvailable: hasOnlyManualUploadAvailableGuard,
1556
- isManualIdUploadSelected: isManualIdUploadSelectedGuard
1674
+ isManualIdUploadSelected: isManualIdUploadSelectedGuard,
1675
+ isManualUploadExhausted: ({ event }) => event.output?.result === "exhausted"
1557
1676
  }
1558
1677
  }).createMachine({
1559
1678
  id: "idCapture",
@@ -1594,19 +1713,7 @@ const _idCaptureMachine = setup({
1594
1713
  deepsightInitAttempted: false,
1595
1714
  availableDocumentTypes: getAvailableDocumentTypes(input.config),
1596
1715
  captureResolution: void 0,
1597
- cameraFallbackLevel: void 0,
1598
- manualUpload: {
1599
- frontFile: null,
1600
- backFile: null,
1601
- passportFile: null,
1602
- activeTab: "id",
1603
- retriesLeft: MANUAL_UPLOAD_MAX_RETRIES,
1604
- errorMessage: null,
1605
- skipBackFromServer: false,
1606
- frontUploaded: false,
1607
- backUploaded: false,
1608
- passportUploaded: false
1609
- }
1716
+ cameraFallbackLevel: void 0
1610
1717
  };
1611
1718
  },
1612
1719
  on: {
@@ -2301,127 +2408,29 @@ const _idCaptureMachine = setup({
2301
2408
  } }
2302
2409
  },
2303
2410
  manualIdUpload: {
2304
- initial: "selecting",
2305
- on: {
2306
- QUIT: { target: "closed" },
2307
- MANUAL_UPLOAD_TAB_CHANGED: {
2308
- target: ".selecting",
2309
- actions: ["setManualUploadActiveTab"]
2310
- },
2311
- MANUAL_UPLOAD_RESET: {
2312
- target: ".selecting",
2313
- actions: ["resetManualUpload"]
2411
+ invoke: {
2412
+ id: "manualIdUpload",
2413
+ src: "manualUploadMachine",
2414
+ input: ({ context }) => ({
2415
+ isSecondId: context.config.isSecondId ?? false,
2416
+ onlyFront: context.config.onlyFront ?? false
2417
+ }),
2418
+ onSnapshot: { actions: () => {} },
2419
+ onDone: [{
2420
+ guard: "isManualUploadExhausted",
2421
+ target: "#idCapture.finished"
2422
+ }, { target: "#idCapture.processing" }],
2423
+ onError: {
2424
+ target: "#idCapture.error",
2425
+ actions: assign({ error: ({ event }) => String(event.error) })
2314
2426
  }
2315
2427
  },
2316
- states: {
2317
- selecting: { on: {
2318
- MANUAL_UPLOAD_FILE_SELECTED: [
2319
- {
2320
- guard: "isSelectedFileTooLarge",
2321
- actions: ["setManualUploadFileTooLargeError"]
2322
- },
2323
- {
2324
- guard: "isFrontFileSelection",
2325
- target: "uploadingFront",
2326
- actions: ["storeSelectedFile"]
2327
- },
2328
- {
2329
- guard: "isBackFileSelection",
2330
- target: "uploadingBack",
2331
- actions: ["storeSelectedFile"]
2332
- },
2333
- {
2334
- guard: "isPassportFileSelection",
2335
- target: "uploadingPassport",
2336
- actions: ["storeSelectedFile"]
2337
- }
2338
- ],
2339
- MANUAL_UPLOAD_CONTINUE: [{
2340
- guard: "canContinueFromIdTab",
2341
- target: "#idCapture.processing"
2342
- }, {
2343
- guard: "canContinueFromPassportTab",
2344
- target: "#idCapture.processing"
2345
- }]
2346
- } },
2347
- uploadingFront: { invoke: {
2348
- id: "uploadManualFile",
2349
- src: "uploadManualFile",
2350
- input: ({ context }) => ({
2351
- side: "front",
2352
- file: context.manualUpload.frontFile,
2353
- retry: context.manualUpload.retriesLeft < MANUAL_UPLOAD_MAX_RETRIES,
2354
- onlyFront: context.config.onlyFront ?? false,
2355
- isSecondId: context.config.isSecondId ?? false
2356
- }),
2357
- onDone: [{
2358
- guard: "manualUploadResponseHasError",
2359
- target: "checkRetries",
2360
- actions: ["decrementManualUploadRetries", "setManualUploadErrorFromResponse"]
2361
- }, {
2362
- target: "selecting",
2363
- actions: [
2364
- "markFrontUploaded",
2365
- "recordSkipBackFromResponse",
2366
- "clearManualUploadError"
2367
- ]
2368
- }],
2369
- onError: {
2370
- target: "checkRetries",
2371
- actions: ["decrementManualUploadRetries", "setManualUploadGenericError"]
2372
- }
2373
- } },
2374
- uploadingBack: { invoke: {
2375
- id: "uploadManualFile",
2376
- src: "uploadManualFile",
2377
- input: ({ context }) => ({
2378
- side: "back",
2379
- file: context.manualUpload.backFile,
2380
- retry: context.manualUpload.retriesLeft < MANUAL_UPLOAD_MAX_RETRIES,
2381
- onlyFront: false,
2382
- isSecondId: context.config.isSecondId ?? false
2383
- }),
2384
- onDone: [{
2385
- guard: "manualUploadResponseHasError",
2386
- target: "checkRetries",
2387
- actions: ["decrementManualUploadRetries", "setManualUploadErrorFromResponse"]
2388
- }, {
2389
- target: "selecting",
2390
- actions: ["markBackUploaded", "clearManualUploadError"]
2391
- }],
2392
- onError: {
2393
- target: "checkRetries",
2394
- actions: ["decrementManualUploadRetries", "setManualUploadGenericError"]
2395
- }
2396
- } },
2397
- uploadingPassport: { invoke: {
2398
- id: "uploadManualFile",
2399
- src: "uploadManualFile",
2400
- input: ({ context }) => ({
2401
- side: "passport",
2402
- file: context.manualUpload.passportFile,
2403
- retry: context.manualUpload.retriesLeft < MANUAL_UPLOAD_MAX_RETRIES,
2404
- onlyFront: false,
2405
- isSecondId: context.config.isSecondId ?? false
2406
- }),
2407
- onDone: [{
2408
- guard: "manualUploadResponseHasError",
2409
- target: "checkRetries",
2410
- actions: ["decrementManualUploadRetries", "setManualUploadErrorFromResponse"]
2411
- }, {
2412
- target: "selecting",
2413
- actions: ["markPassportUploaded", "clearManualUploadError"]
2414
- }],
2415
- onError: {
2416
- target: "checkRetries",
2417
- actions: ["decrementManualUploadRetries", "setManualUploadGenericError"]
2418
- }
2419
- } },
2420
- checkRetries: { always: [{
2421
- guard: "manualUploadRetriesExhausted",
2422
- target: "retriesExhausted"
2423
- }, { target: "selecting" }] },
2424
- retriesExhausted: { after: { [MANUAL_UPLOAD_EXHAUSTION_FORWARD_MS]: { target: "#idCapture.finished" } } }
2428
+ on: {
2429
+ QUIT: { target: "closed" },
2430
+ MANUAL_UPLOAD_TAB_CHANGED: { actions: sendTo("manualIdUpload", ({ event }) => event) },
2431
+ MANUAL_UPLOAD_FILE_SELECTED: { actions: sendTo("manualIdUpload", ({ event }) => event) },
2432
+ MANUAL_UPLOAD_CONTINUE: { actions: sendTo("manualIdUpload", ({ event }) => event) },
2433
+ MANUAL_UPLOAD_RESET: { actions: sendTo("manualIdUpload", ({ event }) => event) }
2425
2434
  }
2426
2435
  },
2427
2436
  digitalIdUpload: { on: { QUIT: { target: "closed" } } }