@licenseseat/js
v0.3.1
Published
Official JavaScript SDK for LicenseSeat – simple, secure software licensing.
Maintainers
Readme
LicenseSeat - JavaScript SDK
The official JavaScript/TypeScript SDK for LicenseSeat – the simple, secure licensing platform for apps, games, and plugins.
Features
- License activation & deactivation – Activate licenses with automatic device fingerprinting
- Online & offline validation – Validate licenses with optional offline fallback
- Entitlement checking – Check feature access with
hasEntitlement()andcheckEntitlement() - Local caching – Secure localStorage-based caching with clock tamper detection
- Auto-retry with exponential backoff – Resilient network handling
- Event-driven architecture – Subscribe to SDK lifecycle events
- TypeScript support – Full type definitions included (auto-generated from JSDoc)
- Modern ESM package – Native ES modules, tree-shakeable
Installation
npm / yarn / pnpm
# npm
npm install @licenseseat/js
# yarn
yarn add @licenseseat/js
# pnpm
pnpm add @licenseseat/jsCDN (Browser)
<!-- ESM via esm.sh -->
<script type="module">
import LicenseSeat from 'https://esm.sh/@licenseseat/js';
const sdk = new LicenseSeat({
apiKey: 'your-api-key',
productSlug: 'your-product'
});
</script>
<!-- ESM via unpkg -->
<script type="module">
import LicenseSeat from 'https://unpkg.com/@licenseseat/js/dist/index.js';
</script>
<!-- ESM via jsDelivr -->
<script type="module">
import LicenseSeat from 'https://cdn.jsdelivr.net/npm/@licenseseat/js/dist/index.js';
</script>Quick Start
JavaScript (ESM)
import LicenseSeat from '@licenseseat/js';
// Create SDK instance
const sdk = new LicenseSeat({
apiKey: 'your-api-key',
productSlug: 'your-product', // Required: Your product slug
debug: true
});
// Activate a license
await sdk.activate('YOUR-LICENSE-KEY');
// Check entitlements (simple boolean)
if (sdk.hasEntitlement('pro')) {
// Enable pro features
}
// Get current status
const status = sdk.getStatus();
console.log(status);
// { status: 'active', license: '...', entitlements: [...] }TypeScript
import LicenseSeat, {
type LicenseSeatConfig,
type ValidationResult,
type EntitlementCheckResult,
type LicenseStatus
} from '@licenseseat/js';
const config: LicenseSeatConfig = {
apiKey: 'your-api-key',
productSlug: 'your-product',
debug: true
};
const sdk = new LicenseSeat(config);
// Full type inference
const result: ValidationResult = await sdk.validateLicense('LICENSE-KEY');
const status: LicenseStatus = sdk.getStatus();
const hasPro: boolean = sdk.hasEntitlement('pro');TypeScript users get full type support automatically – the package includes generated .d.ts declaration files.
Configuration
const sdk = new LicenseSeat({
// Required
productSlug: 'your-product', // Your product slug from LicenseSeat dashboard
// Required for authenticated operations
apiKey: 'your-api-key',
// API Configuration
apiBaseUrl: 'https://licenseseat.com/api/v1', // Default
// Storage
storagePrefix: 'licenseseat_', // localStorage key prefix
// Auto-Validation
autoValidateInterval: 3600000, // 1 hour (in ms)
autoInitialize: true, // Auto-validate cached license on init
// Offline Support
offlineFallbackEnabled: false, // Enable offline validation fallback
maxOfflineDays: 0, // Max days offline (0 = disabled)
offlineLicenseRefreshInterval: 259200000, // 72 hours
maxClockSkewMs: 300000, // 5 minutes
// Network
maxRetries: 3, // Retry attempts for failed requests
retryDelay: 1000, // Initial retry delay (ms)
networkRecheckInterval: 30000, // Check connectivity every 30s when offline
// Debug
debug: false // Enable console logging
});Configuration Options
| Option | Type | Default | Description |
| ------------------------ | --------- | ---------------------------------- | --------------------------------------------------------- |
| productSlug | string | – | Required. Your product slug from the dashboard |
| apiKey | string | null | API key for authentication (required for most operations) |
| apiBaseUrl | string | 'https://licenseseat.com/api/v1' | API base URL |
| storagePrefix | string | 'licenseseat_' | Prefix for localStorage keys |
| autoValidateInterval | number | 3600000 | Auto-validation interval in ms (1 hour) |
| autoInitialize | boolean | true | Auto-initialize and validate cached license |
| offlineFallbackEnabled | boolean | false | Enable offline validation on network errors |
| maxOfflineDays | number | 0 | Maximum days license works offline (0 = disabled) |
| maxRetries | number | 3 | Max retry attempts for failed API calls |
| retryDelay | number | 1000 | Initial retry delay in ms (exponential backoff) |
| debug | boolean | false | Enable debug logging to console |
API Reference
Core Methods
sdk.activate(licenseKey, options?)
Activates a license key on this device.
const result = await sdk.activate('LICENSE-KEY', {
deviceId: 'custom-device-id', // Optional: auto-generated if not provided
deviceName: "John's MacBook Pro", // Optional: human-readable device name
metadata: { version: '1.0.0' } // Optional: custom metadata
});
console.log(result);
// {
// license_key: 'LICENSE-KEY',
// device_id: 'web-abc123',
// activated_at: '2024-01-15T10:30:00Z',
// activation: {
// object: 'activation',
// id: 123,
// device_id: 'web-abc123',
// license_key: 'LICENSE-KEY',
// activated_at: '2024-01-15T10:30:00Z',
// license: { ... }
// }
// }sdk.deactivate()
Deactivates the current license and clears cached data.
const result = await sdk.deactivate();
console.log(result);
// {
// object: 'deactivation',
// activation_id: 123,
// deactivated_at: '2024-01-15T12:00:00Z'
// }sdk.validateLicense(licenseKey, options?)
Validates a license with the server.
const result = await sdk.validateLicense('LICENSE-KEY', {
deviceId: 'device-id' // Optional: required for hardware_locked mode
});
console.log(result);
// {
// valid: true,
// license: {
// key: 'LICENSE-KEY',
// status: 'active',
// mode: 'hardware_locked',
// plan_key: 'pro',
// active_seats: 1,
// seat_limit: 3,
// active_entitlements: [
// { key: 'pro', expires_at: null, metadata: null },
// { key: 'beta', expires_at: '2024-12-31T23:59:59Z', metadata: null }
// ],
// product: { slug: 'your-product', name: 'Your Product' }
// },
// active_entitlements: [...]
// }Entitlement Methods
Note: Entitlements are optional. A license may have zero entitlements if the associated plan has no entitlements configured. The
active_entitlementsarray may be empty or the field may be undefined/null.
sdk.hasEntitlement(key)
Check if an entitlement is active. Returns a simple boolean. Returns false if no entitlements exist.
if (sdk.hasEntitlement('pro')) {
enableProFeatures();
}
if (sdk.hasEntitlement('beta')) {
showBetaUI();
}sdk.checkEntitlement(key)
Check entitlement with detailed information.
const result = sdk.checkEntitlement('pro');
if (result.active) {
console.log('Entitlement:', result.entitlement);
console.log('Expires:', result.entitlement.expires_at);
} else {
console.log('Reason:', result.reason);
// Possible reasons: 'no_license', 'not_found', 'expired'
}Status Methods
sdk.getStatus()
Get current license status.
const status = sdk.getStatus();
// Possible status values:
// - 'inactive': No license activated
// - 'pending': License pending validation
// - 'active': License valid (online)
// - 'invalid': License invalid
// - 'offline-valid': License valid (offline verification)
// - 'offline-invalid': License invalid (offline verification)
console.log(status);
// {
// status: 'active',
// license: 'LICENSE-KEY',
// device: 'web-abc123',
// activated_at: '2024-01-15T10:30:00Z',
// last_validated: '2024-01-15T11:30:00Z',
// entitlements: [...]
// }sdk.testAuth()
Test API connectivity by calling the /health endpoint. Returns health status and API version.
try {
const result = await sdk.testAuth();
console.log('Authenticated:', result.authenticated); // Always true if request succeeds
console.log('Healthy:', result.healthy); // API health status
console.log('API Version:', result.api_version); // e.g., '1.0.0'
} catch (error) {
console.error('Connection failed:', error);
}Note: This method tests API connectivity, not API key validity. A successful response means the API is reachable. Authentication errors will surface when calling protected endpoints like
activate()orvalidateLicense().
sdk.reset()
Clear all cached data and reset SDK state.
sdk.reset();sdk.destroy()
Destroy the SDK instance and release all resources. Call this when you no longer need the SDK to prevent memory leaks. After calling destroy(), the SDK instance should not be used.
// When unmounting a component or closing an app
sdk.destroy();sdk.initialize()
Manually initialize the SDK (only needed if autoInitialize: false).
const sdk = new LicenseSeat({
apiKey: 'key',
productSlug: 'your-product',
autoInitialize: false // Don't auto-initialize
});
// Later, when ready:
sdk.initialize();Events
Subscribe to SDK lifecycle events for reactive UIs.
// Subscribe
const unsubscribe = sdk.on('activation:success', (data) => {
console.log('License activated:', data);
});
// Unsubscribe
unsubscribe();
// or
sdk.off('activation:success', handler);Available Events
| Event | Description | Data |
| ----------------------------------- | ----------------------------------- | ------------------------------- |
| Lifecycle | | |
| license:loaded | Cached license loaded on init | CachedLicense |
| sdk:reset | SDK was reset | – |
| sdk:destroyed | SDK was destroyed | – |
| sdk:error | General SDK error | { message, error? } |
| Activation | | |
| activation:start | Activation started | { licenseKey, deviceId } |
| activation:success | Activation succeeded | CachedLicense |
| activation:error | Activation failed | { licenseKey, error } |
| Deactivation | | |
| deactivation:start | Deactivation started | CachedLicense |
| deactivation:success | Deactivation succeeded | DeactivationResponse |
| deactivation:error | Deactivation failed | { error, license } |
| Validation | | |
| validation:start | Validation started | { licenseKey } |
| validation:success | Online validation succeeded | ValidationResult |
| validation:failed | Validation failed (invalid license) | ValidationResult |
| validation:error | Validation error (network, etc.) | { licenseKey, error } |
| validation:offline-success | Offline validation succeeded | ValidationResult |
| validation:offline-failed | Offline validation failed | ValidationResult |
| validation:auth-failed | Auth failed during validation | { licenseKey, error, cached } |
| Auto-Validation | | |
| autovalidation:cycle | Auto-validation scheduled | { nextRunAt: Date } |
| autovalidation:stopped | Auto-validation stopped | – |
| Network | | |
| network:online | Network connectivity restored | – |
| network:offline | Network connectivity lost | { error } |
| Offline Token | | |
| offlineToken:fetching | Fetching offline token | { licenseKey } |
| offlineToken:fetched | Offline token fetched | { licenseKey, data } |
| offlineToken:fetchError | Offline token fetch failed | { licenseKey, error } |
| offlineToken:ready | Offline assets synced | { kid, exp_at } |
| offlineToken:verified | Offline signature verified | { payload } |
| offlineToken:verificationFailed | Offline signature invalid | { payload } |
Singleton Pattern
For applications that need a shared SDK instance:
import { configure, getSharedInstance, resetSharedInstance } from '@licenseseat/js';
// Configure once at app startup
configure({
apiKey: 'your-key',
productSlug: 'your-product'
});
// Use anywhere in your app
const sdk = getSharedInstance();
await sdk.activate('LICENSE-KEY');
// Reset if needed
resetSharedInstance();Offline Support
The SDK supports offline license validation using cryptographically signed offline tokens (Ed25519).
const sdk = new LicenseSeat({
apiKey: 'your-key',
productSlug: 'your-product',
offlineFallbackEnabled: true, // Enable offline fallback
maxOfflineDays: 7 // Allow 7 days offline
});
// After activation, offline assets are automatically synced
await sdk.activate('LICENSE-KEY');
// Later, even offline, validation will work using cached data
const result = await sdk.validateLicense('LICENSE-KEY');
if (result.offline) {
console.log('Validated offline');
}How Offline Validation Works
- On activation, the SDK fetches a signed offline token from the server
- The offline token contains:
- License data (key, plan, entitlements, expiration)
- Ed25519 signature
- Canonical JSON for verification
- When offline, the SDK verifies the signature locally
- Clock tamper detection prevents users from bypassing expiration
Offline Methods
sdk.syncOfflineAssets()
Fetches the offline token and signing key from the server. Uses the currently cached license. Call this after activation to prepare for offline usage.
// First activate (caches the license)
await sdk.activate('LICENSE-KEY');
// Then sync offline assets (uses cached license)
const assets = await sdk.syncOfflineAssets();
console.log('Offline token key ID:', assets.kid);
console.log('Expires at:', assets.exp_at);sdk.getOfflineToken()
Fetches a signed offline token for the currently cached license. Returns the token structure containing the license data and Ed25519 signature.
// Must have an active license cached first
const token = await sdk.getOfflineToken();
console.log(token);
// {
// object: 'offline_token',
// token: { license_key, product_slug, plan_key, ... },
// signature: { algorithm: 'Ed25519', key_id, value },
// canonical: '...'
// }sdk.getSigningKey(keyId)
Fetches the Ed25519 public key used for verifying offline token signatures.
const signingKey = await sdk.getSigningKey('key-id-001');
console.log(signingKey);
// {
// object: 'signing_key',
// kid: 'key-id-001',
// public_key: 'base64-encoded-public-key',
// algorithm: 'Ed25519',
// created_at: '2024-01-01T00:00:00Z'
// }sdk.verifyOfflineToken(token, publicKeyB64)
Verifies an offline token's Ed25519 signature locally. Both parameters are required.
// Fetch the token and signing key first
const token = await sdk.getOfflineToken();
const signingKey = await sdk.getSigningKey(token.signature.key_id);
// Verify the signature
const isValid = await sdk.verifyOfflineToken(token, signingKey.public_key);
console.log('Signature valid:', isValid);Important: The
verifyOfflineToken()method requires you to pass both the token and the public key. Fetch the signing key usinggetSigningKey()with thekey_idfrom the token's signature.
Offline Token Structure
{
object: 'offline_token',
token: {
schema_version: 1,
license_key: 'LICENSE-KEY',
product_slug: 'your-product',
plan_key: 'pro',
mode: 'hardware_locked',
device_id: 'web-abc123',
iat: 1704067200, // Issued at (Unix timestamp)
exp: 1706659200, // Expires at (Unix timestamp)
nbf: 1704067200, // Not before (Unix timestamp)
license_expires_at: null,
kid: 'key-id-001',
entitlements: [
{ key: 'pro', expires_at: null }
],
metadata: {}
},
signature: {
algorithm: 'Ed25519',
key_id: 'key-id-001',
value: 'base64url-encoded-signature'
},
canonical: '{"entitlements":[...],"exp":...}'
}Error Handling
The SDK exports custom error classes for precise error handling:
import LicenseSeat, {
APIError,
LicenseError,
ConfigurationError,
CryptoError
} from '@licenseseat/js';
try {
await sdk.activate('INVALID-KEY');
} catch (error) {
if (error instanceof APIError) {
console.log('HTTP Status:', error.status);
console.log('Error Code:', error.data?.error?.code);
console.log('Error Message:', error.data?.error?.message);
} else if (error instanceof LicenseError) {
console.log('License error:', error.code);
} else if (error instanceof ConfigurationError) {
console.log('Config error:', error.message);
}
}Error Types
| Error | Description |
| -------------------- | ---------------------------------------------------- |
| APIError | HTTP request failures (includes status and data) |
| LicenseError | License operation failures (includes code) |
| ConfigurationError | SDK misconfiguration (e.g., missing productSlug) |
| CryptoError | Cryptographic operation failures |
API Error Format
API errors follow this structure:
{
error: {
code: 'license_not_found', // Machine-readable error code
message: 'License not found.', // Human-readable message
details: { ... } // Optional additional details
}
}Common error codes:
unauthorized- Invalid or missing API keylicense_not_found- License key doesn't existlicense_expired- License has expiredlicense_suspended- License is suspendedlicense_revoked- License has been revokedseat_limit_reached- No more seats availabledevice_already_activated- Device is already activatedactivation_not_found- Activation doesn't exist (for deactivation)
Browser Support
- Modern browsers: Chrome 80+, Firefox 75+, Safari 14+, Edge 80+
- Bundlers: Vite, Webpack, Rollup, esbuild, Parcel
- Node.js: 18+ (requires polyfills - see below)
Node.js Usage
The SDK is designed for browsers but works in Node.js with polyfills. Add these before importing the SDK:
// Required polyfills for Node.js
const storage = {};
globalThis.localStorage = {
getItem(key) { return Object.prototype.hasOwnProperty.call(storage, key) ? storage[key] : null; },
setItem(key, value) { storage[key] = String(value); },
removeItem(key) { delete storage[key]; },
clear() { for (const key in storage) delete storage[key]; },
};
// Override Object.keys to support localStorage iteration (used by cache.getAllKeys())
const originalKeys = Object.keys;
Object.keys = function(obj) {
if (obj === globalThis.localStorage) return originalKeys(storage);
return originalKeys(obj);
};
// Device fingerprinting polyfills (provides stable fallback values)
globalThis.document = { createElement: () => ({ getContext: () => null }), querySelector: () => null };
globalThis.window = { navigator: {}, screen: {} };
globalThis.navigator = { userAgent: 'Node.js', language: 'en', hardwareConcurrency: 4 };
// Now import the SDK
const { default: LicenseSeat } = await import('@licenseseat/js');Note: In Node.js, device fingerprinting will use fallback values since browser APIs aren't available. For consistent device identification across restarts, pass an explicit
deviceIdtoactivate().
Usage Guide
For JavaScript Users
Simply import and use:
import LicenseSeat from '@licenseseat/js';
const sdk = new LicenseSeat({
apiKey: 'your-key',
productSlug: 'your-product'
});For TypeScript Users
The package includes TypeScript declarations (.d.ts files) automatically. No additional @types/ package needed.
import LicenseSeat from '@licenseseat/js';
// Types are automatically available
const sdk = new LicenseSeat({
apiKey: 'your-key',
productSlug: 'your-product'
});
// Import specific types if needed
import type {
LicenseSeatConfig,
ValidationResult,
EntitlementCheckResult,
LicenseStatus,
Entitlement,
CachedLicense,
ActivationResponse,
DeactivationResponse,
OfflineToken
} from '@licenseseat/js';For CDN/Browser Users
Use ES modules via CDN:
<!DOCTYPE html>
<html>
<head>
<title>LicenseSeat Demo</title>
</head>
<body>
<script type="module">
import LicenseSeat from 'https://esm.sh/@licenseseat/js';
const sdk = new LicenseSeat({
apiKey: 'your-api-key',
productSlug: 'your-product',
debug: true
});
// Check for existing license
const status = sdk.getStatus();
if (status.status === 'active') {
console.log('Already licensed!');
}
// Activate (example with user input)
document.getElementById('activate-btn').onclick = async () => {
const key = document.getElementById('license-key').value;
try {
await sdk.activate(key);
alert('License activated!');
} catch (e) {
alert('Activation failed: ' + e.message);
}
};
</script>
<input id="license-key" placeholder="Enter license key" />
<button id="activate-btn">Activate</button>
</body>
</html>Development
Setup
git clone https://github.com/licenseseat/licenseseat-js.git
cd licenseseat-js
npm installScripts
| Command | Description |
| ----------------------- | ----------------------------------------- |
| npm run build | Build JS bundle + TypeScript declarations |
| npm run build:js | Build JavaScript bundle only |
| npm run build:types | Generate TypeScript declarations |
| npm run build:iife | Build global/IIFE bundle |
| npm run dev | Watch mode for development |
| npm test | Run tests |
| npm run test:watch | Run tests in watch mode |
| npm run test:coverage | Run tests with coverage report |
| npm run typecheck | Type-check without emitting |
Integration Tests
The SDK includes comprehensive integration tests that run against the live LicenseSeat API. These tests verify real-world functionality including activation, validation, deactivation, and offline cryptographic operations.
Running Integration Tests (Node.js)
# Set environment variables
export LICENSESEAT_API_KEY="ls_your_api_key_here"
export LICENSESEAT_PRODUCT_SLUG="your-product"
export LICENSESEAT_LICENSE_KEY="YOUR-LICENSE-KEY"
# Run the tests
node test-live.mjsOr with inline environment variables:
LICENSESEAT_API_KEY=ls_xxx LICENSESEAT_PRODUCT_SLUG=my-app LICENSESEAT_LICENSE_KEY=XXX-XXX node test-live.mjsRunning Integration Tests (Browser)
Open test-live.html in a browser. You'll be prompted to enter your credentials:
- API Key - Your LicenseSeat API key (starts with
ls_) - Product Slug - Your product identifier
- License Key - A valid license key for testing
Credentials are stored in localStorage for convenience during development.
What the Integration Tests Cover
| Category | Tests | |----------|-------| | Initialization | SDK setup, configuration defaults | | Activation | License activation, device ID generation | | Validation | Online validation, entitlement checking | | Deactivation | License deactivation, cache clearing | | Offline Crypto | Ed25519 signature verification, offline token fetching, tamper detection | | Error Handling | Invalid licenses, missing config | | Singleton | Shared instance pattern |
Project Structure
licenseseat-js/
├── src/
│ ├── index.js # Entry point, exports
│ ├── LicenseSeat.js # Main SDK class
│ ├── cache.js # LicenseCache (localStorage)
│ ├── errors.js # Error classes
│ ├── types.js # JSDoc type definitions
│ └── utils.js # Utility functions
├── tests/ # Unit tests (mocked API)
│ ├── setup.js # Test setup
│ ├── mocks/ # MSW handlers
│ ├── LicenseSeat.test.js
│ └── utils.test.js
├── test-live.mjs # Integration tests (Node.js)
├── test-live.html # Integration tests (Browser)
├── dist/ # Build output
│ ├── index.js # ESM bundle
│ └── types/ # TypeScript declarations
├── package.json
├── tsconfig.json
└── vitest.config.jsPublishing
Publishing to npm
Update version in
package.json:npm version patch # or minor, majorBuild the package:
npm run buildVerify the build:
# Check what will be published npm pack --dry-run # Verify TypeScript types ls dist/types/Publish:
# Login if needed npm login # Publish (public package) npm publish --access public
What Gets Published
The files field in package.json controls what's included:
{
"files": ["dist/", "src/"]
}Users receive:
dist/index.js– ESM bundle (JavaScript)dist/types/*.d.ts– TypeScript declarationssrc/*.js– Source files (for debugging/reference)
Package Exports
{
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/types/index.d.ts",
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/types/index.d.ts"
}
}
}This ensures:
- JavaScript users get
dist/index.js - TypeScript users get type definitions from
dist/types/index.d.ts - Both ESM
importand bundlers work correctly
CDN Distribution
Once published to npm, the package is automatically available on CDNs:
| CDN | URL |
| ------------ | ------------------------------------------------------------ |
| esm.sh | https://esm.sh/@licenseseat/js |
| unpkg | https://unpkg.com/@licenseseat/js/dist/index.js |
| jsDelivr | https://cdn.jsdelivr.net/npm/@licenseseat/js/dist/index.js |
| Skypack | https://cdn.skypack.dev/@licenseseat/js |
Version pinning (recommended for production):
<script type="module">
import LicenseSeat from 'https://esm.sh/@licenseseat/[email protected]';
</script>Self-Hosting
To host the SDK yourself:
Build the package:
npm run buildCopy
dist/index.jsto your CDN/serverServe with correct MIME type (
application/javascript) and CORS headers
Building an IIFE Bundle (Legacy Browsers)
For a global LicenseSeat variable (non-module script tags):
npm run build:iifeThis creates dist/index.global.js:
<script src="/path/to/index.global.js"></script>
<script>
const sdk = new LicenseSeat({
apiKey: 'your-key',
productSlug: 'your-product'
});
</script>Versioning
This project follows Semantic Versioning:
- MAJOR (1.0.0 → 2.0.0): Breaking changes
- MINOR (1.0.0 → 1.1.0): New features (backward compatible)
- PATCH (1.0.0 → 1.0.1): Bug fixes
Migration from v0.2.x
Breaking Changes in v0.3.0
This version introduces the v1 API with significant changes:
| Change | Before (v0.2.x) | After (v0.3.0) |
| -------------------------------- | ------------------------------- | ----------------------------------------- |
| productSlug config | Not required | Required for all API operations |
| apiBaseUrl default | https://licenseseat.com/api | https://licenseseat.com/api/v1 |
| deviceIdentifier option | deviceIdentifier | deviceId |
| device_identifier field | device_identifier | device_id |
| Deactivation response | Returns full activation object | Returns { object, activation_id, deactivated_at } |
| getOfflineLicense() method | Available | Renamed to getOfflineToken() |
| getPublicKey() method | Available | Renamed to getSigningKey() |
| Offline license structure | Legacy format | New token/signature/canonical format |
| Error format | Various | { error: { code, message, details? } } |
Migration Steps
Add
productSlugto configuration:// Before const sdk = new LicenseSeat({ apiKey: 'key' }); // After const sdk = new LicenseSeat({ apiKey: 'key', productSlug: 'your-product' // Required! });Update activation options:
// Before await sdk.activate('KEY', { deviceIdentifier: 'id' }); // After await sdk.activate('KEY', { deviceId: 'id' });Update response field access:
// Before const result = await sdk.activate('KEY'); console.log(result.device_identifier); // After const result = await sdk.activate('KEY'); console.log(result.device_id);Update deactivation handling:
// Before const result = await sdk.deactivate(); console.log(result.license_key); // After const result = await sdk.deactivate(); console.log(result.activation_id); console.log(result.deactivated_at);Update offline method calls:
// Before await sdk.getOfflineLicense(key); await sdk.getPublicKey(keyId); // After (note: getOfflineToken uses cached license, no parameter needed) await sdk.getOfflineToken(); await sdk.getSigningKey(keyId);
License
MIT License – see LICENSE for details.
