smartcomply-web-sdk 1.0.88 → 1.0.90

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.
@@ -5764,9 +5764,36 @@ var SmartComplySDK = (() => {
5764
5764
  this.http.setSessionToken(response.token);
5765
5765
  return response;
5766
5766
  }
5767
+ /**
5768
+ * Resume an existing session from a resume_token (client-initiated
5769
+ * resubmit — see the "Resubmit" action in the Adhere dashboard). Unlike
5770
+ * createSession(), this makes no network call: a resume_token IS already
5771
+ * a valid SessionToken row on the backend (SDKSessionTokenAuthentication
5772
+ * checks it against SessionToken.active the same way as any session
5773
+ * token), so there is nothing to create — only to start using directly.
5774
+ *
5775
+ * Must be used INSTEAD OF createSession(), not alongside it. Calling
5776
+ * createSession() after this would mint a second, unrelated session and
5777
+ * silently abandon the resume — the backend's resume-match in
5778
+ * LivenessCreateAPIView only fires for the session actually presented on
5779
+ * the request, so the resume_token has to be the one in use throughout.
5780
+ *
5781
+ * No expires_at is set here — the resume_token's own issuance response
5782
+ * only carries resume_expires_at (a 72h invite-link window), not the
5783
+ * session's own runtime expiry the way createSession() returns one. The
5784
+ * backend still enforces the real expiry server-side regardless; this
5785
+ * only means the client-side "session about to expire" warning timer
5786
+ * (see SmartComplyFlow.initialize()) has nothing to schedule against and
5787
+ * is skipped for a resumed session.
5788
+ */
5789
+ resumeSession(resumeToken) {
5790
+ this._sessionToken = resumeToken;
5791
+ this._sessionExpiresAt = null;
5792
+ this.http.setSessionToken(resumeToken);
5793
+ }
5767
5794
  /**
5768
5795
  * Fetch SDK configuration from the backend.
5769
- * Must be called after createSession().
5796
+ * Must be called after createSession() or resumeSession().
5770
5797
  *
5771
5798
  * GET /v1/initialize/
5772
5799
  * Auth: x-access-token: <sessionToken>
@@ -5781,6 +5808,22 @@ var SmartComplySDK = (() => {
5781
5808
  this._sdkConfig = config;
5782
5809
  return config;
5783
5810
  }
5811
+ /**
5812
+ * Resolve a resume_token to the entry/step it's resuming, without
5813
+ * consuming the single-use resume binding (unlike create/, which does).
5814
+ * Only meaningful after resumeSession() — a normal createSession()
5815
+ * session was never issued for a resume, so this returns a 404
5816
+ * (NOT_A_RESUME_TOKEN) for it, same as the backend.
5817
+ *
5818
+ * GET /v1/sdk/liveness/resume-info/
5819
+ * Auth: x-access-token: <sessionToken>
5820
+ */
5821
+ async getResumeInfo() {
5822
+ return this.http.sessionRequest(
5823
+ "GET",
5824
+ "/v1/sdk/liveness/resume-info/"
5825
+ );
5826
+ }
5784
5827
  };
5785
5828
  /**
5786
5829
  * Package version, hardcoded to match package.json — bump this alongside
@@ -5791,7 +5834,7 @@ var SmartComplySDK = (() => {
5791
5834
  * CDN tag they installed with (e.g. @1, which floats to the latest
5792
5835
  * matching release) actually resolved to the version they expect.
5793
5836
  */
5794
- _SmartComply.VERSION = "1.0.88";
5837
+ _SmartComply.VERSION = "1.0.90";
5795
5838
  var SmartComply = _SmartComply;
5796
5839
 
5797
5840
  // src/flow/theme.ts
