Licensing · Guides

CI and Offline Use

License verification is offline. verifyLicense(token, publicKey) parses the compact token, checks the Ed25519 signature, and returns claims when the signature is valid.

You don't need a network call to know whether a token is signed correctly.

#CI

For CI builds, treat the license token like any other secret:

THREADPLANE_LICENSE=... npm test

Then pass it through provideChat().

provideChat({ license: process.env['THREADPLANE_LICENSE'] });

If you call runLicenseCheck() directly, inject the current time only when you need deterministic tests:

await runLicenseCheck({
  package: '@threadplane/example',
  token,
  publicKey,
  nowSec: 1_735_689_600,
});

#Offline verification

Use verifyLicense() and evaluateLicense() directly when network access is unavailable or unwanted.

import {
  LICENSE_PUBLIC_KEY,
  evaluateLicense,
  verifyLicense,
} from '@threadplane/licensing';
 
const publicKey = LICENSE_PUBLIC_KEY;
const token = process.env['THREADPLANE_LICENSE'] ?? '';
 
const verified = await verifyLicense(token, publicKey);
const result = evaluateLicense(verified, {
  nowSec: Math.floor(Date.now() / 1000),
});
console.log(result.status);

This doesn't emit warnings. The higher-level runLicenseCheck() helper can emit warnings, but it never makes network requests.

#Signing tokens

signLicense() is exported for token minting and tests:

import * as ed from '@noble/ed25519';
import {
  signLicense,
  type LicenseClaims,
} from '@threadplane/licensing';
 
// Generate a keypair. The public key is what `verifyLicense()` consumes;
// the private key never leaves the minting side.
const privateKey = ed.utils.randomPrivateKey();
const publicKey = await ed.getPublicKeyAsync(privateKey);
 
const nowSec = Math.floor(Date.now() / 1000);
const claims: LicenseClaims = {
  sub: 'cus_123',
  tier: 'team',
  iat: nowSec,
  exp: nowSec + 60 * 60 * 24 * 365, // one year out
  seats: 5,
};
 
const token = await signLicense(claims, privateKey);

It signs the UTF-8 JSON payload with Ed25519 and returns the compact token format expected by verifyLicense().

Don't ship private keys in application code. Verification needs only the public key.