@neofaceid/web-sdk 1.36.1 → 1.36.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.
package/dist/index.d.ts CHANGED
@@ -88,7 +88,12 @@ export declare interface AuthorizeOptions {
88
88
  amount?: number;
89
89
  onChallengeStart?: (gesture: ChallengeGesture, index: number, total: number) => void;
90
90
  onChallengeComplete?: (gesture: ChallengeGesture, index: number, total: number) => void;
91
- onSuccess?: (result: LivenessChallengeResult) => void;
91
+ /**
92
+ * NEO-427: agora recebe o resultado da COLETA (sessionId + challenge + gestures
93
+ * capturadas). O SDK não decide aprovação — envie os frames via seu próprio
94
+ * pipeline de recognition (ex.: `POST /auth/recognition/face/`).
95
+ */
96
+ onSuccess?: (result: RunLivenessChallengeCollectResult) => void;
92
97
  onError?: (error: NeoFaceError) => void;
93
98
  onCancel?: () => void;
94
99
  /**
@@ -329,6 +334,11 @@ export declare interface CaptureSession {
329
334
  export declare interface ChallengeGesture {
330
335
  index: number;
331
336
  gesture_key: GestureKey | string;
337
+ /**
338
+ * Instrução pronta pelo backend (v1.4.x, respeita `Accept-Language`).
339
+ * Nos payloads legados vinha via `instruction_i18n`.
340
+ */
341
+ instruction?: string;
332
342
  instruction_i18n?: Record<string, string>;
333
343
  }
334
344
 
@@ -637,7 +647,12 @@ export declare class ForgotPasswordModal {
637
647
  private addStyles;
638
648
  }
639
649
 
640
- export declare type GestureKey = 'turn_left' | 'turn_right' | 'turn_up' | 'turn_down' | 'blink' | 'smile' | 'open_mouth';
650
+ /**
651
+ * Chaves de gesto reconhecidas pelo backend real (case-insensitive; SDK
652
+ * normaliza para maiúsculo). Novos gestos podem aparecer sem impacto no SDK
653
+ * — o campo é `string` na runtime.
654
+ */
655
+ export declare type GestureKey = 'LOOK_LEFT' | 'LOOK_RIGHT' | 'LOOK_UP' | 'LOOK_DOWN' | 'BLINK' | 'SMILE' | 'OPEN_MOUTH' | 'turn_left' | 'turn_right' | 'look_up' | 'look_down' | 'blink' | 'smile' | 'open_mouth';
641
656
 
