@nexus-systems/manager
v0.2.0
Published
Cliente HTTP para validação de licença contra o Nexus License Manager
Readme
@nexus-systems/manager
Cliente HTTP leve para validação de licenças contra o Nexus License Manager (POST /api/v1/license/validate).
O que mudou a partir da v0.2
O servidor passou a devolver (e este pacote a expor) uma política explícita para o seu app saber como proceder, sem inferir só pelo status ou pela mensagem de erro.
| Área | Antes | Agora (recomendado) |
| :--- | :--- | :--- |
| Sucesso | status, datas, paymentUrl, token | Os campos acima mais enforcement e clientActions |
| Erro | error, message, httpStatus | Mantém isso mais code (estável), enforcement (em geral deny) e clientActions quando o servidor enviar |
| Parse | Validação manual de campos | Resposta de sucesso normalizada com os mesmos schemas do contrato interno (compatível com servidor legado sem os novos campos) |
Implementação: o contrato vive em packages/license-contract (só workspace). Os tipos estáveis (LicenseClientAction, LicenseErrorCode, etc.) são reexportados por @nexus-systems/manager — use o manager como única dependência npm.
Uso correto (enforcement + ações)
result.ok— distingue sucesso da chamada HTTP vs. falha de rede/servidor/negócio.- Em sucesso, use
result.enforcementcomo decisão principal:allow— assinatura em dia; operação normal (clientActionscostuma incluirALLOW_FULL_ACCESS).grace— assinatura em atraso (overdue); o JWT costuma ter TTL menor no servidor. Não trate comoactive: mostre aviso, ofereça pagamento; só bloqueie se a sua política de produto exigir.
result.clientActions— lista de códigos estáveis (banner, modal, link de pagamento). Mapeie cada código na sua UI; não dependa só de strings emmessage.- Em erro, use
result.codepara lógica (ex.:LICENSE_NOT_FOUND) e trateresult.enforcement === 'deny'como bloqueio de licença. Para erros HTTP desta rota, se o servidor for antigo,enforcementpode ser omitido no JSON — o pacote assumedenynesses casos.
Exemplo mínimo:
import { NexusManager } from '@nexus-systems/manager';
const nexus = new NexusManager({
licenseKey: process.env.NEXUS_LICENSE_KEY,
clientSecret: process.env.NEXUS_CLIENT_SECRET, // se o servidor exigir LICENSE_CLIENT_SECRET
});
const result = await nexus.validate();
if (!result.ok) {
// Bloquear acesso: enforcement efetiva é deny (ou assumida deny)
console.error(result.code, result.message);
return;
}
switch (result.enforcement) {
case 'allow':
// liberar uso pleno
break;
case 'grace':
// manter acesso com avisos; usar result.clientActions e result.paymentUrl
break;
default:
// defensivo; em sucesso normal da API atual não deve ocorrer
break;
}
for (const action of result.clientActions) {
// ex.: SHOW_PAYMENT_REMINDER → banner; OPEN_PAYMENT_URL → botão para result.paymentUrl
}Evite: tratar só result.status === 'active' como “pode usar” e ignorar overdue — em grace a licença ainda pode ser válida com ressalvas.
Instalação
npm install @nexus-systems/manager
# ou
pnpm add @nexus-systems/manager
# ou
yarn add @nexus-systems/managerO pacote publicado inclui o contrato no bundle e declara zod como dependência de runtime (não é necessário instalar o contrato separadamente).
Configuração
Variáveis de ambiente suportadas
NEXUS_LICENSE_KEY— chave da licença.NEXUS_CLIENT_SECRET— deve coincidir comLICENSE_CLIENT_SECRETno servidor, quando esse segredo estiver configurado.NEXUS_MANAGER_BASE_URL— URL base do gerenciador (sem barra final; padrãohttps://manager.nexus-system.com.br).
Exemplo em Node.js / TypeScript
import { NexusManager } from '@nexus-systems/manager';
const nexus = new NexusManager({
licenseKey: 'SUA_CHAVE_AQUI',
clientSecret: 'SEU_SEGREDO_AQUI',
});
async function checkLicense() {
const result = await nexus.validate();
if (!result.ok) {
console.error(result.error, result.code, result.message);
return;
}
if (result.enforcement === 'grace') {
console.warn('Assinatura em atraso — avisar usuário e priorizar pagamento.');
}
if (result.paymentUrl) {
console.log('Portal de pagamento:', result.paymentUrl);
}
// JWT para verificação offline (conforme sua política de segurança)
console.log('Token até:', result.tokenExpiresAt);
}
void checkLicense();Exemplo em middleware (Next.js)
overdue vem como grace: redirecionar tudo que não é active para uma página de erro bloqueia clientes que ainda têm janela de uso. Prefira ramificar por enforcement:
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { NexusManager } from '@nexus-systems/manager';
const nexus = new NexusManager();
export async function middleware(request: NextRequest) {
const result = await nexus.validate();
if (!result.ok) {
return NextResponse.redirect(new URL('/license-error', request.url));
}
if (result.enforcement === 'deny') {
return NextResponse.redirect(new URL('/license-blocked', request.url));
}
if (result.enforcement === 'grace') {
// Ex.: cookie/header para a app mostrar banner; não precisa bloquear rota inteira
const res = NextResponse.next();
res.headers.set('x-license-grace', '1');
return res;
}
return NextResponse.next();
}
export const config = {
matcher: '/admin/:path*',
};API
NexusManager
constructor(options?: NexusManagerOptions)
| Opção | Tipo | Descrição |
| :--- | :--- | :--- |
| baseUrl | string | URL base do gerenciador (sem / final). |
| licenseKey | string | Chave da licença. |
| clientSecret | string | Segredo alinhado a LICENSE_CLIENT_SECRET no servidor. |
| env | Record<string, string \| undefined> | Variáveis de ambiente alternativas (ex. workers). |
| fetch | typeof fetch | Implementação customizada de fetch. |
validate(): Promise<LicenseValidationResult>
Chama o endpoint de validação e devolve um discriminated union em ok.
Sucesso (ok: true):
| Campo | Descrição |
| :--- | :--- |
| status | active | overdue em respostas válidas atuais (espelho da assinatura). |
| enforcement | allow | grace — use para decidir rigor de bloqueio vs. aviso. |
| clientActions | Códigos estáveis sugeridos (ALLOW_FULL_ACCESS, SHOW_PAYMENT_REMINDER, …). |
| subscriptionPeriodEnd | Fim do período de cobrança atual (UTC). |
| tokenExpiresAt | Expiração do JWT retornado (UTC). |
| paymentUrl | URL de pagamento quando aplicável. |
| token | JWT RS256 do gerenciador. |
Erro (ok: false):
| Campo | Descrição |
| :--- | :--- |
| error | Categoria grossa: unauthorized, forbidden, bad_request, server, network. |
| message | Texto do servidor ou fallback. |
| httpStatus | Status HTTP quando aplicável. |
| code | Código estável (LICENSE_NOT_FOUND, …) quando o servidor enviar. |
| enforcement | Em erros desta rota costuma ser deny; omitido em servidor legado. |
| clientActions | Ações sugeridas em erros estruturados (ex.: BLOCK_ACCESS). |
Licença
MIT
