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.
@@ -1 +1 @@
1
- {"version":3,"file":"FaceDetector.d.ts","sourceRoot":"","sources":["../../src/camera/FaceDetector.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,eAAe,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CAClC;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,UAAU,CAA+B;IAE3C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B3B,MAAM,CAAC,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,GAAG,mBAAmB;IA+BvE,OAAO,IAAI,IAAI;CAMhB"}
1
+ {"version":3,"file":"FaceDetector.d.ts","sourceRoot":"","sources":["../../src/camera/FaceDetector.ts"],"names":[],"mappings":"AA4CA,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,eAAe,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CAClC;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,UAAU,CAA+B;IAE3C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC3B,MAAM,CAAC,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,GAAG,mBAAmB;IA+BvE,OAAO,IAAI,IAAI;CAMhB"}
@@ -2,39 +2,64 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FaceDetectorEngine = void 0;
4
4
  const tasks_vision_1 = require("@mediapipe/tasks-vision");
5
- const WASM_CDN = "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm";
6
- const MODEL_URL = "https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/latest/face_landmarker.task";
5
+ // Pinned to the exact version in package.json ("@mediapipe/tasks-vision":
6
+ // "^0.10.32"). This MUST stay in sync with that dependency — using
7
+ // "@latest" here let jsDelivr silently swap in a newer WASM build than the
8
+ // JS API this SDK was built/tested against, breaking face detection for
9
+ // every user at once with no code change on our side. Bump both together.
10
+ const MEDIAPIPE_VERSION = "0.10.32";
11
+ const WASM_CDN = `https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@${MEDIAPIPE_VERSION}/wasm`;
12
+ // Also pinned (was "/latest/") so a model update can't shift blendshape
13
+ // output out from under ActionDetector's calibrated thresholds unannounced.
14
+ const MODEL_URL = "https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task";
7
15
  // Module-level cache — survives component remounts and retries within the same page session.
8
16
  // First init fetches ~8MB total (WASM + model); subsequent inits reuse the cache instantly.
9
- let _cachedVision = null;
10
- let _cachedModelBuffer = null;
17
+ // Cached as in-flight PROMISES (not resolved values) so concurrent init() calls
18
+ // (e.g. parallel calls from two liveness attempts, or a fast retry) share one
19
+ // fetch instead of racing duplicate downloads — and so a failed attempt
20
+ // (rejected promise) doesn't get treated as "cached" and reused forever.
21
+ let _visionPromise = null;
22
+ let _modelBufferPromise = null;
23
+ /** Max time to wait for the WASM runtime / model download before giving up. */
24
+ const INIT_TIMEOUT_MS = 20000;
25
+ function withTimeout(promise, ms, label) {
26
+ return new Promise((resolve, reject) => {
27
+ const timer = setTimeout(() => reject(new Error(`${label} timed out. Please check your connection and try again.`)), ms);
28
+ promise.then((value) => { clearTimeout(timer); resolve(value); }, (err) => { clearTimeout(timer); reject(err); });
29
+ });
30
+ }
11
31
  class FaceDetectorEngine {
12
32
  constructor() {
13
33
  this.landmarker = null;
14
34
  }
15
35
  async init() {
16
- // Reuse WASM fileset — avoids re-fetching ~3MB on retry / remount
17
- if (!_cachedVision) {
18
- _cachedVision = await tasks_vision_1.FilesetResolver.forVisionTasks(WASM_CDN);
36
+ // Reuse (or join) the in-flight WASM fileset load — avoids re-fetching
37
+ // ~3MB on retry/remount, and avoids kicking off a second parallel fetch
38
+ // if init() is called again before the first finishes.
39
+ if (!_visionPromise) {
40
+ _visionPromise = tasks_vision_1.FilesetResolver.forVisionTasks(WASM_CDN);
41
+ _visionPromise.catch(() => { _visionPromise = null; }); // don't cache a failure
19
42
  }
20
- // Reuse model buffer avoids re-fetching ~5MB on retry / remount
21
- if (!_cachedModelBuffer) {
22
- const res = await fetch(MODEL_URL);
23
- if (!res.ok) {
24
- throw new Error(`Failed to download face model (${res.status})`);
25
- }
26
- _cachedModelBuffer = await res.arrayBuffer();
43
+ // Reuse (or join) the in-flight model download same reasoning.
44
+ if (!_modelBufferPromise) {
45
+ _modelBufferPromise = fetch(MODEL_URL).then((res) => {
46
+ if (!res.ok)
47
+ throw new Error(`Failed to download face model (${res.status})`);
48
+ return res.arrayBuffer();
49
+ });
50
+ _modelBufferPromise.catch(() => { _modelBufferPromise = null; }); // don't cache a failure
27
51
  }
28
- this.landmarker = await tasks_vision_1.FaceLandmarker.createFromOptions(_cachedVision, {
52
+ const [vision, modelBuffer] = await withTimeout(Promise.all([_visionPromise, _modelBufferPromise]), INIT_TIMEOUT_MS, "Face detection setup");
53
+ this.landmarker = await withTimeout(tasks_vision_1.FaceLandmarker.createFromOptions(vision, {
29
54
  baseOptions: {
30
55
  // Pass a copy — MediaPipe takes ownership of the buffer
31
- modelAssetBuffer: new Uint8Array(_cachedModelBuffer.slice(0)),
56
+ modelAssetBuffer: new Uint8Array(modelBuffer.slice(0)),
32
57
  },
33
58
  runningMode: "VIDEO",
34
59
  outputFaceBlendshapes: true,
35
60
  outputFacialTransformationMatrixes: true,
36
61
  numFaces: 1,
37
- });
62
+ }), INIT_TIMEOUT_MS, "Face detection setup");
38
63
  }
39
64
  detect(video, timestamp) {
40
65
  if (!this.landmarker) {
@@ -1 +1 @@
1
- {"version":3,"file":"FaceDetector.js","sourceRoot":"","sources":["../../src/camera/FaceDetector.ts"],"names":[],"mappings":";;;AAAA,0DAIiC;AAEjC,MAAM,QAAQ,GACZ,kEAAkE,CAAC;AACrE,MAAM,SAAS,GACb,qHAAqH,CAAC;AAExH,6FAA6F;AAC7F,4FAA4F;AAC5F,IAAI,aAAa,GAAsE,IAAI,CAAC;AAC5F,IAAI,kBAAkB,GAAuB,IAAI,CAAC;AAQlD,MAAa,kBAAkB;IAA/B;QACU,eAAU,GAA0B,IAAI,CAAC;IAkEnD,CAAC;IAhEC,KAAK,CAAC,IAAI;QACR,kEAAkE;QAClE,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,aAAa,GAAG,MAAM,8BAAe,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QACjE,CAAC;QAED,kEAAkE;QAClE,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC;YACnC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,kCAAkC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;YACnE,CAAC;YACD,kBAAkB,GAAG,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC;QAC/C,CAAC;QAED,IAAI,CAAC,UAAU,GAAG,MAAM,6BAAc,CAAC,iBAAiB,CAAC,aAAa,EAAE;YACtE,WAAW,EAAE;gBACX,wDAAwD;gBACxD,gBAAgB,EAAE,IAAI,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;aAC9D;YACD,WAAW,EAAE,OAAO;YACpB,qBAAqB,EAAE,IAAI;YAC3B,kCAAkC,EAAE,IAAI;YACxC,QAAQ,EAAE,CAAC;SACZ,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,KAAuB,EAAE,SAAiB;QAC/C,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,GAAG,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC;QAChF,CAAC;QAED,IAAI,MAA4B,CAAC;QACjC,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QAC5D,CAAC;QAAC,MAAM,CAAC;YACP,yDAAyD;YACzD,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,GAAG,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC;QAChF,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,eAAe,IAAI,MAAM,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,GAAG,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC;QAChF,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC9C,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;YACtD,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,eAAe,GACnB,MAAM,CAAC,4BAA4B;YACnC,MAAM,CAAC,4BAA4B,CAAC,MAAM,GAAG,CAAC;YAC5C,CAAC,CAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,4BAA4B,CAAC,CAAC,CAAC,CAAC,IAAI,CAAc;YACvE,CAAC,CAAC,IAAI,CAAC;QAEX,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC;IAC9D,CAAC;IAED,OAAO;QACL,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YACxB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACzB,CAAC;IACH,CAAC;CACF;AAnED,gDAmEC"}
1
+ {"version":3,"file":"FaceDetector.js","sourceRoot":"","sources":["../../src/camera/FaceDetector.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"FaceDetector.d.ts","sourceRoot":"","sources":["../../../src/camera/FaceDetector.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,eAAe,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CAClC;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,UAAU,CAA+B;IAE3C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B3B,MAAM,CAAC,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,GAAG,mBAAmB;IA+BvE,OAAO,IAAI,IAAI;CAMhB"}
1
+ {"version":3,"file":"FaceDetector.d.ts","sourceRoot":"","sources":["../../../src/camera/FaceDetector.ts"],"names":[],"mappings":"AA4CA,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,eAAe,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CAClC;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,UAAU,CAA+B;IAE3C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC3B,MAAM,CAAC,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,GAAG,mBAAmB;IA+BvE,OAAO,IAAI,IAAI;CAMhB"}
@@ -1,37 +1,62 @@
1
1
  import { FilesetResolver, FaceLandmarker, } from "@mediapipe/tasks-vision";
2
- const WASM_CDN = "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm";
3
- const MODEL_URL = "https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/latest/face_landmarker.task";
2
+ // Pinned to the exact version in package.json ("@mediapipe/tasks-vision":
3
+ // "^0.10.32"). This MUST stay in sync with that dependency — using
4
+ // "@latest" here let jsDelivr silently swap in a newer WASM build than the
5
+ // JS API this SDK was built/tested against, breaking face detection for
6
+ // every user at once with no code change on our side. Bump both together.
7
+ const MEDIAPIPE_VERSION = "0.10.32";
8
+ const WASM_CDN = `https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@${MEDIAPIPE_VERSION}/wasm`;
9
+ // Also pinned (was "/latest/") so a model update can't shift blendshape
10
+ // output out from under ActionDetector's calibrated thresholds unannounced.
11
+ const MODEL_URL = "https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task";
4
12
  // Module-level cache — survives component remounts and retries within the same page session.
5
13
  // First init fetches ~8MB total (WASM + model); subsequent inits reuse the cache instantly.
6
- let _cachedVision = null;
7
- let _cachedModelBuffer = null;
14
+ // Cached as in-flight PROMISES (not resolved values) so concurrent init() calls
15
+ // (e.g. parallel calls from two liveness attempts, or a fast retry) share one
16
+ // fetch instead of racing duplicate downloads — and so a failed attempt
17
+ // (rejected promise) doesn't get treated as "cached" and reused forever.
18
+ let _visionPromise = null;
19
+ let _modelBufferPromise = null;
20
+ /** Max time to wait for the WASM runtime / model download before giving up. */
21
+ const INIT_TIMEOUT_MS = 20000;
22
+ function withTimeout(promise, ms, label) {
23
+ return new Promise((resolve, reject) => {
24
+ const timer = setTimeout(() => reject(new Error(`${label} timed out. Please check your connection and try again.`)), ms);
25
+ promise.then((value) => { clearTimeout(timer); resolve(value); }, (err) => { clearTimeout(timer); reject(err); });
26
+ });
27
+ }
8
28
  export class FaceDetectorEngine {
9
29
  constructor() {
10
30
  this.landmarker = null;
11
31
  }
12
32
  async init() {
13
- // Reuse WASM fileset — avoids re-fetching ~3MB on retry / remount
14
- if (!_cachedVision) {
15
- _cachedVision = await FilesetResolver.forVisionTasks(WASM_CDN);
33
+ // Reuse (or join) the in-flight WASM fileset load — avoids re-fetching
34
+ // ~3MB on retry/remount, and avoids kicking off a second parallel fetch
35
+ // if init() is called again before the first finishes.
36
+ if (!_visionPromise) {
37
+ _visionPromise = FilesetResolver.forVisionTasks(WASM_CDN);
38
+ _visionPromise.catch(() => { _visionPromise = null; }); // don't cache a failure
16
39
  }
17
- // Reuse model buffer avoids re-fetching ~5MB on retry / remount
18
- if (!_cachedModelBuffer) {
19
- const res = await fetch(MODEL_URL);
20
- if (!res.ok) {
21
- throw new Error(`Failed to download face model (${res.status})`);
22
- }
23
- _cachedModelBuffer = await res.arrayBuffer();
40
+ // Reuse (or join) the in-flight model download same reasoning.
41
+ if (!_modelBufferPromise) {
42
+ _modelBufferPromise = fetch(MODEL_URL).then((res) => {
43
+ if (!res.ok)
44
+ throw new Error(`Failed to download face model (${res.status})`);
45
+ return res.arrayBuffer();
46
+ });
47
+ _modelBufferPromise.catch(() => { _modelBufferPromise = null; }); // don't cache a failure
24
48
  }
25
- this.landmarker = await FaceLandmarker.createFromOptions(_cachedVision, {
49
+ const [vision, modelBuffer] = await withTimeout(Promise.all([_visionPromise, _modelBufferPromise]), INIT_TIMEOUT_MS, "Face detection setup");
50
+ this.landmarker = await withTimeout(FaceLandmarker.createFromOptions(vision, {
26
51
  baseOptions: {
27
52
  // Pass a copy — MediaPipe takes ownership of the buffer
28
- modelAssetBuffer: new Uint8Array(_cachedModelBuffer.slice(0)),
53
+ modelAssetBuffer: new Uint8Array(modelBuffer.slice(0)),
29
54
  },
30
55
  runningMode: "VIDEO",
31
56
  outputFaceBlendshapes: true,
32
57
  outputFacialTransformationMatrixes: true,
33
58
  numFaces: 1,
34
- });
59
+ }), INIT_TIMEOUT_MS, "Face detection setup");
35
60
  }
36
61
  detect(video, timestamp) {
37
62
  if (!this.landmarker) {
@@ -1 +1 @@
1
- {"version":3,"file":"FaceDetector.js","sourceRoot":"","sources":["../../../src/camera/FaceDetector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FaceDetector.js","sourceRoot":"","sources":["../../../src/camera/FaceDetector.ts"],"names":[],"mappings":"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"}
@@ -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;AAwC/C,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IAC1C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,kBAAkB,CAAC,EAAE,sBAAsB,CAAC;CAC7C;AAsRD,qBAAa,eAAe;IAC1B,OAAO,CAAC,GAAG,CAAc;IACzB,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,KAAK,CAAoC;IAGjD,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,WAAW,CAA+B;IAClD,OAAO,CAAC,WAAW,CAA+B;IAClD,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,UAAU,CAA+B;IAGjD,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,eAAe,CAAc;IACrC,OAAO,CAAC,iBAAiB,CAAa;IACtC,OAAO,CAAC,qBAAqB,CAA6D;IAC1F,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,kBAAkB,CAAc;IACxC,OAAO,CAAC,oBAAoB,CAAuC;IACnE,OAAO,CAAC,eAAe,CAA8B;IACrD,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,gBAAgB,CAAqB;IAK7C,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,kBAAkB,CAAuC;IACjE,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,aAAa,CAAkC;IACvD,OAAO,CAAC,eAAe,CAA6C;IACpE,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,gBAAgB,CAA6B;IACrD,OAAO,CAAC,mBAAmB,CAAS;IAGpC,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAK;IAGxC,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,UAAU,CAAc;IAGhC,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,gBAAgB,CAAc;IACtC,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,cAAc,CAAkB;IAGxC,OAAO,CAAC,gBAAgB,CAA4B;IAGpD,OAAO,CAAC,aAAa,CAA8C;IAGnE,OAAO,CAAC,YAAY,CAA8C;IAGlE,OAAO,CAAC,kBAAkB,CAA8C;IACxE,OAAO,CAAC,mBAAmB,CAA8C;IAGzE,OAAO,CAAC,gBAAgB,CAA8C;IAGtE,OAAO,CAAC,UAAU,CAAgC;IAElD,OAAO;IAUP;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,eAAe;IAOlD;;OAEG;IACH,KAAK,IAAI,IAAI;IAwEb,OAAO,CAAC,KAAK;YAwJC,UAAU;IAwDxB,OAAO,CAAC,0BAA0B;IAgBlC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAM;IAClD,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,qBAAqB;IAmB7B,OAAO,CAAC,QAAQ;IAmChB,OAAO,CAAC,UAAU;IA4ElB,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,aAAa;IA4IrB,OAAO,CAAC,mBAAmB;IAoC3B,OAAO,CAAC,kBAAkB;IAsF1B,OAAO,CAAC,aAAa;IAuWrB,OAAO,CAAC,qBAAqB;IAqD7B,OAAO,CAAC,qBAAqB;IA+E7B,OAAO,CAAC,qBAAqB;IAuI7B,OAAO,CAAC,aAAa;IA8GrB,OAAO,CAAC,sBAAsB;IAyB9B,OAAO,CAAC,qBAAqB;IA0C7B;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAwBzB,OAAO,CAAC,UAAU;IA+ClB,OAAO,CAAC,wBAAwB;IAqBhC,OAAO,CAAC,cAAc;IAUtB;;OAEG;YACW,4BAA4B;IAiB1C;;OAEG;YACW,mBAAmB;IA+GjC,OAAO,CAAC,6BAA6B;IA8DrC,OAAO,CAAC,cAAc;IA0GtB,OAAO,CAAC,aAAa;IAsGrB,OAAO,CAAC,YAAY;IAmGpB,OAAO,CAAC,YAAY;IAyBpB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,gBAAgB;IAmDxB,OAAO,CAAC,mBAAmB;IAsB3B,OAAO,CAAC,qBAAqB;IAmB7B,sGAAsG;IACtG,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,cAAc;IAgBtB;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,cAAc;IA0EtB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,YAAY;CAiCrB"}
1
+ {"version":3,"file":"SmartComplyFlow.d.ts","sourceRoot":"","sources":["../../../src/flow/SmartComplyFlow.ts"],"names":[],"mappings":"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"}
@@ -18,6 +18,11 @@ const _INFRASTRUCTURE_ERROR_PATTERNS = [
18
18
  "camera access is not supported",
19
19
  "camera access failed",
20
20
  "recording failed unexpectedly",
21
+ // FaceDetectorEngine.init() failures (FaceDetector.ts) — a slow/blocked
22
+ // CDN or model download is a connectivity issue, not a failed face scan,
23
+ // and must not burn one of the user's limited liveness retry attempts.
24
+ "face detection setup timed out",
25
+ "failed to download face model",
21
26
  ];
22
27
  function _isInfrastructureError(err) {
23
28
  const msg = String(err?.message || "").toLowerCase();
@@ -767,7 +772,8 @@ export class SmartComplyFlow {
767
772
  // ── Welcome ────────────────────────────────────────────────────
768
773
  renderWelcome(container) {
769
774
  container.style.cssText += "display:flex;flex-direction:column;align-items:center;text-align:center;gap:12px;";
770
- const isDocFlow = this.isDocumentFlow();
775
+ const isLivenessOnly = this.isLivenessOnlyFlow();
776
+ const isDocFlow = isLivenessOnly ? false : this.isDocumentFlow();
771
777
  // Icon + badge row (side by side to save vertical space)
772
778
  const topRow = document.createElement("div");
773
779
  topRow.style.cssText = "display:flex;flex-direction:column;align-items:center;gap:8px;";
@@ -790,7 +796,9 @@ export class SmartComplyFlow {
790
796
  color:${this.theme.primary};
791
797
  border:1px solid ${this.theme.primary}30;
792
798
  `;
793
- badge.textContent = isDocFlow ? "📄 Document Verification" : "🔍 Data Verification";
799
+ badge.textContent = isLivenessOnly
800
+ ? "🤳 Liveness Check"
801
+ : isDocFlow ? "📄 Document Verification" : "🔍 Data Verification";
794
802
  topRow.appendChild(badge);
795
803
  container.appendChild(topRow);
796
804
  // Title + subtitle (compact)
@@ -812,23 +820,29 @@ export class SmartComplyFlow {
812
820
  color:${this.theme.textSecondary};font-size:13px;line-height:1.5;
813
821
  margin:0 auto;max-width:300px;text-align:center;
814
822
  `;
815
- desc.textContent = isDocFlow
816
- ? "You'll need your document and camera access. This takes about 2 minutes."
817
- : "You'll need your ID number and camera access. This takes about 2 minutes.";
823
+ desc.textContent = isLivenessOnly
824
+ ? "You'll just need camera access. This takes about 30 seconds."
825
+ : isDocFlow
826
+ ? "You'll need your document and camera access. This takes about 2 minutes."
827
+ : "You'll need your ID number and camera access. This takes about 2 minutes.";
818
828
  titleWrap.appendChild(desc);
819
829
  container.appendChild(titleWrap);
820
830
  // Steps preview — compact rows
821
- const steps = isDocFlow
831
+ const steps = isLivenessOnly
822
832
  ? [
823
- { icon: "🪪", text: "Choose your document type", sub: "Passport, National ID, Driver License" },
824
- { icon: "📷", text: "Scan your document", sub: "Upload or capture a photo of your ID" },
825
833
  { icon: "🤳", text: "Face check", sub: "Quick selfie to confirm it's you" },
826
834
  ]
827
- : [
828
- { icon: "🆔", text: "Choose your ID type", sub: "NIN, BVN, Voter's Card and more" },
829
- { icon: "📝", text: "Enter your ID details", sub: "Exactly as shown on your ID" },
830
- { icon: "🤳", text: "Face check", sub: "Quick selfie to confirm it's you" },
831
- ];
835
+ : isDocFlow
836
+ ? [
837
+ { icon: "🪪", text: "Choose your document type", sub: "Passport, National ID, Driver License" },
838
+ { icon: "📷", text: "Scan your document", sub: "Upload or capture a photo of your ID" },
839
+ { icon: "🤳", text: "Face check", sub: "Quick selfie to confirm it's you" },
840
+ ]
841
+ : [
842
+ { icon: "🆔", text: "Choose your ID type", sub: "NIN, BVN, Voter's Card and more" },
843
+ { icon: "📝", text: "Enter your ID details", sub: "Exactly as shown on your ID" },
844
+ { icon: "🤳", text: "Face check", sub: "Quick selfie to confirm it's you" },
845
+ ];
832
846
  const stepsWrap = document.createElement("div");
833
847
  stepsWrap.style.cssText = `
834
848
  width:100%;display:flex;flex-direction:column;gap:0;
@@ -870,7 +884,27 @@ export class SmartComplyFlow {
870
884
  // CTA
871
885
  const btn = this.createPrimaryButton("Get Started →");
872
886
  btn.style.cssText += "margin-top:2px;";
873
- btn.addEventListener("click", () => this.showStep("country"));
887
+ btn.addEventListener("click", () => {
888
+ if (isLivenessOnly) {
889
+ // Liveness-only has no channels at all, so renderCountrySelect's
890
+ // single-country auto-skip (countries.length === 1) never fires for
891
+ // it — going through "country" here would render an empty,
892
+ // dead-end country-picker screen. Go straight to liveness instead.
893
+ //
894
+ // selectedCountry defaults to "" and is otherwise only ever set by
895
+ // renderCountrySelect, which this mode never visits — renderLiveness
896
+ // sends it as a required, non-blank `country` field, so leaving it
897
+ // empty would fail create() validation before the scan even starts.
898
+ // There's no real country to report here (no identity lookup runs
899
+ // in this mode), so this is a neutral placeholder, not a claim
900
+ // about the user's actual location.
901
+ this.selectedCountry = this.selectedCountry || "global";
902
+ this.showStep("liveness");
903
+ }
904
+ else {
905
+ this.showStep("country");
906
+ }
907
+ });
874
908
  container.appendChild(btn);
875
909
  // Plain-language line on what the camera/photo is for and what happens
876
910
  // to it — shown before the "Get Started" tap that leads to the first
@@ -2414,6 +2448,21 @@ export class SmartComplyFlow {
2414
2448
  .flatMap((ch) => ch.fields || []);
2415
2449
  return allFields.some((f) => isUploadFieldType(f.type));
2416
2450
  }
2451
+ /**
2452
+ * True when the SDK Config is set to skip data/document verification
2453
+ * entirely and only run the liveness/selfie check — no country picker,
2454
+ * no ID-type picker, no ID-number entry or document capture. Unlike
2455
+ * isDocumentFlow(), there's no channel-shape fallback to infer this from:
2456
+ * a liveness-only config carries no channels at all, so the only signal
2457
+ * is verification_type itself.
2458
+ */
2459
+ isLivenessOnlyFlow() {
2460
+ const vType = this.sdkConfig?.verification_type;
2461
+ if (!vType)
2462
+ return false;
2463
+ const types = Array.isArray(vType) ? vType : [vType];
2464
+ return types.includes("liveness_only");
2465
+ }
2417
2466
  /**
2418
2467
  * The "go back one step" target for a given step, if that step is
2419
2468
  * navigable — shared by the header back button and the browser
@@ -2430,16 +2479,28 @@ export class SmartComplyFlow {
2430
2479
  document_capture: () => { this.docCapture?.destroy(); this.showStep("id_type"); },
2431
2480
  document_confirm: () => { this.docCapture?.destroy(); this.showStep("document_capture"); },
2432
2481
  };
2482
+ // liveness-only skips straight from welcome to liveness with nothing in
2483
+ // between — deliberately no backTargets["liveness"] entry added here,
2484
+ // so the back button stays hidden on that step in this mode, same as
2485
+ // it already is for every other mode (liveness has no back target for
2486
+ // document/data flows either — nothing to go back to except closing).
2433
2487
  return backTargets[step];
2434
2488
  }
2435
2489
  updateProgress() {
2436
- const isDocFlow = this.isDocumentFlow();
2490
+ const isLivenessOnly = this.isLivenessOnlyFlow();
2491
+ const isDocFlow = isLivenessOnly ? false : this.isDocumentFlow();
2437
2492
  const countries = Object.keys(this.sdkConfig?.channels || {});
2438
2493
  const singleCountry = countries.length <= 1;
2439
- // Two-stage action steps — Stage 1: validate identity, Stage 2: liveness
2440
- const stage1Steps = isDocFlow
2441
- ? ["country", "id_type", "document_capture", "ocr_gate", "document_confirm"].filter(s => !(s === "country" && singleCountry))
2442
- : ["country", "id_type", "id_input", "confirm_identity"].filter(s => !(s === "country" && singleCountry));
2494
+ // Two-stage action steps — Stage 1: validate identity, Stage 2: liveness.
2495
+ // Liveness-only has no Stage 1 at all — welcome goes straight to
2496
+ // liveness so stage1Steps stays empty and the progress bar reflects
2497
+ // a genuinely single-stage flow instead of implying a step that never
2498
+ // happens in this mode.
2499
+ const stage1Steps = isLivenessOnly
2500
+ ? []
2501
+ : isDocFlow
2502
+ ? ["country", "id_type", "document_capture", "ocr_gate", "document_confirm"].filter(s => !(s === "country" && singleCountry))
2503
+ : ["country", "id_type", "id_input", "confirm_identity"].filter(s => !(s === "country" && singleCountry));
2443
2504
  const stage2Steps = ["liveness"];
2444
2505
  const allActionSteps = [...stage1Steps, ...stage2Steps];
2445
2506
  const totalSteps = allActionSteps.length;
@@ -2451,6 +2512,8 @@ export class SmartComplyFlow {
2451
2512
  this.progressBar.style.width = `${pct}%`;
2452
2513
  }
2453
2514
  // Stage label: "Stage 1 of 2: Verify Identity" / "Stage 2 of 2: Face Check"
2515
+ // — liveness-only has no Stage 1, so it just says "Face Check" with no
2516
+ // "of 2" framing, since there's only ever the one stage in this mode.
2454
2517
  if (this.stepLabel) {
2455
2518
  if (this.currentStep === "loading" || this.currentStep === "welcome") {
2456
2519
  this.stepLabel.textContent = "";
@@ -2459,7 +2522,7 @@ export class SmartComplyFlow {
2459
2522
  this.stepLabel.textContent = "Complete ✓";
2460
2523
  }
2461
2524
  else if (stage2Steps.includes(this.currentStep)) {
2462
- this.stepLabel.textContent = "Stage 2 of 2: Face Check";
2525
+ this.stepLabel.textContent = isLivenessOnly ? "Face Check" : "Stage 2 of 2: Face Check";
2463
2526
  }
2464
2527
  else if (stage1Steps.includes(this.currentStep)) {
2465
2528
  this.stepLabel.textContent = isDocFlow ? "Stage 1 of 2: Scan Document" : "Stage 1 of 2: Verify Identity";