smartcomply-web-sdk 1.0.90 → 1.0.91

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 (35) hide show
  1. package/dist/camera/ActionDetector.d.ts +2 -1
  2. package/dist/camera/ActionDetector.d.ts.map +1 -1
  3. package/dist/camera/ActionDetector.js +21 -5
  4. package/dist/camera/ActionDetector.js.map +1 -1
  5. package/dist/client/Smartcomply.d.ts +2 -2
  6. package/dist/client/Smartcomply.js +2 -2
  7. package/dist/esm/camera/ActionDetector.d.ts +2 -1
  8. package/dist/esm/camera/ActionDetector.d.ts.map +1 -1
  9. package/dist/esm/camera/ActionDetector.js +21 -5
  10. package/dist/esm/camera/ActionDetector.js.map +1 -1
  11. package/dist/esm/client/Smartcomply.d.ts +2 -2
  12. package/dist/esm/client/Smartcomply.js +2 -2
  13. package/dist/esm/flow/SmartComplyFlow.d.ts +10 -0
  14. package/dist/esm/flow/SmartComplyFlow.d.ts.map +1 -1
  15. package/dist/esm/flow/SmartComplyFlow.js +92 -32
  16. package/dist/esm/flow/SmartComplyFlow.js.map +1 -1
  17. package/dist/esm/flow/spinner.js +14 -14
  18. package/dist/esm/modules/liveness/LivenessUI.js +83 -83
  19. package/dist/flow/SmartComplyFlow.d.ts +10 -0
  20. package/dist/flow/SmartComplyFlow.d.ts.map +1 -1
  21. package/dist/flow/SmartComplyFlow.js +93 -32
  22. package/dist/flow/SmartComplyFlow.js.map +1 -1
  23. package/dist/flow/spinner.js +14 -14
  24. package/dist/modules/liveness/LivenessUI.js +83 -83
  25. package/dist/smartcomply.browser.js +46 -15
  26. package/dist/smartcomply.browser.js.map +2 -2
  27. package/package.json +1 -1
  28. package/dist/esm/components/CameraView.d.ts +0 -59
  29. package/dist/esm/components/CameraView.d.ts.map +0 -1
  30. package/dist/esm/components/CameraView.js +0 -238
  31. package/dist/esm/components/CameraView.js.map +0 -1
  32. package/dist/esm/components/DocumentUpload.d.ts +0 -21
  33. package/dist/esm/components/DocumentUpload.d.ts.map +0 -1
  34. package/dist/esm/components/DocumentUpload.js +0 -216
  35. package/dist/esm/components/DocumentUpload.js.map +0 -1
