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:
npm install ./waveform-licensing-sdk.tgzPrefer 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});Client methods
Section titled “Client methods”| 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. |
Standalone exports
Section titled “Standalone exports”| 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. |
Options
Section titled “Options”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.
Result shape
Section titled “Result shape”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.
Build guard
Section titled “Build guard”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.
Without the SDK
Section titled “Without the SDK”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.