smartcomply-web-sdk 1.0.75 → 1.0.77

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.
@@ -1 +1 @@
1
- {"version":3,"file":"SmartComplyFlow.d.ts","sourceRoot":"","sources":["../../src/flow/SmartComplyFlow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SmartComplyFlow.d.ts","sourceRoot":"","sources":["../../src/flow/SmartComplyFlow.ts"],"names":[],"mappings":"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"}
@@ -331,10 +331,12 @@ class SmartComplyFlow {
331
331
  this._uiTimeoutId = null;
332
332
  // Session expiry
333
333
  this.sessionExpiryTimer = null;
334
+ this.sessionExpiredTimer = null;
334
335
  // Status polling (result screen)
335
336
  this._pollStatusTimer = null;
336
337
  // Components
337
338
  this.docCapture = null;
339
+ this._expiryDeferrals = 0;
338
340
  this.options = options;
339
341
  this.sdk = new Smartcomply_1.SmartComply({
340
342
  apiKey: options.apiKey,
@@ -401,6 +403,10 @@ class SmartComplyFlow {
401
403
  clearTimeout(this.sessionExpiryTimer);
402
404
  this.sessionExpiryTimer = null;
403
405
  }
406
+ if (this.sessionExpiredTimer) {
407
+ clearTimeout(this.sessionExpiredTimer);
408
+ this.sessionExpiredTimer = null;
409
+ }
404
410
  if (this._pollStatusTimer) {
405
411
  clearTimeout(this._pollStatusTimer);
406
412
  this._pollStatusTimer = null;
@@ -591,6 +597,15 @@ class SmartComplyFlow {
591
597
  const expiresMs = new Date(expiresAt).getTime() - Date.now();
592
598
  const warnMs = Math.max(expiresMs - 120000, 0); // warn 2 min before
593
599
  this.sessionExpiryTimer = setTimeout(() => this._showExpiryWarningWhenSafe(), warnMs);
600
+ // The warning above is advisory only and can defer indefinitely
601
+ // while the user sits on a camera-active step — without a hard
602
+ // stop, an ignored/deferred warning left the widget open against
603
+ // an already-expired backend session (SessionToken.expires_at,
604
+ // 30 min — see sdk/views.py's SessionToken.objects.create call)
605
+ // for as long as the host page stayed open. Force-close once the
606
+ // real deadline passes so the widget's lifetime never exceeds
607
+ // what the backend actually honors.
608
+ this.sessionExpiredTimer = setTimeout(() => this._enforceSessionExpiry(), Math.max(expiresMs, 0));
594
609
  }
595
610
  // Load config
596
611
  this.sdkConfig = await this.sdk.initializeConfig();
@@ -624,6 +639,19 @@ class SmartComplyFlow {
624
639
  }
625
640
  this.showErrorStep("Your session is about to expire. Please complete verification quickly or restart.");
626
641
  }
642
+ _enforceSessionExpiry() {
643
+ if (this.isDestroyed)
644
+ return;
645
+ const cameraActiveSteps = ["document_capture", "liveness"];
646
+ if (cameraActiveSteps.includes(this.currentStep) &&
647
+ this._expiryDeferrals < SmartComplyFlow.MAX_EXPIRY_DEFERRALS) {
648
+ this._expiryDeferrals += 1;
649
+ this.sessionExpiredTimer = setTimeout(() => this._enforceSessionExpiry(), 5000);
650
+ return;
651
+ }
652
+ this.showErrorStep("Your session has expired. Please restart verification.");
653
+ this.close();
654
+ }
627
655
  // ─────────────────────────────────────────────────────────────────
628
656
  // Step rendering
629
657
  // ─────────────────────────────────────────────────────────────────
@@ -742,7 +770,8 @@ class SmartComplyFlow {
742
770
  // ── Welcome ────────────────────────────────────────────────────
743
771
  renderWelcome(container) {
744
772
  container.style.cssText += "display:flex;flex-direction:column;align-items:center;text-align:center;gap:12px;";
745
- const isDocFlow = this.isDocumentFlow();
773
+ const isLivenessOnly = this.isLivenessOnlyFlow();
774
+ const isDocFlow = isLivenessOnly ? false : this.isDocumentFlow();
746
775
  // Icon + badge row (side by side to save vertical space)
747
776
  const topRow = document.createElement("div");
748
777
  topRow.style.cssText = "display:flex;flex-direction:column;align-items:center;gap:8px;";
@@ -765,7 +794,9 @@ class SmartComplyFlow {
765
794
  color:${this.theme.primary};
766
795
  border:1px solid ${this.theme.primary}30;
767
796
  `;
768
- badge.textContent = isDocFlow ? "📄 Document Verification" : "🔍 Data Verification";
797
+ badge.textContent = isLivenessOnly
798
+ ? "🤳 Liveness Check"
799
+ : isDocFlow ? "📄 Document Verification" : "🔍 Data Verification";
769
800
  topRow.appendChild(badge);
770
801
  container.appendChild(topRow);
771
802
  // Title + subtitle (compact)
@@ -787,23 +818,29 @@ class SmartComplyFlow {
787
818
  color:${this.theme.textSecondary};font-size:13px;line-height:1.5;
788
819
  margin:0 auto;max-width:300px;text-align:center;
789
820
  `;
790
- desc.textContent = isDocFlow
791
- ? "You'll need your document and camera access. This takes about 2 minutes."
792
- : "You'll need your ID number and camera access. This takes about 2 minutes.";
821
+ desc.textContent = isLivenessOnly
822
+ ? "You'll just need camera access. This takes about 30 seconds."
823
+ : isDocFlow
824
+ ? "You'll need your document and camera access. This takes about 2 minutes."
825
+ : "You'll need your ID number and camera access. This takes about 2 minutes.";
793
826
  titleWrap.appendChild(desc);
794
827
  container.appendChild(titleWrap);
795
828
  // Steps preview — compact rows
796
- const steps = isDocFlow
829
+ const steps = isLivenessOnly
797
830
  ? [
798
- { icon: "🪪", text: "Choose your document type", sub: "Passport, National ID, Driver License" },
799
- { icon: "📷", text: "Scan your document", sub: "Upload or capture a photo of your ID" },
800
831
  { icon: "🤳", text: "Face check", sub: "Quick selfie to confirm it's you" },
801
832
  ]
802
- : [
803
- { icon: "🆔", text: "Choose your ID type", sub: "NIN, BVN, Voter's Card and more" },
804
- { icon: "📝", text: "Enter your ID details", sub: "Exactly as shown on your ID" },
805
- { icon: "🤳", text: "Face check", sub: "Quick selfie to confirm it's you" },
806
- ];
833
+ : isDocFlow
834
+ ? [
835
+ { icon: "🪪", text: "Choose your document type", sub: "Passport, National ID, Driver License" },
836
+ { icon: "📷", text: "Scan your document", sub: "Upload or capture a photo of your ID" },
837
+ { icon: "🤳", text: "Face check", sub: "Quick selfie to confirm it's you" },
838
+ ]
839
+ : [
840
+ { icon: "🆔", text: "Choose your ID type", sub: "NIN, BVN, Voter's Card and more" },
841
+ { icon: "📝", text: "Enter your ID details", sub: "Exactly as shown on your ID" },
842
+ { icon: "🤳", text: "Face check", sub: "Quick selfie to confirm it's you" },
843
+ ];
807
844
  const stepsWrap = document.createElement("div");
808
845
  stepsWrap.style.cssText = `
809
846
  width:100%;display:flex;flex-direction:column;gap:0;
@@ -845,7 +882,27 @@ class SmartComplyFlow {
845
882
  // CTA
846
883
  const btn = this.createPrimaryButton("Get Started →");
847
884
  btn.style.cssText += "margin-top:2px;";
848
- btn.addEventListener("click", () => this.showStep("country"));
885
+ btn.addEventListener("click", () => {
886
+ if (isLivenessOnly) {
887
+ // Liveness-only has no channels at all, so renderCountrySelect's
888
+ // single-country auto-skip (countries.length === 1) never fires for
889
+ // it — going through "country" here would render an empty,
890
+ // dead-end country-picker screen. Go straight to liveness instead.
891
+ //
892
+ // selectedCountry defaults to "" and is otherwise only ever set by
893
+ // renderCountrySelect, which this mode never visits — renderLiveness
894
+ // sends it as a required, non-blank `country` field, so leaving it
895
+ // empty would fail create() validation before the scan even starts.
896
+ // There's no real country to report here (no identity lookup runs
897
+ // in this mode), so this is a neutral placeholder, not a claim
898
+ // about the user's actual location.
899
+ this.selectedCountry = this.selectedCountry || "global";
900
+ this.showStep("liveness");
901
+ }
902
+ else {
903
+ this.showStep("country");
904
+ }
905
+ });
849
906
  container.appendChild(btn);
850
907
  // Plain-language line on what the camera/photo is for and what happens
851
908
  // to it — shown before the "Get Started" tap that leads to the first
@@ -2389,6 +2446,21 @@ class SmartComplyFlow {
2389
2446
  .flatMap((ch) => ch.fields || []);
2390
2447
  return allFields.some((f) => isUploadFieldType(f.type));
2391
2448
  }
2449
+ /**
2450
+ * True when the SDK Config is set to skip data/document verification
2451
+ * entirely and only run the liveness/selfie check — no country picker,
2452
+ * no ID-type picker, no ID-number entry or document capture. Unlike
2453
+ * isDocumentFlow(), there's no channel-shape fallback to infer this from:
2454
+ * a liveness-only config carries no channels at all, so the only signal
2455
+ * is verification_type itself.
2456
+ */
2457
+ isLivenessOnlyFlow() {
2458
+ const vType = this.sdkConfig?.verification_type;
2459
+ if (!vType)
2460
+ return false;
2461
+ const types = Array.isArray(vType) ? vType : [vType];
2462
+ return types.includes("liveness_only");
2463
+ }
2392
2464
  /**
2393
2465
  * The "go back one step" target for a given step, if that step is
2394
2466
  * navigable — shared by the header back button and the browser
@@ -2405,16 +2477,28 @@ class SmartComplyFlow {
2405
2477
  document_capture: () => { this.docCapture?.destroy(); this.showStep("id_type"); },
2406
2478
  document_confirm: () => { this.docCapture?.destroy(); this.showStep("document_capture"); },
2407
2479
  };
2480
+ // liveness-only skips straight from welcome to liveness with nothing in
2481
+ // between — deliberately no backTargets["liveness"] entry added here,
2482
+ // so the back button stays hidden on that step in this mode, same as
2483
+ // it already is for every other mode (liveness has no back target for
2484
+ // document/data flows either — nothing to go back to except closing).
2408
2485
  return backTargets[step];
2409
2486
  }
2410
2487
  updateProgress() {
2411
- const isDocFlow = this.isDocumentFlow();
2488
+ const isLivenessOnly = this.isLivenessOnlyFlow();
2489
+ const isDocFlow = isLivenessOnly ? false : this.isDocumentFlow();
2412
2490
  const countries = Object.keys(this.sdkConfig?.channels || {});
2413
2491
  const singleCountry = countries.length <= 1;
2414
- // Two-stage action steps — Stage 1: validate identity, Stage 2: liveness
2415
- const stage1Steps = isDocFlow
2416
- ? ["country", "id_type", "document_capture", "ocr_gate", "document_confirm"].filter(s => !(s === "country" && singleCountry))
2417
- : ["country", "id_type", "id_input", "confirm_identity"].filter(s => !(s === "country" && singleCountry));
2492
+ // Two-stage action steps — Stage 1: validate identity, Stage 2: liveness.
2493
+ // Liveness-only has no Stage 1 at all — welcome goes straight to
2494
+ // liveness — so stage1Steps stays empty and the progress bar reflects
2495
+ // a genuinely single-stage flow instead of implying a step that never
2496
+ // happens in this mode.
2497
+ const stage1Steps = isLivenessOnly
2498
+ ? []
2499
+ : isDocFlow
2500
+ ? ["country", "id_type", "document_capture", "ocr_gate", "document_confirm"].filter(s => !(s === "country" && singleCountry))
2501
+ : ["country", "id_type", "id_input", "confirm_identity"].filter(s => !(s === "country" && singleCountry));
2418
2502
  const stage2Steps = ["liveness"];
2419
2503
  const allActionSteps = [...stage1Steps, ...stage2Steps];
2420
2504
  const totalSteps = allActionSteps.length;
@@ -2426,6 +2510,8 @@ class SmartComplyFlow {
2426
2510
  this.progressBar.style.width = `${pct}%`;
2427
2511
  }
2428
2512
  // Stage label: "Stage 1 of 2: Verify Identity" / "Stage 2 of 2: Face Check"
2513
+ // — liveness-only has no Stage 1, so it just says "Face Check" with no
2514
+ // "of 2" framing, since there's only ever the one stage in this mode.
2429
2515
  if (this.stepLabel) {
2430
2516
  if (this.currentStep === "loading" || this.currentStep === "welcome") {
2431
2517
  this.stepLabel.textContent = "";
@@ -2434,7 +2520,7 @@ class SmartComplyFlow {
2434
2520
  this.stepLabel.textContent = "Complete ✓";
2435
2521
  }
2436
2522
  else if (stage2Steps.includes(this.currentStep)) {
2437
- this.stepLabel.textContent = "Stage 2 of 2: Face Check";
2523
+ this.stepLabel.textContent = isLivenessOnly ? "Face Check" : "Stage 2 of 2: Face Check";
2438
2524
  }
2439
2525
  else if (stage1Steps.includes(this.currentStep)) {
2440
2526
  this.stepLabel.textContent = isDocFlow ? "Stage 1 of 2: Scan Document" : "Stage 1 of 2: Verify Identity";
@@ -2525,4 +2611,11 @@ class SmartComplyFlow {
2525
2611
  }
2526
2612
  exports.SmartComplyFlow = SmartComplyFlow;
2527
2613
  SmartComplyFlow.MAX_RETRIES = 3;
2614
+ // Hard stop once the backend session (SessionToken.expires_at, 30 min)
2615
+ // has actually passed. Deferred the same way as the warning above while
2616
+ // a camera is live so we don't tear down an in-progress scan, but capped
2617
+ // — the earlier warning already gave the user 2 minutes' notice, so
2618
+ // there's no reason to keep deferring past a short grace window the way
2619
+ // the advisory warning does.
2620
+ SmartComplyFlow.MAX_EXPIRY_DEFERRALS = 12; // 12 * 5s = 60s grace
2528
2621
  //# sourceMappingURL=SmartComplyFlow.js.map