@neofaceid/web-sdk 1.40.3 → 1.42.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.
package/README.md CHANGED
@@ -192,7 +192,7 @@ startBiometricRegistration(
192
192
  'seu-token-de-aplicacao',
193
193
  {
194
194
  onSuccess: result => console.log('Cadastro concluído:', result.person_id),
195
- onError: (code, message) => console.error(code, message),
195
+ onError: err => console.error(err.type, err.message),
196
196
  },
197
197
  { appName: 'Minha Aplicação' }
198
198
  );
@@ -210,7 +210,7 @@ startLivenessCapture(
210
210
  'seu-token-de-aplicacao',
211
211
  {
212
212
  onSuccess: (photos: Blob[]) => console.log(`${photos.length} fotos capturadas`),
213
- onError: (code, message) => console.error(code, message),
213
+ onError: err => console.error(err.type, err.message),
214
214
  onCancel: () => console.log('Usuário fechou o modal'),
215
215
  },
216
216
  { appName: 'Minha Aplicação' }
@@ -347,14 +347,14 @@ function onError(err: NeoFaceError) {
347
347
  }
348
348
  ```
349
349
 
350
- > Os fluxos legados `start`, `startBiometricRegistration` e
351
- > `startLivenessCapture` ainda usam `onError(code: string, message: string)`
352
- > em vez de `onError(err: NeoFaceError)` — consulte o `CHANGELOG.md` antes de
353
- > migrar código que dependa dessa assinatura.
350
+ > Desde a 1.41.0, `start`, `startBiometricRegistration` e
351
+ > `startLivenessCapture` também usam `onError(err: NeoFaceError)` — antes
352
+ > usavam `onError(code: string, message: string)`. Veja o `CHANGELOG.md`
353
+ > (breaking change) se seu código ainda depende da assinatura antiga.
354
354
 
355
355
  | `ErrorType` | Quando ocorre |
356
356
  | ----------------------- | --------------------------------------------------------------- |
357
- | `NETWORK` | Erro de conexão com o servidor (alias `@deprecated`: `NETWORK_ERROR`) |
357
+ | `NETWORK` | Erro de conexão com o servidor |
358
358
  | `INVALID_TOKEN` | `applicationToken` inválido ou expirado |
359
359
  | `RECOGNITION_FAILED` | Falha no reconhecimento facial |
360
360
  | `LOGIN_FAILED` | Falha no login biométrico |
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { default as default_2 } from 'react';
1
2
  import { JSX as JSX_2 } from 'react/jsx-runtime';
2
3
  import { z } from 'zod';
3
4
 
@@ -29,6 +30,20 @@ export declare interface ApplicationRegistrationResult {
29
30
  message: string;
30
31
  }
31
32
 
33
+ export declare type AuthMethod = z.infer<typeof AuthMethodSchema>;
34
+
35
+ /**
36
+ * Por qual caminho a pessoa se autenticou.
37
+ *
38
+ * O console trata `password` como caminho degradado — entra, mas não executa
39
+ * operação de risco alto. Sem este campo o host não tem como distinguir, já que
40
+ * o resultado dos dois caminhos tem exatamente a mesma forma.
41
+ */
42
+ declare const AuthMethodSchema: z.ZodEnum<{
43
+ face: "face";
44
+ password: "password";
45
+ }>;
46
+
32
47
  export declare interface AuthorizationOptions {
33
48
  onProgress?: (step: number, totalSteps: number, instruction: string) => void;
34
49
  onPhotoTaken?: (photoNumber: number, blob: Blob) => void;
@@ -106,6 +121,76 @@ export declare interface AuthorizeOptions {
106
121
  autoLighting?: boolean;
107
122
  }
108
123
 
124
+ /** Ver {@link SDKInitOptions.autoFallback}. */
125
+ export declare interface AutoFallbackOptions {
126
+ /**
127
+ * Nível 1 — oferecer confirmação no celular quando o dispositivo atual não
128
+ * dá conta (sem câmera, permissão negada) ou quando o purpose exige.
129
+ *
130
+ * Default `false`. Quem decide se há aparelho é o core, na resposta: o SDK
131
+ * não consegue (e não deve) descobrir isso sozinho — um endpoint que
132
+ * respondesse "esta pessoa tem aparelho?" autenticado por `X-App-Token`,
133
+ * que é público por desenho, seria um oráculo de enumeração.
134
+ */
135
+ toPhone?: boolean;
136
+ /**
137
+ * Nível 2 — abrir o modal de e-mail e senha.
138
+ *
139
+ * Default `true`, que é o comportamento histórico de `startFaceLogin`
140
+ * quando `onFallbackRequest` não é passado. Mudá-lo para `false` por padrão
141
+ * quebraria todo integrador publicado, então a mudança fica explícita.
142
+ */
143
+ toPassword?: boolean;
144
+ }
145
+
146
+ /**
147
+ * Abre a tela "Confirme no seu celular" e aguarda a decisão pelo SSE do core.
148
+ *
149
+ * Este primitivo é avulso de propósito. Desde a NEO-427 o `authorize()` só
150
+ * **coleta** — quem submete ao core é o host, então é o host que recebe a
151
+ * resposta "exige confirmação no celular" e chama esta função com o
152
+ * `requestId` que veio de lá.
153
+ *
154
+ * O SDK nunca fala com a plataforma Push: o canal é sempre o core.
155
+ *
156
+ * @example
157
+ * ```ts
158
+ * const r = await meuBackend.submeter(frames);
159
+ * if (r.requires_push) {
160
+ * const outcome = await awaitPushApproval({
161
+ * requestId: r.request_id,
162
+ * applicationToken: TOKEN,
163
+ * expiresIn: r.expires_in,
164
+ * numericCode: r.numeric_code,
165
+ * });
166
+ * if (outcome.status === 'approved') continuar();
167
+ * else if (outcome.status === 'expired') caiParaSenha();
168
+ * // 'denied' é terminal — não oferece caminho alternativo.
169
+ * }
170
+ * ```
171
+ */
172
+ export declare function awaitPushApproval(options: AwaitPushApprovalOptions): Promise<PushApprovalOutcome>;
173
+
174
+ export declare interface AwaitPushApprovalOptions {
175
+ /**
176
+ * Identificador da solicitação, devolvido pelo core na resposta que exigiu
177
+ * confirmação no celular.
178
+ */
179
+ requestId: string;
180
+ applicationToken: string;
181
+ /** Prazo informado pelo core, em segundos. */
182
+ expiresIn: number;
183
+ /**
184
+ * Código de correspondência numérica de 2 dígitos, quando a política exigir.
185
+ * O SDK apenas **exibe**; conferir é papel do celular contra o servidor.
186
+ */
187
+ numericCode?: string;
188
+ /** Nome do integrador (fallback: `init({ appName })`). */
189
+ appName?: string;
190
+ /** Oferece "entrar de outro jeito" na tela de expiração. */
191
+ onFallback?: () => void;
192
+ }
193
+
109
194
  export declare class BiometricCaptureModal {
110
195
  private modal;
111
196
  private video;
@@ -201,6 +286,11 @@ export declare type BiometricLoginResult = z.infer<typeof BiometricLoginResultSc
201
286
  declare const BiometricLoginResultSchema: z.ZodObject<{
202
287
  success: z.ZodBoolean;
203
288
  accessToken: z.ZodOptional<z.ZodString>;
289
+ refreshToken: z.ZodOptional<z.ZodString>;
290
+ method: z.ZodOptional<z.ZodEnum<{
291
+ face: "face";
292
+ password: "password";
293
+ }>>;
204
294
  alias: z.ZodOptional<z.ZodString>;
205
295
  user: z.ZodOptional<z.ZodObject<{
206
296
  id: z.ZodString;
@@ -223,7 +313,7 @@ declare const BiometricLoginResultSchema: z.ZodObject<{
223
313
 
224
314
  declare interface BiometricRegistrationCallbacks {
225
315
  onSuccess(result: BiometricRegistrationResult): void;
226
- onError(code: string, message: string): void;
316
+ onError(err: NeoFaceError): void;
227
317
  }
228
318
 
229
319
  export declare function BiometricRegistrationModal({ personData, applicationToken, onClose, onSuccess, onPhotosCaptured, onError, onCannotGesture, autoLighting, }: BiometricRegistrationModalProps): JSX_2.Element;
@@ -279,6 +369,7 @@ declare interface BiometricRegistrationResult_2 {
279
369
  /**
280
370
  * Overlay minimalista estilo FaceID para login biométrico
281
371
  * Implementação vanilla JS (sem React) para evitar conflitos de versão
372
+ * @deprecated Utilize o componente CameraOvalGuide (showCameraOvalGuideModal) para preview de câmera com guia oval.
282
373
  */
283
374
  export declare class BiometricStatusOverlay {
284
375
  private container;
@@ -297,7 +388,40 @@ declare interface Callbacks {
297
388
  email: string;
298
389
  documentId: string;
299
390
  }): void;
300
- onError(code: string, message: string): void;
391
+ onError(err: NeoFaceError): void;
392
+ }
393
+
394
+ /**
395
+ * Componente de guia oval para captura facial.
396
+ *
397
+ * Renderiza o preview da câmera com um oval SVG sobreposto e um halo colorido
398
+ * que indica o estado de posicionamento do rosto em tempo real.
399
+ *
400
+ * @example
401
+ * ```tsx
402
+ * <CameraOvalGuide
403
+ * stream={mediaStream}
404
+ * faceState="centered"
405
+ * instruction="Mantenha o rosto no oval"
406
+ * />
407
+ * ```
408
+ */
409
+ export declare function CameraOvalGuide({ stream, faceState, instruction, className, style, }: CameraOvalGuideProps): JSX_2.Element;
410
+
411
+ /**
412
+ * Props do componente CameraOvalGuide.
413
+ */
414
+ export declare interface CameraOvalGuideProps {
415
+ /** Stream de vídeo da câmera. Null enquanto aguarda permissão. */
416
+ stream: MediaStream | null;
417
+ /** Estado de posicionamento do rosto — controla a cor do halo. */
418
+ faceState: FaceState;
419
+ /** Instrução textual exibida abaixo do oval (ex: "Aproxime o rosto"). */
420
+ instruction: string;
421
+ /** Classe CSS adicional aplicada ao container externo. */
422
+ className?: string;
423
+ /** Estilos inline adicionais aplicados ao container externo. */
424
+ style?: default_2.CSSProperties;
301
425
  }
302
426
 
303
427
  /**
@@ -461,6 +585,43 @@ export declare interface ConsentRecord {
461
585
  sdkVersion: string;
462
586
  }
463
587
 
588
+ export declare interface ConsumeSseOptions<T> {
589
+ /**
590
+ * Pede um ticket ao core. Chamado na abertura **e a cada reconexão** — o
591
+ * ticket é de uso único e expira em 60 s (`core/sse_access.py`), então
592
+ * reconectar com o mesmo valor sempre falharia na autenticação.
593
+ */
594
+ requestTicket: () => Promise<string>;
595
+ /** Monta a URL do EventSource a partir de um ticket recém-emitido. */
596
+ buildUrl: (ticket: string) => string;
597
+ /** Decide, frame a frame, se o fluxo terminou. */
598
+ classify: (frame: SseFrame) => SseVerdict<T>;
599
+ /** Teto absoluto do fluxo. Default 310 s (o core faz timeout em 300 s). */
600
+ timeoutMs?: number;
601
+ /** Máximo de reconexões antes de desistir. Default 5. */
602
+ maxReconnects?: number;
603
+ /** Cancela o fluxo de fora (ex.: usuário fechou o modal). */
604
+ signal?: AbortSignal;
605
+ /** Injeção para teste. Default: `globalThis.EventSource`. */
606
+ eventSourceFactory?: (url: string) => EventSource;
607
+ /** Notifica cada frame não-terminal (ex.: atualizar UI). */
608
+ onProgress?: (frame: SseFrame) => void;
609
+ }
610
+
611
+ /**
612
+ * Consome um stream SSE do core até um veredito terminal.
613
+ *
614
+ * Diferenças em relação ao consumidor antigo (`loginWithBiometricSSE`, que era
615
+ * código morto e nunca funcionou):
616
+ *
617
+ * 1. escuta o evento default `message`, que é o que o core de fato emite;
618
+ * 2. reconecta pedindo **ticket novo**, em vez de rejeitar no primeiro soluço
619
+ * de rede — o comentário em `api.ts` prometia isso e o código não fazia;
620
+ * 3. distingue o fechamento normal do servidor (que acontece logo após um
621
+ * status terminal) de uma queda de conexão de verdade.
622
+ */
623
+ export declare function consumeSseStream<T>(options: ConsumeSseOptions<T>): Promise<T>;
624
+
464
625
  /**
465
626
  * Compatibilidade com callers antigos que passavam `{ purpose, legalBasis }`.
466
627
  * Deprecated — remover quando US14.4 unificar tokens.
@@ -484,6 +645,15 @@ export declare interface DetectionResult {
484
645
  details?: any;
485
646
  }
486
647
 
648
+ /** Token de inscrição de aparelho, devolvido por {@link requestDeviceEnrollmentToken}. */
649
+ export declare interface DeviceEnrollmentToken {
650
+ /** JWT RS256 de uso único. Vira o conteúdo do QR. */
651
+ token: string;
652
+ /** Validade em segundos (o core emite 300). */
653
+ expiresIn: number;
654
+ purpose: string;
655
+ }
656
+
487
657
  export declare class DocumentCaptureModal {
488
658
  private overlay;
489
659
  private video;
@@ -593,8 +763,6 @@ export declare const ENVIRONMENT_URLS: Record<Environment, string>;
593
763
  */
594
764
  export declare enum ErrorType {
595
765
  NETWORK = "NetworkError",
596
- /** @deprecated Use `ErrorType.NETWORK`. Mantido para compatibilidade com consumidores existentes do SDK. */
597
- NETWORK_ERROR = "NetworkError",
598
766
  INVALID_TOKEN = "InvalidTokenError",
599
767
  RECOGNITION_FAILED = "RecognitionFailedError",
600
768
  LOGIN_FAILED = "LoginFailedError",
@@ -629,6 +797,16 @@ declare interface FaceCaptureModalProps {
629
797
  autoLighting?: boolean;
630
798
  }
631
799
 
800
+ /**
801
+ * Estado de posicionamento do rosto detectado.
802
+ * - `searching` — nenhum rosto detectado ainda
803
+ * - `too-far` — rosto muito distante da câmera
804
+ * - `too-close` — rosto muito próximo da câmera
805
+ * - `off-center` — rosto fora do centro do oval
806
+ * - `centered` — rosto corretamente posicionado
807
+ */
808
+ export declare type FaceState = 'searching' | 'too-far' | 'too-close' | 'off-center' | 'centered';
809
+
632
810
  /**
633
811
  * Classe para gerenciar o prompt de fallback
634
812
  */
@@ -689,6 +867,9 @@ export declare function getApplicationToken(): string | null;
689
867
  /** Retorna o nome do integrador configurado, se houver. */
690
868
  export declare function getAppName(): string | null;
691
869
 
870
+ /** Retorna a política de quedas automáticas de canal. Ver {@link AutoFallbackOptions}. */
871
+ export declare function getAutoFallback(): Required<AutoFallbackOptions>;
872
+
692
873
  /**
693
874
  * Retorna a URL base configurada para a API.
694
875
  * Se o SDK não foi inicializado, retorna o fallback para sandbox.
@@ -1185,6 +1366,25 @@ export declare interface ProofOfLifeResult {
1185
1366
  error?: string;
1186
1367
  }
1187
1368
 
1369
+ /**
1370
+ * Desfecho da confirmação no celular.
1371
+ *
1372
+ * `denied` e `expired` são desfechos, não exceções — quem chama precisa
1373
+ * distinguir os dois para dirigir a cascata de fallback: expirar pode cair
1374
+ * para senha, recusar **não pode**.
1375
+ */
1376
+ export declare type PushApprovalOutcome = {
1377
+ status: 'approved';
1378
+ data: Record<string, unknown>;
1379
+ } | {
1380
+ status: 'denied';
1381
+ reason?: string;
1382
+ } | {
1383
+ status: 'expired';
1384
+ } | {
1385
+ status: 'cancelled';
1386
+ };
1387
+
1188
1388
  declare interface RecognitionResult {
1189
1389
  success: boolean;
1190
1390
  data: {
@@ -1268,6 +1468,29 @@ export declare function recordConsent(customConsent?: Partial<{
1268
1468
  legalBasis: string;
1269
1469
  }>): Promise<ConsentRecord | null>;
1270
1470
 
1471
+ /** Par de tokens devolvido por {@link refreshSession}. */
1472
+ export declare interface RefreshedSession {
1473
+ accessToken: string;
1474
+ refreshToken: string;
1475
+ }
1476
+
1477
+ /**
1478
+ * Renova a sessão a partir de um refresh token.
1479
+ *
1480
+ * O core **rotaciona**: o refresh antigo entra na blacklist e um novo é
1481
+ * emitido junto do access. Guarde sempre o par devolvido — reenviar o refresh
1482
+ * anterior passa a dar 401.
1483
+ *
1484
+ * Existe para sessões que duram mais que a validade do access token (o console
1485
+ * administrativo é o caso motivador). Fluxos curtos não precisam chamar.
1486
+ *
1487
+ * @param refreshToken Refresh token vigente, vindo de um login anterior.
1488
+ * @param applicationToken Token da aplicação.
1489
+ * @throws NeoFaceError `INVALID_TOKEN` se o refresh expirou, já foi usado ou
1490
+ * foi revogado — nesse caso o caminho é refazer o login.
1491
+ */
1492
+ export declare const refreshSession: (refreshToken: string, applicationToken: string) => Promise<RefreshedSession>;
1493
+
1271
1494
  /**
1272
1495
  * NEO-101: Register biometric data for an existing person
1273
1496
  *
@@ -1390,6 +1613,21 @@ declare interface RequestChallengeWithSessionParams {
1390
1613
  */
1391
1614
  export declare function requestConsent(info?: ConsentInfo): Promise<boolean>;
1392
1615
 
1616
+ /**
1617
+ * Pede ao core um token de inscrição de aparelho.
1618
+ *
1619
+ * Exige **as duas** credenciais ao mesmo tempo: `X-App-Token` da aplicação e o
1620
+ * Bearer de um usuário DONOR autenticado (permission `IsDonorOfApplicationConsumer`
1621
+ * no core). Por isso a inscrição só existe no autosserviço, com a pessoa logada.
1622
+ *
1623
+ * O valor devolvido **não é segredo de longa duração**: é um JWT de 5 minutos,
1624
+ * de uso único. Não guarde, não reaproveite e não exiba duas vezes.
1625
+ *
1626
+ * @param userAccessToken Access token do DONOR autenticado.
1627
+ * @param applicationToken Token da aplicação.
1628
+ */
1629
+ export declare const requestDeviceEnrollmentToken: (userAccessToken: string, applicationToken: string) => Promise<DeviceEnrollmentToken>;
1630
+
1393
1631
  /**
1394
1632
  * Pede ao servidor a sequência de gestos do desafio de liveness.
1395
1633
  * O SDK apenas exibe e coleta — validação de gesto/yaw/pitch é responsabilidade
@@ -1485,6 +1723,7 @@ declare interface SDKConfig {
1485
1723
  locale: string;
1486
1724
  resolvedTheme: ResolvedTheme | null;
1487
1725
  consent: Consent;
1726
+ autoFallback: Required<AutoFallbackOptions>;
1488
1727
  }
1489
1728
 
1490
1729
  /**
@@ -1541,6 +1780,31 @@ export declare interface SDKInitOptions {
1541
1780
  * e emite `console.warn` uma única vez.
1542
1781
  */
1543
1782
  consent?: Consent;
1783
+ /**
1784
+ * Quedas automáticas de canal, em dois níveis independentes.
1785
+ *
1786
+ * O canal mudar é informação de segurança: cair sozinho esconde do usuário
1787
+ * que a verificação passou a acontecer em outro lugar. Por isso o nível 1
1788
+ * nasce desligado e precisa ser pedido.
1789
+ *
1790
+ * ```
1791
+ * nível 0 rosto no dispositivo atual
1792
+ * ├─ purpose exige push, ou câmera ausente/negada → nível 1
1793
+ * └─ ok → fim
1794
+ *
1795
+ * nível 1 confirmar no celular (toPhone, default false)
1796
+ * ├─ core diz que não há aparelho → nível 2
1797
+ * ├─ prazo expirou → nível 2
1798
+ * └─ RECUSADO no celular → falha terminal, não cascateia
1799
+ *
1800
+ * nível 2 e-mail + senha (toPassword, default true)
1801
+ * ```
1802
+ *
1803
+ * A recusa não cai para senha de propósito: se caísse, quem disparou o
1804
+ * pedido e levou "não" entraria pelo outro caminho, e o controle não valeria
1805
+ * nada. Só expiração e ausência de aparelho cascateiam.
1806
+ */
1807
+ autoFallback?: AutoFallbackOptions;
1544
1808
  }
1545
1809
 
1546
1810
  export declare type SDKRadius = 8 | 16 | 24;
@@ -1576,6 +1840,35 @@ export declare const simpleIdentification: (documentType: string, documentNumber
1576
1840
  };
1577
1841
  }>;
1578
1842
 
1843
+ /**
1844
+ * Frame SSE do core.
1845
+ *
1846
+ * O core emite `data: {json}\n\n` **sem linha `event:`**
1847
+ * (`core/sse_notification_service.py:_format_sse_message`). Pela spec SSE, um
1848
+ * frame sem `event:` é despachado como o tipo default `message` — então
1849
+ * `addEventListener('success', …)` nunca dispara. Quem discrimina é o campo
1850
+ * `status` do payload.
1851
+ */
1852
+ export declare interface SseFrame {
1853
+ task_id?: string;
1854
+ status?: string;
1855
+ timestamp?: number;
1856
+ data?: Record<string, unknown>;
1857
+ message?: string;
1858
+ error?: string;
1859
+ }
1860
+
1861
+ /** Veredito do classificador para cada frame recebido. */
1862
+ export declare type SseVerdict<T> = {
1863
+ kind: 'pending';
1864
+ } | {
1865
+ kind: 'resolve';
1866
+ value: T;
1867
+ } | {
1868
+ kind: 'reject';
1869
+ error: NeoFaceError;
1870
+ };
1871
+
1579
1872
  export declare function start(applicationToken: string, callbacks: Callbacks, options?: {
1580
1873
  appName?: string;
1581
1874
  /** NEO-410 · US14.3 — botão "Não consigo fazer esse movimento" visível desde o 1º desafio. */
@@ -1632,7 +1925,7 @@ export declare function startHandLogin(options: BiometricLoginOptions): Promise<
1632
1925
  */
1633
1926
  export declare function startLivenessCapture(applicationToken: string, callbacks: {
1634
1927
  onSuccess(photos: Blob[]): void;
1635
- onError(code: string, message: string): void;
1928
+ onError(err: NeoFaceError): void;
1636
1929
  onCancel?(): void;
1637
1930
  }, options?: {
1638
1931
  appName?: string;
@@ -1739,7 +2032,7 @@ export declare const validateToken: (applicationToken: string) => Promise<boolea
1739
2032
  * MINOR: Incrementado quando adicionamos funcionalidades mantendo compatibilidade
1740
2033
  * PATCH: Incrementado quando corrigimos bugs mantendo compatibilidade
1741
2034
  */
1742
- export declare const VERSION = "1.40.3";
2035
+ export declare const VERSION = "1.42.0";
1743
2036
 
1744
2037
  /**
1745
2038
  * Executa `fn(sessionId)`. Se o servidor devolver 410 (sessão consumida/expirada),