npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

digilicense-sdk

v1.0.6

Published

Official TypeScript SDK for the DigiLicense License Management API

Readme

DigiLicense SDK

SDK TypeScript oficial para a API DigiLicense de gerenciamento de licenças.

  • Dois clients separados: ExternalClient (software do cliente) e InternalClient (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 fetch nativo (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-sdk

Requisito: Node.js >= 18 (usa fetch nativo).


Base URL

A base URL é fixa no SDK:

https://api.digilicense.com.br

Os 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_URL para 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.js

InternalClient

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 undefined em 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 LicenseTelemetry com 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-id do host (montado via /proc), MAC do host e hostname do container. Em containers do mesmo nó, o hostname pode variar — veja resolveMachineId() 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 local

Quando 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_id enviado 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.sh

O script:

  1. Gera o MACHINE_ID do hardware atual
  2. Injeta em /etc/${INSTANCIA}/backend/.env
  3. Atualiza config.digitalsac (se existir)
  4. 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 arquivos

Variável de Ambiente (apenas para testes)

DIGILICENSE_BASE_URL=http://localhost:4000 npx tsx examples/external-basic.ts

Licença

MIT — veja LICENSE.