@incodetech/core 2.4.1-agentic → 2.4.1-agentic.1
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/BrowserNetworkStatusProvider-BrDXBEDd.esm.js +21 -0
- package/dist/{multipartRecordingService-DMBxHKS2.esm.js → CameraCompositor-DN7NkJzV.esm.js} +7 -734
- package/dist/{FaceDetectionProvider-B83VmClw.esm.js → FaceDetectionProvider-CAY43vSI.esm.js} +11 -12
- package/dist/MultipartRecordingProvider-D9mauUdS.esm.js +146 -0
- package/dist/StreamCanvasProcessingSession-CBnbTnOr.esm.js +42 -0
- package/dist/{WasmUtilProvider-GTkoJyFY.esm.js → WasmUtilProvider-Dp2V-Uct.esm.js} +2 -2
- package/dist/WorkerEncoderRecordingProvider-B1ODYtgN.esm.js +80 -0
- package/dist/{addressSearch-41sMcnJk.esm.js → addressSearch-DzbE9Ogt.esm.js} +2 -352
- package/dist/ae-signature.esm.js +1 -1
- package/dist/antifraud.esm.js +2 -2
- package/dist/{antifraudManager-CQ08atTC.esm.js → antifraudManager-BObuHBjn.esm.js} +2 -2
- package/dist/{antifraudStateMachine-BcsUTTIr.esm.js → antifraudStateMachine-Dfrd2-26.esm.js} +1 -1
- package/dist/{api-BO8JA7Pf.esm.js → api-CpP4PS4S.esm.js} +2 -0
- package/dist/{apiError-CfuIvnUy.esm.js → apiError-DH-CH4Nz.esm.js} +1 -1
- package/dist/{attemptCarry-BjTJ6bMQ.esm.js → attemptCarry-WOkfvFMw.esm.js} +2 -2
- package/dist/authentication.d.ts +3 -3
- package/dist/authentication.esm.js +2 -2
- package/dist/{authenticationManager-C-cOki0Y.d.ts → authenticationManager-CWmh7aSY.d.ts} +1 -1
- package/dist/{authenticationManager-DvmklBTE.esm.js → authenticationManager-DjX0XDyH.esm.js} +5 -5
- package/dist/{authenticationStateMachine-BL2ptOA0.esm.js → authenticationStateMachine-BMbZL8wm.esm.js} +3 -3
- package/dist/backCameraLabel-yda5ugE4.esm.js +67 -0
- package/dist/{backCameraStream-C5_NNfUN.esm.js → backCameraStream-DS1oDiUq.esm.js} +10 -65
- package/dist/camera.d.ts +2 -2
- package/dist/camera.esm.js +1 -1
- package/dist/certificate-issuance.esm.js +2 -2
- package/dist/{certificateIssuanceManager-CM0fuqDC.esm.js → certificateIssuanceManager-C1nETQos.esm.js} +2 -2
- package/dist/{certificateIssuanceStateMachine-kksIUOPD.esm.js → certificateIssuanceStateMachine-DThXMDqr.esm.js} +1 -1
- package/dist/{connectivity-HSl0diCx.esm.js → connectivity-BCuEoQ-n.esm.js} +2 -21
- package/dist/consent.d.ts +1 -1
- package/dist/consent.esm.js +2 -2
- package/dist/{consentManager-CBwFozhv.esm.js → consentManager-DMlSL6Ax.esm.js} +2 -2
- package/dist/{consentManager-_q9yJUku.d.ts → consentManager-bjfVXO7p.d.ts} +9 -9
- package/dist/{consentStateMachine-CpmRAcr2.esm.js → consentStateMachine-DIYSMxKQ.esm.js} +1 -1
- package/dist/cross-document-data-match.esm.js +1 -1
- package/dist/{crossDocumentDataMatchManager-64O8t10a.esm.js → crossDocumentDataMatchManager-BFTdiEDB.esm.js} +2 -2
- package/dist/curp-validation.d.ts +1 -1
- package/dist/curp-validation.esm.js +2 -2
- package/dist/{curpValidationManager-CLgJQcx0.esm.js → curpValidationManager-DNpC3wyf.esm.js} +2 -2
- package/dist/{curpValidationManager-CXpFE-Mv.d.ts → curpValidationManager-z8428oCM.d.ts} +1 -1
- package/dist/{curpValidationStateMachine-Bx9YhVkJ.esm.js → curpValidationStateMachine-B3iVsDyt.esm.js} +2 -2
- package/dist/custom-fields.esm.js +1 -1
- package/dist/custom-watchlist.esm.js +2 -2
- package/dist/{customFieldsManager-DWt_0YtJ.esm.js → customFieldsManager-CvI-pDT3.esm.js} +2 -2
- package/dist/{customWatchlistManager-D8o-2Nej.esm.js → customWatchlistManager-BuHtUb0y.esm.js} +2 -2
- package/dist/{customWatchlistStateMachine-Sbi6DIcK.esm.js → customWatchlistStateMachine-CiVD9wyF.esm.js} +1 -1
- package/dist/{deepsightService-twg3bXqY.esm.js → deepsightLoader-B7DEYoyY.esm.js} +34 -29
- package/dist/{desktopCameraElection-kHY2IDJi.esm.js → desktopCameraElection-BGMtYwk3.esm.js} +5 -5
- package/dist/document-capture.d.ts +3 -3
- package/dist/document-capture.esm.js +2 -2
- package/dist/{documentCaptureManager-6tnnDkMX.d.ts → documentCaptureManager-CD5iQiUI.d.ts} +24 -3
- package/dist/{documentCaptureManager-CMSC_Mhd.esm.js → documentCaptureManager-DLPqruXJ.esm.js} +3 -2
- package/dist/{documentCaptureStateMachine-BCwD5Rto.esm.js → documentCaptureStateMachine-DCvWQhFG.esm.js} +67 -26
- package/dist/dynamic-forms.esm.js +2 -2
- package/dist/{dynamicFormsManager-DU6W1e20.esm.js → dynamicFormsManager-DfqCEPg9.esm.js} +2 -2
- package/dist/{dynamicFormsStateMachine-C8Z7k3vo.esm.js → dynamicFormsStateMachine-USQMB-uV.esm.js} +2 -2
- package/dist/ekyb.d.ts +4 -4
- package/dist/ekyb.esm.js +3 -3
- package/dist/{ekybManager-TB6ZG5lX.d.ts → ekybManager-BLOkwmWO.d.ts} +2 -2
- package/dist/{ekybManager-TGfqyjuu.esm.js → ekybManager-CR8YSYux.esm.js} +2 -2
- package/dist/{ekybStateMachine-DBgFuEPK.esm.js → ekybStateMachine-kHwdz6hm.esm.js} +5 -3
- package/dist/ekybUtils-Cw8Ta9Qi.esm.js +140 -0
- package/dist/ekyc.d.ts +3 -2
- package/dist/ekyc.esm.js +3 -3
- package/dist/{ekycManager-BSQteIfC.d.ts → ekycManager-DlGIn9wA.d.ts} +2 -1
- package/dist/{ekycManager-C2cgG2Pl.esm.js → ekycManager-DymCvmVB.esm.js} +2 -2
- package/dist/{ekycStateMachine-CuNF7z4O.esm.js → ekycStateMachine-CoFCUJ2z.esm.js} +141 -68
- package/dist/{ekycUtils-BFncpC4F.esm.js → ekycUtils-GRuMELYr.esm.js} +80 -9
- package/dist/electronic-signature.esm.js +1 -1
- package/dist/{electronicSignatureManager-C7pqXsRm.esm.js → electronicSignatureManager-BCE3uA3z.esm.js} +3 -3
- package/dist/email.esm.js +2 -2
- package/dist/{emailManager-FH_CP0cT.esm.js → emailManager-CGoE3CUe.esm.js} +2 -2
- package/dist/{emailStateMachine-Cx-uTaBV.esm.js → emailStateMachine-KgHfDNvM.esm.js} +2 -2
- package/dist/{events-CQteqXfy.esm.js → events-ggpBBaZ8.esm.js} +1 -1
- package/dist/events.esm.js +1 -1
- package/dist/extensibility.d.ts +15 -14
- package/dist/extensibility.esm.js +36 -35
- package/dist/face-match.esm.js +2 -2
- package/dist/{faceCaptureManagerFactory-C-xKdj-d.d.ts → faceCaptureManagerFactory-DV2ULUYS.d.ts} +3 -3
- package/dist/{faceCaptureManagerFactory-CBm05KnT.esm.js → faceCaptureManagerFactory-Dp90bedH.esm.js} +4 -4
- package/dist/{faceCaptureSetup-BQjCbL51.esm.js → faceCaptureSetup-ZfiWg0fo.esm.js} +12 -403
- package/dist/{faceMatchManager-B2zp7yP4.esm.js → faceMatchManager-D2xKPjjQ.esm.js} +2 -2
- package/dist/{faceMatchStateMachine-ByTMQCUC.esm.js → faceMatchStateMachine-CUvwiQi9.esm.js} +2 -2
- package/dist/{feature-management-DjAG5lsJ.esm.js → feature-management-BbCIA4og.esm.js} +35 -21
- package/dist/feature-management.esm.js +1 -1
- package/dist/field-comparison.esm.js +1 -1
- package/dist/{fieldComparisonManager-CC0vKmpf.esm.js → fieldComparisonManager-DgDbEeFZ.esm.js} +2 -2
- package/dist/fiscal-qr.esm.js +1 -1
- package/dist/{fiscalQrManager-Be-r4oZj.esm.js → fiscalQrManager-BZeklojR.esm.js} +3 -3
- package/dist/flow-events.d.ts +1 -1
- package/dist/flow.d.ts +8 -8
- package/dist/flow.esm.js +10 -6
- package/dist/{flowCompletionService-ChMU2v79.esm.js → flowCompletionService-CcCnPs_T.esm.js} +2 -2
- package/dist/{flowServices-g2tVWsJl.esm.js → flowServices-Dmnc8Rye.esm.js} +69 -143
- package/dist/geolocation.esm.js +2 -2
- package/dist/{geolocationManager-DLbvZwUB.esm.js → geolocationManager-BJJ3m_I8.esm.js} +2 -2
- package/dist/{geolocationStateMachine-CAJVongM.esm.js → geolocationStateMachine-CTI3m4Ie.esm.js} +3 -3
- package/dist/government-validation.esm.js +2 -2
- package/dist/{governmentValidationManager-CkX9TEkh.esm.js → governmentValidationManager-CjChjZ3C.esm.js} +2 -2
- package/dist/{governmentValidationStateMachine-PTPCP26N.esm.js → governmentValidationStateMachine-AEbn3Afi.esm.js} +1 -1
- package/dist/home.d.ts +1 -1
- package/dist/home.esm.js +1 -1
- package/dist/http.esm.js +1 -1
- package/dist/id-ocr.d.ts +1 -1
- package/dist/id-ocr.esm.js +2 -2
- package/dist/id-selfie-flow.d.ts +1 -1
- package/dist/id-selfie-flow.esm.js +10 -9
- package/dist/id-verification.esm.js +2 -2
- package/dist/id.d.ts +3 -3
- package/dist/id.esm.js +4 -4
- package/dist/{idCaptureDefaults-MSQoqScU.esm.js → idCaptureDefaults-Dszuq9ng.esm.js} +3 -3
- package/dist/{idCaptureManager-zZdTcpG1.esm.js → idCaptureManager-B3oR4RnA.esm.js} +9 -8
- package/dist/{idCaptureManager-DzTfQ1Am.d.ts → idCaptureManager-CCA2D1Ah.d.ts} +5 -3
- package/dist/{idCaptureServices-8OHinO0N.esm.js → idCaptureServices-DK0QboqT.esm.js} +27 -196
- package/dist/{idCaptureStateMachine-B3G6XoDG.esm.js → idCaptureStateMachine-zzar9MPy.esm.js} +20 -20
- package/dist/{idOcrManager-DT3kPIB3.d.ts → idOcrManager-BTdHlJ9D.d.ts} +1 -1
- package/dist/{idOcrManager-B64-fjWg.esm.js → idOcrManager-xyEZNOBa.esm.js} +2 -2
- package/dist/{idOcrStateMachine-B1aZnobs.esm.js → idOcrStateMachine-DNKXh4Rn.esm.js} +1 -1
- package/dist/{idVerificationManager-_Kebv-Ue.esm.js → idVerificationManager-DdnvYfgN.esm.js} +2 -2
- package/dist/{idVerificationStateMachine-DQn6c84z.esm.js → idVerificationStateMachine-DtIBCa32.esm.js} +1 -1
- package/dist/identity-reuse.esm.js +2 -2
- package/dist/{identityReuseManager-DDXkNVZi.esm.js → identityReuseManager-CcpovlfD.esm.js} +2 -2
- package/dist/{identityReuseStateMachine-Bcnkbjf8.esm.js → identityReuseStateMachine-DxZFWy47.esm.js} +1 -1
- package/dist/{index-DMDAk85K.d.ts → index-DC0P2Vzw.d.ts} +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/{invokeOnCaptureCallback-CXIBwBeE.esm.js → invokeOnCaptureCallback-BJ0GVHGr.esm.js} +1 -1
- package/dist/kyb-checks.d.ts +3 -0
- package/dist/kyb-checks.esm.js +3 -0
- package/dist/kybChecksManager-CblEL97E.d.ts +95 -0
- package/dist/kybChecksManager-DpGOp4Su.esm.js +89 -0
- package/dist/kybChecksStateMachine-B43NAnv7.esm.js +718 -0
- package/dist/mandatory-consent.d.ts +2 -2
- package/dist/mandatory-consent.esm.js +2 -2
- package/dist/{mandatoryConsentManager-43W5d_8G.esm.js → mandatoryConsentManager-B4vCYslr.esm.js} +2 -2
- package/dist/{mandatoryConsentManager-xx3mY-xw.d.ts → mandatoryConsentManager-B88Sm5nd.d.ts} +6 -6
- package/dist/{mandatoryConsentStateMachine-CVlgdlnt.esm.js → mandatoryConsentStateMachine-DWslYPA3.esm.js} +1 -1
- package/dist/mediaRecorderOptions-B9-IEVtV.esm.js +70 -0
- package/dist/multipartRecordingService-BTqkHGG9.esm.js +407 -0
- package/dist/{permissionGuards-B3OPL8Si.esm.js → permissionGuards-DFV-Ws0a.esm.js} +1 -1
- package/dist/{permissionServices-DnBAN_hW.esm.js → permissionServices-D190ATGD.esm.js} +8 -6
- package/dist/phone.esm.js +2 -2
- package/dist/phoneFormat-JJNaWthV.esm.js +75 -0
- package/dist/{phoneManager-C6jut_pz.esm.js → phoneManager-Dy5tODCU.esm.js} +3 -3
- package/dist/phoneServices-DJgyOzU2.esm.js +77 -0
- package/dist/{phoneStateMachine-T1-drWfG.esm.js → phoneStateMachine-DnlPhnw7.esm.js} +20 -60
- package/dist/{processFaceMatch-BWme3kVV.esm.js → processFaceMatch-Bst83HaS.esm.js} +1 -1
- package/dist/qe-signature.esm.js +1 -1
- package/dist/recordingService-CTko6Cjn.esm.js +397 -0
- package/dist/redirect-to-mobile.esm.js +2 -2
- package/dist/{redirectToMobileManager-BJXC6Kx9.esm.js → redirectToMobileManager-CgGaT2NP.esm.js} +3 -3
- package/dist/{redirectToMobileStateMachine-BBMAc2Gb.esm.js → redirectToMobileStateMachine-CbhN8uVN.esm.js} +39 -21
- package/dist/resolveForm-O7-r79VA.esm.js +351 -0
- package/dist/{runChildModule-DPHTqSdF.esm.js → runChildModule-BffFArwl.esm.js} +2 -2
- package/dist/{sdkVersion-C3_P-Qbq.esm.js → sdkVersion-CDd_gaR7.esm.js} +1 -1
- package/dist/selfie.d.ts +3 -3
- package/dist/selfie.esm.js +10 -10
- package/dist/{selfieErrorUtils-BL0BLMnp.esm.js → selfieErrorUtils-f4MgAG2A.esm.js} +1 -1
- package/dist/{selfieManager-BMmpUii2.d.ts → selfieManager-DmZFzs1-.d.ts} +1 -1
- package/dist/{selfieManager-Cbliomv7.esm.js → selfieManager-hopelYEk.esm.js} +5 -5
- package/dist/{selfieStateMachine-B5m_Kn0O.esm.js → selfieStateMachine-DaZIVv3Q.esm.js} +3 -3
- package/dist/{session-DAaAewMX.esm.js → session-CdSX4wsZ.esm.js} +4 -4
- package/dist/session.d.ts +1 -1
- package/dist/session.esm.js +6 -6
- package/dist/{sessionInitializer-CWFT4dfw.esm.js → sessionInitializer-DsL7X2j9.esm.js} +83 -24
- package/dist/{setup-CDAKwTr7.esm.js → setup-DDahygZs.esm.js} +28 -27
- package/dist/signature.esm.js +2 -2
- package/dist/{signatureManager-BeEVCcsC.esm.js → signatureManager-CwqjcxPg.esm.js} +2 -2
- package/dist/{signatureStateMachine-_1c1vSid.esm.js → signatureStateMachine-DBVDd1Eu.esm.js} +1 -1
- package/dist/{stats-BpMz-hTP.esm.js → stats-CatA2dea.esm.js} +1 -1
- package/dist/stats.esm.js +1 -1
- package/dist/textRules-D4NRinKY.d.ts +41 -0
- package/dist/{tri-BajQnjbf.esm.js → tri-DG6priFa.esm.js} +1 -1
- package/dist/tri.esm.js +1 -1
- package/dist/{trueSightService-BujtUIW6.esm.js → trueSightService-GuLthUVK.esm.js} +4 -4
- package/dist/trust-graph.esm.js +1 -1
- package/dist/{types--3HDl2SF.d.ts → types-BEVHQbbC.d.ts} +1 -1
- package/dist/{types-xEEWCx1j.d.ts → types-BPm1JSu7.d.ts} +1 -1
- package/dist/{types-C397LhmN.d.ts → types-BgRHw-dR.d.ts} +1 -1
- package/dist/{types-DuD8TRJU.d.ts → types-CRaFu6wS.d.ts} +4 -2
- package/dist/types-CTaL0XJz.d.ts +80 -0
- package/dist/{types-PTZHRhGX.d.ts → types-Cd0J0F9D.d.ts} +1 -1
- package/dist/{types-e8fCsvvk.d.ts → types-Csh8vzPo.d.ts} +1 -1
- package/dist/{types-B2FK_wYb.d.ts → types-CuMJ2M7D.d.ts} +2 -41
- package/dist/{types-ZTZelfbM.d.ts → types-CyNndVAT.d.ts} +14 -6
- package/dist/types-J6g6iKe_.d.ts +6 -0
- package/dist/video-selfie.d.ts +1 -1
- package/dist/video-selfie.esm.js +9 -7
- package/dist/{videoSelfieCameraWarmer-DjkPpoj_.esm.js → videoSelfieCameraWarmer-e3irGfcO.esm.js} +8 -8
- package/dist/{videoSelfieStepDetector-RfSmlFFW.d.ts → videoSelfieStepDetector-Dv3Mgws-.d.ts} +2 -2
- package/dist/virtualCameraCheck-eFOm2C9q.esm.js +27 -0
- package/dist/{warmup-BkfxQZsC.esm.js → warmup-DtB0DJpl.esm.js} +24 -17
- package/dist/wasm.esm.js +3 -3
- package/dist/{wasmDsFlagSync-BhU5H2oR.esm.js → wasmDsFlagSync-BtiR5pig.esm.js} +1 -1
- package/dist/{wasmWebClient-DTj9auyA.esm.js → wasmWebClient-BDrax6Eu.esm.js} +12 -9
- package/dist/watchlist-for-business.esm.js +2 -2
- package/dist/watchlist.esm.js +2 -2
- package/dist/{watchlistForBusinessManager-CVay6-9A.esm.js → watchlistForBusinessManager-DqUpAEj_.esm.js} +2 -2
- package/dist/{watchlistForBusinessStateMachine-DA6K5na4.esm.js → watchlistForBusinessStateMachine-DdaPl2PS.esm.js} +1 -1
- package/dist/{watchlistManager-B8gQ_rw3.esm.js → watchlistManager-CdpXzT4B.esm.js} +2 -2
- package/dist/{watchlistStateMachine-CSi_ZhtT.esm.js → watchlistStateMachine-ofHW_lPk.esm.js} +1 -1
- package/dist/workflow.d.ts +1 -1
- package/dist/workflow.esm.js +42 -42
- package/package.json +11 -5
- package/dist/deepsightLoader-DMxtowCm.esm.js +0 -33
- package/dist/types-D9r3zRfY.d.ts +0 -6
|
@@ -0,0 +1,718 @@
|
|
|
1
|
+
import { t as api, u as endpoints } from "./api-CpP4PS4S.esm.js";
|
|
2
|
+
import { i as toIncodeApiError, t as IncodeApiError } from "./apiError-DH-CH4Nz.esm.js";
|
|
3
|
+
import { n as loadPhoneValidation } from "./phoneValidation-OggtfjRt.esm.js";
|
|
4
|
+
import { i as assign, t as setup } from "./xstate.esm-DSajW7CJ.esm.js";
|
|
5
|
+
import { n as fromPromise } from "./xstate-actors.esm-8Gzepa_A.esm.js";
|
|
6
|
+
import { i as usStateOptions, n as checkSupport, r as DYNAMIC_REQUIRED_KEY, t as resolveForm } from "./resolveForm-O7-r79VA.esm.js";
|
|
7
|
+
import { r as hasAllowedCharacters, t as formatPhoneE164 } from "./phoneFormat-JJNaWthV.esm.js";
|
|
8
|
+
function isSupportedSchema(form) {
|
|
9
|
+
return String(form.schemaVersion).split(".")[0] === "1";
|
|
10
|
+
}
|
|
11
|
+
/** Every field of the form, in display order. */
|
|
12
|
+
function formFields(form) {
|
|
13
|
+
if (!form) return [];
|
|
14
|
+
return form.steps.flatMap((step) => step.sections.flatMap((section) => section.fields));
|
|
15
|
+
}
|
|
16
|
+
function findField(form, name) {
|
|
17
|
+
return formFields(form).find((field) => field.name === name);
|
|
18
|
+
}
|
|
19
|
+
/** Blank text, or a list with no non-blank entry. */
|
|
20
|
+
function isBlank(value) {
|
|
21
|
+
if (Array.isArray(value)) return value.every((v) => v.trim() === "");
|
|
22
|
+
return value === void 0 || value.trim() === "";
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/modules/kyb-checks/kybChecksDefinition.ts
|
|
26
|
+
const KYB_CHECKS_MODULE = "kybChecks";
|
|
27
|
+
/** Served field name → vocabulary group. Every group is on: the backend already chose the fields. */
|
|
28
|
+
const GROUPS = {
|
|
29
|
+
country: "country",
|
|
30
|
+
taxId: "taxId",
|
|
31
|
+
businessName: "businessName",
|
|
32
|
+
alternativeNames: "alternativeNames",
|
|
33
|
+
street: "address",
|
|
34
|
+
city: "address",
|
|
35
|
+
state: "address",
|
|
36
|
+
postalCode: "address",
|
|
37
|
+
website: "website",
|
|
38
|
+
phoneNumber: "phone",
|
|
39
|
+
email: "email",
|
|
40
|
+
personNames: "personNames"
|
|
41
|
+
};
|
|
42
|
+
/** The group of a served field name this build has no group for. */
|
|
43
|
+
const OTHER_GROUP = "other";
|
|
44
|
+
/** Served field type → vocabulary kind. Any other type renders as text. */
|
|
45
|
+
const KINDS = {
|
|
46
|
+
text: "text",
|
|
47
|
+
select: "choice",
|
|
48
|
+
phone: "phone",
|
|
49
|
+
list: "list"
|
|
50
|
+
};
|
|
51
|
+
const KEYBOARDS = /* @__PURE__ */ new Set(["url", "email"]);
|
|
52
|
+
const TRANSFORMS = /* @__PURE__ */ new Set(["trim", "e164"]);
|
|
53
|
+
const KYB_CHECKS_SUPPORTED_IDS = {
|
|
54
|
+
schemaVersions: [1],
|
|
55
|
+
vocabulary: "1.3",
|
|
56
|
+
kinds: new Set(Object.values(KINDS)),
|
|
57
|
+
groups: /* @__PURE__ */ new Set([...Object.values(GROUPS), OTHER_GROUP]),
|
|
58
|
+
rules: /* @__PURE__ */ new Set(["allowedCharacters"]),
|
|
59
|
+
transforms: TRANSFORMS,
|
|
60
|
+
groupRules: /* @__PURE__ */ new Set(["oneOfRequired"]),
|
|
61
|
+
optionLists: /* @__PURE__ */ new Set(["US_STATES"]),
|
|
62
|
+
conditions: /* @__PURE__ */ new Set(),
|
|
63
|
+
prefillSources: /* @__PURE__ */ new Set()
|
|
64
|
+
};
|
|
65
|
+
/** A served regex of the one shape `allowedCharacters` can express: `^[…]{1,n}$` or `^[…]+$`. */
|
|
66
|
+
const CHARACTER_CLASS_REGEX = /^\^\[([^\]]+)\](?:\{[01],(\d+)\}|\+)\$$/;
|
|
67
|
+
/**
|
|
68
|
+
* Reads a served pattern as `allowedCharacters` (ASCII letters) plus a maximum
|
|
69
|
+
* length. Returns `undefined` for any other regex, which the adapter leaves
|
|
70
|
+
* out.
|
|
71
|
+
*/
|
|
72
|
+
function toCharacterPattern(regex, flags = "") {
|
|
73
|
+
const match = regex ? CHARACTER_CLASS_REGEX.exec(regex) : null;
|
|
74
|
+
if (!match || flags !== "" && flags !== "i") return void 0;
|
|
75
|
+
const [, body, max] = match;
|
|
76
|
+
let upper = false;
|
|
77
|
+
let lower = false;
|
|
78
|
+
let digit = false;
|
|
79
|
+
let space = false;
|
|
80
|
+
let extra = "";
|
|
81
|
+
for (let i = 0; i < body.length; i++) {
|
|
82
|
+
const range = body.slice(i, i + 3);
|
|
83
|
+
if (range === "A-Z" || range === "a-z" || range === "0-9") {
|
|
84
|
+
if (range === "A-Z") upper = true;
|
|
85
|
+
if (range === "a-z") lower = true;
|
|
86
|
+
if (range === "0-9") digit = true;
|
|
87
|
+
i += 2;
|
|
88
|
+
} else if (body[i] === "\\" && i + 1 < body.length) {
|
|
89
|
+
const escaped = body[++i];
|
|
90
|
+
if (escaped === "d") digit = true;
|
|
91
|
+
else if (/[A-Za-z]/.test(escaped)) return void 0;
|
|
92
|
+
else extra += escaped;
|
|
93
|
+
} else if (body[i] === "-" && i > 0 && i < body.length - 1) return;
|
|
94
|
+
else if (body[i] === " ") space = true;
|
|
95
|
+
else extra += body[i];
|
|
96
|
+
}
|
|
97
|
+
const letter = upper && lower || flags === "i" && (upper || lower);
|
|
98
|
+
if ((upper || lower) && !letter) return void 0;
|
|
99
|
+
const classes = [];
|
|
100
|
+
if (letter) classes.push("letter");
|
|
101
|
+
if (digit) classes.push("digit");
|
|
102
|
+
if (space) classes.push("space");
|
|
103
|
+
return {
|
|
104
|
+
classes,
|
|
105
|
+
extra,
|
|
106
|
+
max: max ? Number(max) : void 0
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const toFormText = ({ key, text }) => ({
|
|
110
|
+
key,
|
|
111
|
+
text
|
|
112
|
+
});
|
|
113
|
+
function toField(field, section, country) {
|
|
114
|
+
const options = field.options?.map((option) => ({
|
|
115
|
+
value: option.value,
|
|
116
|
+
label: toFormText(option.label)
|
|
117
|
+
}));
|
|
118
|
+
let kind = KINDS[field.type] ?? "text";
|
|
119
|
+
if (kind === "choice" && !options?.length) kind = "text";
|
|
120
|
+
const rules = [];
|
|
121
|
+
let maxLength;
|
|
122
|
+
for (const rule of field.rules) {
|
|
123
|
+
if (rule.kind !== "pattern" || kind === "phone") continue;
|
|
124
|
+
const pattern = toCharacterPattern(rule.regex, rule.flags);
|
|
125
|
+
if (!pattern) continue;
|
|
126
|
+
rules.push({
|
|
127
|
+
id: "allowedCharacters",
|
|
128
|
+
params: {
|
|
129
|
+
classes: pattern.classes,
|
|
130
|
+
extra: pattern.extra,
|
|
131
|
+
ascii: true
|
|
132
|
+
},
|
|
133
|
+
message: toFormText(rule.message)
|
|
134
|
+
});
|
|
135
|
+
if (pattern.max !== void 0) maxLength = Math.min(maxLength ?? pattern.max, pattern.max);
|
|
136
|
+
}
|
|
137
|
+
const keyboard = field.input?.keyboard;
|
|
138
|
+
const input = {
|
|
139
|
+
...maxLength !== void 0 && { maxLength },
|
|
140
|
+
...keyboard && KEYBOARDS.has(keyboard) && { keyboard }
|
|
141
|
+
};
|
|
142
|
+
const usStates = kind === "choice" && field.name === "state" && country === "US";
|
|
143
|
+
return {
|
|
144
|
+
name: field.name,
|
|
145
|
+
kind,
|
|
146
|
+
group: GROUPS[field.name] ?? OTHER_GROUP,
|
|
147
|
+
section,
|
|
148
|
+
required: field.required,
|
|
149
|
+
label: toFormText(field.label),
|
|
150
|
+
...Object.keys(input).length > 0 && { input },
|
|
151
|
+
...kind === "choice" && (usStates ? { optionsRef: "US_STATES" } : { options }),
|
|
152
|
+
...kind === "phone" && { phone: {
|
|
153
|
+
lockCountry: !field.phone?.allowCountryChange,
|
|
154
|
+
defaultCountry: "definition"
|
|
155
|
+
} },
|
|
156
|
+
...rules.length > 0 && { rules },
|
|
157
|
+
payload: {
|
|
158
|
+
key: field.payload.key,
|
|
159
|
+
transforms: field.payload.transforms.filter((id) => TRANSFORMS.has(id)).map((id) => ({ id })),
|
|
160
|
+
omitWhenEmpty: field.payload.omitWhenEmpty
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function toGroupRules(form, names) {
|
|
165
|
+
return [...form.rules, ...formFields(form).flatMap((field) => field.rules)].flatMap((rule) => {
|
|
166
|
+
const fields = (rule.fields ?? []).filter((name) => names.has(name));
|
|
167
|
+
if (rule.kind !== "requireAnyOf" || fields.length === 0) return [];
|
|
168
|
+
return [{
|
|
169
|
+
id: "oneOfRequired",
|
|
170
|
+
fields,
|
|
171
|
+
message: toFormText(rule.message)
|
|
172
|
+
}];
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* The served form as a form definition, plus what the definition has no slot
|
|
177
|
+
* for. Steps are flattened: the backend always sends one.
|
|
178
|
+
*/
|
|
179
|
+
function toKybChecksDefinition(form) {
|
|
180
|
+
const country = form.context.country;
|
|
181
|
+
const sections = [];
|
|
182
|
+
const fields = [];
|
|
183
|
+
const layoutFields = {};
|
|
184
|
+
for (const step of form.steps) for (const section of step.sections) {
|
|
185
|
+
sections.push(section.title ? {
|
|
186
|
+
id: section.id,
|
|
187
|
+
title: toFormText(section.title)
|
|
188
|
+
} : { id: section.id });
|
|
189
|
+
for (const field of section.fields) {
|
|
190
|
+
fields.push(toField(field, section.id, country));
|
|
191
|
+
layoutFields[field.name] = {
|
|
192
|
+
value: field.value,
|
|
193
|
+
readonly: field.display !== "editable",
|
|
194
|
+
...field.refetchOnChange && { refetchOnChange: field.refetchOnChange }
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const groupRules = toGroupRules(form, new Set(fields.map((field) => field.name)));
|
|
199
|
+
return {
|
|
200
|
+
definition: {
|
|
201
|
+
schemaVersion: 1,
|
|
202
|
+
vocabulary: KYB_CHECKS_SUPPORTED_IDS.vocabulary,
|
|
203
|
+
id: `${KYB_CHECKS_MODULE}/${country ?? "country"}`,
|
|
204
|
+
module: KYB_CHECKS_MODULE,
|
|
205
|
+
...country && { country },
|
|
206
|
+
sections,
|
|
207
|
+
fields,
|
|
208
|
+
...groupRules.length > 0 && { groupRules },
|
|
209
|
+
submit: { static: form.submit?.static ?? {} }
|
|
210
|
+
},
|
|
211
|
+
layout: {
|
|
212
|
+
title: form.steps[0]?.title,
|
|
213
|
+
fields: layoutFields
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region src/modules/kyb-checks/kybChecksFields.ts
|
|
219
|
+
const PHONE_FORMAT_ERROR = {
|
|
220
|
+
key: "kyb.errors.phoneNumberFormat",
|
|
221
|
+
text: "Enter a valid phone number"
|
|
222
|
+
};
|
|
223
|
+
const INVALID_CHARACTERS = {
|
|
224
|
+
key: "verification.errors.invalidCharacters",
|
|
225
|
+
text: "Use only the allowed characters"
|
|
226
|
+
};
|
|
227
|
+
const ALL_GROUPS_ON = Object.fromEntries([...KYB_CHECKS_SUPPORTED_IDS.groups].map((group) => [group, true]));
|
|
228
|
+
const TYPES = {
|
|
229
|
+
choice: "dropdown",
|
|
230
|
+
phone: "phone",
|
|
231
|
+
list: "list"
|
|
232
|
+
};
|
|
233
|
+
const toText = (text, fallback) => text ? {
|
|
234
|
+
key: text.key,
|
|
235
|
+
text: text.text ?? fallback.text
|
|
236
|
+
} : fallback;
|
|
237
|
+
const fromFormText = (text) => ({
|
|
238
|
+
key: text.key,
|
|
239
|
+
text: text.text ?? ""
|
|
240
|
+
});
|
|
241
|
+
function projectRules(rules, required, maxLength) {
|
|
242
|
+
const validation = required ? [{ type: "required" }] : [];
|
|
243
|
+
let lengthMessage;
|
|
244
|
+
for (const rule of rules ?? []) {
|
|
245
|
+
if (rule.id !== "allowedCharacters") continue;
|
|
246
|
+
const params = rule.params ?? {};
|
|
247
|
+
const message = toText(rule.message, INVALID_CHARACTERS);
|
|
248
|
+
validation.push({
|
|
249
|
+
type: "allowedCharacters",
|
|
250
|
+
classes: params.classes ?? [],
|
|
251
|
+
extra: typeof params.extra === "string" ? params.extra : "",
|
|
252
|
+
ascii: params.ascii === true,
|
|
253
|
+
message
|
|
254
|
+
});
|
|
255
|
+
lengthMessage ??= message;
|
|
256
|
+
}
|
|
257
|
+
if (maxLength !== void 0 && lengthMessage) validation.push({
|
|
258
|
+
type: "maxLength",
|
|
259
|
+
max: maxLength,
|
|
260
|
+
message: lengthMessage
|
|
261
|
+
});
|
|
262
|
+
return validation;
|
|
263
|
+
}
|
|
264
|
+
function projectField(resolved, layout, country) {
|
|
265
|
+
const { field, required, phoneLocked } = resolved;
|
|
266
|
+
const type = TYPES[field.kind] ?? "text";
|
|
267
|
+
const served = layout.fields[field.name];
|
|
268
|
+
const keyboard = field.input?.keyboard;
|
|
269
|
+
const maxLength = field.input?.maxLength;
|
|
270
|
+
const options = field.optionsRef === "US_STATES" ? usStateOptions.map((option) => ({ ...option })) : field.options?.map((option) => ({
|
|
271
|
+
value: option.value,
|
|
272
|
+
label: option.label.key,
|
|
273
|
+
labelText: option.label.text
|
|
274
|
+
}));
|
|
275
|
+
return {
|
|
276
|
+
name: field.name,
|
|
277
|
+
type,
|
|
278
|
+
label: field.label.key,
|
|
279
|
+
labelText: field.label.text ?? "",
|
|
280
|
+
required,
|
|
281
|
+
...field.section && { section: field.section },
|
|
282
|
+
...maxLength !== void 0 && { maxLength },
|
|
283
|
+
...type === "dropdown" && { options },
|
|
284
|
+
...(keyboard === "url" || keyboard === "email") && { inputType: keyboard },
|
|
285
|
+
...type === "phone" && {
|
|
286
|
+
phoneCountry: country,
|
|
287
|
+
disableCountrySelector: phoneLocked
|
|
288
|
+
},
|
|
289
|
+
...served?.readonly && { readonly: true },
|
|
290
|
+
...served?.refetchOnChange && { refetchOnChange: served.refetchOnChange },
|
|
291
|
+
initialValue: served?.value ?? (type === "list" ? [] : ""),
|
|
292
|
+
validation: projectRules(field.rules, required, maxLength)
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
const preparedForms = /* @__PURE__ */ new WeakMap();
|
|
296
|
+
/**
|
|
297
|
+
* The served form on the forms kernel: translated to a definition, checked,
|
|
298
|
+
* resolved with every group on and projected. `undefined` when this build
|
|
299
|
+
* can't render it: a newer schema major, or an adapter output that fails
|
|
300
|
+
* `checkSupport`, which would be a bug in the adapter.
|
|
301
|
+
*/
|
|
302
|
+
function prepareKybChecksForm(form) {
|
|
303
|
+
if (preparedForms.has(form)) return preparedForms.get(form) ?? void 0;
|
|
304
|
+
let prepared = null;
|
|
305
|
+
if (isSupportedSchema(form)) {
|
|
306
|
+
const { definition, layout } = toKybChecksDefinition(form);
|
|
307
|
+
const support = checkSupport(definition, KYB_CHECKS_SUPPORTED_IDS);
|
|
308
|
+
if (support.supported) {
|
|
309
|
+
const resolved = resolveForm(definition, { groups: ALL_GROUPS_ON });
|
|
310
|
+
const sections = (definition.sections ?? []).map((section) => ({
|
|
311
|
+
id: section.id,
|
|
312
|
+
...section.title && { title: fromFormText(section.title) },
|
|
313
|
+
fields: resolved.fields.filter((field) => field.field.section === section.id).map((field) => projectField(field, layout, definition.country))
|
|
314
|
+
}));
|
|
315
|
+
const formRules = resolved.groupRules.map(({ rule, fields }) => ({
|
|
316
|
+
type: "oneOfRequired",
|
|
317
|
+
fields: [...fields],
|
|
318
|
+
message: fromFormText(rule.message ?? { key: rule.id })
|
|
319
|
+
}));
|
|
320
|
+
prepared = {
|
|
321
|
+
submit: toSubmitPlan(definition),
|
|
322
|
+
title: layout.title,
|
|
323
|
+
sections,
|
|
324
|
+
formRules
|
|
325
|
+
};
|
|
326
|
+
} else console.warn("[kyb-checks] Unsupported form definition", support.problems);
|
|
327
|
+
}
|
|
328
|
+
preparedForms.set(form, prepared);
|
|
329
|
+
return prepared ?? void 0;
|
|
330
|
+
}
|
|
331
|
+
function sectionFields(prepared) {
|
|
332
|
+
return prepared.sections.flatMap((section) => section.fields);
|
|
333
|
+
}
|
|
334
|
+
function canKeep(field, before, value) {
|
|
335
|
+
if (field.readonly) return false;
|
|
336
|
+
if (before && before.type !== field.type) return false;
|
|
337
|
+
if (Array.isArray(value) !== Array.isArray(field.initialValue)) return false;
|
|
338
|
+
if (field.type !== "dropdown" || value === "") return true;
|
|
339
|
+
return (field.options ?? []).some((option) => option.value === value);
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Values for a newly fetched form. What the user entered carries over to the
|
|
343
|
+
* field of the same name only when that field is editable, has the same type
|
|
344
|
+
* and shape as before and, for a dropdown, still offers the value. A phone
|
|
345
|
+
* the input flagged as invalid stays flagged with it. Every other field
|
|
346
|
+
* starts from its served value.
|
|
347
|
+
*/
|
|
348
|
+
function carryOverValues(prepared, before, previous, invalidFormats) {
|
|
349
|
+
const beforeFields = new Map((before ? sectionFields(before) : []).map((field) => [field.name, field]));
|
|
350
|
+
const values = {};
|
|
351
|
+
const stillInvalid = {};
|
|
352
|
+
for (const field of sectionFields(prepared)) {
|
|
353
|
+
const kept = previous[field.name];
|
|
354
|
+
if (kept !== void 0 && canKeep(field, beforeFields.get(field.name), kept)) {
|
|
355
|
+
values[field.name] = kept;
|
|
356
|
+
if (field.type === "phone" && invalidFormats[field.name]) stillInvalid[field.name] = true;
|
|
357
|
+
} else values[field.name] = field.initialValue;
|
|
358
|
+
}
|
|
359
|
+
return {
|
|
360
|
+
values,
|
|
361
|
+
invalidFormats: stillInvalid
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
function requiredMessage(field) {
|
|
365
|
+
return {
|
|
366
|
+
key: DYNAMIC_REQUIRED_KEY,
|
|
367
|
+
text: `${field.labelText} is required`,
|
|
368
|
+
params: { fieldName: {
|
|
369
|
+
key: field.label,
|
|
370
|
+
text: field.labelText
|
|
371
|
+
} }
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
function failsRule(rule, value) {
|
|
375
|
+
if (rule.type === "required") return isBlank(value);
|
|
376
|
+
const entries = (Array.isArray(value) ? value : [value]).map((entry) => entry.trim()).filter((entry) => entry !== "");
|
|
377
|
+
if (rule.type === "maxLength") return entries.some((entry) => entry.length > rule.max);
|
|
378
|
+
return entries.some((entry) => !hasAllowedCharacters(entry, rule.classes, rule.extra, rule.ascii));
|
|
379
|
+
}
|
|
380
|
+
/** The first failing rule's message for a field, in rule order. */
|
|
381
|
+
function validateField(field, values, invalidFormats = {}) {
|
|
382
|
+
const value = values[field.name] ?? field.initialValue;
|
|
383
|
+
for (const rule of field.validation) if (failsRule(rule, value)) return rule.type === "required" ? requiredMessage(field) : rule.message;
|
|
384
|
+
if (invalidFormats[field.name] && !isBlank(value)) return PHONE_FORMAT_ERROR;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Errors for the whole form. A form-level rule is shown on the first field it
|
|
388
|
+
* names, unless that field already has an error.
|
|
389
|
+
*/
|
|
390
|
+
function validateForm(prepared, values, invalidFormats = {}) {
|
|
391
|
+
const errors = {};
|
|
392
|
+
for (const field of sectionFields(prepared)) {
|
|
393
|
+
const error = validateField(field, values, invalidFormats);
|
|
394
|
+
if (error) errors[field.name] = error;
|
|
395
|
+
}
|
|
396
|
+
for (const rule of prepared.formRules) {
|
|
397
|
+
const [target] = rule.fields;
|
|
398
|
+
const allBlank = rule.fields.every((name) => isBlank(values[name]));
|
|
399
|
+
if (target && !errors[target] && allBlank) errors[target] = rule.message;
|
|
400
|
+
}
|
|
401
|
+
return errors;
|
|
402
|
+
}
|
|
403
|
+
function applyTransforms(value, transforms, country) {
|
|
404
|
+
let current = value;
|
|
405
|
+
for (const transform of transforms) if (transform === "trim") current = Array.isArray(current) ? current.map((entry) => entry.trim()) : current.trim();
|
|
406
|
+
else if (transform === "e164" && typeof current === "string") current = current ? formatPhoneE164(current, country ?? "") : current;
|
|
407
|
+
return current;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* The request body the definition describes, in the module's own terms.
|
|
411
|
+
* `submit.static` wins over a field with the same key: the backend sends the
|
|
412
|
+
* country both ways, with the same value. The catalog compiler rejects two
|
|
413
|
+
* fields writing one key, but a served form is never compiled, so a later
|
|
414
|
+
* field whose key an earlier field already writes is left out, with a warning.
|
|
415
|
+
*/
|
|
416
|
+
function toSubmitPlan(definition) {
|
|
417
|
+
const staticKeys = new Set(Object.keys(definition.submit.static ?? {}));
|
|
418
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
419
|
+
const fields = [];
|
|
420
|
+
for (const field of definition.fields) {
|
|
421
|
+
if (field.payload?.omit) continue;
|
|
422
|
+
const key = field.payload?.key ?? field.name;
|
|
423
|
+
if (staticKeys.has(key)) continue;
|
|
424
|
+
if (claimed.has(key)) {
|
|
425
|
+
console.warn(`[kyb-checks] Not sending field "${field.name}": request key "${key}" is already written`);
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
claimed.add(key);
|
|
429
|
+
fields.push({
|
|
430
|
+
name: field.name,
|
|
431
|
+
key,
|
|
432
|
+
transforms: (field.payload?.transforms ?? []).map((t) => t.id),
|
|
433
|
+
omitWhenEmpty: field.payload?.omitWhenEmpty === true,
|
|
434
|
+
isList: field.kind === "list"
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
return {
|
|
438
|
+
static: { ...definition.submit.static },
|
|
439
|
+
country: definition.country,
|
|
440
|
+
fields
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* The `POST /omni/kyb` body: `submit.static`, then each field's value under
|
|
445
|
+
* its request key after its transforms. List fields drop blank entries, and
|
|
446
|
+
* a field marked `omitWhenEmpty` is left out when it's empty.
|
|
447
|
+
*/
|
|
448
|
+
function buildSubmitBody(submit, values) {
|
|
449
|
+
const body = { ...submit.static };
|
|
450
|
+
for (const field of submit.fields) {
|
|
451
|
+
let value = applyTransforms(values[field.name] ?? (field.isList ? [] : ""), field.transforms, submit.country);
|
|
452
|
+
if (Array.isArray(value)) value = value.filter((entry) => entry.trim() !== "");
|
|
453
|
+
if (field.omitWhenEmpty && isBlank(value)) continue;
|
|
454
|
+
body[field.key] = value;
|
|
455
|
+
}
|
|
456
|
+
return body;
|
|
457
|
+
}
|
|
458
|
+
//#endregion
|
|
459
|
+
//#region src/modules/kyb-checks/kybChecksServices.ts
|
|
460
|
+
/**
|
|
461
|
+
* Fetches the KYB form for the session. Without `country` it holds only the
|
|
462
|
+
* country picker; with it, the fields that country needs and a `submit` block.
|
|
463
|
+
*/
|
|
464
|
+
async function fetchKybForm(country, signal) {
|
|
465
|
+
try {
|
|
466
|
+
const res = await api.get(endpoints.kybForm, {
|
|
467
|
+
query: { country },
|
|
468
|
+
signal
|
|
469
|
+
});
|
|
470
|
+
if (!res.ok) throw res;
|
|
471
|
+
return res.data;
|
|
472
|
+
} catch (error) {
|
|
473
|
+
throw toIncodeApiError(endpoints.kybForm, error);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Runs the KYB checks. Always posts to `endpoints.kybSubmit`: the form's
|
|
478
|
+
* `submit.endpoint` and `submit.method` are not followed.
|
|
479
|
+
*/
|
|
480
|
+
async function submitKyb(body, signal) {
|
|
481
|
+
try {
|
|
482
|
+
const res = await api.post(endpoints.kybSubmit, body, { signal });
|
|
483
|
+
if (!res.ok) throw res;
|
|
484
|
+
return res.data;
|
|
485
|
+
} catch (error) {
|
|
486
|
+
throw toIncodeApiError(endpoints.kybSubmit, error);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
//#endregion
|
|
490
|
+
//#region src/modules/kyb-checks/kybChecksStateMachine.ts
|
|
491
|
+
/** The only `refetchOnChange` query parameter `GET /omni/kyb/form` takes. */
|
|
492
|
+
const COUNTRY_PARAM = "country";
|
|
493
|
+
function isForbidden(error) {
|
|
494
|
+
return error instanceof IncodeApiError && error.httpStatus === 403;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* A submit is retried only when the server answered with a 4xx: it rejected
|
|
498
|
+
* the request, so no check ran. After a timeout, a network failure or a 5xx
|
|
499
|
+
* the checks may already have run, and `POST /omni/kyb` has no duplicate
|
|
500
|
+
* guard, so a retry could run (and charge) them twice.
|
|
501
|
+
*/
|
|
502
|
+
function canRetrySubmit(error) {
|
|
503
|
+
return error instanceof IncodeApiError && error.httpStatus >= 400 && error.httpStatus < 500;
|
|
504
|
+
}
|
|
505
|
+
function errorMessageOf(error) {
|
|
506
|
+
return error instanceof Error ? error.message : String(error);
|
|
507
|
+
}
|
|
508
|
+
const kybChecksMachine = setup({
|
|
509
|
+
types: {
|
|
510
|
+
context: {},
|
|
511
|
+
events: {},
|
|
512
|
+
input: {},
|
|
513
|
+
output: {}
|
|
514
|
+
},
|
|
515
|
+
actors: {
|
|
516
|
+
fetchForm: fromPromise(async ({ input, signal }) => fetchKybForm(input.country, signal)),
|
|
517
|
+
submit: fromPromise(async ({ input, signal }) => {
|
|
518
|
+
await loadPhoneValidation();
|
|
519
|
+
return submitKyb(buildSubmitBody(input.submit, input.values), signal);
|
|
520
|
+
})
|
|
521
|
+
},
|
|
522
|
+
actions: {
|
|
523
|
+
startPhoneValidationLoad: () => {
|
|
524
|
+
loadPhoneValidation();
|
|
525
|
+
},
|
|
526
|
+
applyForm: assign(({ context, event }) => {
|
|
527
|
+
const form = event.output;
|
|
528
|
+
const prepared = prepareKybChecksForm(form);
|
|
529
|
+
return {
|
|
530
|
+
form,
|
|
531
|
+
prepared,
|
|
532
|
+
...carryOverValues(prepared, context.prepared, context.values, context.invalidFormats),
|
|
533
|
+
errors: {},
|
|
534
|
+
country: form.context.country ?? context.country
|
|
535
|
+
};
|
|
536
|
+
}),
|
|
537
|
+
setFieldValue: assign(({ context, event }) => {
|
|
538
|
+
const { name, value, isValid } = event;
|
|
539
|
+
const invalidFormats = { ...context.invalidFormats };
|
|
540
|
+
if (isValid === false) invalidFormats[name] = true;
|
|
541
|
+
else delete invalidFormats[name];
|
|
542
|
+
const errors = { ...context.errors };
|
|
543
|
+
delete errors[name];
|
|
544
|
+
return {
|
|
545
|
+
values: {
|
|
546
|
+
...context.values,
|
|
547
|
+
[name]: value
|
|
548
|
+
},
|
|
549
|
+
errors,
|
|
550
|
+
invalidFormats
|
|
551
|
+
};
|
|
552
|
+
}),
|
|
553
|
+
setCountryFromEvent: assign(({ event }) => ({ country: String(event.value) })),
|
|
554
|
+
validateAll: assign(({ context }) => ({ errors: context.prepared ? validateForm(context.prepared, context.values, context.invalidFormats) : {} })),
|
|
555
|
+
setLoadError: assign(({ event }) => ({
|
|
556
|
+
errorKind: "load",
|
|
557
|
+
canRetry: true,
|
|
558
|
+
errorMessage: errorMessageOf(event.error)
|
|
559
|
+
})),
|
|
560
|
+
setSubmitError: assign(({ event }) => {
|
|
561
|
+
const { error } = event;
|
|
562
|
+
return {
|
|
563
|
+
errorKind: "submit",
|
|
564
|
+
canRetry: canRetrySubmit(error),
|
|
565
|
+
errorMessage: errorMessageOf(error)
|
|
566
|
+
};
|
|
567
|
+
}),
|
|
568
|
+
clearError: assign({
|
|
569
|
+
errorKind: void 0,
|
|
570
|
+
errorMessage: void 0,
|
|
571
|
+
canRetry: false
|
|
572
|
+
}),
|
|
573
|
+
setResult: assign(({ event }) => ({ result: { referenceId: event.output?.referenceId } }))
|
|
574
|
+
},
|
|
575
|
+
guards: {
|
|
576
|
+
isSupportedForm: ({ event }) => !!prepareKybChecksForm(event.output),
|
|
577
|
+
isForbidden: ({ event }) => isForbidden(event.error),
|
|
578
|
+
changesCountry: ({ context, event }) => {
|
|
579
|
+
const { name, value } = event;
|
|
580
|
+
return findField(context.form, name)?.refetchOnChange === COUNTRY_PARAM && typeof value === "string" && value !== "" && value !== context.country;
|
|
581
|
+
},
|
|
582
|
+
hasNoErrors: ({ context }) => Object.keys(context.errors).length === 0 && !!context.form?.submit,
|
|
583
|
+
failedLoadingFirstForm: ({ context }) => context.errorKind === "load" && context.form === void 0,
|
|
584
|
+
failedLoading: ({ context }) => context.errorKind === "load",
|
|
585
|
+
canRetry: ({ context }) => context.canRetry
|
|
586
|
+
}
|
|
587
|
+
}).createMachine({
|
|
588
|
+
id: "kybChecks",
|
|
589
|
+
initial: "idle",
|
|
590
|
+
context: ({ input }) => ({
|
|
591
|
+
config: input?.config ?? {},
|
|
592
|
+
form: void 0,
|
|
593
|
+
prepared: void 0,
|
|
594
|
+
values: {},
|
|
595
|
+
errors: {},
|
|
596
|
+
invalidFormats: {},
|
|
597
|
+
country: void 0,
|
|
598
|
+
errorKind: void 0,
|
|
599
|
+
errorMessage: void 0,
|
|
600
|
+
canRetry: false,
|
|
601
|
+
result: void 0
|
|
602
|
+
}),
|
|
603
|
+
output: ({ context }) => context.result ?? {},
|
|
604
|
+
states: {
|
|
605
|
+
idle: { on: { LOAD: "loading" } },
|
|
606
|
+
loading: {
|
|
607
|
+
entry: "startPhoneValidationLoad",
|
|
608
|
+
invoke: {
|
|
609
|
+
id: "fetchForm",
|
|
610
|
+
src: "fetchForm",
|
|
611
|
+
input: ({ context }) => ({ country: context.country }),
|
|
612
|
+
onDone: [{
|
|
613
|
+
guard: "isSupportedForm",
|
|
614
|
+
target: "form",
|
|
615
|
+
actions: "applyForm"
|
|
616
|
+
}, { target: "misconfigured" }],
|
|
617
|
+
onError: [{
|
|
618
|
+
guard: "isForbidden",
|
|
619
|
+
target: "misconfigured"
|
|
620
|
+
}, {
|
|
621
|
+
target: "error",
|
|
622
|
+
actions: "setLoadError"
|
|
623
|
+
}]
|
|
624
|
+
}
|
|
625
|
+
},
|
|
626
|
+
form: {
|
|
627
|
+
initial: "inputting",
|
|
628
|
+
states: {
|
|
629
|
+
inputting: { on: {
|
|
630
|
+
SET_FIELD: [{
|
|
631
|
+
guard: "changesCountry",
|
|
632
|
+
target: "refetching",
|
|
633
|
+
actions: ["setFieldValue", "setCountryFromEvent"]
|
|
634
|
+
}, { actions: "setFieldValue" }],
|
|
635
|
+
SUBMIT: "validating"
|
|
636
|
+
} },
|
|
637
|
+
refetching: {
|
|
638
|
+
invoke: {
|
|
639
|
+
id: "refetchForm",
|
|
640
|
+
src: "fetchForm",
|
|
641
|
+
input: ({ context }) => ({ country: context.country }),
|
|
642
|
+
onDone: [{
|
|
643
|
+
guard: "isSupportedForm",
|
|
644
|
+
target: "inputting",
|
|
645
|
+
actions: "applyForm"
|
|
646
|
+
}, { target: "#kybChecks.misconfigured" }],
|
|
647
|
+
onError: [{
|
|
648
|
+
guard: "isForbidden",
|
|
649
|
+
target: "#kybChecks.misconfigured"
|
|
650
|
+
}, {
|
|
651
|
+
target: "#kybChecks.error",
|
|
652
|
+
actions: "setLoadError"
|
|
653
|
+
}]
|
|
654
|
+
},
|
|
655
|
+
on: { SET_FIELD: [{
|
|
656
|
+
guard: "changesCountry",
|
|
657
|
+
target: "refetching",
|
|
658
|
+
reenter: true,
|
|
659
|
+
actions: ["setFieldValue", "setCountryFromEvent"]
|
|
660
|
+
}, { actions: "setFieldValue" }] }
|
|
661
|
+
},
|
|
662
|
+
validating: {
|
|
663
|
+
entry: "validateAll",
|
|
664
|
+
always: [{
|
|
665
|
+
guard: "hasNoErrors",
|
|
666
|
+
target: "#kybChecks.submitting"
|
|
667
|
+
}, { target: "inputting" }]
|
|
668
|
+
}
|
|
669
|
+
},
|
|
670
|
+
on: { CLOSE: "closed" }
|
|
671
|
+
},
|
|
672
|
+
submitting: { invoke: {
|
|
673
|
+
id: "submit",
|
|
674
|
+
src: "submit",
|
|
675
|
+
input: ({ context }) => ({
|
|
676
|
+
submit: context.prepared?.submit,
|
|
677
|
+
values: context.values
|
|
678
|
+
}),
|
|
679
|
+
onDone: {
|
|
680
|
+
target: "finished",
|
|
681
|
+
actions: "setResult"
|
|
682
|
+
},
|
|
683
|
+
onError: [{
|
|
684
|
+
guard: "isForbidden",
|
|
685
|
+
target: "misconfigured"
|
|
686
|
+
}, {
|
|
687
|
+
target: "error",
|
|
688
|
+
actions: "setSubmitError"
|
|
689
|
+
}]
|
|
690
|
+
} },
|
|
691
|
+
error: { on: {
|
|
692
|
+
RETRY: [
|
|
693
|
+
{
|
|
694
|
+
guard: "failedLoadingFirstForm",
|
|
695
|
+
target: "loading",
|
|
696
|
+
actions: "clearError"
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
guard: "failedLoading",
|
|
700
|
+
target: "form.refetching",
|
|
701
|
+
actions: "clearError"
|
|
702
|
+
},
|
|
703
|
+
{
|
|
704
|
+
guard: "canRetry",
|
|
705
|
+
target: "submitting",
|
|
706
|
+
actions: "clearError"
|
|
707
|
+
}
|
|
708
|
+
],
|
|
709
|
+
CLOSE: "closed"
|
|
710
|
+
} },
|
|
711
|
+
/** KYB is not in the session's flow, the session is closed, or the form schema is newer than this SDK. */
|
|
712
|
+
misconfigured: { on: { CLOSE: "closed" } },
|
|
713
|
+
finished: { type: "final" },
|
|
714
|
+
closed: { type: "final" }
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
//#endregion
|
|
718
|
+
export { kybChecksMachine as t };
|