smartcomply-web-sdk 1.0.76 → 1.0.78
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/camera/FaceDetector.d.ts.map +1 -1
- package/dist/camera/FaceDetector.js +42 -17
- package/dist/camera/FaceDetector.js.map +1 -1
- package/dist/esm/camera/FaceDetector.d.ts.map +1 -1
- package/dist/esm/camera/FaceDetector.js +42 -17
- package/dist/esm/camera/FaceDetector.js.map +1 -1
- package/dist/esm/flow/SmartComplyFlow.d.ts +9 -0
- package/dist/esm/flow/SmartComplyFlow.d.ts.map +1 -1
- package/dist/esm/flow/SmartComplyFlow.js +83 -20
- package/dist/esm/flow/SmartComplyFlow.js.map +1 -1
- package/dist/esm/modules/liveness/liveness.d.ts.map +1 -1
- package/dist/esm/modules/liveness/liveness.js +29 -2
- package/dist/esm/modules/liveness/liveness.js.map +1 -1
- package/dist/flow/SmartComplyFlow.d.ts +9 -0
- package/dist/flow/SmartComplyFlow.d.ts.map +1 -1
- package/dist/flow/SmartComplyFlow.js +83 -20
- package/dist/flow/SmartComplyFlow.js.map +1 -1
- package/dist/modules/liveness/liveness.d.ts.map +1 -1
- package/dist/modules/liveness/liveness.js +29 -2
- package/dist/modules/liveness/liveness.js.map +1 -1
- package/dist/smartcomply.browser.js +102 -33
- package/dist/smartcomply.browser.js.map +3 -3
- package/package.json +1 -1
|
@@ -137,6 +137,15 @@ export declare class SmartComplyFlow {
|
|
|
137
137
|
/** Click handler that fires once and disables the button, preventing a double-tap double-dispatch. */
|
|
138
138
|
private _onceClick;
|
|
139
139
|
private isDocumentFlow;
|
|
140
|
+
/**
|
|
141
|
+
* True when the SDK Config is set to skip data/document verification
|
|
142
|
+
* entirely and only run the liveness/selfie check — no country picker,
|
|
143
|
+
* no ID-type picker, no ID-number entry or document capture. Unlike
|
|
144
|
+
* isDocumentFlow(), there's no channel-shape fallback to infer this from:
|
|
145
|
+
* a liveness-only config carries no channels at all, so the only signal
|
|
146
|
+
* is verification_type itself.
|
|
147
|
+
*/
|
|
148
|
+
private isLivenessOnlyFlow;
|
|
140
149
|
/**
|
|
141
150
|
* The "go back one step" target for a given step, if that step is
|
|
142
151
|
* navigable — shared by the header back button and the browser
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SmartComplyFlow.d.ts","sourceRoot":"","sources":["../../src/flow/SmartComplyFlow.ts"],"names":[],"mappings":"AACA,OAAO,EAA6B,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAIxF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"SmartComplyFlow.d.ts","sourceRoot":"","sources":["../../src/flow/SmartComplyFlow.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,6 +21,11 @@ const _INFRASTRUCTURE_ERROR_PATTERNS = [
|
|
|
21
21
|
"camera access is not supported",
|
|
22
22
|
"camera access failed",
|
|
23
23
|
"recording failed unexpectedly",
|
|
24
|
+
// FaceDetectorEngine.init() failures (FaceDetector.ts) — a slow/blocked
|
|
25
|
+
// CDN or model download is a connectivity issue, not a failed face scan,
|
|
26
|
+
// and must not burn one of the user's limited liveness retry attempts.
|
|
27
|
+
"face detection setup timed out",
|
|
28
|
+
"failed to download face model",
|
|
24
29
|
];
|
|
25
30
|
function _isInfrastructureError(err) {
|
|
26
31
|
const msg = String(err?.message || "").toLowerCase();
|
|
@@ -770,7 +775,8 @@ class SmartComplyFlow {
|
|
|
770
775
|
// ── Welcome ────────────────────────────────────────────────────
|
|
771
776
|
renderWelcome(container) {
|
|
772
777
|
container.style.cssText += "display:flex;flex-direction:column;align-items:center;text-align:center;gap:12px;";
|
|
773
|
-
const
|
|
778
|
+
const isLivenessOnly = this.isLivenessOnlyFlow();
|
|
779
|
+
const isDocFlow = isLivenessOnly ? false : this.isDocumentFlow();
|
|
774
780
|
// Icon + badge row (side by side to save vertical space)
|
|
775
781
|
const topRow = document.createElement("div");
|
|
776
782
|
topRow.style.cssText = "display:flex;flex-direction:column;align-items:center;gap:8px;";
|
|
@@ -793,7 +799,9 @@ class SmartComplyFlow {
|
|
|
793
799
|
color:${this.theme.primary};
|
|
794
800
|
border:1px solid ${this.theme.primary}30;
|
|
795
801
|
`;
|
|
796
|
-
badge.textContent =
|
|
802
|
+
badge.textContent = isLivenessOnly
|
|
803
|
+
? "🤳 Liveness Check"
|
|
804
|
+
: isDocFlow ? "📄 Document Verification" : "🔍 Data Verification";
|
|
797
805
|
topRow.appendChild(badge);
|
|
798
806
|
container.appendChild(topRow);
|
|
799
807
|
// Title + subtitle (compact)
|
|
@@ -815,23 +823,29 @@ class SmartComplyFlow {
|
|
|
815
823
|
color:${this.theme.textSecondary};font-size:13px;line-height:1.5;
|
|
816
824
|
margin:0 auto;max-width:300px;text-align:center;
|
|
817
825
|
`;
|
|
818
|
-
desc.textContent =
|
|
819
|
-
? "You'll need
|
|
820
|
-
:
|
|
826
|
+
desc.textContent = isLivenessOnly
|
|
827
|
+
? "You'll just need camera access. This takes about 30 seconds."
|
|
828
|
+
: isDocFlow
|
|
829
|
+
? "You'll need your document and camera access. This takes about 2 minutes."
|
|
830
|
+
: "You'll need your ID number and camera access. This takes about 2 minutes.";
|
|
821
831
|
titleWrap.appendChild(desc);
|
|
822
832
|
container.appendChild(titleWrap);
|
|
823
833
|
// Steps preview — compact rows
|
|
824
|
-
const steps =
|
|
834
|
+
const steps = isLivenessOnly
|
|
825
835
|
? [
|
|
826
|
-
{ icon: "🪪", text: "Choose your document type", sub: "Passport, National ID, Driver License" },
|
|
827
|
-
{ icon: "📷", text: "Scan your document", sub: "Upload or capture a photo of your ID" },
|
|
828
836
|
{ icon: "🤳", text: "Face check", sub: "Quick selfie to confirm it's you" },
|
|
829
837
|
]
|
|
830
|
-
:
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
838
|
+
: isDocFlow
|
|
839
|
+
? [
|
|
840
|
+
{ icon: "🪪", text: "Choose your document type", sub: "Passport, National ID, Driver License" },
|
|
841
|
+
{ icon: "📷", text: "Scan your document", sub: "Upload or capture a photo of your ID" },
|
|
842
|
+
{ icon: "🤳", text: "Face check", sub: "Quick selfie to confirm it's you" },
|
|
843
|
+
]
|
|
844
|
+
: [
|
|
845
|
+
{ icon: "🆔", text: "Choose your ID type", sub: "NIN, BVN, Voter's Card and more" },
|
|
846
|
+
{ icon: "📝", text: "Enter your ID details", sub: "Exactly as shown on your ID" },
|
|
847
|
+
{ icon: "🤳", text: "Face check", sub: "Quick selfie to confirm it's you" },
|
|
848
|
+
];
|
|
835
849
|
const stepsWrap = document.createElement("div");
|
|
836
850
|
stepsWrap.style.cssText = `
|
|
837
851
|
width:100%;display:flex;flex-direction:column;gap:0;
|
|
@@ -873,7 +887,27 @@ class SmartComplyFlow {
|
|
|
873
887
|
// CTA
|
|
874
888
|
const btn = this.createPrimaryButton("Get Started →");
|
|
875
889
|
btn.style.cssText += "margin-top:2px;";
|
|
876
|
-
btn.addEventListener("click", () =>
|
|
890
|
+
btn.addEventListener("click", () => {
|
|
891
|
+
if (isLivenessOnly) {
|
|
892
|
+
// Liveness-only has no channels at all, so renderCountrySelect's
|
|
893
|
+
// single-country auto-skip (countries.length === 1) never fires for
|
|
894
|
+
// it — going through "country" here would render an empty,
|
|
895
|
+
// dead-end country-picker screen. Go straight to liveness instead.
|
|
896
|
+
//
|
|
897
|
+
// selectedCountry defaults to "" and is otherwise only ever set by
|
|
898
|
+
// renderCountrySelect, which this mode never visits — renderLiveness
|
|
899
|
+
// sends it as a required, non-blank `country` field, so leaving it
|
|
900
|
+
// empty would fail create() validation before the scan even starts.
|
|
901
|
+
// There's no real country to report here (no identity lookup runs
|
|
902
|
+
// in this mode), so this is a neutral placeholder, not a claim
|
|
903
|
+
// about the user's actual location.
|
|
904
|
+
this.selectedCountry = this.selectedCountry || "global";
|
|
905
|
+
this.showStep("liveness");
|
|
906
|
+
}
|
|
907
|
+
else {
|
|
908
|
+
this.showStep("country");
|
|
909
|
+
}
|
|
910
|
+
});
|
|
877
911
|
container.appendChild(btn);
|
|
878
912
|
// Plain-language line on what the camera/photo is for and what happens
|
|
879
913
|
// to it — shown before the "Get Started" tap that leads to the first
|
|
@@ -2417,6 +2451,21 @@ class SmartComplyFlow {
|
|
|
2417
2451
|
.flatMap((ch) => ch.fields || []);
|
|
2418
2452
|
return allFields.some((f) => isUploadFieldType(f.type));
|
|
2419
2453
|
}
|
|
2454
|
+
/**
|
|
2455
|
+
* True when the SDK Config is set to skip data/document verification
|
|
2456
|
+
* entirely and only run the liveness/selfie check — no country picker,
|
|
2457
|
+
* no ID-type picker, no ID-number entry or document capture. Unlike
|
|
2458
|
+
* isDocumentFlow(), there's no channel-shape fallback to infer this from:
|
|
2459
|
+
* a liveness-only config carries no channels at all, so the only signal
|
|
2460
|
+
* is verification_type itself.
|
|
2461
|
+
*/
|
|
2462
|
+
isLivenessOnlyFlow() {
|
|
2463
|
+
const vType = this.sdkConfig?.verification_type;
|
|
2464
|
+
if (!vType)
|
|
2465
|
+
return false;
|
|
2466
|
+
const types = Array.isArray(vType) ? vType : [vType];
|
|
2467
|
+
return types.includes("liveness_only");
|
|
2468
|
+
}
|
|
2420
2469
|
/**
|
|
2421
2470
|
* The "go back one step" target for a given step, if that step is
|
|
2422
2471
|
* navigable — shared by the header back button and the browser
|
|
@@ -2433,16 +2482,28 @@ class SmartComplyFlow {
|
|
|
2433
2482
|
document_capture: () => { this.docCapture?.destroy(); this.showStep("id_type"); },
|
|
2434
2483
|
document_confirm: () => { this.docCapture?.destroy(); this.showStep("document_capture"); },
|
|
2435
2484
|
};
|
|
2485
|
+
// liveness-only skips straight from welcome to liveness with nothing in
|
|
2486
|
+
// between — deliberately no backTargets["liveness"] entry added here,
|
|
2487
|
+
// so the back button stays hidden on that step in this mode, same as
|
|
2488
|
+
// it already is for every other mode (liveness has no back target for
|
|
2489
|
+
// document/data flows either — nothing to go back to except closing).
|
|
2436
2490
|
return backTargets[step];
|
|
2437
2491
|
}
|
|
2438
2492
|
updateProgress() {
|
|
2439
|
-
const
|
|
2493
|
+
const isLivenessOnly = this.isLivenessOnlyFlow();
|
|
2494
|
+
const isDocFlow = isLivenessOnly ? false : this.isDocumentFlow();
|
|
2440
2495
|
const countries = Object.keys(this.sdkConfig?.channels || {});
|
|
2441
2496
|
const singleCountry = countries.length <= 1;
|
|
2442
|
-
// Two-stage action steps — Stage 1: validate identity, Stage 2: liveness
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2497
|
+
// Two-stage action steps — Stage 1: validate identity, Stage 2: liveness.
|
|
2498
|
+
// Liveness-only has no Stage 1 at all — welcome goes straight to
|
|
2499
|
+
// liveness — so stage1Steps stays empty and the progress bar reflects
|
|
2500
|
+
// a genuinely single-stage flow instead of implying a step that never
|
|
2501
|
+
// happens in this mode.
|
|
2502
|
+
const stage1Steps = isLivenessOnly
|
|
2503
|
+
? []
|
|
2504
|
+
: isDocFlow
|
|
2505
|
+
? ["country", "id_type", "document_capture", "ocr_gate", "document_confirm"].filter(s => !(s === "country" && singleCountry))
|
|
2506
|
+
: ["country", "id_type", "id_input", "confirm_identity"].filter(s => !(s === "country" && singleCountry));
|
|
2446
2507
|
const stage2Steps = ["liveness"];
|
|
2447
2508
|
const allActionSteps = [...stage1Steps, ...stage2Steps];
|
|
2448
2509
|
const totalSteps = allActionSteps.length;
|
|
@@ -2454,6 +2515,8 @@ class SmartComplyFlow {
|
|
|
2454
2515
|
this.progressBar.style.width = `${pct}%`;
|
|
2455
2516
|
}
|
|
2456
2517
|
// Stage label: "Stage 1 of 2: Verify Identity" / "Stage 2 of 2: Face Check"
|
|
2518
|
+
// — liveness-only has no Stage 1, so it just says "Face Check" with no
|
|
2519
|
+
// "of 2" framing, since there's only ever the one stage in this mode.
|
|
2457
2520
|
if (this.stepLabel) {
|
|
2458
2521
|
if (this.currentStep === "loading" || this.currentStep === "welcome") {
|
|
2459
2522
|
this.stepLabel.textContent = "";
|
|
@@ -2462,7 +2525,7 @@ class SmartComplyFlow {
|
|
|
2462
2525
|
this.stepLabel.textContent = "Complete ✓";
|
|
2463
2526
|
}
|
|
2464
2527
|
else if (stage2Steps.includes(this.currentStep)) {
|
|
2465
|
-
this.stepLabel.textContent = "Stage 2 of 2: Face Check";
|
|
2528
|
+
this.stepLabel.textContent = isLivenessOnly ? "Face Check" : "Stage 2 of 2: Face Check";
|
|
2466
2529
|
}
|
|
2467
2530
|
else if (stage1Steps.includes(this.currentStep)) {
|
|
2468
2531
|
this.stepLabel.textContent = isDocFlow ? "Stage 1 of 2: Scan Document" : "Stage 1 of 2: Verify Identity";
|