@neofaceid/web-sdk 1.10.0 → 1.11.1

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.
@@ -1124,7 +1124,7 @@ var ErrorType = /* @__PURE__ */ ((ErrorType2) => {
1124
1124
  class NeoFaceError extends Error {
1125
1125
  /**
1126
1126
  * Constrói um erro do SDK com mensagem e tipo categórico.
1127
- * @param message Mensagem descritiva do erro
1127
+ * @param message Mensagem descritiva do erro (pode ser técnica)
1128
1128
  * @param type Tipo categórico do erro
1129
1129
  */
1130
1130
  constructor(message, type) {
@@ -1133,6 +1133,35 @@ class NeoFaceError extends Error {
1133
1133
  this.name = type;
1134
1134
  this.type = type;
1135
1135
  }
1136
+ /**
1137
+ * Retorna uma mensagem amigável para o usuário final, ocultando termos técnicos.
1138
+ */
1139
+ getFriendlyMessage() {
1140
+ if (/[áéíóúãõç]/i.test(this.message)) {
1141
+ return this.message;
1142
+ }
1143
+ switch (this.type) {
1144
+ case "NetworkError":
1145
+ if (this.message.includes("timeout")) return "A conexão demorou muito. Tente novamente.";
1146
+ return "Não foi possível conectar ao servidor. Verifique sua internet.";
1147
+ case "InvalidTokenError":
1148
+ return "Falha na autenticação do aplicativo. Entre em contato com o suporte.";
1149
+ case "CameraError":
1150
+ case "NoCameraError":
1151
+ return "Não conseguimos acessar sua câmera. Verifique as permissões do navegador.";
1152
+ case "LoginFailedError":
1153
+ case "RecognitionFailedError":
1154
+ return "Não foi possível reconhecer seu rosto. Tente se posicionar em um local mais iluminado.";
1155
+ case "ValidationError":
1156
+ return "Dados inválidos ou rosto não detectado corretamente.";
1157
+ case "ApiError":
1158
+ if (this.message.includes("400")) return "Requisição inválida. Tente novamente.";
1159
+ if (this.message.includes("500")) return "Ocorreu um erro interno no sistema. Tente mais tarde.";
1160
+ return "O serviço encontrou um problema inesperado.";
1161
+ default:
1162
+ return "Ocorreu um erro inesperado. Por favor, tente novamente.";
1163
+ }
1164
+ }
1136
1165
  }
1137
1166
  const __vite_import_meta_env__ = {};
1138
1167
  const ENVIRONMENT_URLS = {
@@ -1291,15 +1320,18 @@ const validateToken = async (applicationToken) => {
1291
1320
  body: JSON.stringify({}),
1292
1321
  signal: controller.signal
1293
1322
  });
1323
+ if (!response.ok) {
1324
+ throw new NeoFaceError(`API Error ${response.status}`, ErrorType.INVALID_TOKEN);
1325
+ }
1294
1326
  return response.ok;
1295
1327
  } catch (error) {
1296
1328
  if (error instanceof Error) {
1297
1329
  if (error.name === "AbortError") {
1298
- throw new NeoFaceError("Request timed out", ErrorType.NETWORK_ERROR);
1330
+ throw new NeoFaceError("Request timeout", ErrorType.NETWORK_ERROR);
1299
1331
  }
1300
1332
  throw new NeoFaceError(error.message, ErrorType.NETWORK_ERROR);
1301
1333
  }
1302
- throw new NeoFaceError("Unknown error occurred", ErrorType.NETWORK_ERROR);
1334
+ throw new NeoFaceError("Unknown error", ErrorType.NETWORK_ERROR);
1303
1335
  }
1304
1336
  };
1305
1337
  const getOnboardingDetails = async (applicationToken, onboardingToken) => {
@@ -1554,7 +1586,7 @@ const recognize = async (image, applicationToken) => {
1554
1586
  throw new NeoFaceError("Unknown error occurred", ErrorType.NETWORK_ERROR);
1555
1587
  }
1556
1588
  };
1557
- const loginWithBiometric$1 = async (image, applicationToken) => {
1589
+ const loginWithBiometric = async (image, applicationToken) => {
1558
1590
  var _a, _b, _c, _d, _e;
1559
1591
  ensureSecureContext();
1560
1592
  const controller = createTimeoutController();
@@ -1578,9 +1610,12 @@ const loginWithBiometric$1 = async (image, applicationToken) => {
1578
1610
  });
1579
1611
  if (!response.ok) {
1580
1612
  if (response.status === 401 || response.status === 403) {
1581
- throw new NeoFaceError("Invalid or expired application token", ErrorType.INVALID_TOKEN);
1613
+ throw new NeoFaceError("Invalid application token", ErrorType.INVALID_TOKEN);
1582
1614
  }
1583
- throw new NeoFaceError(`Server returned status ${response.status}`, ErrorType.NETWORK);
1615
+ if (response.status >= 500) {
1616
+ throw new NeoFaceError(`Server Error ${response.status}`, ErrorType.API_ERROR);
1617
+ }
1618
+ throw new NeoFaceError(`API Error ${response.status}`, ErrorType.API_ERROR);
1584
1619
  }
1585
1620
  const data = await response.json();
1586
1621
  if (!data.success) {
@@ -2003,9 +2038,9 @@ const loginWithEmail = async (email, password, applicationToken) => {
2003
2038
  });
2004
2039
  if (!response.ok) {
2005
2040
  if (response.status === 401 || response.status === 403) {
2006
- throw new NeoFaceError("Invalid credentials or application token", ErrorType.INVALID_TOKEN);
2041
+ throw new NeoFaceError("Email ou senha inválidos", ErrorType.INVALID_TOKEN);
2007
2042
  }
2008
- throw new NeoFaceError(`Server returned status ${response.status}`, ErrorType.NETWORK);
2043
+ throw new NeoFaceError(`API Error ${response.status}`, ErrorType.API_ERROR);
2009
2044
  }
2010
2045
  const data = await response.json();
2011
2046
  return {
@@ -3848,7 +3883,7 @@ function BiometricRegistrationModal({
3848
3883
  /* @__PURE__ */ jsxRuntimeExports.jsx("canvas", { ref: canvasRef })
3849
3884
  ] });
3850
3885
  }
3851
- let BiometricCaptureModal$1 = class BiometricCaptureModal2 {
3886
+ class BiometricCaptureModal {
3852
3887
  constructor(options) {
3853
3888
  __publicField(this, "modal", null);
3854
3889
  __publicField(this, "video", null);
@@ -4342,7 +4377,7 @@ let BiometricCaptureModal$1 = class BiometricCaptureModal2 {
4342
4377
  `;
4343
4378
  document.head.appendChild(style);
4344
4379
  }
4345
- };
4380
+ }
4346
4381
  class BiometricStatusOverlay {
4347
4382
  constructor() {
4348
4383
  __publicField(this, "container", null);
@@ -4366,43 +4401,21 @@ class BiometricStatusOverlay {
4366
4401
  opacity: 1;
4367
4402
  }
4368
4403
  50% {
4369
- transform: scale(1.1);
4404
+ transform: scale(1.05);
4370
4405
  opacity: 0.9;
4371
4406
  }
4372
4407
  }
4373
4408
 
4374
- @keyframes neofaceid-checkmark {
4375
- 0% {
4376
- stroke-dashoffset: 100;
4377
- opacity: 0;
4378
- }
4379
- 50% {
4380
- opacity: 1;
4381
- }
4382
- 100% {
4383
- stroke-dashoffset: 0;
4384
- opacity: 1;
4385
- }
4409
+ @keyframes neofaceid-scaleIn {
4410
+ 0% { transform: scale(0); opacity: 0; }
4411
+ 50% { transform: scale(1.1); }
4412
+ 100% { transform: scale(1); opacity: 1; }
4386
4413
  }
4387
4414
 
4388
4415
  @keyframes neofaceid-errorShake {
4389
- 0%, 100% { transform: translateX(0) scale(1); }
4390
- 10%, 30%, 50%, 70%, 90% { transform: translateX(-4px) scale(1); }
4391
- 20%, 40%, 60%, 80% { transform: translateX(4px) scale(1); }
4392
- }
4393
-
4394
- @keyframes neofaceid-scaleIn {
4395
- 0% {
4396
- transform: scale(0);
4397
- opacity: 0;
4398
- }
4399
- 50% {
4400
- transform: scale(1.1);
4401
- }
4402
- 100% {
4403
- transform: scale(1);
4404
- opacity: 1;
4405
- }
4416
+ 0%, 100% { transform: translateX(0); }
4417
+ 10%, 30%, 50%, 70%, 90% { transform: translateX(-4px); }
4418
+ 20%, 40%, 60%, 80% { transform: translateX(4px); }
4406
4419
  }
4407
4420
 
4408
4421
  .neofaceid-overlay-container {
@@ -4417,6 +4430,7 @@ class BiometricStatusOverlay {
4417
4430
  z-index: 10000;
4418
4431
  pointer-events: none;
4419
4432
  animation: neofaceid-fadeIn 0.3s ease-out;
4433
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
4420
4434
  }
4421
4435
 
4422
4436
  .neofaceid-overlay-container.fade-out {
@@ -4432,10 +4446,10 @@ class BiometricStatusOverlay {
4432
4446
  pointer-events: auto;
4433
4447
  }
4434
4448
 
4435
- .neofaceid-logo-wrapper {
4449
+ .neofaceid-visual-wrapper {
4436
4450
  position: relative;
4437
- width: 120px;
4438
- height: 120px;
4451
+ width: 100px;
4452
+ height: 100px;
4439
4453
  display: flex;
4440
4454
  align-items: center;
4441
4455
  justify-content: center;
@@ -4445,13 +4459,57 @@ class BiometricStatusOverlay {
4445
4459
  width: 80px;
4446
4460
  height: 80px;
4447
4461
  object-fit: contain;
4462
+ transition: all 0.5s ease;
4448
4463
  filter: drop-shadow(0 4px 12px rgba(124, 58, 237, 0.3));
4449
4464
  }
4450
4465
 
4466
+ /* Cores por estado */
4467
+ .neofaceid-state-preparing .neofaceid-logo { filter: drop-shadow(0 0 15px rgba(124, 58, 237, 0.4)); }
4468
+ .neofaceid-state-detecting .neofaceid-logo { filter: hue-rotate(180deg) drop-shadow(0 0 15px rgba(59, 130, 246, 0.6)); }
4469
+ .neofaceid-state-capturing .neofaceid-logo { filter: hue-rotate(45deg) drop-shadow(0 0 15px rgba(245, 158, 11, 0.6)); }
4470
+ .neofaceid-state-verifying .neofaceid-logo { filter: hue-rotate(90deg) drop-shadow(0 0 15px rgba(34, 197, 94, 0.6)); }
4471
+
4451
4472
  .neofaceid-logo.pulsing {
4452
4473
  animation: neofaceid-pulse 2s ease-in-out infinite;
4453
4474
  }
4454
4475
 
4476
+ @keyframes neofaceid-dots {
4477
+ 0%, 20% { opacity: 0; transform: translateY(0); }
4478
+ 50% { opacity: 1; transform: translateY(-2px); }
4479
+ 80%, 100% { opacity: 0; transform: translateY(0); }
4480
+ }
4481
+
4482
+ .neofaceid-status-text {
4483
+ font-size: 15px;
4484
+ font-weight: 500;
4485
+ color: #ffffff;
4486
+ text-align: center;
4487
+ padding: 10px 24px;
4488
+ background: rgba(15, 23, 42, 0.8);
4489
+ backdrop-filter: blur(8px);
4490
+ border-radius: 100px;
4491
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
4492
+ border: 1px solid rgba(255, 255, 255, 0.1);
4493
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
4494
+ animation: neofaceid-fadeIn 0.3s ease-out;
4495
+ display: flex;
4496
+ align-items: center;
4497
+ gap: 2px;
4498
+ }
4499
+
4500
+ .neofaceid-dots {
4501
+ display: inline-flex;
4502
+ margin-left: 2px;
4503
+ }
4504
+
4505
+ .neofaceid-dot {
4506
+ animation: neofaceid-dots 1.5s infinite;
4507
+ opacity: 0;
4508
+ }
4509
+
4510
+ .neofaceid-dot:nth-child(2) { animation-delay: 0.2s; }
4511
+ .neofaceid-dot:nth-child(3) { animation-delay: 0.4s; }
4512
+
4455
4513
  .neofaceid-status-icon {
4456
4514
  position: absolute;
4457
4515
  inset: 0;
@@ -4461,42 +4519,50 @@ class BiometricStatusOverlay {
4461
4519
  }
4462
4520
 
4463
4521
  .neofaceid-success-icon {
4464
- width: 60px;
4465
- height: 60px;
4522
+ width: 80px;
4523
+ height: 80px;
4466
4524
  color: #10b981;
4467
- animation: neofaceid-scaleIn 0.6s ease-out;
4525
+ animation: neofaceid-scaleIn 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
4468
4526
  }
4469
4527
 
4470
4528
  .neofaceid-error-icon {
4471
- width: 60px;
4472
- height: 60px;
4529
+ width: 80px;
4530
+ height: 80px;
4473
4531
  color: #ef4444;
4474
- animation: neofaceid-errorShake 0.5s ease-out, neofaceid-scaleIn 0.4s ease-out;
4475
- }
4476
-
4477
- @media (max-width: 640px) {
4478
- .neofaceid-logo-wrapper {
4479
- width: 100px;
4480
- height: 100px;
4481
- }
4482
-
4483
- .neofaceid-logo {
4484
- width: 70px;
4485
- height: 70px;
4486
- }
4532
+ animation: neofaceid-errorShake 0.5s linear, neofaceid-scaleIn 0.4s ease-out;
4487
4533
  }
4488
4534
  `;
4489
4535
  }
4536
+ getStatusText() {
4537
+ switch (this.currentStatus) {
4538
+ case "preparing":
4539
+ return "Iniciando câmera";
4540
+ case "detecting":
4541
+ return "Posicione seu rosto";
4542
+ case "capturing":
4543
+ return "Capturando";
4544
+ case "verifying":
4545
+ return "Verificando identidade";
4546
+ case "success":
4547
+ return "Identificado!";
4548
+ case "error":
4549
+ return "Falha na identificação";
4550
+ default:
4551
+ return "";
4552
+ }
4553
+ }
4490
4554
  renderContent() {
4491
- const isPulsing = this.currentStatus === "verifying";
4492
- const showLogo = this.currentStatus === "preparing" || this.currentStatus === "verifying";
4555
+ const isPulsing = ["detecting", "verifying"].includes(this.currentStatus);
4556
+ const showLogo = !["success", "error"].includes(this.currentStatus);
4493
4557
  const showSuccess = this.currentStatus === "success";
4494
4558
  const showError = this.currentStatus === "error";
4559
+ const statusText = this.getStatusText();
4560
+ const showDots = ["preparing", "detecting", "capturing", "verifying"].includes(this.currentStatus);
4495
4561
  return `
4496
4562
  <style>${this.getStyles()}</style>
4497
- <div class="neofaceid-overlay-container">
4563
+ <div class="neofaceid-overlay-container neofaceid-state-${this.currentStatus}">
4498
4564
  <div class="neofaceid-overlay-content">
4499
- <div class="neofaceid-logo-wrapper">
4565
+ <div class="neofaceid-visual-wrapper">
4500
4566
  ${showLogo ? `
4501
4567
  <img
4502
4568
  src="/logo-icone-no-background.png"
@@ -4524,13 +4590,22 @@ class BiometricStatusOverlay {
4524
4590
  </div>
4525
4591
  ` : ""}
4526
4592
  </div>
4593
+
4594
+ ${statusText ? `
4595
+ <div class="neofaceid-status-text">
4596
+ ${statusText}${showDots ? `
4597
+ <span class="neofaceid-dots">
4598
+ <span class="neofaceid-dot">.</span>
4599
+ <span class="neofaceid-dot">.</span>
4600
+ <span class="neofaceid-dot">.</span>
4601
+ </span>
4602
+ ` : ""}
4603
+ </div>
4604
+ ` : ""}
4527
4605
  </div>
4528
4606
  </div>
4529
4607
  `;
4530
4608
  }
4531
- /**
4532
- * Cria e exibe o overlay
4533
- */
4534
4609
  show(status = "preparing") {
4535
4610
  if (this.container) {
4536
4611
  this.updateStatus(status);
@@ -4542,18 +4617,12 @@ class BiometricStatusOverlay {
4542
4617
  this.container.innerHTML = this.renderContent();
4543
4618
  document.body.appendChild(this.container);
4544
4619
  }
4545
- /**
4546
- * Atualiza o status do overlay
4547
- */
4548
4620
  updateStatus(status) {
4549
4621
  this.currentStatus = status;
4550
4622
  if (this.container) {
4551
4623
  this.container.innerHTML = this.renderContent();
4552
4624
  }
4553
4625
  }
4554
- /**
4555
- * Fecha e remove o overlay
4556
- */
4557
4626
  close() {
4558
4627
  if (this.container) {
4559
4628
  const overlayElement = this.container.querySelector(".neofaceid-overlay-container");
@@ -4732,7 +4801,7 @@ function FallbackPromptComponent({
4732
4801
  )
4733
4802
  ] }) }),
4734
4803
  /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "neofaceid-fallback-title", children: "Não foi possível reconhecer" }),
4735
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "neofaceid-fallback-message", children: (error == null ? void 0 : error.message) || "Não conseguimos reconhecer sua face. Tente novamente ou use email e senha." }),
4804
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "neofaceid-fallback-message", children: (error == null ? void 0 : error.getFriendlyMessage()) || "Não conseguimos reconhecer sua face. Tente novamente ou use email e senha." }),
4736
4805
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "neofaceid-fallback-actions", children: [
4737
4806
  /* @__PURE__ */ jsxRuntimeExports.jsx(
4738
4807
  "button",
@@ -5272,8 +5341,12 @@ async function detectFaceQuickly(video, maxTime = FACE_DETECTION_TIME, interval
5272
5341
  checkFace();
5273
5342
  });
5274
5343
  }