642
657
  export declare interface GestureResponse {
643
658
  gesture_key: string;
@@ -769,9 +784,18 @@ export declare function isAdvancedDetectionAvailable(): boolean;
769
784
  export declare function isInitialized(): boolean;
770
785
 
771
786
  export declare interface LivenessChallenge {
772
- challenge_id: string;
787
+ /**
788
+ * ID do desafio. **Opcional no contrato v1.4.x** — o backend real rastreia
789
+ * o desafio pelo `session_id` e não devolve `challenge_id` no payload.
790
+ * Mantido opcional para consumidores que ainda dependem do valor.
791
+ */
792
+ challenge_id?: string;
773
793
  gestures: ChallengeGesture[];
794
+ /** Data ISO derivada de `expires_in` (segundos) ou legado `expires_at`. */
774
795
  expires_at?: string;
796
+ /** Segundos até expirar (contrato v1.4.x). */
797
+ expires_in?: number;
798
+ language?: string;
775
799
  }
776
800
 
777
801
  export declare interface LivenessChallengeResult {
@@ -1367,16 +1391,33 @@ declare interface ResolvedTheme {
1367
1391
  }
1368
1392
 
1369
1393
  /**
1370
- * Orquestra o fluxo completo:
1394
+ * Orquestra:
1371
1395
  * 1. Abre `capture/session`
1372
- * 2. Pede `liveness/challenge` (sequência sorteada pelo servidor)
1396
+ * 2. Pede `liveness/challenge` (backend sorteia)
1373
1397
  * 3. Delega a coleta de frames ao consumidor gesto a gesto
1374
- * 4. Submete a resposta para o servidor validar
1398
+ * 4. **Retorna a coleta** para o consumidor submeter no pipeline dele.
1375
1399
  *
1376
- * Retry: em 410 no submit, reabre a sessão + refaz o desafio + reenvia UMA vez.
1377
- * Segunda falha propaga.
1400
+ * Retry: em 410 ao abrir sessão/pedir desafio, reabre + refaz 1x. Segunda falha propaga.
1401
+ *
1402
+ * Nota: até 1.36.1 esta função chamava `submitLivenessChallenge` no fim, mas o
1403
+ * endpoint não existe no backend real. NEO-427 removeu essa chamada. Quando
1404
+ * NEO-428 identificar o endpoint real de submit, o consumidor pode usá-lo, ou
1405
+ * uma variante `runLivenessChallengeAndSubmit` pode ser reintroduzida.
1378
1406
  */
1379
- export declare function runLivenessChallenge({ applicationToken, purpose, collectFramesForGesture, retryOnSessionExpired, }: RunLivenessChallengeParams): Promise<LivenessChallengeResult>;
1407
+ export declare function runLivenessChallenge({ applicationToken, purpose, collectFramesForGesture, retryOnSessionExpired, }: RunLivenessChallengeParams): Promise<RunLivenessChallengeCollectResult>;
1408
+
1409
+ /**
1410
+ * Resultado da coleta orquestrada. NEO-427: NÃO submete os frames automaticamente
1411
+ * (o endpoint de submit `/challenge/{id}/submit/` não existe no backend v1.4.x —
1412
+ * devolve 404). O consumidor recebe as gestures coletadas e envia via seu próprio
1413
+ * pipeline (ex.: `POST /auth/recognition/face/` com `challenge_response` no body).
1414
+ */
1415
+ export declare interface RunLivenessChallengeCollectResult {
1416
+ sessionId: string;
1417
+ challenge: LivenessChallenge;
1418
+ /** Frames coletados por gesto, na ordem sorteada pelo servidor. */
1419
+ capturedGestures: GestureResponse[];
1420
+ }
1380
1421
 
1381
1422
  export declare interface RunLivenessChallengeParams {
1382
1423
  applicationToken: string;
@@ -1384,10 +1425,10 @@ export declare interface RunLivenessChallengeParams {
1384
1425
  /**
1385
1426
  * Callback fornecido pelo consumidor: para cada gesto na sequência sorteada
1386
1427
  * pelo servidor, retorna os frames coletados. SDK NÃO decide se o gesto foi
1387
- * cumprido — só coleta e envia; validação é 100% servidor.
1428
+ * cumprido — só coleta; validação é 100% servidor.
1388
1429
  */
1389
1430
  collectFramesForGesture: (gesture: ChallengeGesture, index: number, total: number) => Promise<string[]>;
1390
- /** Se true, quando o servidor devolver 410 no submit, reabre sessão + refaz o desafio 1x. */
1431
+ /** Se true, quando o servidor devolver 410 na abertura do desafio, reabre sessão + refaz 1x. */
1391
1432
  retryOnSessionExpired?: boolean;
1392
1433
  }
1393
1434
 
@@ -1583,14 +1624,18 @@ export declare interface StartOnboardingOptions {
1583
1624
  }
1584
1625
 
1585
1626
  /**
1586
- * Envia os frames coletados para o servidor validar o desafio de liveness.
1587
- * Endpoint: `POST /api/v1/auth/liveness/challenge/{challenge_id}/submit/`
1588
- * O SDK apenas empacota e envia — nenhuma decisão de aprovar/reprovar aqui.
1627
+ * @deprecated NEO-427: o endpoint `POST /liveness/challenge/{id}/submit/` NÃO
1628
+ * EXISTE no backend v1.4.x — devolve 404. `runLivenessChallenge` não chama mais
1629
+ * esta função. Mantida apenas para consumidores que ainda dependem do símbolo;
1630
+ * será removida quando o endpoint real de submit for identificado (NEO-428).
1631
+ *
1632
+ * Continua tentando o path histórico e propaga o erro do servidor.
1589
1633
  */
1590
1634
  export declare function submitLivenessChallenge({ challengeId, sessionId, applicationToken, gestures, }: SubmitLivenessChallengeParams): Promise<LivenessChallengeResult>;
1591
1635
 
1592
1636
  export declare interface SubmitLivenessChallengeParams {
1593
- challengeId: string;
1637
+ /** Opcional no v1.4.x — backend rastreia via session_id. */
1638
+ challengeId?: string;
1594
1639
  sessionId: string;
1595
1640
  applicationToken: string;
1596
1641
  gestures: GestureResponse[];
@@ -1650,7 +1695,7 @@ export declare const validateToken: (applicationToken: string) => Promise<boolea
1650
1695
  * MINOR: Incrementado quando adicionamos funcionalidades mantendo compatibilidade
1651
1696
  * PATCH: Incrementado quando corrigimos bugs mantendo compatibilidade
1652
1697
  */
1653
- export declare const VERSION = "1.36.1";
1698
+ export declare const VERSION = "1.36.2";
1654
1699
 
1655
1700
  /**
1656
1701
  * Executa `fn(sessionId)`. Se o servidor devolver 410 (sessão consumida/expirada),
@@ -11177,7 +11177,7 @@ const biometricDetection = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.
11177
11177
  initializeBiometricDetection,
11178
11178
  isAdvancedDetectionAvailable
11179
11179
  }, Symbol.toStringTag, { value: "Module" }));
11180
- const VERSION = "1.36.1";
11180
+ const VERSION = "1.36.2";
11181
11181
  const RELEASE_DATE = "2026-09-03";
11182
11182
  let cachedSession = null;
11183
11183
  function getCachedCaptureSession() {
@@ -11305,18 +11305,33 @@ async function requestLivenessChallenge({
11305
11305
  }
11306
11306
  const raw = await response.json().catch(() => null);
11307
11307
  const payload = (raw == null ? void 0 : raw.data) ?? raw;
11308
- const challengeId = payload == null ? void 0 : payload.challenge_id;
11309
- const gestures = payload == null ? void 0 : payload.gestures;
11310
- if (!challengeId || !Array.isArray(gestures) || gestures.length === 0) {
11308
+ const rawSteps = payload == null ? void 0 : payload.steps;
11309
+ const rawGestures = payload == null ? void 0 : payload.gestures;
11310
+ const source = Array.isArray(rawSteps) ? rawSteps : Array.isArray(rawGestures) ? rawGestures : void 0;
11311
+ if (!source || source.length === 0) {
11311
11312
  throw new NeoFaceError(
11312
- "Resposta inválida ao solicitar desafio (campos ausentes)",
11313
+ "Resposta inválida ao solicitar desafio (steps/gestures ausentes)",
11313
11314
  ErrorType.API_ERROR
11314
11315
  );
11315
11316
  }
11317
+ const gestures = source.map((s, i) => {
11318
+ const item = s;
11319
+ const gestureRaw = item.gesture ?? item.gesture_key;
11320
+ return {
11321
+ index: typeof item.order === "number" ? item.order : typeof item.index === "number" ? item.index : i + 1,
11322
+ gesture_key: gestureRaw ?? "",
11323
+ instruction: typeof item.instruction === "string" ? item.instruction : void 0,
11324
+ instruction_i18n: item.instruction_i18n && typeof item.instruction_i18n === "object" ? item.instruction_i18n : void 0
11325
+ };
11326
+ });
11327
+ const expiresIn = typeof (payload == null ? void 0 : payload.expires_in) === "number" ? payload.expires_in : void 0;
11328
+ const expiresAt = typeof (payload == null ? void 0 : payload.expires_at) === "string" && payload.expires_at.length > 0 ? payload.expires_at : expiresIn !== void 0 ? new Date(Date.now() + expiresIn * 1e3).toISOString() : void 0;
11316
11329
  return {
11317
- challenge_id: challengeId,
11330
+ challenge_id: typeof (payload == null ? void 0 : payload.challenge_id) === "string" ? payload.challenge_id : void 0,
11318
11331
  gestures,
11319
- expires_at: payload == null ? void 0 : payload.expires_at
11332
+ expires_at: expiresAt,
11333
+ expires_in: expiresIn,
11334
+ language: typeof (payload == null ? void 0 : payload.language) === "string" ? payload.language : void 0
11320
11335
  };
11321
11336
  }
11322
11337
  async function requestLivenessChallengeWithSession({
@@ -11342,22 +11357,26 @@ async function submitLivenessChallenge({
11342
11357
  applicationToken,
11343
11358
  gestures
11344
11359
  }) {
11360
+ console.warn(
11361
+ "[NeoFaceID SDK] submitLivenessChallenge está deprecated (NEO-427): o endpoint /liveness/challenge/{id}/submit/ não existe no backend v1.4.x. Coleta os frames via runLivenessChallenge e envie via seu próprio pipeline até que NEO-428 defina o endpoint real."
11362
+ );
11345
11363
  if (!applicationToken) {
11346
11364
  throw new NeoFaceError(
11347
11365
  "applicationToken é obrigatório para submeter desafio",
11348
11366
  ErrorType.INVALID_TOKEN
11349
11367
  );
11350
11368
  }
11351
- if (!challengeId || !sessionId) {
11369
+ if (!sessionId) {
11352
11370
  throw new NeoFaceError(
11353
- "challenge_id e session_id são obrigatórios para submeter desafio",
11371
+ "session_id é obrigatório para submeter desafio",
11354
11372
  ErrorType.VALIDATION_ERROR
11355
11373
  );
11356
11374
  }
11357
11375
  if (!Array.isArray(gestures) || gestures.length === 0) {
11358
11376
  throw new NeoFaceError("gestures[] vazio — nada para submeter", ErrorType.VALIDATION_ERROR);
11359
11377
  }
11360
- const url = `${getBaseUrl()}/api/v1/auth/liveness/challenge/${encodeURIComponent(challengeId)}/submit/`;
11378
+ const idSuffix = challengeId ? `${encodeURIComponent(challengeId)}/submit/` : "submit/";
11379
+ const url = `${getBaseUrl()}/api/v1/auth/liveness/challenge/${idSuffix}`;
11361
11380
  let response;
11362
11381
  try {
11363
11382
  response = await fetch(url, {
@@ -11408,18 +11427,13 @@ async function runLivenessChallenge({
11408
11427
  sessionId: session.session_id,
11409
11428
  applicationToken
11410
11429
  });
11411
- const gestures = [];
11430
+ const capturedGestures = [];
11412
11431
  for (let i = 0; i < challenge.gestures.length; i += 1) {
11413
11432
  const g = challenge.gestures[i];
11414
11433
  const images = await collectFramesForGesture(g, i, challenge.gestures.length);
11415
- gestures.push({ gesture_key: String(g.gesture_key), images });
11434
+ capturedGestures.push({ gesture_key: String(g.gesture_key), images });
11416
11435
  }
11417
- return submitLivenessChallenge({
11418
- challengeId: challenge.challenge_id,
11419
- sessionId: session.session_id,
11420
- applicationToken,
11421
- gestures
11422
- });
11436
+ return { sessionId: session.session_id, challenge, capturedGestures };
11423
11437
  };
11424
11438
  try {
11425
11439
  return await attempt();
@@ -12924,12 +12938,6 @@ function AuthorizeModalComponent({
12924
12938
  });
12925
12939
  if (stream) stream.getTracks().forEach((t) => t.stop());
12926
12940
  stream = null;
12927
- if (result.success === false || result.liveness_passed === false) {
12928
- setFailureCode("LIVENESS_LOW");
12929
- setFailureAt(/* @__PURE__ */ new Date());
12930
- setPhase("failure");
12931
- return;
12932
- }
12933
12941
  setPhase("success");
12934
12942
  if (onSuccess) onSuccess(result);
12935
12943
  } catch (err) {