🟩 SDK Oficial para Node.js, Bun & TypeScript (Manual Técnico & API)
El paquete validlicense-sdk es el cliente oficial para entornos de servidor (Node.js, Bun, Deno) y aplicaciones de escritorio (Electron, Tauri). Opera de forma autónoma con el módulo nativo node:crypto sin librerías externas de terceros.
🏛️ 1. Estructura de Tipos e Interfaces
ValidLicenseOptions
Configuración del cliente:
export interface ValidLicenseOptions {
serverUrl: string; // URL del servidor VPS (ej: 'https://licencias.labtec.sbs')
publicKeyHex?: string; // Clave Pública Ed25519 en formato hexadecimal de 64 caracteres
clientVersion?: string; // Versión del software cliente (por defecto '2026.1')
}
VerifyParams
Parámetros enviados en la petición de verificación:
export interface VerifyParams {
companyNit?: string; // NIT o documento de identificación de la empresa
companyName?: string; // Nombre o razón social
licenseToken?: string; // Token firmado almacenado localmente
customData?: Record<string, any>; // Metadatos personalizados (ej: { maxClusters: 4 })
features?: string[]; // Lista de módulos solicitados
isPrimaryHost?: boolean; // Indica si el host actual es el nodo principal
onRevoked?: () => void; // Callback ejecutado si la licencia fue revocada en el VPS
}
ValidLicenseRecord
Respuesta tipada que describe el estado y privilegios de la licencia:
export interface ValidLicenseRecord {
isActive: boolean; // true si la licencia está vigente y autorizada
status: 'ACTIVE' | 'SUSPENDED' | 'EXPIRED' | 'REVOKED' | 'NOT_FOUND'; // Estado operacional
companyName: string; // Razón social del cliente
companyNit?: string; // NIT del cliente
plan: string; // Nombre del plan contratado
expiresAt: string; // Fecha de vencimiento en formato ISO 8601
daysLeft: number; // Días enteros restantes
isTrial: boolean; // true si está en período de prueba
maxUsers: number; // Límite de usuarios simultáneos
dianQuota: number; // Cuota autorizada de facturas electrónicas
dianUsed: number; // Facturas emitidas en el ciclo
features: string[]; // Módulos contratados
customData: Record<string, any>; // Datos adicionales
serverMessage: string; // Mensaje emitido por el servidor
token?: string; // Token renovado emitido por el VPS
}
⚙️ 2. Métodos de la Clase ValidLicenseClient
Constructor
const client = new ValidLicenseClient({
serverUrl: 'https://licencias.labtec.sbs',
publicKeyHex: process.env.ED25519_PUBLIC_KEY,
clientVersion: '2026.1',
});
getMachineId(): Promise<string>
- Propósito: Genera el identificador de hardware único formateado como
REX-XXXX-XXXX-XXXX. - Implementación por Sistema Operativo:
- Windows: Consulta
HKLM\SOFTWARE\Microsoft\Cryptography\MachineGuidvíareg.exe query. En caso de fallo, realiza una consulta WMI aWin32_ComputerSystemProduct.UUID. - Linux / Docker: Lee
/etc/machine-ido/var/lib/dbus/machine-id. - macOS: Ejecuta
ioreg -rd1 -c IOPlatformExpertDeviceextrayendo elIOPlatformUUID. - Genera una suma criptográfica
crypto.createHash('sha256')memoizada en memoria.
- Windows: Consulta
verifyTokenSignature(token: string): boolean
- Propósito: Valida matemáticamente si la firma digital Ed25519 del token es auténtica sin realizar ninguna petición HTTP.
- Funcionamiento Criptográfico:
- Descompone el token en
payloadBase64UrlysignatureHex. - Construye el prefijo estándar ASN.1 SPKI DER de 12 bytes (
302a300506032b6570032100) para encapsular los 32 bytes de la clave pública Ed25519. - Crea un objeto de clave pública mediante
crypto.createPublicKey({ key: spkiDer, format: 'der', type: 'spki' }). - Ejecuta la verificación estricta con
crypto.verify(null, messageBytes, keyObject, sigBytes).
- Descompone el token en
decodeToken(token: string): any | null
- Propósito: Valida la firma del token y retorna el objeto JSON decodificado del payload. Si la firma fue alterada o no corresponde a la clave pública, retorna
null.
verify(params: VerifyParams): Promise<ValidLicenseRecord>
- Propósito: Realiza la verificación completa en dos fases:
- Fase 1 (Online): Realiza un POST a
${serverUrl}/api/v1/license/verify. Si el servidor responde200 OK, actualiza la fecha de último latido y extrae las cuotas actualizadas. Si la licencia está revocada, ejecutaparams.onRevoked?.()y retornaisActive: false. - Fase 2 (Fallback Offline Criptográfico): Si el servidor no responde (o no hay conexión de red), invoca
decodeToken(params.licenseToken). Si la firma es legítima, elMachine IDcoincide y la fecha de expiración no ha pasado, retornaisActive: true.
- Fase 1 (Online): Realiza un POST a
🛡️ 3. Módulo AntiTamperHelper (Defensa Avanzada en Node.js / Bun)
Proporciona utilidades para impedir el parcheo de binarios y el retraso de reloj:
AntiTamperHelper.deriveEncryptionKey(rawToken, salt):- Deriva una clave AES-256 a partir de la firma Ed25519 para descifrar bases de datos locales o credenciales en memoria.
AntiTamperHelper.verifyClockIntegrity(params):- Valida el avance del reloj comparando la marca de tiempo contra el hash firmado anterior.
AntiTamperHelper.isDebuggerAttached():- Detecta si el proceso Node.js o Bun se ejecuta con
--inspect,--debugo el inspector V8 activo.
- Detecta si el proceso Node.js o Bun se ejecuta con
🔒 4. Módulo UiGuard (Protección de Vistas & Frontend en Node / React / Vue)
Permite blindar vistas de SSR, Next.js, Nuxt o aplicaciones Electron/Tauri:
import { UiGuard } from 'validlicense-sdk';
// 1. Proteger una vista o componente
const viewHtml = UiGuard.guardView(
license,
() => renderFacturacionPage(), // Se ejecuta solo si la licencia es válida
() => renderPantallaBloqueo() // Fallback si no está autorizada
);
// 2. Proteger por Feature Flag
const copilotWidget = UiGuard.guardFeature(
license,
'ai_assistant',
() => renderCopilotWidget(),
() => ''
);
// 3. Proteger páginas compiladas de React (PageVenta.tsx) o Vue (PageVenta.vue)
const finalHtml = UiGuard.guardAsset(license, bundledReactHtml);
💻 5. Ejemplo Completo de Integración
import { ValidLicenseClient } from 'validlicense-sdk';
import 'dotenv/config';
async function bootstrap() {
const client = new ValidLicenseClient({
serverUrl: process.env.VALID_LICENSE_SERVER_URL || 'https://licencias.labtec.sbs',
publicKeyHex: process.env.ED25519_PUBLIC_KEY,
});
const machineId = await client.getMachineId();
console.log(`🔒 Identificador de Hardware: ${machineId}`);
const license = await client.verify({
companyNit: '900.888.777-1',
companyName: 'Comercializadora Global SAS',
licenseToken: process.env.LICENSE_TOKEN,
features: ['api_gateway', 'electronic_billing'],
onRevoked: () => {
console.error('⛔ ALERTA: La licencia fue revocada o suspendida en el VPS.');
process.exit(1);
},
});
if (!license.isActive) {
console.error('❌ Acceso Denegado:', license.serverMessage);
process.exit(1);
}
console.log('✅ Licencia Autorizada:', license.companyName);
console.log(`📦 Plan: ${license.plan} | Vence: ${license.expiresAt} (${license.daysLeft} días restantes)`);
}
bootstrap();