5275
- async function attemptLogin(applicationToken, overlay, fastMode = false) {
5276
- overlay.updateStatus("verifying");
5344
+ async function attemptLogin(applicationToken, overlay, fastMode = false, isRetry = false) {
5345
+ if (!isRetry) {
5346
+ overlay.updateStatus("preparing");
5347
+ } else {
5348
+ overlay.updateStatus("detecting");
5349
+ }
5277
5350
  const video = document.createElement("video");
5278
5351
  video.style.position = "fixed";
5279
5352
  video.style.top = "-9999px";
@@ -5304,6 +5377,7 @@ async function attemptLogin(applicationToken, overlay, fastMode = false) {
5304
5377
  video.onloadedmetadata = () => resolve(void 0);
5305
5378
  }
5306
5379
  });
5380
+ overlay.updateStatus("detecting");
5307
5381
  await new Promise((resolve) => setTimeout(resolve, CAMERA_STABILITY_DELAY));
5308
5382
  let faceDetected = true;
5309
5383
  if (!fastMode) {
@@ -5318,6 +5392,7 @@ async function attemptLogin(applicationToken, overlay, fastMode = false) {
5318
5392
  }
5319
5393
  throw new NeoFaceError("Rosto não detectado. Posicione seu rosto na frente da câmera.", ErrorType.VALIDATION_ERROR);
5320
5394
  }