@@ -3,30 +3,30 @@ function injectLivenessKeyframes() {
3
3
  return;
4
4
  const s = document.createElement("style");
5
5
  s.id = "sc-liveness-kf";
6
- s.textContent = `
7
- @keyframes sc-pop-in {
8
- 0% { transform:scale(0.7); opacity:0; }
9
- 60% { transform:scale(1.05); }
10
- 100% { transform:scale(1); opacity:1; }
11
- }
12
- @keyframes sc-scan-dot {
13
- 0%,100% { opacity:0.3; transform:scale(0.85); }
14
- 50% { opacity:1; transform:scale(1); }
15
- }
16
- @keyframes sc-scanline-sweep {
17
- 0% { transform:translateY(-4%); opacity:0; }
18
- 8% { opacity:0.9; }
19
- 92% { opacity:0.9; }
20
- 100% { transform:translateY(104%); opacity:0; }
21
- }
22
- @keyframes sc-corner-pulse {
23
- 0%,100% { opacity:0.55; }
24
- 50% { opacity:1; }
25
- }
26
- @keyframes sc-oval-breathe {
27
- 0%,100% { opacity:0.5; }
28
- 50% { opacity:0.85; }
29
- }
6
+ s.textContent = `
7
+ @keyframes sc-pop-in {
8
+ 0% { transform:scale(0.7); opacity:0; }
9
+ 60% { transform:scale(1.05); }
10
+ 100% { transform:scale(1); opacity:1; }
11
+ }
12
+ @keyframes sc-scan-dot {
13
+ 0%,100% { opacity:0.3; transform:scale(0.85); }
14
+ 50% { opacity:1; transform:scale(1); }
15
+ }
16
+ @keyframes sc-scanline-sweep {
17
+ 0% { transform:translateY(-4%); opacity:0; }
18
+ 8% { opacity:0.9; }
19
+ 92% { opacity:0.9; }
20
+ 100% { transform:translateY(104%); opacity:0; }
21
+ }
22
+ @keyframes sc-corner-pulse {
23
+ 0%,100% { opacity:0.55; }
24
+ 50% { opacity:1; }
25
+ }
26
+ @keyframes sc-oval-breathe {
27
+ 0%,100% { opacity:0.5; }
28
+ 50% { opacity:0.85; }
29
+ }
30
30
  `;
31
31
  document.head.appendChild(s);
32
32
  }
@@ -56,38 +56,38 @@ export class LivenessUI {
56
56
  mount(container, challenge) {
57
57
  injectLivenessKeyframes();
58
58
  this.root = document.createElement("div");
59
- this.root.style.cssText = `
60
- position:relative;width:100%;max-width:420px;margin:0 auto;
61
- background:#0a0a0a;border-radius:16px;overflow:hidden;
62
- font-family:system-ui,-apple-system,sans-serif;
63
- box-shadow:0 8px 32px rgba(0,0,0,0.4);
64
- aspect-ratio:3/4;
59
+ this.root.style.cssText = `
60
+ position:relative;width:100%;max-width:420px;margin:0 auto;
61
+ background:#0a0a0a;border-radius:16px;overflow:hidden;
62
+ font-family:system-ui,-apple-system,sans-serif;
63
+ box-shadow:0 8px 32px rgba(0,0,0,0.4);
64
+ aspect-ratio:3/4;
65
65
  `;
66
66
  this.videoEl = document.createElement("video");
67
67
  this.videoEl.autoplay = true;
68
68
  this.videoEl.playsInline = true;
69
69
  this.videoEl.muted = true;
70
70
  this.videoEl.setAttribute("aria-label", "Live camera preview for face verification");
71
- this.videoEl.style.cssText = `
72
- width:100%;height:100%;display:block;
73
- filter:brightness(1.03) contrast(1.03);
74
- transform:scaleX(-1);object-fit:cover;
71
+ this.videoEl.style.cssText = `
72
+ width:100%;height:100%;display:block;
73
+ filter:brightness(1.03) contrast(1.03);
74
+ transform:scaleX(-1);object-fit:cover;
75
75
  `;
76
76
  // Dim everything outside the oval so the guide reads as a scan aperture
77
77
  // rather than a shape floating over the raw feed.
78
78
  const vignette = document.createElement("div");
79
- vignette.style.cssText = `
80
- position:absolute;inset:0;pointer-events:none;
81
- background:radial-gradient(ellipse 34% 44% at 50% 47%, transparent 55%, rgba(0,0,0,0.55) 100%);
79
+ vignette.style.cssText = `
80
+ position:absolute;inset:0;pointer-events:none;
81
+ background:radial-gradient(ellipse 34% 44% at 50% 47%, transparent 55%, rgba(0,0,0,0.55) 100%);
82
82
  `;
83
83
  // Oval guide — centred
84
84
  const guideWrap = document.createElement("div");
85
- guideWrap.style.cssText = `
86
- position:absolute;top:50%;left:50%;
87
- transform:translate(-50%,-52%);
88
- width:64%;aspect-ratio:140/180;pointer-events:none;
89
- filter:drop-shadow(0 0 18px rgba(59,130,246,0.35));
90
- transition:filter 0.3s ease;
85
+ guideWrap.style.cssText = `
86
+ position:absolute;top:50%;left:50%;
87
+ transform:translate(-50%,-52%);
88
+ width:64%;aspect-ratio:140/180;pointer-events:none;
89
+ filter:drop-shadow(0 0 18px rgba(59,130,246,0.35));
90
+ transition:filter 0.3s ease;
91
91
  `;
92
92
  this.guideWrapEl = guideWrap;
93
93
  const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
@@ -176,49 +176,49 @@ export class LivenessUI {
176
176
  // Scan-line sweep — clipped to the oval, gives a visible "actively
177
177
  // scanning" motion cue instead of a static outline.
178
178
  const scanlineClipWrap = document.createElement("div");
179
- scanlineClipWrap.style.cssText = `
180
- position:absolute;inset:0;
181
- clip-path:ellipse(45.7% 47.8% at 50% 50%);
182
- overflow:hidden;
179
+ scanlineClipWrap.style.cssText = `
180
+ position:absolute;inset:0;
181
+ clip-path:ellipse(45.7% 47.8% at 50% 50%);
182
+ overflow:hidden;
183
183
  `;
184
184
  const scanline = document.createElement("div");
185
- scanline.style.cssText = `
186
- position:absolute;left:0;right:0;height:26%;top:0;
187
- background:linear-gradient(180deg,transparent 0%,rgba(59,130,246,0.32) 45%,rgba(147,197,253,0.55) 50%,rgba(59,130,246,0.32) 55%,transparent 100%);
188
- animation:sc-scanline-sweep 2.6s ease-in-out infinite;
185
+ scanline.style.cssText = `
186
+ position:absolute;left:0;right:0;height:26%;top:0;
187
+ background:linear-gradient(180deg,transparent 0%,rgba(59,130,246,0.32) 45%,rgba(147,197,253,0.55) 50%,rgba(59,130,246,0.32) 55%,transparent 100%);
188
+ animation:sc-scanline-sweep 2.6s ease-in-out infinite;
189
189
  `;
190
190
  this.scanlineEl = scanline;
191
191
  scanlineClipWrap.appendChild(scanline);
192
192
  guideWrap.appendChild(scanlineClipWrap);
193
193
  // Instruction — top, gradient scrim
194
194
  const camTop = document.createElement("div");
195
- camTop.style.cssText = `
196
- position:absolute;top:0;left:0;right:0;
197
- background:linear-gradient(180deg,rgba(0,0,0,0.8) 0%,transparent 100%);
198
- padding:14px 16px 32px;
195
+ camTop.style.cssText = `
196
+ position:absolute;top:0;left:0;right:0;
197
+ background:linear-gradient(180deg,rgba(0,0,0,0.8) 0%,transparent 100%);
198
+ padding:14px 16px 32px;
199
199
  `;
200
200
  this.instructionEl = document.createElement("div");
201
201
  this.instructionEl.setAttribute("aria-live", "polite");
202
202
  this.instructionEl.setAttribute("role", "status");
203
- this.instructionEl.style.cssText = `
204
- color:#fff;font-size:14px;font-weight:600;text-align:center;line-height:1.4;
203
+ this.instructionEl.style.cssText = `
204
+ color:#fff;font-size:14px;font-weight:600;text-align:center;line-height:1.4;
205
205
  `;
206
206
  this.instructionEl.textContent = challenge.instruction;
207
207
  camTop.appendChild(this.instructionEl);
208
208
  // Scan progress dots — bottom
209
209
  const camBottom = document.createElement("div");
210
- camBottom.style.cssText = `
211
- position:absolute;bottom:0;left:0;right:0;
212
- background:linear-gradient(0deg,rgba(0,0,0,0.7) 0%,transparent 100%);
213
- padding:28px 10px 18px;display:flex;justify-content:center;
210
+ camBottom.style.cssText = `
211
+ position:absolute;bottom:0;left:0;right:0;
212
+ background:linear-gradient(0deg,rgba(0,0,0,0.7) 0%,transparent 100%);
213
+ padding:28px 10px 18px;display:flex;justify-content:center;
214
214
  `;
215
215
  this.dotsEl = document.createElement("div");
216
216
  this.dotsEl.style.cssText = "display:flex;gap:6px;";
217
217
  for (let i = 0; i < 3; i++) {
218
218
  const dot = document.createElement("div");
219
- dot.style.cssText = `
220
- width:6px;height:6px;border-radius:50%;background:${this.colors.primary};
221
- animation:sc-scan-dot 1.1s ease-in-out ${i * 0.18}s infinite;
219
+ dot.style.cssText = `
220
+ width:6px;height:6px;border-radius:50%;background:${this.colors.primary};
221
+ animation:sc-scan-dot 1.1s ease-in-out ${i * 0.18}s infinite;
222
222
  `;
223
223
  this.dotsEl.appendChild(dot);
224
224
  }
@@ -230,10 +230,10 @@ export class LivenessUI {
230
230
  this.root.appendChild(camBottom);
231
231
  // Result overlay
232
232
  this.overlayEl = document.createElement("div");
233
- this.overlayEl.style.cssText = `
234
- position:absolute;inset:0;display:none;align-items:center;
235
- justify-content:center;z-index:10;
236
- background:rgba(0,0,0,0.88);backdrop-filter:blur(8px);
233
+ this.overlayEl.style.cssText = `
234
+ position:absolute;inset:0;display:none;align-items:center;
235
+ justify-content:center;z-index:10;
236
+ background:rgba(0,0,0,0.88);backdrop-filter:blur(8px);
237
237
  `;
238
238
  this.root.appendChild(this.overlayEl);
239
239
  container.appendChild(this.root);
@@ -294,15 +294,15 @@ export class LivenessUI {
294
294
  }
295
295
  const ok = status === "processing";
296
296
  this.overlayEl.style.display = "flex";
297
- this.overlayEl.innerHTML = `
298
- <div style="text-align:center;color:#fff;animation:sc-pop-in 0.35s ease;padding:24px;">
299
- <div style="width:72px;height:72px;border-radius:50%;margin:0 auto 16px;display:flex;align-items:center;justify-content:center;font-size:32px;
300
- background:${ok ? "rgba(34,197,94,0.2)" : "rgba(239,68,68,0.2)"};
301
- border:3px solid ${ok ? this.colors.success : this.colors.error};">
302
- ${ok ? "✓" : "✕"}
303
- </div>
304
- <div style="font-size:17px;font-weight:700;margin-bottom:8px;">${ok ? "Verification submitted" : "Submission failed"}</div>
305
- <div style="font-size:12px;opacity:0.6;line-height:1.6;">${ok ? "Hold on while we wrap up…" : "Something went wrong. Please try again."}</div>
297
+ this.overlayEl.innerHTML = `
298
+ <div style="text-align:center;color:#fff;animation:sc-pop-in 0.35s ease;padding:24px;">
299
+ <div style="width:72px;height:72px;border-radius:50%;margin:0 auto 16px;display:flex;align-items:center;justify-content:center;font-size:32px;
300
+ background:${ok ? "rgba(34,197,94,0.2)" : "rgba(239,68,68,0.2)"};
301
+ border:3px solid ${ok ? this.colors.success : this.colors.error};">
302
+ ${ok ? "✓" : "✕"}
303
+ </div>
304
+ <div style="font-size:17px;font-weight:700;margin-bottom:8px;">${ok ? "Verification submitted" : "Submission failed"}</div>
305
+ <div style="font-size:12px;opacity:0.6;line-height:1.6;">${ok ? "Hold on while we wrap up…" : "Something went wrong. Please try again."}</div>
306
306
  </div>`;
307
307
  setTimeout(resolve, 1800);
308
308
  });
@@ -314,12 +314,12 @@ export class LivenessUI {
314
314
  return;
315
315
  }
316
316
  this.overlayEl.style.display = "flex";
317
- this.overlayEl.innerHTML = `
318
- <div style="text-align:center;color:#fff;animation:sc-pop-in 0.35s ease;padding:24px;">
319
- <div style="width:72px;height:72px;border-radius:50%;margin:0 auto 14px;display:flex;align-items:center;justify-content:center;font-size:32px;background:rgba(251,191,36,0.15);border:3px solid ${this.colors.warning};">⏱</div>
320
- <div style="font-size:17px;font-weight:700;margin-bottom:8px;">Time's Up</div>
321
- <div style="font-size:12px;opacity:0.6;margin-bottom:18px;">We couldn't confirm liveness in time. Please try again.</div>
322
- <button id="sc-retry-btn" style="padding:11px 28px;border-radius:10px;background:${this.colors.primary};color:#fff;border:none;cursor:pointer;font-size:14px;font-weight:600;width:100%;max-width:180px;">Try Again</button>
317
+ this.overlayEl.innerHTML = `
318
+ <div style="text-align:center;color:#fff;animation:sc-pop-in 0.35s ease;padding:24px;">
319
+ <div style="width:72px;height:72px;border-radius:50%;margin:0 auto 14px;display:flex;align-items:center;justify-content:center;font-size:32px;background:rgba(251,191,36,0.15);border:3px solid ${this.colors.warning};">⏱</div>
320
+ <div style="font-size:17px;font-weight:700;margin-bottom:8px;">Time's Up</div>
321
+ <div style="font-size:12px;opacity:0.6;margin-bottom:18px;">We couldn't confirm liveness in time. Please try again.</div>
322
+ <button id="sc-retry-btn" style="padding:11px 28px;border-radius:10px;background:${this.colors.primary};color:#fff;border:none;cursor:pointer;font-size:14px;font-weight:600;width:100%;max-width:180px;">Try Again</button>
323
323
  </div>`;
324
324
  const btn = this.overlayEl.querySelector("#sc-retry-btn");
325
325
  if (btn) {
@@ -40,6 +40,16 @@ export interface FlowResult {
40
40
  submittedAt: string | null;
41
41
  verificationResult?: VerifyIdentityResponse;
42
42
  }
43
+ /**
44
+ * Whether a showErrorStep() message is about an expired/invalid resume or
45
+ * resubmit link (RESUME_TARGET_UNAVAILABLE / NOT_A_RESUME_TOKEN — see
46
+ * SmartComplyFlow._resolveResumeStep), rather than a plain session timeout.
47
+ * Extracted to a standalone function so this specific classification is
48
+ * independently testable, same as resolveIdTypeInfo below — showErrorStep's
49
+ * own regex-based classification block is otherwise tightly coupled to DOM
50
+ * rendering it doesn't make sense to extract wholesale for this fix.
51
+ */
52
+ export declare function isResumeLinkErrorMessage(message: string): boolean;
43
53
  export declare function resolveIdTypeInfo(typeName: string, isDocumentFlow: boolean): {
44
54
  icon: string;
45
55
  desc: string;
@@ -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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"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SmartComplyFlow = void 0;
4
+ exports.isResumeLinkErrorMessage = isResumeLinkErrorMessage;
4
5
  exports.resolveIdTypeInfo = resolveIdTypeInfo;
5
6
  const Smartcomply_1 = require("../client/Smartcomply");
6
7
  const theme_1 = require("./theme");
@@ -10,6 +11,7 @@ const documentRules_1 = require("../utils/documentRules");
10
11
  const constants_1 = require("../utils/constants");
11
12
  const icons_1 = require("./icons");
12
13
  const spinner_1 = require("./spinner");
14
+ const SDKError_1 = require("../errors/SDKError");
13
15
  // A dropped camera/network/upload error is not the user's fault and must not
14
16
  // cost them a retry attempt — only a genuine verification outcome should.
15
17
  // Classified by message rather than a typed error class since the errors
@@ -70,6 +72,18 @@ const COUNTRY_LABELS = {
70
72
  function isUploadFieldType(type) {
71
73
  return type === "upload" || type === "image" || type === "file";
72
74
  }
75
+ /**
76
+ * Whether a showErrorStep() message is about an expired/invalid resume or
77
+ * resubmit link (RESUME_TARGET_UNAVAILABLE / NOT_A_RESUME_TOKEN — see
78
+ * SmartComplyFlow._resolveResumeStep), rather than a plain session timeout.
79
+ * Extracted to a standalone function so this specific classification is
80
+ * independently testable, same as resolveIdTypeInfo below — showErrorStep's
81
+ * own regex-based classification block is otherwise tightly coupled to DOM
82
+ * rendering it doesn't make sense to extract wholesale for this fix.
83
+ */
84
+ function isResumeLinkErrorMessage(message) {
85
+ return /resume link|resubmit link/i.test(message);
86
+ }
73
87
  function resolveIdTypeInfo(typeName, isDocumentFlow) {
74
88
  const u = typeName.toUpperCase();
75
89
  const advanced = u.includes("ADVANCED");
@@ -658,7 +672,18 @@ class SmartComplyFlow {
658
672
  }
659
673
  if (this.isDestroyed)
660
674
  return;
661
- this.showStep(this.options.resumeToken ? await this._resolveResumeStep() : "welcome");
675
+ if (this.options.resumeToken) {
676
+ // null means _resolveResumeStep already rendered an error itself
677
+ // (a provably expired/invalid resume link — see that method) and
678
+ // there is no step left to show; calling showStep() in that case
679
+ // would wipe the error message straight back out.
680
+ const resumeStep = await this._resolveResumeStep();
681
+ if (resumeStep !== null)
682
+ this.showStep(resumeStep);
683
+ }
684
+ else {
685
+ this.showStep("welcome");
686
+ }
662
687
  }
663
688
  catch (err) {
664
689
  this.showErrorStep(err.message || "Failed to initialize. Please try again.");
@@ -669,9 +694,23 @@ class SmartComplyFlow {
669
694
  // same state renderCountrySelect/renderIdTypeSelect's own click handlers
670
695
  // set) so document_capture/liveness render correctly instead of assuming
671
696
  // state that was never set. Falls back to "welcome" on anything that
672
- // doesn't resolve cleanly — this is a UX improvement, not a requirement:
673
- // the backend's own resume-match at create/ time still works correctly
674
- // even if the widget can't figure out which screen to pre-select.
697
+ // doesn't resolve cleanly for an UNCERTAIN reason (network error, timeout)
698
+ // — this is a UX improvement, not a requirement: the backend's own
699
+ // resume-match at create/ time still works correctly even if the widget
700
+ // can't figure out which screen to pre-select.
701
+ //
702
+ // Returns null instead when the lookup fails for a CERTAIN, known reason
703
+ // — the resume link itself is provably expired or already used
704
+ // (RESUME_TARGET_UNAVAILABLE) or was never a resume link at all
705
+ // (NOT_A_RESUME_TOKEN). Unlike a transient failure, there is no "try the
706
+ // real request and it'll still work" fallback for these: create/'s own
707
+ // resume-match reads the exact same resume_target_entry binding this
708
+ // lookup just found missing/invalid, so falling through to a generic
709
+ // welcome screen would silently walk the customer into a brand-new,
710
+ // unrelated verification attempt with no explanation — worse than telling
711
+ // them plainly that their link no longer works. The caller shows this
712
+ // error itself (via showErrorStep, called here directly) rather than
713
+ // rendering a step.
675
714
  async _resolveResumeStep() {
676
715
  try {
677
716
  const info = await this.sdk.getResumeInfo();
@@ -723,10 +762,21 @@ class SmartComplyFlow {
723
762
  // server-side regardless of which screen the widget shows first.
724
763
  return "welcome";
725
764
  }
726
- catch {
727
- // NOT_A_RESUME_TOKEN / RESUME_TARGET_UNAVAILABLE / network error —
728
- // never block the flow on this lookup. create/'s own resume-match
729
- // still runs correctly once the customer gets there.
765
+ catch (err) {
766
+ const code = err instanceof SDKError_1.SDKError ? err.errorCode : undefined;
767
+ if (code === "RESUME_TARGET_UNAVAILABLE" || code === "NOT_A_RESUME_TOKEN") {
768
+ // A certain, known failure — this specific link is provably no
769
+ // longer usable (already used, expired, or was never a resume link
770
+ // at all). Tell the customer plainly rather than silently starting
771
+ // a new, unrelated verification on a welcome screen with no
772
+ // explanation — see this method's own docstring above.
773
+ this.showErrorStep("This resume link has expired or is no longer valid.");
774
+ return null;
775
+ }
776
+ // Anything else (network error, timeout, an SDKError with a
777
+ // different/absent code) — never block the flow on this lookup.
778
+ // create/'s own resume-match still runs correctly once the customer
779
+ // gets there, so falling through to a generic welcome screen is safe.
730
780
  return "welcome";
731
781
  }
732
782
  }
@@ -2334,7 +2384,14 @@ class SmartComplyFlow {
2334
2384
  // Classify the error into a user-friendly category
2335
2385
  const isCameraErr = /camera|permission|notallowed|notfound/i.test(message);
2336
2386
  const isNetworkErr = /network|timeout|connection|fetch/i.test(message);
2337
- const isAuthErr = /session.*expired|token.*expired|authentication/i.test(message);
2387
+ // Checked before the generic isAuthErr below — a resume/resubmit link
2388
+ // (RESUME_TARGET_UNAVAILABLE / NOT_A_RESUME_TOKEN from the backend, see
2389
+ // _resolveResumeStep) also matches "token...expired"/"link" wording, but
2390
+ // the corrective action is different from a plain session timeout: the
2391
+ // customer can't just "start again" themselves, they need a fresh link
2392
+ // from whoever sent them this one.
2393
+ const isResumeLinkErr = isResumeLinkErrorMessage(message);
2394
+ const isAuthErr = !isResumeLinkErr && /session.*expired|token.*expired|authentication/i.test(message);
2338
2395
  const isDocQuality = /blurry|blur|quality|glare|dark|bright|lighting/i.test(message);
2339
2396
  const isExpiredDoc = /document.*expired|expired.*document/i.test(message);
2340
2397
  const isFaceMatch = /face.*match|selfie.*match|does not match/i.test(message);
@@ -2344,36 +2401,40 @@ class SmartComplyFlow {
2344
2401
  const isBillingErr = /wallet|balance|insufficient.*fund|payment.*required/i.test(message);
2345
2402
  const errorIconName = isCameraErr ? "camera"
2346
2403
  : isNetworkErr ? "network"
2347
- : isAuthErr ? "clock"
2348
- : isDocQuality ? "search"
2349
- : isExpiredDoc ? "calendar"
2350
- : isFaceMatch ? "face"
2351
- : isBillingErr ? "warning"
2352
- : "close";
2404
+ : isResumeLinkErr ? "clock"
2405
+ : isAuthErr ? "clock"
2406
+ : isDocQuality ? "search"
2407
+ : isExpiredDoc ? "calendar"
2408
+ : isFaceMatch ? "face"
2409
+ : isBillingErr ? "warning"
2410
+ : "close";
2353
2411
  const errorTitle = isCameraErr ? "Camera Access Required"
2354
2412
  : isNetworkErr ? "Connection Problem"
2355
- : isAuthErr ? "Session Expired"
2356
- : isDocQuality ? "Document Photo Unclear"
2357
- : isExpiredDoc ? "Document Expired"
2358
- : isFaceMatch ? "Face Match Failed"
2359
- : isBillingErr ? "Verification Unavailable"
2360
- : "Verification Unsuccessful";
2413
+ : isResumeLinkErr ? "Link No Longer Valid"
2414
+ : isAuthErr ? "Session Expired"
2415
+ : isDocQuality ? "Document Photo Unclear"
2416
+ : isExpiredDoc ? "Document Expired"
2417
+ : isFaceMatch ? "Face Match Failed"
2418
+ : isBillingErr ? "Verification Unavailable"
2419
+ : "Verification Unsuccessful";
2361
2420
  // Map to user-facing guidance — never show raw internal message
2362
2421
  const userMessage = isCameraErr
2363
2422
  ? "Please allow camera access in your browser settings and try again."
2364
2423
  : isNetworkErr
2365
2424
  ? "Check your internet connection and try again."
2366
- : isAuthErr
2367
- ? "Your session has expired. Please start again."
2368
- : isDocQuality
2369
- ? _sanitizeUserMessage(message) || "Please retake your document photo in good lighting with no glare."
2370
- : isExpiredDoc
2371
- ? "The document you submitted has expired. Please use a valid, current ID."
2372
- : isFaceMatch
2373
- ? "Your selfie did not match the photo on your ID. Please ensure you are using your own valid document and face the camera directly."
2374
- : isBillingErr
2375
- ? "Verification is temporarily unavailable. Please contact support."
2376
- : _sanitizeUserMessage(message) || "We were unable to complete your verification. Please try again.";
2425
+ : isResumeLinkErr
2426
+ ? "This link has expired or has already been used. Please contact us to request a new one."
2427
+ : isAuthErr
2428
+ ? "Your session has expired. Please start again."
2429
+ : isDocQuality
2430
+ ? _sanitizeUserMessage(message) || "Please retake your document photo in good lighting with no glare."
2431
+ : isExpiredDoc
2432
+ ? "The document you submitted has expired. Please use a valid, current ID."
2433
+ : isFaceMatch
2434
+ ? "Your selfie did not match the photo on your ID. Please ensure you are using your own valid document and face the camera directly."
2435
+ : isBillingErr
2436
+ ? "Verification is temporarily unavailable. Please contact support."
2437
+ : _sanitizeUserMessage(message) || "We were unable to complete your verification. Please try again.";
2377
2438
  const iconWrap = document.createElement("div");
2378
2439
  iconWrap.style.cssText = `
2379
2440
  width:72px;height:72px;border-radius:50%;