@clientsdemo/license-client
v3.2.0
Published
TypeScript client SDK for the ClientsDemo License Server. Validate licenses, manage seats, renew, activate/deactivate machines, send heartbeats, and verify offline.
Maintainers
Readme
@clientsdemo/license-client
TypeScript client SDK for the ClientsDemo License Server. Validate licenses, activate/deactivate machines, send heartbeats, manage subscriptions, and verify offline with Ed25519 signatures.
Installation
npm install @clientsdemo/license-client
# or
pnpm add @clientsdemo/license-clientQuick Start
import { LicenseClient } from "@clientsdemo/license-client";
const client = new LicenseClient({
serverUrl: "https://license.clientsdemo.site",
apiKey: "lsk_...",
appId: "ehs",
});
// Validate a license
const result = await client.validate("XXXX-XXXX-XXXX-XXXX-XXXX");
if (result.valid) {
console.log("Features:", result.license?.features);
}
// Activate on this machine
const machineId = await LicenseClient.generateMachineId();
await client.activate("XXXX-XXXX-XXXX-XXXX-XXXX", machineId, {
machineName: "prod-server-01",
appVersion: "2.1.0",
});
// Start auto-heartbeat (every hour)
const stopHeartbeat = client.startHeartbeat("XXXX-XXXX-XXXX-XXXX-XXXX", machineId);
// Later: stopHeartbeat();Middleware Guard
Use the guard for automatic license checking in your middleware:
import { createLicenseGuard } from "@clientsdemo/license-client";
const guard = createLicenseGuard({
serverUrl: "https://license.clientsdemo.site",
apiKey: "lsk_...",
appId: "ehs",
licenseKey: "XXXX-XXXX-XXXX-XXXX-XXXX",
});
// Check feature access
if (guard.hasFeature("audits")) {
// Enable audit module
}
// Request-scoped guard (Cloudflare Workers — isolated cache per request)
const scopedGuard = guard.forRequest();Service Binding (Worker-to-Worker)
For zero-latency validation between Cloudflare Workers:
import { ServiceBindingClient } from "@clientsdemo/license-client/service-binding";
const client = new ServiceBindingClient(env.LICENSE_SERVER);
const result = await client.validate("XXXX-XXXX-XXXX-XXXX-XXXX", "ehs");Public Activation (No API Key)
For customer-facing activation flows:
import { activateSetupLicense } from "@clientsdemo/license-client";
const result = await activateSetupLicense({
serverUrl: "https://license.clientsdemo.site",
licenseKey: "XXXX-XXXX-XXXX-XXXX-XXXX",
orgName: "Acme Corp",
email: "[email protected]",
});Offline Verification
import { LicenseClient, verifyOffline } from "@clientsdemo/license-client";
// Download and cache the license file
const licenseFile = await client.downloadLicenseFile("XXXX-XXXX-XXXX-XXXX-XXXX");
// Store licenseFile in localStorage, a file, etc.
// Later, verify offline (no network needed)
const result = await verifyOffline(licenseFile);
if (result.valid) {
console.log("License valid offline");
}
// Or use validateWithFallback for automatic offline fallback
const result2 = await client.validateWithFallback(
"XXXX-XXXX-XXXX-XXXX-XXXX",
cachedLicenseFile,
machineId,
);Billing Methods
// Get pricing plans for an app
const pricing = await client.getPricing();
// Create a checkout session
const { checkoutUrl } = await client.createCheckout({
planTier: "professional",
billingPeriod: "yearly",
email: "[email protected]",
orgName: "Acme Corp",
});
// Get subscription status
const sub = await client.getSubscription("XXXX-XXXX-XXXX-XXXX-XXXX");
// Get invoices
const invoices = await client.getInvoices("XXXX-XXXX-XXXX-XXXX-XXXX");
// Get billing portal URL
const { portalUrl } = await client.getBillingPortalUrl(customerId);Configuration
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| serverUrl | string | required | Base URL of the license server |
| apiKey | string | required | API key for authentication |
| appId | string | required | Application identifier |
| timeout | number | 10000 | Request timeout in ms |
| maxRetries | number | 3 | Max retry attempts for failed requests |
| retryBaseDelay | number | 1000 | Base delay in ms for exponential backoff |
Supported App IDs
ehs, ehr, ksdb, isms, partnerhub, shoprewards, safearena, bustracker, gstfiling
API Reference
client.validate(licenseKey, machineId?)
Validate a license key. Returns { valid, reason?, license? }.
client.activate(licenseKey, machineId, options?)
Activate a license on a machine. Returns { success, reason?, activationId? }.
client.activatePublic(params)
Activate without API key (rate limited). Returns { success, reason?, activationId? }.
client.deactivate(licenseKey, machineId)
Deactivate a license from a machine. Returns { success, reason? }.
client.heartbeat(licenseKey, machineId)
Send a heartbeat for an active license. Returns { success, reason? }.
client.status(licenseKey)
Get full license status including activations.
client.downloadLicenseFile(licenseKey)
Download a signed offline license file.
client.startHeartbeat(licenseKey, machineId, intervalMs?)
Start automatic heartbeat. Returns a stop function.
client.validateWithFallback(licenseKey, cachedFile, machineId?)
Validate with automatic offline fallback.
client.getPricing()
Get pricing plans for the configured app.
client.createCheckout(params)
Create a Stripe checkout session.
client.getSubscription(licenseKey)
Get subscription status for a license.
client.getInvoices(licenseKey)
Get invoice history for a license.
client.getBillingPortalUrl(customerId)
Get Stripe billing portal URL.
LicenseClient.generateMachineId() (static)
Generate a machine ID from hostname/OS info (Node.js).
LicenseClient.generateBrowserMachineId() (static)
Generate a machine ID from browser navigator data.
verifyOffline(licenseFile)
Verify a license file offline using Ed25519 Web Crypto API.
createLicenseGuard(config)
Create a middleware guard for automatic license validation with caching.
guard.forRequest()
Create a request-scoped guard (Cloudflare Workers safety).
License
MIT