@@ -7761,19 +7804,23 @@ var SmartComplySDK = (() => {
7761
7804
  async initialize() {
7762
7805
  this.showStep("loading");
7763
7806
  try {
7764
- await this.sdk.createSession();
7765
- const expiresAt = this.sdk.sessionExpiresAt;
7766
- if (expiresAt) {
7767
- const expiresMs = new Date(expiresAt).getTime() - Date.now();
7768
- const warnMs = Math.max(expiresMs - 12e4, 0);
7769
- this.sessionExpiryTimer = setTimeout(
7770
- () => this._showExpiryWarningWhenSafe(),
7771
- warnMs
7772
- );
7773
- this.sessionExpiredTimer = setTimeout(
7774
- () => this._enforceSessionExpiry(),
7775
- Math.max(expiresMs, 0)
7776
- );
7807
+ if (this.options.resumeToken) {
7808
+ this.sdk.resumeSession(this.options.resumeToken);
7809
+ } else {
7810
+ await this.sdk.createSession();
7811
+ const expiresAt = this.sdk.sessionExpiresAt;
7812
+ if (expiresAt) {
7813
+ const expiresMs = new Date(expiresAt).getTime() - Date.now();
7814
+ const warnMs = Math.max(expiresMs - 12e4, 0);
7815
+ this.sessionExpiryTimer = setTimeout(
7816
+ () => this._showExpiryWarningWhenSafe(),
7817
+ warnMs
7818
+ );
7819
+ this.sessionExpiredTimer = setTimeout(
7820
+ () => this._enforceSessionExpiry(),
7821
+ Math.max(expiresMs, 0)
7822
+ );
7823
+ }
7777
7824
  }
7778
7825
  this.sdkConfig = await this.sdk.initializeConfig();
7779
7826
  if (this.sdkConfig.theme) {
@@ -7788,11 +7835,61 @@ var SmartComplySDK = (() => {
7788
7835
  this.brandLogoImg.style.display = "block";
7789
7836
  }
7790
7837
  if (this.isDestroyed) return;
7791
- this.showStep("welcome");
7838
+ this.showStep(this.options.resumeToken ? await this._resolveResumeStep() : "welcome");
7792
7839
  } catch (err) {
7793
7840
  this.showErrorStep(err.message || "Failed to initialize. Please try again.");
7794
7841
  }
7795
7842
  }
7843
+ // Resolves a resume_token to the step the customer should land on,
7844
+ // pre-selecting the same country/ID type the original attempt used (the
7845
+ // same state renderCountrySelect/renderIdTypeSelect's own click handlers
7846
+ // set) so document_capture/liveness render correctly instead of assuming
7847
+ // state that was never set. Falls back to "welcome" on anything that
7848
+ // doesn't resolve cleanly — this is a UX improvement, not a requirement:
7849
+ // the backend's own resume-match at create/ time still works correctly
7850
+ // even if the widget can't figure out which screen to pre-select.
7851
+ async _resolveResumeStep() {
7852
+ try {
7853
+ const info = await this.sdk.getResumeInfo();
7854
+ if (info.verification_type === "liveness_only" || info.failure_stage === "liveness" || // data_match is always a selfie-vs-identity-photo mismatch (see the
7855
+ // backend's own comment in _process_identity_face_match) — fixed by
7856
+ // redoing the selfie/video, same as a "liveness" failure. There is
7857
+ // no document step in data verification at all, so this can never
7858
+ // legitimately need document_capture.
7859
+ info.failure_stage === "data_match") {
7860
+ this.selectedCountry = info.country || this.selectedCountry || "global";
7861
+ return "liveness";
7862
+ }
7863
+ if (info.failure_stage === "document" && info.country && info.identifier_type) {
7864
+ const channels = this.sdkConfig?.channels || {};
7865
+ const idTypes = channels[info.country] || [];
7866
+ const match = idTypes.find((idType) => {
7867
+ const code = typeof idType === "string" ? idType : idType.code || idType.name;
7868
+ return code === info.identifier_type;
7869
+ });
7870
+ if (match) {
7871
+ const typeName = typeof match === "string" ? match : match.name;
7872
+ const typeCode = typeof match === "string" ? match : match.code || match.name;
7873
+ const channelFields = typeof match !== "string" ? match.fields || [] : [];
7874
+ const isDocFlow = channelFields.some((f2) => isUploadFieldType(f2.type)) || this.isDocumentFlow();
7875
+ const info2 = resolveIdTypeInfo(typeName, isDocFlow);
7876
+ const requiresBackFromBackend = typeof match !== "string" ? match.requires_back_side : void 0;
7877
+ this.selectedCountry = info.country;
7878
+ this.selectedIdType = typeCode;
7879
+ this.selectedIdTypeName = typeName;
7880
+ this.selectedRequiresBack = requiresBackFromBackend ?? info2.requiresBack;
7881
+ if (typeof match !== "string") {
7882
+ this.selectedChannelId = match.id;
7883
+ this.selectedChannelFields = match.fields || [];
7884
+ }
7885
+ return "document_capture";
7886
+ }
7887
+ }
7888
+ return "welcome";
7889
+ } catch {
7890
+ return "welcome";
7891
+ }
7892
+ }
7796
7893
  // Defers the expiry warning while the user is on a camera-active step
7797
7894
  // (document_capture/liveness) — showing it there would blow away a live
7798
7895
  // video element and in-progress MediaRecorder mid-scan.