@neofaceid/web-sdk 1.13.0 → 1.13.2
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.
|
@@ -2288,13 +2288,30 @@ const registerApplication = async (jwtToken, consumerId, applicationData) => {
|
|
|
2288
2288
|
};
|
|
2289
2289
|
const recordFaceVideo = async (options = {}) => {
|
|
2290
2290
|
ensureSecureContext();
|
|
2291
|
-
const { durationMs = 3e3,
|
|
2291
|
+
const { durationMs = 3e3, onProgress } = options;
|
|
2292
|
+
const getSupportedMimeType = () => {
|
|
2293
|
+
const types = [
|
|
2294
|
+
"video/mp4;codecs=avc1",
|
|
2295
|
+
// iOS Safari (prioritário quando disponível)
|
|
2296
|
+
"video/mp4",
|
|
2297
|
+
// iOS Safari fallback
|
|
2298
|
+
"video/webm;codecs=vp9",
|
|
2299
|
+
// Chrome/Firefox
|
|
2300
|
+
"video/webm;codecs=vp8",
|
|
2301
|
+
// Chrome/Firefox fallback
|
|
2302
|
+
"video/webm"
|
|
2303
|
+
// Android Chrome
|
|
2304
|
+
];
|
|
2305
|
+
for (const type of types) {
|
|
2306
|
+
if (MediaRecorder.isTypeSupported(type)) return type;
|
|
2307
|
+
}
|
|
2308
|
+
return "";
|
|
2309
|
+
};
|
|
2292
2310
|
return new Promise(async (resolve, reject) => {
|
|
2293
|
-
let
|
|
2294
|
-
let mediaRecorder = null;
|
|
2311
|
+
let cameraStream = null;
|
|
2295
2312
|
const chunks = [];
|
|
2296
2313
|
try {
|
|
2297
|
-
|
|
2314
|
+
cameraStream = await navigator.mediaDevices.getUserMedia({
|
|
2298
2315
|
video: {
|
|
2299
2316
|
facingMode: "user",
|
|
2300
2317
|
width: { ideal: 640 },
|
|
@@ -2302,38 +2319,33 @@ const recordFaceVideo = async (options = {}) => {
|
|
|
2302
2319
|
},
|
|
2303
2320
|
audio: false
|
|
2304
2321
|
});
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
mimeType: selectedMimeType,
|
|
2315
|
-
videoBitsPerSecond: 1e6
|
|
2316
|
-
// 1 Mbps
|
|
2317
|
-
});
|
|
2318
|
-
mediaRecorder.ondataavailable = (event) => {
|
|
2322
|
+
const selectedMimeType = getSupportedMimeType();
|
|
2323
|
+
let recorder;
|
|
2324
|
+
try {
|
|
2325
|
+
recorder = selectedMimeType ? new MediaRecorder(cameraStream, { mimeType: selectedMimeType, videoBitsPerSecond: 1e6 }) : new MediaRecorder(cameraStream, { videoBitsPerSecond: 1e6 });
|
|
2326
|
+
} catch {
|
|
2327
|
+
recorder = new MediaRecorder(cameraStream);
|
|
2328
|
+
}
|
|
2329
|
+
const finalMimeType = recorder.mimeType || selectedMimeType;
|
|
2330
|
+
recorder.ondataavailable = (event) => {
|
|
2319
2331
|
if (event.data.size > 0) {
|
|
2320
2332
|
chunks.push(event.data);
|
|
2321
2333
|
}
|
|
2322
2334
|
};
|
|
2323
|
-
|
|
2324
|
-
if (
|
|
2325
|
-
|
|
2335
|
+
recorder.onstop = () => {
|
|
2336
|
+
if (cameraStream) {
|
|
2337
|
+
cameraStream.getTracks().forEach((track) => track.stop());
|
|
2326
2338
|
}
|
|
2327
|
-
const videoBlob = new Blob(chunks, { type:
|
|
2339
|
+
const videoBlob = new Blob(chunks, { type: finalMimeType });
|
|
2328
2340
|
resolve(videoBlob);
|
|
2329
2341
|
};
|
|
2330
|
-
|
|
2331
|
-
if (
|
|
2332
|
-
|
|
2342
|
+
recorder.onerror = (event) => {
|
|
2343
|
+
if (cameraStream) {
|
|
2344
|
+
cameraStream.getTracks().forEach((track) => track.stop());
|
|
2333
2345
|
}
|
|
2334
2346
|
reject(new NeoFaceError(`Recording error: ${event}`, ErrorType.CAPTURE_ERROR));
|
|
2335
2347
|
};
|
|
2336
|
-
|
|
2348
|
+
recorder.start(100);
|
|
2337
2349
|
if (onProgress) {
|
|
2338
2350
|
const progressInterval = 100;
|
|
2339
2351
|
let elapsed = 0;
|
|
@@ -2347,13 +2359,13 @@ const recordFaceVideo = async (options = {}) => {
|
|
|
2347
2359
|
}, progressInterval);
|
|
2348
2360
|
}
|
|
2349
2361
|
setTimeout(() => {
|
|
2350
|
-
if (
|
|
2351
|
-
|
|
2362
|
+
if (recorder && recorder.state === "recording") {
|
|
2363
|
+
recorder.stop();
|
|
2352
2364
|
}
|
|
2353
2365
|
}, durationMs);
|
|
2354
2366
|
} catch (error) {
|
|
2355
|
-
if (
|
|
2356
|
-
|
|
2367
|
+
if (cameraStream) {
|
|
2368
|
+
cameraStream.getTracks().forEach((track) => track.stop());
|
|
2357
2369
|
}
|
|
2358
2370
|
if (error instanceof Error) {
|
|
2359
2371
|
if (error.name === "NotAllowedError") {
|
|
@@ -5321,14 +5333,15 @@ async function captureFaceSilently() {
|
|
|
5321
5333
|
video.style.width = "1px";
|
|
5322
5334
|
video.style.height = "1px";
|
|
5323
5335
|
video.style.opacity = "0";
|
|
5336
|
+
video.muted = true;
|
|
5337
|
+
video.playsInline = true;
|
|
5324
5338
|
video.setAttribute("autoplay", "");
|
|
5325
|
-
video.setAttribute("muted", "");
|
|
5326
5339
|
video.setAttribute("playsinline", "");
|
|
5327
5340
|
const canvas = document.createElement("canvas");
|
|
5328
5341
|
canvas.style.display = "none";
|
|
5329
5342
|
let stream = null;
|
|
5330
5343
|
let faceDetectionAttempts = 0;
|
|
5331
|
-
const MAX_FACE_DETECTION_ATTEMPTS =
|
|
5344
|
+
const MAX_FACE_DETECTION_ATTEMPTS = 30;
|
|
5332
5345
|
const cleanup = () => {
|
|
5333
5346
|
if (stream) {
|
|
5334
5347
|
stream.getTracks().forEach((track) => track.stop());
|
|
@@ -5342,22 +5355,27 @@ async function captureFaceSilently() {
|
|
|
5342
5355
|
};
|
|
5343
5356
|
document.body.appendChild(video);
|
|
5344
5357
|
document.body.appendChild(canvas);
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5358
|
+
const tryGetUserMedia = (withConstraints) => {
|
|
5359
|
+
if (withConstraints) {
|
|
5360
|
+
return navigator.mediaDevices.getUserMedia({
|
|
5361
|
+
video: {
|
|
5362
|
+
width: { ideal: 640 },
|
|
5363
|
+
height: { ideal: 480 },
|
|
5364
|
+
facingMode: "user"
|
|
5365
|
+
},
|
|
5366
|
+
audio: false
|
|
5367
|
+
});
|
|
5368
|
+
}
|
|
5369
|
+
return navigator.mediaDevices.getUserMedia({ video: { facingMode: "user" }, audio: false });
|
|
5370
|
+
};
|
|
5371
|
+
tryGetUserMedia(true).catch(() => tryGetUserMedia(false)).then((mediaStream) => {
|
|
5353
5372
|
stream = mediaStream;
|
|
5354
5373
|
video.srcObject = stream;
|
|
5355
|
-
video.play();
|
|
5356
5374
|
const tryCapture = () => {
|
|
5357
5375
|
if (!video.videoWidth || !video.videoHeight) {
|
|
5358
5376
|
if (faceDetectionAttempts < MAX_FACE_DETECTION_ATTEMPTS) {
|
|
5359
5377
|
faceDetectionAttempts++;
|
|
5360
|
-
setTimeout(tryCapture,
|
|
5378
|
+
setTimeout(tryCapture, 150);
|
|
5361
5379
|
return;
|
|
5362
5380
|
}
|
|
5363
5381
|
cleanup();
|
|
@@ -5387,7 +5405,7 @@ async function captureFaceSilently() {
|
|
|
5387
5405
|
detectFace2().then((hasFace) => {
|
|
5388
5406
|
if (!hasFace && faceDetectionAttempts < MAX_FACE_DETECTION_ATTEMPTS) {
|
|
5389
5407
|
faceDetectionAttempts++;
|
|
5390
|
-
setTimeout(tryCapture,
|
|
5408
|
+
setTimeout(tryCapture, 150);
|
|
5391
5409
|
return;
|
|
5392
5410
|
}
|
|
5393
5411
|
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
@@ -5405,9 +5423,26 @@ async function captureFaceSilently() {
|
|
|
5405
5423
|
);
|
|
5406
5424
|
});
|
|
5407
5425
|
};
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5426
|
+
const playPromise = video.play();
|
|
5427
|
+
if (playPromise !== void 0) {
|
|
5428
|
+
playPromise.then(() => {
|
|
5429
|
+
if (video.videoWidth && video.videoHeight) {
|
|
5430
|
+
setTimeout(tryCapture, CAMERA_READY_DELAY);
|
|
5431
|
+
} else {
|
|
5432
|
+
video.onloadedmetadata = () => setTimeout(tryCapture, CAMERA_READY_DELAY);
|
|
5433
|
+
setTimeout(() => {
|
|
5434
|
+
if (video.videoWidth && video.videoHeight) {
|
|
5435
|
+
tryCapture();
|
|
5436
|
+
}
|
|
5437
|
+
}, 1500);
|
|
5438
|
+
}
|
|
5439
|
+
}).catch((err) => {
|
|
5440
|
+
cleanup();
|
|
5441
|
+
reject(new NeoFaceError("Erro ao reproduzir câmera: " + err.message, ErrorType.CAMERA_ERROR));
|
|
5442
|
+
});
|
|
5443
|
+
} else {
|
|
5444
|
+
video.onloadedmetadata = () => setTimeout(tryCapture, CAMERA_READY_DELAY);
|
|
5445
|
+
}
|
|
5411
5446
|
video.onerror = () => {
|
|
5412
5447
|
cleanup();
|
|
5413
5448
|
reject(new NeoFaceError("Erro ao acessar câmera", ErrorType.CAMERA_ERROR));
|
|
@@ -5481,27 +5516,55 @@ async function attemptLogin(applicationToken, overlay, fastMode = false, isRetry
|
|
|
5481
5516
|
video.style.width = "1px";
|
|
5482
5517
|
video.style.height = "1px";
|
|
5483
5518
|
video.style.opacity = "0";
|
|
5519
|
+
video.muted = true;
|
|
5520
|
+
video.playsInline = true;
|
|
5484
5521
|
video.setAttribute("autoplay", "");
|
|
5485
|
-
video.setAttribute("muted", "");
|
|
5486
5522
|
video.setAttribute("playsinline", "");
|
|
5487
5523
|
document.body.appendChild(video);
|
|
5488
5524
|
let stream = null;
|
|
5489
5525
|
try {
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5526
|
+
try {
|
|
5527
|
+
stream = await navigator.mediaDevices.getUserMedia({
|
|
5528
|
+
video: {
|
|
5529
|
+
width: { ideal: 640 },
|
|
5530
|
+
height: { ideal: 480 },
|
|
5531
|
+
facingMode: "user"
|
|
5532
|
+
},
|
|
5533
|
+
audio: false
|
|
5534
|
+
});
|
|
5535
|
+
} catch {
|
|
5536
|
+
stream = await navigator.mediaDevices.getUserMedia({
|
|
5537
|
+
video: { facingMode: "user" },
|
|
5538
|
+
audio: false
|
|
5539
|
+
});
|
|
5540
|
+
}
|
|
5498
5541
|
video.srcObject = stream;
|
|
5542
|
+
await new Promise((resolve) => {
|
|
5543
|
+
if (video.readyState >= 1) {
|
|
5544
|
+
resolve();
|
|
5545
|
+
} else {
|
|
5546
|
+
const handler = () => {
|
|
5547
|
+
video.removeEventListener("loadedmetadata", handler);
|
|
5548
|
+
resolve();
|
|
5549
|
+
};
|
|
5550
|
+
video.addEventListener("loadedmetadata", handler);
|
|
5551
|
+
setTimeout(resolve, 2e3);
|
|
5552
|
+
}
|
|
5553
|
+
});
|
|
5499
5554
|
await video.play();
|
|
5500
5555
|
await new Promise((resolve) => {
|
|
5501
|
-
if (video.
|
|
5502
|
-
resolve(
|
|
5556
|
+
if (video.videoWidth && video.videoHeight) {
|
|
5557
|
+
resolve();
|
|
5503
5558
|
} else {
|
|
5504
|
-
|
|
5559
|
+
const checkSize = () => {
|
|
5560
|
+
if (video.videoWidth && video.videoHeight) {
|
|
5561
|
+
resolve();
|
|
5562
|
+
} else {
|
|
5563
|
+
setTimeout(checkSize, 100);
|
|
5564
|
+
}
|
|
5565
|
+
};
|
|
5566
|
+
setTimeout(resolve, 3e3);
|
|
5567
|
+
checkSize();
|
|
5505
5568
|
}
|
|
5506
5569
|
});
|
|
5507
5570
|
overlay.updateStatus("detecting");
|
|
@@ -5971,8 +6034,8 @@ const biometricDetection = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.
|
|
|
5971
6034
|
initializeBiometricDetection,
|
|
5972
6035
|
isAdvancedDetectionAvailable
|
|
5973
6036
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
5974
|
-
const VERSION = "1.13.
|
|
5975
|
-
const RELEASE_DATE = "2026-02-
|
|
6037
|
+
const VERSION = "1.13.2";
|
|
6038
|
+
const RELEASE_DATE = "2026-02-21";
|
|
5976
6039
|
class OnboardingCaptureModal {
|
|
5977
6040
|
constructor(options) {
|
|
5978
6041
|
__publicField(this, "overlay", null);
|
|
@@ -6023,7 +6086,7 @@ class OnboardingCaptureModal {
|
|
|
6023
6086
|
<div class="neofaceid-modal-body">
|
|
6024
6087
|
<p class="neofaceid-subtitle">${this.subtitle ?? "Vamos capturar sua face e documento"}</p>
|
|
6025
6088
|
<div class="neofaceid-camera-container">
|
|
6026
|
-
<video class="neofaceid-video" autoplay playsinline></video>
|
|
6089
|
+
<video class="neofaceid-video" autoplay muted playsinline></video>
|
|
6027
6090
|
<canvas class="neofaceid-canvas"></canvas>
|
|
6028
6091
|
<div class="neofaceid-overlay">
|
|
6029
6092
|
<div class="neofaceid-frame"></div>
|
|
@@ -6074,12 +6137,20 @@ class OnboardingCaptureModal {
|
|
|
6074
6137
|
* Inicia a câmera do usuário com resolução adequada.
|
|
6075
6138
|
*/
|
|
6076
6139
|
async startCamera() {
|
|
6077
|
-
const constraints = {
|
|
6078
|
-
video: { facingMode: "user", width: { ideal: 1280 }, height: { ideal: 720 } },
|
|
6079
|
-
audio: false
|
|
6080
|
-
};
|
|
6081
|
-
this.stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
6082
6140
|
if (!this.video) throw new Error("Elemento de vídeo não encontrado");
|
|
6141
|
+
this.video.muted = true;
|
|
6142
|
+
this.video.playsInline = true;
|
|
6143
|
+
try {
|
|
6144
|
+
this.stream = await navigator.mediaDevices.getUserMedia({
|
|
6145
|
+
video: { facingMode: "user", width: { ideal: 1280 }, height: { ideal: 720 } },
|
|
6146
|
+
audio: false
|
|
6147
|
+
});
|
|
6148
|
+
} catch {
|
|
6149
|
+
this.stream = await navigator.mediaDevices.getUserMedia({
|
|
6150
|
+
video: { facingMode: "user" },
|
|
6151
|
+
audio: false
|
|
6152
|
+
});
|
|
6153
|
+
}
|
|
6083
6154
|
this.video.srcObject = this.stream;
|
|
6084
6155
|
await this.video.play();
|
|
6085
6156
|
}
|
|
@@ -6759,7 +6830,7 @@ class DocumentCaptureModal {
|
|
|
6759
6830
|
|
|
6760
6831
|
<div class="neoface-doc-body">
|
|
6761
6832
|
<div class="neoface-doc-camera-container">
|
|
6762
|
-
<video class="neoface-doc-video" autoplay playsinline></video>
|
|
6833
|
+
<video class="neoface-doc-video" autoplay muted playsinline></video>
|
|
6763
6834
|
<canvas class="neoface-doc-canvas"></canvas>
|
|
6764
6835
|
|
|
6765
6836
|
<div class="neoface-doc-guide">
|
|
@@ -7011,6 +7082,8 @@ class DocumentCaptureModal {
|
|
|
7011
7082
|
this.video = (_a = this.overlay) == null ? void 0 : _a.querySelector(".neoface-doc-video");
|
|
7012
7083
|
this.canvas = (_b = this.overlay) == null ? void 0 : _b.querySelector(".neoface-doc-canvas");
|
|
7013
7084
|
if (this.video) {
|
|
7085
|
+
this.video.muted = true;
|
|
7086
|
+
this.video.playsInline = true;
|
|
7014
7087
|
this.video.srcObject = this.stream;
|
|
7015
7088
|
await this.video.play();
|
|
7016
7089
|
}
|