Fecha as duas pendências da leva anterior (módulo de Assinatura Eletrônica): tela de backoffice para gerenciar envelopes (criação, envio, cancelamento, checkpoint/finalização, auditoria) e as duas páginas públicas (/assinar/:token, /verificar/:verificationId). Backend: novos endpoints de streaming de PDF (documento congelado e PDF final consolidado, autenticados e via token público) que faltavam para a UI funcionar — o signatário não tinha como ver o próprio documento antes de confirmar leitura. Rate limiting (guard próprio, em memória, chaves por IP e por token) em todas as rotas sem sessão: auth (login/mfa/forgot-password/reset-password/refresh/logout) e todo o fluxo público de assinatura/verificação. Suíte: 77/77 verdes. pnpm turbo run typecheck build: 28/28. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
77 lines
2.8 KiB
TypeScript
77 lines
2.8 KiB
TypeScript
/**
|
|
* Client for `apps/api` `/v1/public-signature/:token/*` — the signer-facing
|
|
* flow reached via the emailed link `/assinar/:token` (see
|
|
* apps/api/src/signatures/public-signature.controller.ts +
|
|
* public-signature.service.ts for the source of truth). Deliberately NOT
|
|
* authenticated: the token in the URL is the entire authorization,
|
|
* there's never an `accessToken` header here — mirrored by never taking
|
|
* one as a parameter in this file, unlike `./signatures.ts`.
|
|
*/
|
|
import { API_BASE_URL, apiRequest } from "./http.js";
|
|
import type { PartyRole, PersonType, SignerStatus } from "./signatures.js";
|
|
|
|
export interface PublicSignerState {
|
|
id: string;
|
|
party: PartyRole;
|
|
person_type: PersonType | null;
|
|
full_name: string;
|
|
cpf: string | null;
|
|
email: string;
|
|
phone: string | null;
|
|
company_name: string | null;
|
|
cnpj: string | null;
|
|
role_title: string | null;
|
|
status: SignerStatus;
|
|
documentsRead: string[];
|
|
}
|
|
|
|
export interface PublicDocumentState {
|
|
id: string;
|
|
title: string;
|
|
documentVersion: number;
|
|
pageCount: number | null;
|
|
confirmedRead: boolean;
|
|
}
|
|
|
|
export interface PublicSignatureState {
|
|
envelope: { id: string; envelopeNumber: string; status: string };
|
|
signer: PublicSignerState;
|
|
documents: PublicDocumentState[];
|
|
}
|
|
|
|
export function getPublicSignatureState(token: string): Promise<PublicSignatureState> {
|
|
return apiRequest<PublicSignatureState>(`/public-signature/${token}`, { method: "GET" });
|
|
}
|
|
|
|
/** Opens the document's PDF in a new tab — no bearer token needed, the token is already in the path, so a plain `window.open` works (unlike the authenticated backoffice equivalent in `./signatures.ts`). */
|
|
export function publicDocumentPdfUrl(token: string, documentId: string): string {
|
|
return `${API_BASE_URL}/public-signature/${token}/documents/${documentId}/pdf`;
|
|
}
|
|
|
|
export function confirmDocumentRead(token: string, documentId: string): Promise<void> {
|
|
return apiRequest<void>(`/public-signature/${token}/documents/${documentId}/confirm-read`, { method: "POST" });
|
|
}
|
|
|
|
export function confirmSignerData(token: string): Promise<void> {
|
|
return apiRequest<void>(`/public-signature/${token}/confirm-data`, { method: "POST" });
|
|
}
|
|
|
|
export function acceptConsent(token: string): Promise<void> {
|
|
return apiRequest<void>(`/public-signature/${token}/consent`, { method: "POST" });
|
|
}
|
|
|
|
export function requestOtp(token: string): Promise<void> {
|
|
return apiRequest<void>(`/public-signature/${token}/otp/request`, { method: "POST" });
|
|
}
|
|
|
|
export function verifyOtp(token: string, code: string): Promise<void> {
|
|
return apiRequest<void>(`/public-signature/${token}/otp/verify`, {
|
|
method: "POST",
|
|
body: JSON.stringify({ code }),
|
|
});
|
|
}
|
|
|
|
export function commitSignature(token: string): Promise<void> {
|
|
return apiRequest<void>(`/public-signature/${token}/sign`, { method: "POST" });
|
|
}
|