smartcomply-web-sdk 1.0.35 → 1.0.38
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/esm/flow/DocumentCapture.d.ts.map +1 -1
- package/dist/esm/flow/DocumentCapture.js +6 -1
- package/dist/esm/flow/DocumentCapture.js.map +1 -1
- package/dist/esm/flow/SmartComplyFlow.d.ts.map +1 -1
- package/dist/esm/flow/SmartComplyFlow.js +65 -43
- package/dist/esm/flow/SmartComplyFlow.js.map +1 -1
- package/dist/esm/modules/liveness/LivenessUI.js +11 -7
- package/dist/esm/modules/liveness/LivenessUI.js.map +1 -1
- package/dist/esm/modules/liveness/liveness.d.ts +6 -0
- package/dist/esm/modules/liveness/liveness.d.ts.map +1 -1
- package/dist/esm/modules/liveness/liveness.js +35 -7
- package/dist/esm/modules/liveness/liveness.js.map +1 -1
- package/dist/flow/DocumentCapture.d.ts.map +1 -1
- package/dist/flow/DocumentCapture.js +6 -1
- package/dist/flow/DocumentCapture.js.map +1 -1
- package/dist/flow/SmartComplyFlow.d.ts.map +1 -1
- package/dist/flow/SmartComplyFlow.js +65 -43
- package/dist/flow/SmartComplyFlow.js.map +1 -1
- package/dist/modules/liveness/LivenessUI.js +11 -7
- package/dist/modules/liveness/LivenessUI.js.map +1 -1
- package/dist/modules/liveness/liveness.d.ts +6 -0
- package/dist/modules/liveness/liveness.d.ts.map +1 -1
- package/dist/modules/liveness/liveness.js +35 -7
- package/dist/modules/liveness/liveness.js.map +1 -1
- package/dist/smartcomply.browser.js +77 -49
- package/dist/smartcomply.browser.js.map +3 -3
- package/package.json +1 -1
|
@@ -4925,7 +4925,10 @@ var SmartComplySDK = (() => {
|
|
|
4925
4925
|
docVideo.play().catch(() => {
|
|
4926
4926
|
});
|
|
4927
4927
|
const cleanup = () => {
|
|
4928
|
-
|
|
4928
|
+
try {
|
|
4929
|
+
docRoot.remove();
|
|
4930
|
+
} catch (_2) {
|
|
4931
|
+
}
|
|
4929
4932
|
this.docCaptureRoot = null;
|
|
4930
4933
|
};
|
|
4931
4934
|
const captureBtn = bottomPanel.querySelector("#sc-capture-doc-btn");
|
|
@@ -4968,12 +4971,14 @@ var SmartComplySDK = (() => {
|
|
|
4968
4971
|
}
|
|
4969
4972
|
unmount() {
|
|
4970
4973
|
this.stopTimer();
|
|
4971
|
-
|
|
4972
|
-
this.docCaptureRoot
|
|
4973
|
-
|
|
4974
|
+
try {
|
|
4975
|
+
this.docCaptureRoot?.remove();
|
|
4976
|
+
} catch (_2) {
|
|
4974
4977
|
}
|
|
4975
|
-
|
|
4976
|
-
|
|
4978
|
+
this.docCaptureRoot = null;
|
|
4979
|
+
try {
|
|
4980
|
+
this.root?.remove();
|
|
4981
|
+
} catch (_2) {
|
|
4977
4982
|
}
|
|
4978
4983
|
this.root = null;
|
|
4979
4984
|
this.videoEl = null;
|
|
@@ -5361,6 +5366,8 @@ var SmartComplySDK = (() => {
|
|
|
5361
5366
|
*/
|
|
5362
5367
|
async captureFrame(video, maxAttempts = 5) {
|
|
5363
5368
|
const MIN_BLUR_SCORE = 120;
|
|
5369
|
+
const MIN_BRIGHTNESS = 40;
|
|
5370
|
+
const MAX_BRIGHTNESS = 220;
|
|
5364
5371
|
const RETRY_DELAY_MS2 = 200;
|
|
5365
5372
|
let bestBlob = null;
|
|
5366
5373
|
let bestScore = -1;
|
|
@@ -5371,15 +5378,18 @@ var SmartComplySDK = (() => {
|
|
|
5371
5378
|
const ctx = canvas.getContext("2d");
|
|
5372
5379
|
if (!ctx) throw new Error("Failed to get canvas context");
|
|
5373
5380
|
ctx.drawImage(video, 0, 0);
|
|
5374
|
-
const
|
|
5381
|
+
const blurScore = this._computeBlurScore(canvas);
|
|
5382
|
+
const brightness = this._computeBrightness(canvas);
|
|
5383
|
+
const brightnessOk = brightness >= MIN_BRIGHTNESS && brightness <= MAX_BRIGHTNESS;
|
|
5384
|
+
const qualityScore = brightnessOk ? blurScore : 0;
|
|
5375
5385
|
const blob = await new Promise(
|
|
5376
5386
|
(res) => canvas.toBlob((b2) => res(b2), "image/jpeg", 0.92)
|
|
5377
5387
|
);
|
|
5378
|
-
if (blob &&
|
|
5388
|
+
if (blob && qualityScore > bestScore) {
|
|
5379
5389
|
bestBlob = blob;
|
|
5380
|
-
bestScore =
|
|
5390
|
+
bestScore = qualityScore;
|
|
5381
5391
|
}
|
|
5382
|
-
if (
|
|
5392
|
+
if (blurScore >= MIN_BLUR_SCORE && brightnessOk) break;
|
|
5383
5393
|
if (attempt < maxAttempts - 1) {
|
|
5384
5394
|
await new Promise((r2) => setTimeout(r2, RETRY_DELAY_MS2));
|
|
5385
5395
|
}
|
|
@@ -5387,6 +5397,26 @@ var SmartComplySDK = (() => {
|
|
|
5387
5397
|
if (bestBlob) return bestBlob;
|
|
5388
5398
|
throw new Error("Failed to capture frame");
|
|
5389
5399
|
}
|
|
5400
|
+
/**
|
|
5401
|
+
* Compute average brightness (0–255) of the centre-cropped frame.
|
|
5402
|
+
* Used to reject frames that are too dark or overexposed before sending
|
|
5403
|
+
* to face comparison — server rejects IMAGE_TOO_DARK below ~40 luminance.
|
|
5404
|
+
*/
|
|
5405
|
+
_computeBrightness(canvas) {
|
|
5406
|
+
const ctx = canvas.getContext("2d");
|
|
5407
|
+
if (!ctx) return 128;
|
|
5408
|
+
const sw = Math.min(canvas.width, 320);
|
|
5409
|
+
const sh = Math.min(canvas.height, 240);
|
|
5410
|
+
const sx = Math.floor((canvas.width - sw) / 2);
|
|
5411
|
+
const sy = Math.floor((canvas.height - sh) / 2);
|
|
5412
|
+
const { data } = ctx.getImageData(sx, sy, sw, sh);
|
|
5413
|
+
let total = 0;
|
|
5414
|
+
const pixels = sw * sh;
|
|
5415
|
+
for (let i2 = 0; i2 < pixels; i2++) {
|
|
5416
|
+
total += 0.299 * data[i2 * 4] + 0.587 * data[i2 * 4 + 1] + 0.114 * data[i2 * 4 + 2];
|
|
5417
|
+
}
|
|
5418
|
+
return total / pixels;
|
|
5419
|
+
}
|
|
5390
5420
|
/**
|
|
5391
5421
|
* Sum-of-squared Laplacian blur metric on a centre-cropped region (320×240 max).
|
|
5392
5422
|
* Higher score = sharper image.
|
|
@@ -5655,7 +5685,7 @@ var SmartComplySDK = (() => {
|
|
|
5655
5685
|
}
|
|
5656
5686
|
requiresBackSide(documentType) {
|
|
5657
5687
|
const type = documentType.toLowerCase();
|
|
5658
|
-
return type.includes("voter") || type.includes("
|
|
5688
|
+
return type.includes("voter") || type.includes("driver") || type.includes("license") || type.includes("national id") || type.includes("national id card") || type.includes("ghana");
|
|
5659
5689
|
}
|
|
5660
5690
|
shouldCaptureBackSide(documentType) {
|
|
5661
5691
|
return this.requiresBackOverride !== void 0 ? this.requiresBackOverride : this.requiresBackSide(documentType);
|
|
@@ -6359,24 +6389,21 @@ var SmartComplySDK = (() => {
|
|
|
6359
6389
|
};
|
|
6360
6390
|
function resolveIdTypeInfo(typeName, isDocumentFlow) {
|
|
6361
6391
|
const u2 = typeName.toUpperCase();
|
|
6362
|
-
const withFace = u2.includes("WITH FACE") || u2.includes("FACE");
|
|
6363
6392
|
const advanced = u2.includes("ADVANCED");
|
|
6393
|
+
const cleanName = typeName.replace(/\s*with\s+face\s*/gi, " ").replace(/\s*\(NIN\)\s*/gi, " ").replace(/\s*\(BVN\)\s*/gi, " ").replace(/\s{2,}/g, " ").trim();
|
|
6364
6394
|
const requiresBackSide = (type) => {
|
|
6365
6395
|
const t2 = type.toLowerCase();
|
|
6366
|
-
return t2.includes("voter") || t2.includes("
|
|
6396
|
+
return t2.includes("voter") || t2.includes("driver") || t2.includes("license") || t2.includes("national id") || t2.includes("national id card");
|
|
6367
6397
|
};
|
|
6368
6398
|
if (u2.includes("BVN") || u2.includes("BANK VERIFICATION")) {
|
|
6369
|
-
|
|
6370
|
-
return { icon: "\u{1F3E6}", desc: `Enter your 11-digit BVN${extra}`, requiresBack: false };
|
|
6399
|
+
return { icon: "\u{1F3E6}", desc: "Enter your 11-digit Bank Verification Number (BVN)", requiresBack: false };
|
|
6371
6400
|
}
|
|
6372
6401
|
if (u2.includes("NIN") || u2.includes("NATIONAL IDENTITY NUMBER")) {
|
|
6373
|
-
|
|
6374
|
-
return { icon: "\u{1F194}", desc: `Enter your 11-digit NIN${extra}`, requiresBack: false };
|
|
6402
|
+
return { icon: "\u{1F194}", desc: "Enter your 11-digit National Identification Number (NIN)", requiresBack: false };
|
|
6375
6403
|
}
|
|
6376
6404
|
if (u2.includes("GHANA")) {
|
|
6377
6405
|
if (isDocumentFlow) return { icon: "\u{1FAAA}", desc: "Capture or upload your Ghana Card", requiresBack: true };
|
|
6378
|
-
|
|
6379
|
-
return { icon: "\u{1FAAA}", desc: `Enter your Ghana Card number${extra}`, requiresBack: false };
|
|
6406
|
+
return { icon: "\u{1FAAA}", desc: "Enter your Ghana Card number", requiresBack: false };
|
|
6380
6407
|
}
|
|
6381
6408
|
if (u2.includes("SSNIT"))
|
|
6382
6409
|
return { icon: "\u{1F3DB}\uFE0F", desc: "Enter your SSNIT number", requiresBack: false };
|
|
@@ -6512,8 +6539,9 @@ var SmartComplySDK = (() => {
|
|
|
6512
6539
|
if (this.overlay) {
|
|
6513
6540
|
this.overlay.style.opacity = "0";
|
|
6514
6541
|
setTimeout(() => {
|
|
6515
|
-
|
|
6516
|
-
this.overlay
|
|
6542
|
+
try {
|
|
6543
|
+
this.overlay?.remove();
|
|
6544
|
+
} catch (_2) {
|
|
6517
6545
|
}
|
|
6518
6546
|
this.overlay = null;
|
|
6519
6547
|
this.modal = null;
|
|
@@ -6849,8 +6877,9 @@ var SmartComplySDK = (() => {
|
|
|
6849
6877
|
if (requiresBack && isThisDocFlow) {
|
|
6850
6878
|
subtitle2 += " \u26A0\uFE0F Both sides required";
|
|
6851
6879
|
}
|
|
6880
|
+
const displayName = typeName.replace(/\s*with\s+face\s*/gi, " ").replace(/\s*\(NIN\)\s*/gi, " ").replace(/\s*\(BVN\)\s*/gi, " ").replace(/\s{2,}/g, " ").trim();
|
|
6852
6881
|
const card = this.createOptionCard(
|
|
6853
|
-
`${info.icon} ${
|
|
6882
|
+
`${info.icon} ${displayName}`,
|
|
6854
6883
|
subtitle2,
|
|
6855
6884
|
() => {
|
|
6856
6885
|
const idTypeChanged = this.selectedIdType !== typeCode;
|
|
@@ -6884,7 +6913,8 @@ var SmartComplySDK = (() => {
|
|
|
6884
6913
|
container.style.cssText += "display:flex;flex-direction:column;gap:16px;";
|
|
6885
6914
|
const dataFields = this.selectedChannelFields.filter((f2) => f2.type !== "upload");
|
|
6886
6915
|
const info = resolveIdTypeInfo(this.selectedIdTypeName || this.selectedIdType, false);
|
|
6887
|
-
const
|
|
6916
|
+
const cleanStepTitle = (this.selectedIdTypeName || this.selectedIdType).replace(/\s*with\s+face\s*/gi, " ").replace(/\s*\(NIN\)\s*/gi, " ").replace(/\s*\(BVN\)\s*/gi, " ").replace(/\s{2,}/g, " ").trim();
|
|
6917
|
+
const title = this.createStepTitle(`${info.icon} ${cleanStepTitle}`);
|
|
6888
6918
|
container.appendChild(title);
|
|
6889
6919
|
const subtitle = document.createElement("div");
|
|
6890
6920
|
subtitle.style.cssText = `color:${this.theme.textSecondary};font-size:13px;margin-top:-8px;`;
|
|
@@ -7070,7 +7100,9 @@ var SmartComplySDK = (() => {
|
|
|
7070
7100
|
// ── Document Capture ────────────────────────────────────────────
|
|
7071
7101
|
renderDocumentCapture(container) {
|
|
7072
7102
|
container.style.cssText += "display:flex;flex-direction:column;gap:16px;";
|
|
7073
|
-
const
|
|
7103
|
+
const rawName = this.selectedIdTypeName || this.selectedIdType || "your document";
|
|
7104
|
+
const cleanDocTitle = rawName.replace(/\s*with\s+face\s*/gi, " ").replace(/\s*\(NIN\)\s*/gi, " ").replace(/\s*\(BVN\)\s*/gi, " ").replace(/\s{2,}/g, " ").trim();
|
|
7105
|
+
const title = this.createStepTitle(`Capture ${cleanDocTitle}`);
|
|
7074
7106
|
container.appendChild(title);
|
|
7075
7107
|
const subtitle = document.createElement("div");
|
|
7076
7108
|
subtitle.style.cssText = `color:${this.theme.textSecondary};font-size:13px;margin-top:-8px;`;
|
|
@@ -7103,69 +7135,65 @@ var SmartComplySDK = (() => {
|
|
|
7103
7135
|
}
|
|
7104
7136
|
// ── Processing ────────────────────────────────────────────────────
|
|
7105
7137
|
renderProcessing(container) {
|
|
7106
|
-
container.style.cssText += "display:flex;flex-direction:column;align-items:center;gap:
|
|
7138
|
+
container.style.cssText += "display:flex;flex-direction:column;align-items:center;gap:14px;padding:16px;";
|
|
7107
7139
|
const animationWrap = document.createElement("div");
|
|
7108
|
-
animationWrap.style.cssText = "position:relative;width:
|
|
7140
|
+
animationWrap.style.cssText = "position:relative;width:52px;height:52px;flex-shrink:0;";
|
|
7109
7141
|
const spinner = document.createElement("div");
|
|
7110
7142
|
spinner.style.cssText = `
|
|
7111
7143
|
position:absolute;inset:0;border-radius:50%;
|
|
7112
|
-
border:
|
|
7144
|
+
border:3px solid ${this.theme.border};
|
|
7113
7145
|
border-top-color:${this.theme.primary};
|
|
7114
|
-
animation:sc-spin
|
|
7146
|
+
animation:sc-spin 0.9s linear infinite;
|
|
7115
7147
|
`;
|
|
7116
7148
|
animationWrap.appendChild(spinner);
|
|
7117
7149
|
const centerIcon = document.createElement("div");
|
|
7118
7150
|
centerIcon.style.cssText = `
|
|
7119
7151
|
position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
|
|
7120
|
-
font-size:
|
|
7152
|
+
font-size:20px;
|
|
7121
7153
|
`;
|
|
7122
7154
|
centerIcon.textContent = "\u{1F50D}";
|
|
7123
7155
|
animationWrap.appendChild(centerIcon);
|
|
7124
7156
|
container.appendChild(animationWrap);
|
|
7125
7157
|
const title = document.createElement("div");
|
|
7126
|
-
title.style.cssText = `color:${this.theme.text};font-size:
|
|
7127
|
-
title.textContent = "Processing
|
|
7158
|
+
title.style.cssText = `color:${this.theme.text};font-size:15px;font-weight:700;text-align:center;`;
|
|
7159
|
+
title.textContent = "Processing your document";
|
|
7128
7160
|
container.appendChild(title);
|
|
7129
7161
|
const subtitle = document.createElement("div");
|
|
7130
|
-
subtitle.style.cssText = `color:${this.theme.textSecondary};font-size:
|
|
7131
|
-
subtitle.textContent = "Scanning and verifying your
|
|
7162
|
+
subtitle.style.cssText = `color:${this.theme.textSecondary};font-size:12px;text-align:center;max-width:260px;line-height:1.5;`;
|
|
7163
|
+
subtitle.textContent = "Scanning and verifying your ID. This usually takes a few seconds.";
|
|
7132
7164
|
container.appendChild(subtitle);
|
|
7133
7165
|
const stepsContainer = document.createElement("div");
|
|
7134
7166
|
stepsContainer.style.cssText = `
|
|
7135
|
-
width:100%;
|
|
7136
|
-
margin-top:16px;
|
|
7167
|
+
width:100%;display:grid;grid-template-columns:1fr 1fr;gap:8px;
|
|
7137
7168
|
`;
|
|
7138
7169
|
const steps = [
|
|
7139
|
-
{ id: "uploading", text: "Uploading
|
|
7140
|
-
{ id: "scanning", text: "Scanning
|
|
7141
|
-
{ id: "verifying", text: "Verifying
|
|
7142
|
-
{ id: "analyzing", text: "
|
|
7170
|
+
{ id: "uploading", text: "Uploading", icon: "\u{1F4E4}" },
|
|
7171
|
+
{ id: "scanning", text: "Scanning", icon: "\u{1F50D}" },
|
|
7172
|
+
{ id: "verifying", text: "Verifying", icon: "\u2713" },
|
|
7173
|
+
{ id: "analyzing", text: "Checking quality", icon: "\u{1F52C}" }
|
|
7143
7174
|
];
|
|
7144
|
-
steps.forEach((step
|
|
7175
|
+
steps.forEach((step) => {
|
|
7145
7176
|
const stepEl = document.createElement("div");
|
|
7146
7177
|
stepEl.style.cssText = `
|
|
7147
|
-
display:flex;align-items:center;gap:
|
|
7178
|
+
display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:10px;
|
|
7148
7179
|
background:${this.theme.cardBg};border:1px solid ${this.theme.border};
|
|
7149
7180
|
transition:all 0.3s ease;
|
|
7150
7181
|
`;
|
|
7151
7182
|
stepEl.id = `processing-step-${step.id}`;
|
|
7152
7183
|
const iconEl = document.createElement("div");
|
|
7153
7184
|
iconEl.style.cssText = `
|
|
7154
|
-
width:
|
|
7155
|
-
|
|
7185
|
+
width:26px;height:26px;border-radius:7px;flex-shrink:0;
|
|
7186
|
+
display:flex;align-items:center;justify-content:center;
|
|
7187
|
+
font-size:12px;background:${this.theme.shimmer};
|
|
7156
7188
|
`;
|
|
7157
7189
|
iconEl.textContent = step.icon;
|
|
7158
7190
|
iconEl.id = `step-icon-${step.id}`;
|
|
7159
7191
|
const textEl = document.createElement("div");
|
|
7160
|
-
textEl.style.cssText = `flex:1;color:${this.theme.textSecondary};font-size:
|
|
7192
|
+
textEl.style.cssText = `flex:1;color:${this.theme.textSecondary};font-size:11px;font-weight:500;`;
|
|
7161
7193
|
textEl.textContent = step.text;
|
|
7162
7194
|
textEl.id = `step-text-${step.id}`;
|
|
7163
7195
|
const statusEl = document.createElement("div");
|
|
7164
|
-
statusEl.style.cssText = `
|
|
7165
|
-
width:20px;height:20px;border-radius:50%;
|
|
7166
|
-
border:2px solid ${this.theme.border};
|
|
7167
|
-
position:relative;
|
|
7168
|
-
`;
|
|
7196
|
+
statusEl.style.cssText = `width:16px;height:16px;border-radius:50%;border:2px solid ${this.theme.border};position:relative;flex-shrink:0;`;
|
|
7169
7197
|
statusEl.id = `step-status-${step.id}`;
|
|
7170
7198
|
stepEl.appendChild(iconEl);
|
|
7171
7199
|
stepEl.appendChild(textEl);
|