@neofaceid/web-sdk 1.26.1 → 1.28.0

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.
@@ -8064,156 +8064,289 @@ function BiometricRegistrationModal({
8064
8064
  /* @__PURE__ */ jsx("canvas", { ref: canvasRef })
8065
8065
  ] });
8066
8066
  }
8067
+ const DEFAULT_PRIVACY_URL = "https://neofaceid.com/privacidade";
8068
+ const DEFAULT_RETENTION_DAYS = 90;
8069
+ const COPY = {
8070
+ verification: {
8071
+ title: "Vamos confirmar que é você",
8072
+ duration: "Leva cerca de 20 segundos e usa a câmera do seu dispositivo.",
8073
+ bullet1Title: "Sua câmera liga agora",
8074
+ bullet1Body: "Você vê a imagem o tempo todo e pode encerrar quando quiser.",
8075
+ bullet2Title: "Pediremos dois movimentos simples",
8076
+ bullet2Body: "Virar o rosto ou piscar — é assim que sabemos que há alguém ali.",
8077
+ bullet3Title: "A imagem não fica guardada",
8078
+ bullet3Body: "Ela é usada para a verificação e descartada em seguida.",
8079
+ primary: "Começar verificação"
8080
+ },
8081
+ registration: {
8082
+ title: "Vamos cadastrar seu rosto",
8083
+ duration: "Leva cerca de 20 segundos e usa a câmera do seu dispositivo.",
8084
+ bullet1Title: "Sua câmera liga agora",
8085
+ bullet1Body: "Você vê a imagem o tempo todo e pode encerrar quando quiser.",
8086
+ bullet2Title: "Pediremos dois movimentos simples",
8087
+ bullet2Body: "Virar o rosto ou piscar — é assim que sabemos que há alguém ali.",
8088
+ bullet3Title: "Guardamos um vetor matemático do seu rosto",
8089
+ bullet3Body: "Não a foto. A imagem é descartada.",
8090
+ primary: "Começar cadastro"
8091
+ }
8092
+ };
8093
+ const IconCamera = () => /* @__PURE__ */ jsxs(
8094
+ "svg",
8095
+ {
8096
+ width: "24",
8097
+ height: "24",
8098
+ viewBox: "0 0 24 24",
8099
+ fill: "none",
8100
+ stroke: "currentColor",
8101
+ strokeWidth: "1.75",
8102
+ strokeLinecap: "round",
8103
+ strokeLinejoin: "round",
8104
+ "aria-hidden": "true",
8105
+ children: [
8106
+ /* @__PURE__ */ jsx("path", { d: "M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3Z" }),
8107
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "13", r: "4" })
8108
+ ]
8109
+ }
8110
+ );
8111
+ const IconGesture = () => /* @__PURE__ */ jsxs(
8112
+ "svg",
8113
+ {
8114
+ width: "24",
8115
+ height: "24",
8116
+ viewBox: "0 0 24 24",
8117
+ fill: "none",
8118
+ stroke: "currentColor",
8119
+ strokeWidth: "1.75",
8120
+ strokeLinecap: "round",
8121
+ strokeLinejoin: "round",
8122
+ "aria-hidden": "true",
8123
+ children: [
8124
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "9" }),
8125
+ /* @__PURE__ */ jsx("path", { d: "M4 12h16" }),
8126
+ /* @__PURE__ */ jsx("path", { d: "M15 8l4 4-4 4" })
8127
+ ]
8128
+ }
8129
+ );
8130
+ const IconShield = () => /* @__PURE__ */ jsxs(
8131
+ "svg",
8132
+ {
8133
+ width: "24",
8134
+ height: "24",
8135
+ viewBox: "0 0 24 24",
8136
+ fill: "none",
8137
+ stroke: "currentColor",
8138
+ strokeWidth: "1.75",
8139
+ strokeLinecap: "round",
8140
+ strokeLinejoin: "round",
8141
+ "aria-hidden": "true",
8142
+ children: [
8143
+ /* @__PURE__ */ jsx("path", { d: "M12 2 4 5v7c0 5 3.5 8.5 8 10 4.5-1.5 8-5 8-10V5l-8-3Z" }),
8144
+ /* @__PURE__ */ jsx("path", { d: "m9 12 2 2 4-4" })
8145
+ ]
8146
+ }
8147
+ );
8067
8148
  function ConsentModalComponent({
8068
- purpose,
8069
- legalBasis,
8070
- privacyPolicyUrl,
8071
- retentionDays,
8149
+ appName,
8150
+ flow,
8151
+ privacyPolicyUrl = DEFAULT_PRIVACY_URL,
8152
+ retentionDays = DEFAULT_RETENTION_DAYS,
8072
8153
  onAccept,
8073
8154
  onDecline
8074
8155
  }) {
8156
+ const copy = COPY[flow];
8075
8157
  return /* @__PURE__ */ jsxs(Fragment, { children: [
8076
8158
  /* @__PURE__ */ jsx("style", { children: `
8077
- @keyframes neofaceidConsentFadeIn {
8078
- from { opacity: 0; }
8079
- to { opacity: 1; }
8080
- }
8081
-
8159
+ @keyframes neofaceidConsentFadeIn { from { opacity: 0 } to { opacity: 1 } }
8082
8160
  @keyframes neofaceidConsentSlideUp {
8083
- from {
8084
- opacity: 0;
8085
- transform: translateY(20px);
8086
- }
8087
- to {
8088
- opacity: 1;
8089
- transform: translateY(0);
8090
- }
8161
+ from { opacity: 0; transform: translateY(12px) }
8162
+ to { opacity: 1; transform: translateY(0) }
8091
8163
  }
8092
-
8093
8164
  .neofaceid-consent-overlay {
8094
- position: fixed;
8095
- inset: 0;
8096
- background: rgba(0, 0, 0, 0.6);
8097
- backdrop-filter: blur(8px);
8098
- display: flex;
8099
- align-items: center;
8100
- justify-content: center;
8101
- z-index: 10001;
8102
- padding: 20px;
8103
- animation: neofaceidConsentFadeIn 0.3s ease-out;
8104
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
8165
+ position: fixed; inset: 0;
8166
+ background: rgba(10, 19, 32, 0.55);
8167
+ backdrop-filter: blur(3px);
8168
+ -webkit-backdrop-filter: blur(3px);
8169
+ display: flex; align-items: center; justify-content: center;
8170
+ z-index: 10001; padding: 20px;
8171
+ animation: neofaceidConsentFadeIn 200ms ease-out;
8172
+ font-family: inherit;
8173
+ color: #0A1320;
8105
8174
  }
8106
-
8107
8175
  .neofaceid-consent-modal {
8108
- background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
8109
- border-radius: 20px;
8110
- padding: 32px;
8111
- max-width: 420px;
8176
+ background: #FFFFFF;
8177
+ border-radius: 16px;
8178
+ padding: 28px;
8179
+ max-width: 440px;
8112
8180
  width: 100%;
8113
- box-shadow: 0 24px 48px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.1);
8114
- animation: neofaceidConsentSlideUp 0.4s ease-out;
8181
+ box-shadow: 0 1px 3px rgba(10, 19, 32, 0.08);
8182
+ animation: neofaceidConsentSlideUp 320ms cubic-bezier(.2,0,0,1);
8183
+ box-sizing: border-box;
8184
+ }
8185
+ .neofaceid-consent-header {
8186
+ display: flex;
8187
+ align-items: baseline;
8188
+ gap: 10px;
8189
+ margin-bottom: 20px;
8190
+ }
8191
+ .neofaceid-consent-appname {
8192
+ font-size: 17px;
8193
+ font-weight: 700;
8194
+ color: #0A1320;
8195
+ line-height: 1.2;
8196
+ }
8197
+ .neofaceid-consent-brand-caption {
8198
+ font-size: 11px;
8199
+ font-weight: 700;
8200
+ letter-spacing: 0.09em;
8201
+ text-transform: uppercase;
8202
+ color: #617489;
8115
8203
  }
8116
-
8117
8204
  .neofaceid-consent-title {
8118
- font-size: 20px;
8205
+ font-size: 22px;
8119
8206
  font-weight: 700;
8120
- color: white;
8121
- margin: 0 0 12px 0;
8207
+ color: #0A1320;
8208
+ margin: 0 0 8px;
8209
+ line-height: 1.25;
8210
+ letter-spacing: -0.015em;
8122
8211
  }
8123
-
8124
- .neofaceid-consent-message {
8212
+ .neofaceid-consent-duration {
8125
8213
  font-size: 14px;
8126
- color: rgba(255, 255, 255, 0.7);
8127
- margin: 0 0 16px 0;
8214
+ color: #48586B;
8215
+ margin: 0 0 20px;
8128
8216
  line-height: 1.5;
8129
8217
  }
8130
-
8218
+ .neofaceid-consent-bullets {
8219
+ display: flex;
8220
+ flex-direction: column;
8221
+ gap: 14px;
8222
+ margin-bottom: 20px;
8223
+ }
8224
+ .neofaceid-consent-bullet {
8225
+ display: flex;
8226
+ gap: 12px;
8227
+ align-items: flex-start;
8228
+ }
8229
+ .neofaceid-consent-bullet-icon {
8230
+ flex-shrink: 0;
8231
+ color: #0059C4;
8232
+ margin-top: 2px;
8233
+ }
8234
+ .neofaceid-consent-bullet-title {
8235
+ font-size: 14px;
8236
+ font-weight: 600;
8237
+ color: #0A1320;
8238
+ margin: 0 0 2px;
8239
+ line-height: 1.35;
8240
+ }
8241
+ .neofaceid-consent-bullet-body {
8242
+ font-size: 13px;
8243
+ color: #48586B;
8244
+ margin: 0;
8245
+ line-height: 1.45;
8246
+ }
8131
8247
  .neofaceid-consent-link {
8132
8248
  display: inline-block;
8133
- font-size: 14px;
8134
- color: #a78bfa;
8249
+ font-size: 13px;
8250
+ color: #0059C4;
8135
8251
  text-decoration: underline;
8136
- margin-bottom: 24px;
8137
- }
8138
-
8139
- .neofaceid-consent-link:hover {
8140
- color: #c4b5fd;
8252
+ margin-bottom: 20px;
8141
8253
  }
8142
-
8254
+ .neofaceid-consent-link:hover { color: #00449A; }
8143
8255
  .neofaceid-consent-actions {
8144
8256
  display: flex;
8145
8257
  flex-direction: column;
8146
- gap: 12px;
8258
+ gap: 10px;
8147
8259
  }
8148
-
8149
8260
  .neofaceid-consent-button {
8150
- padding: 14px 24px;
8151
- border-radius: 12px;
8261
+ min-height: 44px;
8262
+ padding: 12px 20px;
8263
+ border-radius: 16px;
8152
8264
  border: none;
8153
- font-size: 16px;
8265
+ font-size: 15px;
8154
8266
  font-weight: 600;
8155
8267
  cursor: pointer;
8156
- transition: all 0.2s;
8268
+ transition: background 120ms ease-out, transform 120ms ease-out;
8157
8269
  font-family: inherit;
8158
8270
  }
8159
-
8160
8271
  .neofaceid-consent-button-primary {
8161
- background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%);
8162
- color: white;
8163
- box-shadow: 0 4px 16px rgba(124, 58, 237, 0.3);
8272
+ background: #0059C4;
8273
+ color: #FFFFFF;
8164
8274
  }
8165
-
8166
- .neofaceid-consent-button-primary:hover {
8167
- transform: translateY(-2px);
8168
- box-shadow: 0 8px 24px rgba(124, 58, 237, 0.4);
8275
+ .neofaceid-consent-button-primary:hover { background: #00449A; }
8276
+ .neofaceid-consent-button-primary:focus-visible {
8277
+ outline: 2px solid #0059C4;
8278
+ outline-offset: 2px;
8169
8279
  }
8170
-
8171
- .neofaceid-consent-button-primary:active {
8172
- transform: translateY(0);
8280
+ .neofaceid-consent-button-ghost {
8281
+ background: transparent;
8282
+ color: #334255;
8173
8283
  }
8174
-
8175
- .neofaceid-consent-button-secondary {
8176
- background: rgba(255, 255, 255, 0.1);
8177
- color: white;
8178
- border: 1px solid rgba(255, 255, 255, 0.2);
8284
+ .neofaceid-consent-button-ghost:hover { background: #F1F5FA; }
8285
+ .neofaceid-consent-footer {
8286
+ display: flex;
8287
+ justify-content: center;
8288
+ margin-top: 20px;
8289
+ padding-top: 16px;
8290
+ border-top: 1px solid #E6ECF4;
8179
8291
  }
8180
-
8181
- .neofaceid-consent-button-secondary:hover {
8182
- background: rgba(255, 255, 255, 0.15);
8183
- border-color: rgba(255, 255, 255, 0.3);
8292
+ .neofaceid-consent-seal {
8293
+ font-size: 11px;
8294
+ font-weight: 700;
8295
+ letter-spacing: 0.09em;
8296
+ text-transform: uppercase;
8297
+ color: #617489;
8184
8298
  }
8185
-
8186
8299
  @media (max-width: 640px) {
8187
- .neofaceid-consent-modal {
8188
- padding: 24px;
8189
- border-radius: 16px;
8190
- }
8191
-
8192
- .neofaceid-consent-title {
8193
- font-size: 18px;
8194
- }
8300
+ .neofaceid-consent-modal { padding: 22px; border-radius: 16px; }
8301
+ .neofaceid-consent-title { font-size: 20px; }
8302
+ }
8303
+ @media (prefers-reduced-motion: reduce) {
8304
+ .neofaceid-consent-overlay,
8305
+ .neofaceid-consent-modal { animation: none; }
8195
8306
  }
8196
8307
  ` }),
8197
- /* @__PURE__ */ jsx("div", { className: "neofaceid-consent-overlay", children: /* @__PURE__ */ jsxs("div", { className: "neofaceid-consent-modal", children: [
8198
- /* @__PURE__ */ jsxs("h3", { className: "neofaceid-consent-title", children: [
8199
- "Uso do seu rosto para ",
8200
- purpose
8308
+ /* @__PURE__ */ jsx("div", { className: "neofaceid-consent-overlay", role: "dialog", "aria-modal": "true", "aria-labelledby": "neofaceid-consent-title", children: /* @__PURE__ */ jsxs("div", { className: "neofaceid-consent-modal", children: [
8309
+ /* @__PURE__ */ jsxs("div", { className: "neofaceid-consent-header", children: [
8310
+ /* @__PURE__ */ jsx("span", { className: "neofaceid-consent-appname", children: appName }),
8311
+ /* @__PURE__ */ jsx("span", { className: "neofaceid-consent-brand-caption", children: "NeoFaceID" })
8201
8312
  ] }),
8202
- /* @__PURE__ */ jsxs("p", { className: "neofaceid-consent-message", children: [
8203
- "Esta captura é realizada com base em ",
8204
- legalBasis,
8205
- ". Os dados biométricos coletados são retidos por até ",
8206
- retentionDays,
8207
- " dias, conforme a finalidade informada."
8313
+ /* @__PURE__ */ jsx("h1", { id: "neofaceid-consent-title", className: "neofaceid-consent-title", children: copy.title }),
8314
+ /* @__PURE__ */ jsx("p", { className: "neofaceid-consent-duration", children: copy.duration }),
8315
+ /* @__PURE__ */ jsxs("div", { className: "neofaceid-consent-bullets", children: [
8316
+ /* @__PURE__ */ jsxs("div", { className: "neofaceid-consent-bullet", children: [
8317
+ /* @__PURE__ */ jsx("div", { className: "neofaceid-consent-bullet-icon", children: /* @__PURE__ */ jsx(IconCamera, {}) }),
8318
+ /* @__PURE__ */ jsxs("div", { children: [
8319
+ /* @__PURE__ */ jsx("p", { className: "neofaceid-consent-bullet-title", children: copy.bullet1Title }),
8320
+ /* @__PURE__ */ jsx("p", { className: "neofaceid-consent-bullet-body", children: copy.bullet1Body })
8321
+ ] })
8322
+ ] }),
8323
+ /* @__PURE__ */ jsxs("div", { className: "neofaceid-consent-bullet", children: [
8324
+ /* @__PURE__ */ jsx("div", { className: "neofaceid-consent-bullet-icon", children: /* @__PURE__ */ jsx(IconGesture, {}) }),
8325
+ /* @__PURE__ */ jsxs("div", { children: [
8326
+ /* @__PURE__ */ jsx("p", { className: "neofaceid-consent-bullet-title", children: copy.bullet2Title }),
8327
+ /* @__PURE__ */ jsx("p", { className: "neofaceid-consent-bullet-body", children: copy.bullet2Body })
8328
+ ] })
8329
+ ] }),
8330
+ /* @__PURE__ */ jsxs("div", { className: "neofaceid-consent-bullet", children: [
8331
+ /* @__PURE__ */ jsx("div", { className: "neofaceid-consent-bullet-icon", children: /* @__PURE__ */ jsx(IconShield, {}) }),
8332
+ /* @__PURE__ */ jsxs("div", { children: [
8333
+ /* @__PURE__ */ jsx("p", { className: "neofaceid-consent-bullet-title", children: copy.bullet3Title }),
8334
+ /* @__PURE__ */ jsx("p", { className: "neofaceid-consent-bullet-body", children: copy.bullet3Body })
8335
+ ] })
8336
+ ] })
8208
8337
  ] }),
8209
- /* @__PURE__ */ jsx(
8338
+ /* @__PURE__ */ jsxs(
8210
8339
  "a",
8211
8340
  {
8212
8341
  href: privacyPolicyUrl,
8213
8342
  target: "_blank",
8214
8343
  rel: "noopener noreferrer",
8215
8344
  className: "neofaceid-consent-link",
8216
- children: "Ver política de privacidade"
8345
+ children: [
8346
+ "Ver política de privacidade (retenção de até ",
8347
+ retentionDays,
8348
+ " dias)"
8349
+ ]
8217
8350
  }
8218
8351
  ),
8219
8352
  /* @__PURE__ */ jsxs("div", { className: "neofaceid-consent-actions", children: [
@@ -8223,19 +8356,20 @@ function ConsentModalComponent({
8223
8356
  type: "button",
8224
8357
  className: "neofaceid-consent-button neofaceid-consent-button-primary",
8225
8358
  onClick: onAccept,
8226
- children: "Aceito e continuar"
8359
+ children: copy.primary
8227
8360
  }
8228
8361
  ),
8229
8362
  /* @__PURE__ */ jsx(
8230
8363
  "button",
8231
8364
  {
8232
8365
  type: "button",
8233
- className: "neofaceid-consent-button neofaceid-consent-button-secondary",
8366
+ className: "neofaceid-consent-button neofaceid-consent-button-ghost",
8234
8367
  onClick: onDecline,
8235
- children: "Recusar"
8368
+ children: "Agora não"
8236
8369
  }
8237
8370
  )
8238
- ] })
8371
+ ] }),
8372
+ /* @__PURE__ */ jsx("div", { className: "neofaceid-consent-footer", children: /* @__PURE__ */ jsx("span", { className: "neofaceid-consent-seal", children: "Protegido por NeoFaceID" }) })
8239
8373
  ] }) })
8240
8374
  ] });
8241
8375
  }
@@ -8245,9 +8379,7 @@ class ConsentModal {
8245
8379
  __publicField(this, "root", null);
8246
8380
  }
8247
8381
  show(props) {
8248
- if (this.container) {
8249
- return;
8250
- }
8382
+ if (this.container) return;
8251
8383
  this.container = document.createElement("div");
8252
8384
  this.container.id = "neofaceid-consent-modal-container";
8253
8385
  document.body.appendChild(this.container);
@@ -8271,32 +8403,39 @@ class ConsentModal {
8271
8403
  }
8272
8404
  close() {
8273
8405
  if (this.container && document.body.contains(this.container)) {
8274
- if (this.root) {
8275
- this.root.unmount();
8276
- }
8406
+ if (this.root) this.root.unmount();
8277
8407
  document.body.removeChild(this.container);
8278
8408
  this.container = null;
8279
8409
  this.root = null;
8280
8410
  }
8281
8411
  }
8282
8412
  }
8283
- const DEFAULT_CONSENT_INFO = {
8284
- purpose: "autenticação facial",
8285
- legalBasis: "seu consentimento explícito (Art. 7º, I da LGPD)",
8286
- privacyPolicyUrl: "https://neofaceid.com/privacidade",
8287
- retentionDays: 90
8288
- };
8413
+ const DEFAULT_APP_NAME = "sua aplicação";
8289
8414
  function requestConsent(info = {}) {
8415
+ const appName = info.appName ?? DEFAULT_APP_NAME;
8416
+ if (!info.appName) {
8417
+ console.warn(
8418
+ '[NeoFaceID SDK] requestConsent chamado sem appName — usando fallback "sua aplicação". Passe o nome do integrador via NeoFaceSDK.init({ appName }).'
8419
+ );
8420
+ }
8421
+ const flow = info.flow ?? "verification";
8290
8422
  return new Promise((resolve) => {
8291
8423
  const modal = new ConsentModal();
8292
8424
  modal.show({
8293
- ...DEFAULT_CONSENT_INFO,
8294
- ...info,
8425
+ appName,
8426
+ flow,
8427
+ privacyPolicyUrl: info.privacyPolicyUrl ?? DEFAULT_PRIVACY_URL,
8428
+ retentionDays: info.retentionDays ?? DEFAULT_RETENTION_DAYS,
8295
8429
  onAccept: () => resolve(true),
8296
8430
  onDecline: () => resolve(false)
8297
8431
  });
8298
8432
  });
8299
8433
  }
8434
+ const DEFAULT_CONSENT_INFO = {
8435
+ flow: "verification",
8436
+ privacyPolicyUrl: DEFAULT_PRIVACY_URL,
8437
+ retentionDays: DEFAULT_RETENTION_DAYS
8438
+ };
8300
8439
  class BiometricCaptureModal {
8301
8440
  constructor(options) {
8302
8441
  __publicField(this, "modal", null);
@@ -10088,7 +10227,10 @@ const biometricLoginFlow = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.
10088
10227
  }, Symbol.toStringTag, { value: "Module" }));
10089
10228
  const CONSENT_DENIED_MESSAGE$1 = "Consentimento recusado pelo usuário.";
10090
10229
  async function startFaceLogin(options) {
10091
- const consentAccepted = await requestConsent();
10230
+ const consentAccepted = await requestConsent({
10231
+ appName: options.appName,
10232
+ flow: "verification"
10233
+ });
10092
10234
  if (!consentAccepted) {
10093
10235
  options.onError(new NeoFaceError(CONSENT_DENIED_MESSAGE$1, ErrorType.CONSENT_DENIED));
10094
10236
  return;
@@ -10121,7 +10263,10 @@ async function startFaceLogin(options) {
10121
10263
  }
10122
10264
  }
10123
10265
  async function startHandLogin(options) {
10124
- const consentAccepted = await requestConsent();
10266
+ const consentAccepted = await requestConsent({
10267
+ appName: options.appName,
10268
+ flow: "verification"
10269
+ });
10125
10270
  if (!consentAccepted) {
10126
10271
  options.onError(new NeoFaceError(CONSENT_DENIED_MESSAGE$1, ErrorType.CONSENT_DENIED));
10127
10272
  return;
@@ -10156,7 +10301,10 @@ async function startHandLogin(options) {
10156
10301
  }
10157
10302
  }
10158
10303
  async function startAutoLogin(options) {
10159
- const consentAccepted = await requestConsent();
10304
+ const consentAccepted = await requestConsent({
10305
+ appName: options.appName,
10306
+ flow: "verification"
10307
+ });
10160
10308
  if (!consentAccepted) {
10161
10309
  options.onError(new NeoFaceError(CONSENT_DENIED_MESSAGE$1, ErrorType.CONSENT_DENIED));
10162
10310
  return;
@@ -10417,8 +10565,254 @@ const biometricDetection = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.
10417
10565
  initializeBiometricDetection,
10418
10566
  isAdvancedDetectionAvailable
10419
10567
  }, Symbol.toStringTag, { value: "Module" }));
10420
- const VERSION = "1.26.1";
10568
+ const VERSION = "1.28.0";
10421
10569
  const RELEASE_DATE = "2026-09-01";
10570
+ let cachedSession = null;
10571
+ function getCachedCaptureSession() {
10572
+ return cachedSession;
10573
+ }
10574
+ function resetCaptureSession() {
10575
+ cachedSession = null;
10576
+ }
10577
+ async function openCaptureSession({
10578
+ applicationToken,
10579
+ purpose
10580
+ }) {
10581
+ if (!applicationToken) {
10582
+ throw new NeoFaceError(
10583
+ "applicationToken é obrigatório para abrir sessão de captura",
10584
+ ErrorType.INVALID_TOKEN
10585
+ );
10586
+ }
10587
+ const url = `${getBaseUrl()}/api/v1/auth/capture/session/`;
10588
+ let response;
10589
+ try {
10590
+ response = await fetch(url, {
10591
+ method: "POST",
10592
+ headers: {
10593
+ "Content-Type": "application/json",
10594
+ "X-App-Token": applicationToken
10595
+ },
10596
+ body: JSON.stringify({ purpose })
10597
+ });
10598
+ } catch (err) {
10599
+ const message = err instanceof Error ? err.message : "Erro de rede";
10600
+ throw new NeoFaceError(`Falha de rede ao abrir sessão: ${message}`, ErrorType.NETWORK);
10601
+ }
10602
+ if (response.status === 401 || response.status === 403) {
10603
+ throw new NeoFaceError("Token de aplicação inválido ou expirado", ErrorType.INVALID_TOKEN);
10604
+ }
10605
+ if (!response.ok) {
10606
+ throw new NeoFaceError(
10607
+ `Falha ao abrir sessão de captura (${response.status})`,
10608
+ ErrorType.API_ERROR
10609
+ );
10610
+ }
10611
+ const raw = await response.json().catch(() => null);
10612
+ const payload = (raw == null ? void 0 : raw.data) ?? raw;
10613
+ const sessionId = payload == null ? void 0 : payload.session_id;
10614
+ const expiresAt = payload == null ? void 0 : payload.expires_at;
10615
+ if (!sessionId || !expiresAt) {
10616
+ throw new NeoFaceError(
10617
+ "Resposta inválida ao abrir sessão de captura (campos ausentes)",
10618
+ ErrorType.API_ERROR
10619
+ );
10620
+ }
10621
+ cachedSession = { session_id: sessionId, expires_at: expiresAt };
10622
+ return cachedSession;
10623
+ }
10624
+ async function withCaptureSession(params, fn) {
10625
+ const session = cachedSession ?? await openCaptureSession(params);
10626
+ try {
10627
+ return await fn(session.session_id);
10628
+ } catch (err) {
10629
+ if (err instanceof NeoFaceError && err.message.includes("410")) {
10630
+ resetCaptureSession();
10631
+ const fresh = await openCaptureSession(params);
10632
+ return fn(fresh.session_id);
10633
+ }
10634
+ throw err;
10635
+ }
10636
+ }
10637
+ function withSessionId(payload) {
10638
+ const session = cachedSession;
10639
+ if (!session) return payload;
10640
+ return { ...payload, session_id: session.session_id };
10641
+ }
10642
+ async function requestLivenessChallenge({
10643
+ sessionId,
10644
+ applicationToken
10645
+ }) {
10646
+ if (!applicationToken) {
10647
+ throw new NeoFaceError(
10648
+ "applicationToken é obrigatório para solicitar desafio de liveness",
10649
+ ErrorType.INVALID_TOKEN
10650
+ );
10651
+ }
10652
+ if (!sessionId) {
10653
+ throw new NeoFaceError(
10654
+ "session_id é obrigatório para solicitar desafio de liveness",
10655
+ ErrorType.VALIDATION_ERROR
10656
+ );
10657
+ }
10658
+ const url = `${getBaseUrl()}/api/v1/auth/liveness/challenge/`;
10659
+ let response;
10660
+ try {
10661
+ response = await fetch(url, {
10662
+ method: "POST",
10663
+ headers: {
10664
+ "Content-Type": "application/json",
10665
+ "X-App-Token": applicationToken
10666
+ },
10667
+ body: JSON.stringify({ session_id: sessionId })
10668
+ });
10669
+ } catch (err) {
10670
+ const message = err instanceof Error ? err.message : "Erro de rede";
10671
+ throw new NeoFaceError(`Falha de rede ao solicitar desafio: ${message}`, ErrorType.NETWORK);
10672
+ }
10673
+ if (response.status === 401 || response.status === 403) {
10674
+ throw new NeoFaceError("Token de aplicação inválido ou expirado", ErrorType.INVALID_TOKEN);
10675
+ }
10676
+ if (response.status === 410) {
10677
+ throw new NeoFaceError(
10678
+ "Sessão de captura expirada (410) — reabrir sessão",
10679
+ ErrorType.API_ERROR
10680
+ );
10681
+ }
10682
+ if (!response.ok) {
10683
+ throw new NeoFaceError(
10684
+ `Falha ao solicitar desafio de liveness (${response.status})`,
10685
+ ErrorType.API_ERROR
10686
+ );
10687
+ }
10688
+ const raw = await response.json().catch(() => null);
10689
+ const payload = (raw == null ? void 0 : raw.data) ?? raw;
10690
+ const challengeId = payload == null ? void 0 : payload.challenge_id;
10691
+ const gestures = payload == null ? void 0 : payload.gestures;
10692
+ if (!challengeId || !Array.isArray(gestures) || gestures.length === 0) {
10693
+ throw new NeoFaceError(
10694
+ "Resposta inválida ao solicitar desafio (campos ausentes)",
10695
+ ErrorType.API_ERROR
10696
+ );
10697
+ }
10698
+ return {
10699
+ challenge_id: challengeId,
10700
+ gestures,
10701
+ expires_at: payload == null ? void 0 : payload.expires_at
10702
+ };
10703
+ }
10704
+ async function requestLivenessChallengeWithSession({
10705
+ applicationToken,
10706
+ purpose,
10707
+ sessionId
10708
+ }) {
10709
+ let currentSessionId = sessionId ?? (await openCaptureSession({ applicationToken, purpose })).session_id;
10710
+ try {
10711
+ return await requestLivenessChallenge({ sessionId: currentSessionId, applicationToken });
10712
+ } catch (err) {
10713
+ if (err instanceof NeoFaceError && err.message.includes("410")) {
10714
+ resetCaptureSession();
10715
+ currentSessionId = (await openCaptureSession({ applicationToken, purpose })).session_id;
10716
+ return requestLivenessChallenge({ sessionId: currentSessionId, applicationToken });
10717
+ }
10718
+ throw err;
10719
+ }
10720
+ }
10721
+ async function submitLivenessChallenge({
10722
+ challengeId,
10723
+ sessionId,
10724
+ applicationToken,
10725
+ gestures
10726
+ }) {
10727
+ if (!applicationToken) {
10728
+ throw new NeoFaceError(
10729
+ "applicationToken é obrigatório para submeter desafio",
10730
+ ErrorType.INVALID_TOKEN
10731
+ );
10732
+ }
10733
+ if (!challengeId || !sessionId) {
10734
+ throw new NeoFaceError(
10735
+ "challenge_id e session_id são obrigatórios para submeter desafio",
10736
+ ErrorType.VALIDATION_ERROR
10737
+ );
10738
+ }
10739
+ if (!Array.isArray(gestures) || gestures.length === 0) {
10740
+ throw new NeoFaceError("gestures[] vazio — nada para submeter", ErrorType.VALIDATION_ERROR);
10741
+ }
10742
+ const url = `${getBaseUrl()}/api/v1/auth/liveness/challenge/${encodeURIComponent(challengeId)}/submit/`;
10743
+ let response;
10744
+ try {
10745
+ response = await fetch(url, {
10746
+ method: "POST",
10747
+ headers: {
10748
+ "Content-Type": "application/json",
10749
+ "X-App-Token": applicationToken
10750
+ },
10751
+ body: JSON.stringify({ session_id: sessionId, gestures })
10752
+ });
10753
+ } catch (err) {
10754
+ const message = err instanceof Error ? err.message : "Erro de rede";
10755
+ throw new NeoFaceError(`Falha de rede ao submeter desafio: ${message}`, ErrorType.NETWORK);
10756
+ }
10757
+ if (response.status === 401 || response.status === 403) {
10758
+ throw new NeoFaceError("Token de aplicação inválido ou expirado", ErrorType.INVALID_TOKEN);
10759
+ }
10760
+ if (response.status === 410) {
10761
+ throw new NeoFaceError(
10762
+ "Sessão ou desafio expirado (410) — reabrir sessão",
10763
+ ErrorType.API_ERROR
10764
+ );
10765
+ }
10766
+ if (!response.ok) {
10767
+ throw new NeoFaceError(
10768
+ `Falha ao submeter desafio de liveness (${response.status})`,
10769
+ ErrorType.API_ERROR
10770
+ );
10771
+ }
10772
+ const raw = await response.json().catch(() => null);
10773
+ const payload = (raw == null ? void 0 : raw.data) ?? raw ?? {};
10774
+ return {
10775
+ success: (payload == null ? void 0 : payload.success) ?? true,
10776
+ liveness_passed: payload == null ? void 0 : payload.liveness_passed,
10777
+ score: payload == null ? void 0 : payload.score,
10778
+ raw
10779
+ };
10780
+ }
10781
+ async function runLivenessChallenge({
10782
+ applicationToken,
10783
+ purpose,
10784
+ collectFramesForGesture,
10785
+ retryOnSessionExpired = true
10786
+ }) {
10787
+ const attempt = async () => {
10788
+ const session = await openCaptureSession({ applicationToken, purpose });
10789
+ const challenge = await requestLivenessChallenge({
10790
+ sessionId: session.session_id,
10791
+ applicationToken
10792
+ });
10793
+ const gestures = [];
10794
+ for (let i = 0; i < challenge.gestures.length; i += 1) {
10795
+ const g = challenge.gestures[i];
10796
+ const images = await collectFramesForGesture(g, i, challenge.gestures.length);
10797
+ gestures.push({ gesture_key: String(g.gesture_key), images });
10798
+ }
10799
+ return submitLivenessChallenge({
10800
+ challengeId: challenge.challenge_id,
10801
+ sessionId: session.session_id,
10802
+ applicationToken,
10803
+ gestures
10804
+ });
10805
+ };
10806
+ try {
10807
+ return await attempt();
10808
+ } catch (err) {
10809
+ if (retryOnSessionExpired && err instanceof NeoFaceError && err.message.includes("410")) {
10810
+ resetCaptureSession();
10811
+ return attempt();
10812
+ }
10813
+ throw err;
10814
+ }
10815
+ }
10422
10816
  class OnboardingCaptureModal {
10423
10817
  constructor(options) {
10424
10818
  __publicField(this, "overlay", null);
@@ -10636,7 +11030,10 @@ class OnboardingCaptureModal {
10636
11030
  const startOnboarding = async (options) => {
10637
11031
  const { applicationToken, onboardingToken, countdown, title, subtitle, onSuccess, onError } = options;
10638
11032
  try {
10639
- const consentAccepted = await requestConsent();
11033
+ const consentAccepted = await requestConsent({
11034
+ appName: options.appName,
11035
+ flow: "registration"
11036
+ });
10640
11037
  if (!consentAccepted) {
10641
11038
  onError(new NeoFaceError("Consentimento recusado pelo usuário.", ErrorType.CONSENT_DENIED));
10642
11039
  return;
@@ -11015,7 +11412,10 @@ const authorizeOperation = async (applicationToken, cpf, options) => {
11015
11412
  }
11016
11413
  const capturedPhotos = [];
11017
11414
  const captureDelay = (options == null ? void 0 : options.captureDelay) || 2e3;
11018
- const consentAccepted = await requestConsent();
11415
+ const consentAccepted = await requestConsent({
11416
+ appName: options == null ? void 0 : options.appName,
11417
+ flow: "verification"
11418
+ });
11019
11419
  if (!consentAccepted) {
11020
11420
  throw new NeoFaceError("Consentimento recusado pelo usuário.", ErrorType.CONSENT_DENIED);
11021
11421
  }
@@ -11162,6 +11562,18 @@ class DocumentCaptureModal {
11162
11562
  };
11163
11563
  }
11164
11564
  async open() {
11565
+ if (!this.options.skipConsent) {
11566
+ const consentAccepted = await requestConsent({
11567
+ appName: this.options.appName,
11568
+ flow: "verification"
11569
+ });
11570
+ if (!consentAccepted) {
11571
+ throw new NeoFaceError(
11572
+ "Consentimento recusado pelo usuário.",
11573
+ ErrorType.CONSENT_DENIED
11574
+ );
11575
+ }
11576
+ }
11165
11577
  return new Promise((resolve) => {
11166
11578
  this.resolvePromise = resolve;
11167
11579
  if (this.options.preSelectedDocument) {
@@ -12124,8 +12536,8 @@ const DocumentCaptureModal$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Obj
12124
12536
  startDocumentCapture
12125
12537
  }, Symbol.toStringTag, { value: "Module" }));
12126
12538
  const CONSENT_DENIED_MESSAGE = "Consentimento recusado pelo usuário.";
12127
- function start(applicationToken, callbacks) {
12128
- requestConsent().then((accepted) => {
12539
+ function start(applicationToken, callbacks, options) {
12540
+ requestConsent({ appName: options == null ? void 0 : options.appName, flow: "verification" }).then((accepted) => {
12129
12541
  if (!accepted) {
12130
12542
  callbacks.onError("CONSENT_DENIED", CONSENT_DENIED_MESSAGE);
12131
12543
  return;
@@ -12160,7 +12572,7 @@ function start(applicationToken, callbacks) {
12160
12572
  });
12161
12573
  }
12162
12574
  function startBiometricRegistration(personData, applicationToken, callbacks, options) {
12163
- requestConsent().then((accepted) => {
12575
+ requestConsent({ appName: options == null ? void 0 : options.appName, flow: "registration" }).then((accepted) => {
12164
12576
  if (!accepted) {
12165
12577
  callbacks.onError("CONSENT_DENIED", CONSENT_DENIED_MESSAGE);
12166
12578
  return;
@@ -12201,8 +12613,8 @@ function startBiometricRegistration(personData, applicationToken, callbacks, opt
12201
12613
  });
12202
12614
  });
12203
12615
  }
12204
- function startLivenessCapture(applicationToken, callbacks) {
12205
- requestConsent().then((accepted) => {
12616
+ function startLivenessCapture(applicationToken, callbacks, options) {
12617
+ requestConsent({ appName: options == null ? void 0 : options.appName, flow: "verification" }).then((accepted) => {
12206
12618
  if (!accepted) {
12207
12619
  callbacks.onError("CONSENT_DENIED", CONSENT_DENIED_MESSAGE);
12208
12620
  return;
@@ -12275,6 +12687,7 @@ export {
12275
12687
  detectBiometricType,
12276
12688
  getApplicationToken,
12277
12689
  getBaseUrl,
12690
+ getCachedCaptureSession,
12278
12691
  getConfig,
12279
12692
  getEnvironment,
12280
12693
  identifyPerson,
@@ -12285,6 +12698,7 @@ export {
12285
12698
  isInitialized,
12286
12699
  loginWithBiometric,
12287
12700
  loginWithEmail,
12701
+ openCaptureSession,
12288
12702
  preloadFaceDetectionModels,
12289
12703
  recognize,
12290
12704
  recognizeBiometric,
@@ -12293,7 +12707,11 @@ export {
12293
12707
  registerPersonWithBiometric,
12294
12708
  registerPersonWithoutFace,
12295
12709
  requestConsent,
12710
+ requestLivenessChallenge,
12711
+ requestLivenessChallengeWithSession,
12296
12712
  requestPasswordReset,
12713
+ resetCaptureSession,
12714
+ runLivenessChallenge,
12297
12715
  simpleIdentification,
12298
12716
  start,
12299
12717
  startAutoLogin,
@@ -12303,6 +12721,9 @@ export {
12303
12721
  startHandLogin,
12304
12722
  startLivenessCapture,
12305
12723
  startOnboarding,
12724
+ submitLivenessChallenge,
12306
12725
  validateOnboardingToken,
12307
- validateToken
12726
+ validateToken,
12727
+ withCaptureSession,
12728
+ withSessionId
12308
12729
  };