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 testThen 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.