5395
+ overlay.updateStatus("capturing");
5321
5396
  const canvas = document.createElement("canvas");
5322
5397
  canvas.width = video.videoWidth;
5323
5398
  canvas.height = video.videoHeight;
@@ -5352,7 +5427,8 @@ async function attemptLogin(applicationToken, overlay, fastMode = false) {
5352
5427
  0.85
5353
5428
  );
5354
5429
  });
5355
- const result = await loginWithBiometric$1(imageBlob, applicationToken);
5430
+ overlay.updateStatus("verifying");
5431
+ const result = await loginWithBiometric(imageBlob, applicationToken);
5356
5432
  if (!result.success) {
5357
5433
  throw new NeoFaceError("Login falhou", ErrorType.LOGIN_FAILED);
5358
5434
  }
@@ -5387,7 +5463,7 @@ async function executeBiometricLoginFlow(options) {
5387
5463
  const tryLogin = async () => {
5388
5464
  try {
5389
5465
  attempts++;
5390
- const result = await attemptLogin(applicationToken, overlay, fastMode);
5466
+ const result = await attemptLogin(applicationToken, overlay, fastMode, attempts > 1);
5391
5467
  overlay.updateStatus("success");
5392
5468
  setTimeout(() => {
5393
5469
  overlay.close();
@@ -5768,8 +5844,8 @@ const biometricDetection = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.
5768
5844
  initializeBiometricDetection,
5769
5845
  isAdvancedDetectionAvailable
5770
5846
  }, Symbol.toStringTag, { value: "Module" }));
5771
- const VERSION = "1.10.0";
5772
- const RELEASE_DATE = "2026-01-21";
5847
+ const VERSION = "1.11.1";
5848
+ const RELEASE_DATE = "2026-02-12";
5773
5849
  class OnboardingCaptureModal {
5774
5850
  constructor(options) {
5775
5851
  __publicField(this, "overlay", null);
@@ -7488,7 +7564,7 @@ function startLivenessCapture(applicationToken, callbacks) {
7488
7564
  });
7489
7565
  }
7490
7566
  export {
7491
- BiometricCaptureModal$1 as BiometricCaptureModal,
7567
+ BiometricCaptureModal,
7492
7568
  BiometricRegistrationModal,
7493
7569
  BiometricStatusOverlay,
7494
7570
  DocumentCaptureModal,
@@ -7516,7 +7592,7 @@ export {
7516
7592
  initializeBiometricDetection,
7517
7593
  isAdvancedDetectionAvailable,
7518
7594
  isInitialized,
7519
- loginWithBiometric$1 as loginWithBiometric,
7595
+ loginWithBiometric,
7520
7596
  loginWithEmail,
7521
7597
  preloadFaceDetectionModels,
7522
7598
  recognize,