Skip to content

TypeScript SDK

@waveform/licensing is the official SDK for the license API. It is zero-dependency, typed, and works on Node 18 or later and in Electron. It uses node:crypto, so for edge and browser runtimes call the HTTP API directly.

The TypeScript SDK is delivered as a package file, not through the public npm registry. Download it from theIntegration page of the Waveform app in your store admin (or from your Waveform account), then install it from disk:

Terminal window
npm install ./waveform-licensing-sdk.tgz

Prefer not to install anything? Every example below also works as plain HTTP.

import { createClient } from "@waveform/licensing";
const license = createClient({
apiBaseUrl: "https://api.waveformanager.com",
publicKey: "<your public key>", // only needed for offline verification
});
Method Use
validate({ key, instanceId?, label? }) Real-time check plus session register or refresh (online).
recordUsage({ key, amount? }) Meter usage; allowed: false at the limit (online).
endSession({ key, instanceId }) Free a concurrency slot (online).
activate({ key, fingerprint, deviceName, productId? }) Activate a device and get a signed token (offline).
startDemo({ productId, fingerprint, deviceName }) Time-limited demo token (offline).
heartbeat({ key, fingerprint, productId? }) Renew the offline lease.
listDevices({ key }) List the devices on a key.
deactivate({ key, fingerprint? | deviceId? }) Free a seat.
verifyLicense(token, { fingerprint, now? }) Low-level token verification. Prefer evaluateOffline.
fingerprint(rawMachineId, appSalt) The server-matching device fingerprint.
checkForUpdate(...), skipVersion(...) Optional update notifications. Entirely outside the licensing gate; every failure is silent.
Export Use
evaluateOffline(input) The offline gate. Composes signature, product binding, machine binding, a monotonic clock, and an offline deadline. See Offline integration.
computeFingerprint(rawMachineId, appSalt) Device fingerprint.
verifyLicenseToken(token, keys, options) Low-level verifier; options.fingerprint is required unless allowAnyDevice is set.
checkClock, sealMark, openMark Anti-rollback primitives, for clients that persist the sealed mark themselves.
computeKid(publicKey) The kid of a public key.

createClient takes:

Option Default
apiBaseUrl required Must be https://; the client throws otherwise. Plain http:// is accepted only for loopback (localhost, 127.0.0.1, [::1]) so local development works.
publicKey none A raw Ed25519 public key, or an array of them, for verification and key rotation.
timeoutMs 20000 Per-request timeout.
maxAttempts 3 Attempts for transient failures (connection errors, 5xx).
clientVersion none Your SDK or build version, reported with activation as telemetry. Never gates entitlement.
productVersion none Your product’s version, reported with activation and heartbeats. Used by the merchant’s version-adoption view.
fetch global fetch Override, for tests or custom transports.

Keys travel in request bodies, so the HTTPS requirement is deliberate: a key sniffed off a cleartext connection can be replayed to burn a seat. The JUCE kit enforces the same rule.

Every call returns a discriminated union rather than throwing:

const r = await license.validate({ key, instanceId });
if (r.ok) { /* r.features, r.sessions, r.usage */ }
else { /* r.error: "invalid-key" | "revoked" | "expired" | "session-limit" | "rate-limited" | "network" | ... */ }

error: "network" means the request never produced an answer; it is not a verdict. See Errors.

The package ships a verify-baked-key command that fails a build if the public key you embedded has drifted from the service’s. See Build-time key check.

Everything the SDK does is plain JSON over HTTPS, and the token format is open. Use the API reference and Token format from any language.