digilicense-sdk
v1.0.6
Published
Official TypeScript SDK for the DigiLicense License Management API
Maintainers
Readme
DigiLicense SDK
SDK TypeScript oficial para a API DigiLicense de gerenciamento de licenças.
- Dois clients separados:
ExternalClient(software do cliente) eInternalClient(backend do produto) - Fortemente tipado — todos os payloads e respostas possuem tipos TypeScript
- ESM + CJS — compatível com projetos modernos e legados
- Sem dependências pesadas — usa
fetchnativo (Node 18+) - Tratamento de erros padronizado com classes específicas
- Timeout e AbortSignal configuráveis por instância ou por request
Instalação
npm install digilicense-sdk
# ou
yarn add digilicense-sdk
# ou
pnpm add digilicense-sdkRequisito: Node.js >= 18 (usa
fetchnativo).
Base URL
A base URL é fixa no SDK:
https://api.digilicense.com.brOs prefixos utilizados são:
/api_external— endpoints externos (software do cliente final)/api_internal— endpoints internos (backend do produto)
Para ambientes de teste, defina a variável de ambiente
DIGILICENSE_BASE_URLpara sobrescrever a base URL.
Importação
import { ExternalClient, InternalClient } from "digilicense-sdk";Ou importação nomeada de tipos, erros e utilitários:
import {
ExternalClient,
InternalClient,
DigiLicenseApiError,
DigiLicenseHttpError,
DigiLicenseTimeoutError,
DigiLicenseNetworkError,
// Utilitários de Machine ID (v1.0.4+)
generateMachineId,
resolveMachineId,
} from "digilicense-sdk";ExternalClient
Usado pelo software do cliente final para ativar, verificar e gerenciar licenças.
Construtor
const client = new ExternalClient({
apiKey: "SUA_API_KEY", // enviado como header LB-API-KEY
defaultLbUrl: "https://site.com", // header LB-URL padrão
defaultLbIp: "1.2.3.4", // header LB-IP padrão
defaultLang: "portuguese", // idioma das mensagens da API (LB-LANG)
timeoutMs: 10_000, // timeout em ms (padrão: 15000)
defaultHeaders: { // headers adicionais fixos
"X-App-Version": "2.0.0",
},
});Métodos disponíveis
| Método | Endpoint | Descrição |
|--------|----------|-----------|
| checkConnection(options?) | POST /check_connection | Testa conectividade e valida API key |
| activateLicense(payload, options?) | POST /activate_license | Registra nova ativação |
| verifyLicense(payload, options?) | POST /verify_license | Verifica se a ativação é válida |
| deactivateLicense(payload, options?) | POST /deactivate_license | Desativa a ativação atual |
| latestVersion(payload, options?) | POST /latest_version | Retorna metadados da versão mais recente |
| checkUpdate(payload, options?) | POST /check_update | Verifica se há versão mais nova |
| downloadUpdate(payload, options?) | POST /download_update | Baixa o arquivo de atualização (binary) |
| getUpdateSize(payload, options?) | HEAD /download_update | Retorna o tamanho do arquivo sem baixar |
Exemplos
import { ExternalClient } from "digilicense-sdk";
const client = new ExternalClient({
apiKey: process.env.DIGILICENSE_API_KEY,
defaultLbUrl: "https://meusite.com",
defaultLbIp: "1.2.3.4",
});
// Ativar licença
const res = await client.activateLicense({
product_id: "MEU_PRODUTO",
license_code: "XXXX-XXXX-XXXX-XXXX",
client_name: "João Silva",
});
console.log(res.data?.uses_left);
// Verificar licença (sobrescrevendo LB-URL por request)
const verify = await client.verifyLicense(
{ product_id: "MEU_PRODUTO", license_code: "XXXX-XXXX-XXXX-XXXX" },
{ lbUrl: "https://outro.com", lbIp: "9.9.9.9" }
);
// Verificar atualização
const update = await client.checkUpdate({
product_id: "MEU_PRODUTO",
current_version: "1.0.0",
});
if (update.status) {
console.log("Nova versão disponível:", update.version);
}
// Baixar atualização
const response = await client.downloadUpdate({ product_id: "MEU_PRODUTO" });
const buffer = await response.arrayBuffer();
// Buffer.from(buffer) para salvar em disco com Node.jsInternalClient
Usado pelo backend do produto para gerenciar produtos e licenças programaticamente.
Construtor
const client = new InternalClient({
apiKey: "SUA_API_KEY_INTERNA",
timeoutMs: 20_000,
});Métodos disponíveis
Sistema
| Método | Endpoint | Descrição |
|--------|----------|-----------|
| checkConnection(options?) | POST /check_connection | Testa conectividade |
Produtos
| Método | Endpoint | Descrição |
|--------|----------|-----------|
| addProduct(payload, options?) | POST /add_product | Cria produto |
| getProduct(payload, options?) | POST /get_product | Busca produto por ID |
| getProducts(payload?, options?) | POST /get_products | Lista produtos |
| markProductActive(payload, options?) | POST /mark_product_active | Ativa produto |
| markProductInactive(payload, options?) | POST /mark_product_inactive | Desativa produto |
Licenças
| Método | Endpoint | Descrição |
|--------|----------|-----------|
| createLicense(payload, options?) | POST /create_license | Cria licença |
| editLicense(payload, options?) | POST /edit_license | Edita licença |
| getLicense(payload, options?) | POST /get_license | Busca detalhes da licença |
| searchLicense(payload, options?) | POST /search_license | Pesquisa licenças |
| deleteLicense(payload, options?) | POST /delete_license | Remove licença permanentemente |
| blockLicense(payload, options?) | POST /block_license | Bloqueia licença |
| unblockLicense(payload, options?) | POST /unblock_license | Desbloqueia licença |
| deactivateLicenseActivations(payload, options?) | POST /deactivate_license_activations | Desativa todas as ativações |
Exemplos
import { InternalClient } from "digilicense-sdk";
const client = new InternalClient({
apiKey: process.env.DIGILICENSE_API_KEY,
});
// Criar licença com campos personalizados
const created = await client.createLicense({
product_id: "MEU_PRODUTO",
client_name: "Empresa XYZ",
client_email: "[email protected]",
uses: 5,
parallel_uses: 2,
expiry_days: 365,
licensed_domains: "https://xyz.com",
custom_fields: { plan: "enterprise", seats: 10 },
});
console.log("Código:", created.license_code);
// Buscar licença
const lic = await client.getLicense({
product_id: "MEU_PRODUTO",
license_code: created.license_code!,
});
console.log(lic.uses_left, lic.custom_fields);
// Bloquear e desbloquear
await client.blockLicense({ product_id: "MEU_PRODUTO", license_code: "XXX" });
await client.unblockLicense({ product_id: "MEU_PRODUTO", license_code: "XXX" });
// Desativar todas as ativações
await client.deactivateLicenseActivations({
product_id: "MEU_PRODUTO",
license_code: "XXX",
});Headers LB-URL, LB-IP e LB-LANG
LB-URL e LB-IP
Identificam a URL e o IP do cliente que está fazendo a requisição.
São relevantes no ExternalClient para controle de domínios/IPs licenciados.
LB-LANG — Idioma das mensagens
Controla o idioma das mensagens de resposta da API. Valores aceitos:
| Valor | Idioma |
|-------|--------|
| english | Inglês (padrão) |
| portuguese | Português (Brasil) |
| german | Alemão |
| chinese | Chinês |
Global (construtor):
const client = new ExternalClient({
defaultLbUrl: "https://cliente.com",
defaultLbIp: "1.2.3.4",
defaultLang: "portuguese", // todas as mensagens virão em português
});Por request (options) — sobrescreve o padrão:
await client.verifyLicense(payload, {
lbUrl: "https://outro.com",
lbIp: "5.6.7.8",
lbLang: "english", // esta request específica em inglês
headers: { "X-Custom": "valor" },
timeoutMs: 5_000,
});Telemetria — Monitoramento das Instalações
O SDK inclui suporte completo para envio de telemetria periódica ao DigiLicense. Com isso, você passa a ver em tempo real quais instalações estão online/offline, versão instalada, uso de CPU/RAM, usuários ativos e muito mais.
Método sendTelemetry()
import { ExternalClient, resolveMachineId } from "digilicense-sdk";
import os from "node:os";
const client = new ExternalClient({
apiKey: process.env.DIGILICENSE_API_KEY,
defaultLbUrl: process.env.FRONTEND_URL,
});
await client.sendTelemetry({
license_code: "XXXXX-XXXXX-XXXXX-XXXXX",
product_id: "MEU_PRODUTO",
iid: process.env.INSTANCE_NAME ?? os.hostname(), // identificador único da instalação
version: "4.0.2",
cpu_process_pct: await ExternalClient.measureCpuProcess(), // Opção A — qualquer OS
cpu_system_pct: await ExternalClient.measureCpuSystem(), // Opção B — somente Linux
ram_total_mb: Math.round(os.totalmem() / 1024 / 1024),
ram_used_mb: Math.round((os.totalmem() - os.freemem()) / 1024 / 1024),
uptime_seconds: Math.floor(process.uptime()),
users_online: 12,
connections: 37,
os: `${os.platform()} ${os.release()}`,
db: "postgres 16",
extra: { machine_id: resolveMachineId() }, // opcional
});Medição de CPU
ExternalClient.measureCpuProcess() — Estático, async
Mede o uso de CPU do processo Node.js atual ao longo de 100ms.
- Funciona em qualquer OS (Linux, macOS, Windows)
- Usa
process.cpuUsage()com delta - Retorna um valor entre 0 e 100
const cpu = await ExternalClient.measureCpuProcess();
console.log(`CPU do processo: ${cpu}%`);ExternalClient.measureCpuSystem() — Estático, async
Mede o uso de CPU total da máquina ao longo de 500ms lendo /proc/stat.
- Somente Linux — retorna
undefinedem outros sistemas - Representa a CPU de toda a máquina/container host
- Retorna um valor entre 0 e 100, ou
undefined
const cpuSys = await ExternalClient.measureCpuSystem();
if (cpuSys !== undefined) {
console.log(`CPU do sistema: ${cpuSys}%`); // 🐧 somente Linux
}Rodando a cada 5 minutos (cron)
Exemplo com node-cron:
import cron from "node-cron";
import { ExternalClient, resolveMachineId } from "digilicense-sdk";
import os from "node:os";
const client = new ExternalClient({ apiKey: "...", defaultLbUrl: "..." });
cron.schedule("*/5 * * * *", async () => {
try {
await client.sendTelemetry({
license_code: "XXXXX-XXXXX-XXXXX-XXXXX",
product_id: "MEU_PRODUTO",
iid: process.env.INSTANCE_NAME ?? os.hostname(),
version: "4.0.2",
cpu_process_pct: await ExternalClient.measureCpuProcess(),
cpu_system_pct: await ExternalClient.measureCpuSystem(),
ram_total_mb: Math.round(os.totalmem() / 1024 / 1024),
ram_used_mb: Math.round((os.totalmem() - os.freemem()) / 1024 / 1024),
uptime_seconds: Math.floor(process.uptime()),
os: `${os.platform()} ${os.release()}`,
});
} catch (e) {
// Falha de telemetria não deve parar o sistema
}
});O que o DigiLicense faz com os dados
- Salva na tabela
LicenseTelemetrycom retenção de 7 dias - Considera offline se não receber dados por mais de 10 minutos
- Exibe no painel:
- Dashboard: widgets de instalações online/offline, sobrecarregadas, versão mais usada
- Página "Installations": tabela com todas as instalações, status, métricas
- Aba "Telemetry" no detalhe de cada licença: histórico de 7 dias por iid
Campos do payload (TelemetryRequest)
| Campo | Tipo | Descrição |
|---|---|---|
| license_code | string | Obrigatório — código da licença |
| product_id | string | Obrigatório — ID do produto |
| iid | string | Obrigatório — identificador da instalação (ex: hostname) |
| version | string? | Versão instalada do software |
| cpu_process_pct | number? | % CPU do processo Node.js (0–100) |
| cpu_system_pct | number? | % CPU total da máquina — somente Linux (0–100) |
| ram_total_mb | number? | RAM total da máquina em MB |
| ram_used_mb | number? | RAM usada em MB |
| uptime_seconds | number? | Uptime do processo em segundos |
| users_online | number? | Usuários ativos/online |
| connections | number? | Conexões ativas (ex: canais WhatsApp) |
| os | string? | Sistema operacional (ex: "ubuntu 24.04") |
| db | string? | Banco de dados (ex: "postgres 16") |
| extra | Record<string, unknown>? | Campos extras para uso futuro |
Machine ID — Impressão Digital do Servidor
O SDK inclui utilitários para gerar um identificador único e estável do servidor (machine_id).
Esse ID é usado na ativação e verificação de licenças quando o produto tem a opção "Exigir Machine ID" habilitada no DigiLicense — garantindo que a licença só funcione na máquina onde foi ativada.
Funções disponíveis
import { generateMachineId, resolveMachineId } from "digilicense-sdk";generateMachineId(): string
Gera um fingerprint de hardware da máquina atual usando:
| Fonte | Descrição |
|-------|-----------|
| /etc/machine-id | ID único da instalação do Linux (gerado no boot da VM/servidor) |
| MAC address | Endereço da primeira interface de rede não-interna |
| Hostname | Nome da máquina (os.hostname()) |
O resultado é um hash SHA-256 (64 caracteres hexadecimais). O valor é cached em memória — calculado apenas uma vez por processo.
import { generateMachineId } from "digilicense-sdk";
const id = generateMachineId();
// ex: "a3f8c2d1e4b9f07e2a6c18d9e3b2f1a0c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2"
console.log("Machine ID:", id);Estabilidade: O mesmo servidor sempre gera o mesmo hash, mesmo após reinicializações do processo ou do sistema operacional.
Containers: Em containers Docker, o valor é baseado no
/etc/machine-iddo host (montado via/proc), MAC do host e hostname do container. Em containers do mesmo nó, o hostname pode variar — vejaresolveMachineId()para a solução recomendada em Docker Swarm.
resolveMachineId(): string
Resolve o Machine ID a ser usado, com a seguinte ordem de prioridade:
1. Variável de ambiente MACHINE_ID → usa o valor definido
2. generateMachineId() → gera do hardware localQuando usar cada abordagem:
| Cenário | Recomendação |
|---------|-------------|
| Servidor standalone (bare metal / VPS simples) | resolveMachineId() — gera automaticamente do hardware |
| Docker Swarm / múltiplos workers | Definir MACHINE_ID no env do container (via instalador) |
| Kubernetes / containers efêmeros | Definir MACHINE_ID como variável de ambiente fixa |
import { resolveMachineId } from "digilicense-sdk";
// Usa MACHINE_ID do env se definido, senão gera do hardware
const machineId = resolveMachineId();
console.log("Machine ID resolvido:", machineId);Integrando com activateLicense e verifyLicense
O machine_id é enviado como campo opcional nos payloads de ativação e verificação:
import { ExternalClient, resolveMachineId } from "digilicense-sdk";
const client = new ExternalClient({
apiKey: process.env.DIGILICENSE_API_KEY,
defaultLbUrl: process.env.FRONTEND_URL,
});
const machineId = resolveMachineId();
// Ativar licença com machine_id
const activation = await client.activateLicense({
product_id: "MEU_PRODUTO",
license_code: "XXXXX-XXXXX-XXXXX-XXXXX",
client_name: "[email protected]",
machine_id: machineId, // <- enviado aqui
});
// Verificar licença com machine_id (DigiLicense valida se bate com o registrado)
const verify = await client.verifyLicense({
product_id: "MEU_PRODUTO",
license_code: "XXXXX-XXXXX-XXXXX-XXXXX",
client_name: "[email protected]",
machine_id: machineId, // <- enviado aqui
});Se o produto tiver "Exigir Machine ID" habilitado no DigiLicense e o
machine_idenviado não corresponder ao registrado na ativação, a verificação retornará erro — impedindo uso em máquinas não autorizadas.
Configuração em Docker Swarm (recomendado)
Em Docker Swarm, cada worker pode ter um hostname diferente, mas o instalador gera um MACHINE_ID único por instalação baseado no hardware do nó e salva em config.digitalsac. Esse valor é injetado no .env do container:
# config.digitalsac (gerado pelo instalador)
MACHINE_ID=a3f8c2d1e4b9f07e2a6c18d9...
# .env do backend (gerado pelo instalador)
MACHINE_ID=a3f8c2d1e4b9f07e2a6c18d9...No código Node.js, basta usar resolveMachineId() — ele detecta automaticamente a variável de ambiente:
// Sem Docker Swarm: gera do hardware
// Com Docker Swarm: usa process.env.MACHINE_ID
const machineId = resolveMachineId();Instalações existentes (sem Machine ID)
Se você já tem uma instalação em produção e precisa gerar o MACHINE_ID retroativamente, use o script:
bash /caminho/para/Instalador/gera-machine-id.shO script:
- Gera o
MACHINE_IDdo hardware atual - Injeta em
/etc/${INSTANCIA}/backend/.env - Atualiza
config.digitalsac(se existir) - Força o restart do serviço Docker Swarm
RequestOptions (por request)
type RequestOptions = {
lbUrl?: string; // Sobrescreve LB-URL header
lbIp?: string; // Sobrescreve LB-IP header
headers?: Record<string, string>; // Headers adicionais
timeoutMs?: number; // Timeout em ms
signal?: AbortSignal; // Para cancelamento externo
};Tratamento de Erros
Todos os erros herdam de DigiLicenseError.
| Classe | Quando é lançada |
|--------|-----------------|
| DigiLicenseApiError | API retorna { status: false, message: "..." } |
| DigiLicenseHttpError | Servidor retorna status HTTP não-2xx |
| DigiLicenseTimeoutError | Requisição excede o timeout configurado |
| DigiLicenseNetworkError | Falha de rede (sem resposta do servidor) |
import {
DigiLicenseApiError,
DigiLicenseHttpError,
DigiLicenseTimeoutError,
DigiLicenseNetworkError,
} from "digilicense-sdk";
try {
await client.activateLicense({ ... });
} catch (err) {
if (err instanceof DigiLicenseApiError) {
// Licença inválida, bloqueada, limite atingido, etc.
console.error("Erro da API:", err.apiMessage);
console.error("Resposta completa:", err.raw);
} else if (err instanceof DigiLicenseHttpError) {
console.error(`HTTP ${err.status}:`, err.body);
} else if (err instanceof DigiLicenseTimeoutError) {
console.error("Timeout após", err.timeoutMs, "ms");
} else if (err instanceof DigiLicenseNetworkError) {
console.error("Erro de rede:", err.message);
} else {
throw err;
}
}Build
npm install
npm run build # gera dist/ com ESM + CJS + .d.ts
npm run typecheck # type-check sem gerar arquivosVariável de Ambiente (apenas para testes)
DIGILICENSE_BASE_URL=http://localhost:4000 npx tsx examples/external-basic.tsLicença
MIT — veja LICENSE.
