@licensehub/license-client
Version:
TypeScript license management client for protecting and monetizing proprietary software
530 lines (511 loc) • 19.4 kB
TypeScript
/**
* License activation status enum (mirrored from server)
* - active: The activation is currently valid and operational
* - revoked: The activation has been revoked
* - deleted: The activation has been deleted
*/
export declare enum EnumLicenseActivationStatus {
ACTIVE = "active",
REVOKED = "revoked",
DELETED = "deleted"
}
/**
* License status enum (mirrored from server)
* - pending: The license is pending activation. Users cannot utilize any features or services associated with this license until it is activated.
* - active: The license is currently valid and operational. Users can utilize all features or services associated with this license.
* - expired: The license has expired. Users can no longer utilize any features or services associated with this license.
* - inactive: The license has been deactivated. Users can no longer utilize any features or services associated with this license.
* - revoked: The license has been revoked. Users can no longer utilize any features or services associated with this license.
* - deleted: The license has been deleted. Users can no longer utilize any features or services associated with this license.
*/
export declare enum EnumLicenseStatus {
PENDING = "pending",
ACTIVE = "active",
EXPIRED = "expired",
INACTIVE = "inactive",
REVOKED = "revoked",
DELETED = "deleted"
}
/**
* License Client Enums
*
* This file contains all enums used by the License Client, including:
* - Client-specific message codes and texts
* - Server response message codes and texts (mirrored from server)
* - License status enums
* - License activation status enums
*/
/**
* Message Code Enum
*
* Defines all message codes used by the license client for error handling and responses.
* Includes both client-specific codes and server response codes.
*/
export declare enum EnumMessageCode {
SUCCESS = "SUCCESS",
MISSING_LICENSE_DATA = "MISSING_LICENSE_DATA",
MISSING_FEATURES = "MISSING_FEATURES",
REQUEST_FAILED = "REQUEST_FAILED",
NETWORK_ERROR = "NETWORK_ERROR",
LICENSE_NOT_FOUND = "LICENSE_NOT_FOUND",
LICENSE_EXPIRED = "LICENSE_EXPIRED",
LICENSE_DISABLED = "LICENSE_DISABLED",
INVALID_DOMAIN = "INVALID_DOMAIN",
ACTIVATION_LIMIT_REACHED = "ACTIVATION_LIMIT_REACHED",
INVALID_LICENSE_TYPE = "INVALID_LICENSE_TYPE",
LICENSE_ALREADY_ACTIVATED = "LICENSE_ALREADY_ACTIVATED",
LICENSE_NOT_ACTIVATED = "LICENSE_NOT_ACTIVATED",
INVALID_RESPONSE = "INVALID_RESPONSE",
INVALID_JSON_FORMAT = "invalid_json_format",
EXCEPTION = "exception",
LICENSE_PENDING = "license_pending",
LICENSE_INACTIVE = "license_inactive",
LICENSE_REVOKED = "license_revoked",
LICENSE_DELETED = "license_deleted",
LICENSE_INVALID_STATUS = "license_invalid_status",
MAX_ACTIVATIONS_REACHED = "max_activations_reached",
INVALID_ACTIVATION = "invalid_activation",
ACTIVATION_REVOKED = "activation_revoked",
ACTIVATION_DELETED = "activation_deleted",
ACTIVATION_INVALID_STATUS = "activation_invalid_status",
ACTIVATION_FAILED = "activation_failed",
LICENSE_TYPE_NOT_FOUND = "license_type_not_found"
}
/**
* Message source enum (mirrored from server)
*/
export declare enum EnumMessageSource {
REQUEST = "request",
RESPONSE = "response"
}
/**
* Message Text Enum
*
* Human-readable messages corresponding to message codes.
* Provides descriptive text for both client errors and server responses.
*/
export declare enum EnumMessageText {
SUCCESS = "Operation completed successfully.",
MISSING_LICENSE_DATA = "License key and/or domain are required.",
MISSING_FEATURES = "Missing required features.",
REQUEST_FAILED = "The server request failed.",
NETWORK_ERROR = "A network error occurred. Please check your connection.",
LICENSE_NOT_FOUND = "License key not found.",
LICENSE_EXPIRED = "License has expired.",
LICENSE_DISABLED = "License is disabled.",
INVALID_DOMAIN = "Invalid domain for this license.",
ACTIVATION_LIMIT_REACHED = "Activation limit reached.",
INVALID_LICENSE_TYPE = "Invalid license type.",
LICENSE_ALREADY_ACTIVATED = "License is already activated for this domain.",
LICENSE_NOT_ACTIVATED = "License is not activated for this domain.",
UNKNOWN_ERROR = "Unknown error",
INVALID_JSON_FORMAT = "Invalid JSON format",
LICENSE_PENDING = "License is pending activation",
LICENSE_INACTIVE = "License is inactive",
LICENSE_REVOKED = "License has been revoked",
LICENSE_DELETED = "License has been deleted",
LICENSE_INVALID_STATUS = "License has an invalid status",
MAX_ACTIVATIONS_REACHED = "Maximum number of activations reached",
INVALID_ACTIVATION = "Invalid activation conditions",
ACTIVATION_REVOKED = "Activation has been revoked",
ACTIVATION_DELETED = "Activation has been deleted",
ACTIVATION_INVALID_STATUS = "Activation has an invalid status",
ACTIVATION_FAILED = "Activation failed",
LICENSE_TYPE_NOT_FOUND = "License type not found"
}
/**
* Client for interacting with the license server.
* Supports offline validation via JWT caching and automatic public key fetching.
*
* @example
* ```typescript
* const client = new LicenseClient({
* LICENSE_SERVER_URL: 'https://license.example.com/api/v1',
* // LICENSE_PUBLIC_KEY is optional; it will be fetched if not provided.
* });
*
* const response = await client.validate({
* licenseKey: 'YOUR_LICENSE_KEY',
* domain: 'your-domain.com',
* });
*
* if (response.success) {
* console.log('License is valid!', response.data);
* }
* ```
*/
export declare class LicenseClient {
/**
* Creates a new LicenseClient instance.
* @param {TypeLicenseClientOptions} options - The configuration for the client
* @throws {Error} When required configuration is missing or invalid
*/
constructor(options: TypeLicenseClientOptions);
/**
* Activates a license key with the server.
* @param {TypeLicensePayload} [payload] - The license data to activate. Uses the default if not provided
* @param {string[]} [requiredFeatures] - Optional array of features that must be available in the license
* @returns {Promise<TypeResponse>} The server's response containing activation details
* @throws {Error} When payload is missing and no default is set
*/
activate(payload?: TypeLicensePayload, requiredFeatures?: string[]): Promise<TypeResponse>;
/**
* Clears all cached data including JWT tokens, operation results, and public key.
*
* WHY simplified clearing: With IntegrityCache used everywhere, we can clear
* all cached data through the single cache instance, making the logic much simpler.
*
* Useful for logout scenarios or when switching between different license contexts.
* @returns {Promise<void>}
*/
clearAllCaches(): Promise<void>;
/**
* Deactivates a license key on the server. This also clears any cached JWT for the license.
* @param {TypeLicensePayload} [payload] - The license data to deactivate. Uses the default if not provided
* @returns {Promise<TypeResponse>} The server's response confirming deactivation
* @throws {Error} When payload is missing and no default is set
*/
deactivate(payload?: TypeLicensePayload): Promise<TypeResponse>;
/**
* Sets a default license payload for subsequent method calls.
* This invalidates the cached validation response for the previous license context only.
* @param {TypeLicensePayload} payload - The license data to use as a default
*/
setLicensePayload(payload: TypeLicensePayload): void;
/**
* Validates a license key. It first attempts to use cached validation response,
* then offline validation using a cached JWT, and finally falls back to server validation.
* Uses periodic server validation to catch license abuse at unpredictable intervals.
* @param {TypeLicensePayload} [payload] - The license data to validate. Uses the default if not provided
* @param {string[]} [requiredFeatures] - Optional array of features that must be available in the license
* @returns {Promise<TypeResponse>} The validation result with license details
* @throws {Error} When payload is missing and no default is set
*/
validate(payload?: TypeLicensePayload, requiredFeatures?: string[]): Promise<TypeResponse>;
}
/**
* Singleton wrapper for LicenseClient.
* Provides a global access point to a single LicenseClient instance.
*
* @example
* ```typescript
* // Set the instance first
* const client = new LicenseClient({
* LICENSE_SERVER_URL: 'https://license.example.com/api/v1'
* });
* LicenseClientSingleton.setInstance(client);
*
* // Later, get the instance anywhere in your app
* const client = LicenseClientSingleton.getInstance();
* if (client) {
* const response = await client.validate({ licenseKey: 'key' });
* }
* ```
*/
export declare class LicenseClientSingleton {
/**
* Gets the singleton instance.
* @returns {LicenseClient | undefined} The LicenseClient instance, or undefined if not set.
*/
static getInstance(): LicenseClient | undefined;
/**
* Sets the singleton instance.
* @param {LicenseClient} client - The LicenseClient instance to use as singleton.
*/
static setInstance(client: LicenseClient): void;
}
/**
* Complete JWT structure with typed header and payload.
* Used when we need to work with the complete decoded JWT structure.
*/
export declare interface TypeDecodedJwt<T = TypeLicenseJwtPayload> {
/**
* JWT header containing algorithm and type information
*/
header: TypeJwtHeader;
/**
* JWT payload containing claims and license data
*/
payload: T;
/**
* JWT signature (when available from verification)
*/
signature?: string;
}
/**
* Default response data type for license operations
* Contains token, public key, and source information with extensible properties
*/
export declare interface TypeDefaultResponseData {
token?: string;
publicKey?: string;
source?: 'cache' | 'server';
features?: string[];
[key: string]: unknown;
}
/**
* Error response interface for failed operations
* Always has success: false and required messages array
*/
export declare interface TypeErrorResponse extends TypeResponse<undefined> {
success: false;
messages: TypeMessage[];
}
/**
* JWT Header interface.
* Represents the JWT header structure.
*/
export declare interface TypeJwtHeader {
/**
* Algorithm used to sign the JWT (e.g., 'RS256', 'HS256')
*/
alg: string;
/**
* Token type (typically 'JWT')
*/
typ: string;
/**
* Key ID hint indicating which key was used to secure the JWS
*/
kid?: string;
}
/**
* JWT Payload Type Definitions
*
* Type definitions for JWT token structures used in the License Client.
* These types ensure proper typing when decoding JWT tokens.
*/
/**
* Standard JWT claims interface.
* Based on RFC 7519 JWT standard claims.
*/
export declare interface TypeJwtStandardClaims {
/**
* Issuer claim (iss) - identifies the principal that issued the JWT
*/
iss?: string;
/**
* Subject claim (sub) - identifies the principal that is the subject of the JWT
*/
sub?: string;
/**
* Audience claim (aud) - identifies the recipients that the JWT is intended for
*/
aud?: string | string[];
/**
* Expiration Time claim (exp) - identifies the expiration time on or after which the JWT MUST NOT be accepted
*/
exp?: number;
/**
* Not Before claim (nbf) - identifies the time before which the JWT MUST NOT be accepted
*/
nbf?: number;
/**
* Issued At claim (iat) - identifies the time at which the JWT was issued
*/
iat?: number;
/**
* JWT ID claim (jti) - provides a unique identifier for the JWT
*/
jti?: string;
}
/**
* License Client - Configuration Options Type
*
* Configuration options for the LicenseClient.
*
* **Cache Types:**
* - `memory-cache` (default): In-memory caching, works everywhere, no setup required
* - `cloudflare-cache`: For Cloudflare Workers/Edge environments (+3 kB bundle size)
* - `upstash-redis-cache`: For serverless Redis environments (+138 kB bundle size)
* - `redis-cache`: For traditional Redis setups (+743 kB bundle size)
*
* **Enabling Additional Cache Types:**
* To use cache types other than memory cache, uncomment the corresponding import
* in the LicenseClient source code:
* ```typescript
* // In LicenseClient.ts, uncomment the desired cache type:
* import '@cachehub/cloudflare-cache'; // For Cloudflare Workers/Edge
* import '@cachehub/upstash-redis-cache'; // For serverless Redis
* import '@cachehub/redis-cache'; // For traditional Redis
* ```
*
* @example
* ```typescript
* // Memory cache (default) - works out of the box
* const options: TypeLicenseClientOptions = {
* LICENSE_SERVER_URL: 'https://license-server.example.com/api/v1',
* LICENSE_PUBLIC_KEY: '-----BEGIN PUBLIC KEY-----...',
* CACHE_TYPE: 'memory-cache' // or omit for default
* };
*
* // Cloudflare cache (requires enabling cloudflare-cache import)
* const cloudflareOptions: TypeLicenseClientOptions = {
* LICENSE_SERVER_URL: 'https://license-server.example.com/api/v1',
* LICENSE_PUBLIC_KEY: '-----BEGIN PUBLIC KEY-----...',
* CACHE_TYPE: 'cloudflare-cache',
* CACHE_BASE_URL: 'https://api.cloudflare.com/client/v4',
* CACHE_NAME: 'my-cache'
* };
*
* // Upstash Redis cache (requires enabling upstash-redis-cache import)
* const upstashOptions: TypeLicenseClientOptions = {
* LICENSE_SERVER_URL: 'https://license-server.example.com/api/v1',
* LICENSE_PUBLIC_KEY: '-----BEGIN PUBLIC KEY-----...',
* CACHE_TYPE: 'upstash-redis-cache',
* CACHE_REDIS_URL: 'https://your-redis-url.upstash.io',
* CACHE_REDIS_TOKEN: 'your-redis-token',
* CACHE_KEY_PREFIX: 'license:'
* };
*
* // Traditional Redis cache (requires enabling redis-cache import)
* const redisOptions: TypeLicenseClientOptions = {
* LICENSE_SERVER_URL: 'https://license-server.example.com/api/v1',
* LICENSE_PUBLIC_KEY: '-----BEGIN PUBLIC KEY-----...',
* CACHE_TYPE: 'redis-cache',
* CACHE_REDIS_URL: 'redis://localhost:6379'
* };
* ```
*/
export declare interface TypeLicenseClientOptions {
/**
* The base URL of the license server API.
* @example 'https://license-server.example.com/api/v1'
*/
LICENSE_SERVER_URL: string;
/**
* The public key used to verify JWT tokens (optional).
* If not provided, the client will contact the server for validation.
* @example '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...\n-----END PUBLIC KEY-----'
*/
LICENSE_PUBLIC_KEY?: string;
/**
* The type of cache to use for storing JWT tokens.
* @default 'memory-cache'
* @example 'memory-cache', 'cloudflare-cache', 'upstash-redis-cache', 'redis-cache'
*/
CACHE_TYPE?: string;
/**
* Redis server URL (required for redis-cache and upstash-redis-cache).
* @example 'redis://localhost:6379' or 'https://your-redis-url.upstash.io'
*/
CACHE_REDIS_URL?: string;
/**
* Redis authentication token (required for upstash-redis-cache).
* @example 'your-redis-token'
*/
CACHE_REDIS_TOKEN?: string;
/**
* Optional prefix for cache keys (used by upstash-redis-cache).
* @example 'license:'
*/
CACHE_KEY_PREFIX?: string;
/**
* Minimum hours between forced server validations (default: 6).
* @example 1
*/
VALIDATION_MIN_INTERVAL_HOURS?: number;
/**
* Maximum hours between forced server validations (default: 24).
* @example 48
*/
VALIDATION_MAX_INTERVAL_HOURS?: number;
/**
* Probability (0-1) of forcing server validation on each check (default: 0.1).
* Set to 0 to disable probabilistic validation for testing.
* @example 0.05
*/
VALIDATION_PROBABILITY?: number;
/**
* Cloudflare API base URL (required for cloudflare-cache).
* @example 'https://api.cloudflare.com/client/v4'
*/
CACHE_BASE_URL?: string;
/**
* Cloudflare cache name (optional for cloudflare-cache).
* @example 'my-cache'
*/
CACHE_NAME?: string;
}
/**
* License Information Interface
*
* Represents comprehensive license information extracted from JWT tokens
* including features, expiration, validity status, and license metadata.
*/
/**
* Complete license information extracted from JWT token
*
* @interface TypeLicenseInfo
*/
export declare interface TypeLicenseInfo {
/** Array of feature strings available in this license */
features: string[];
/** Whether the license token is currently valid (has cached token) */
isValid: boolean;
/** Type/tier of the license (e.g., 'basic', 'professional', 'enterprise') */
licenseType?: string;
/** Domain this license is valid for (from JWT audience claim) */
domain?: string;
/** Date when the license expires */
expiresAt?: Date;
}
/**
* License-specific JWT payload interface.
* Extends standard JWT claims with license-specific data.
*/
export declare interface TypeLicenseJwtPayload extends TypeJwtStandardClaims {
/**
* License features array.
* Contains the list of features available in this license.
*/
features?: string[];
/**
* License key identifier.
* The license key this token was issued for.
*/
licenseKey?: string;
/**
* License type identifier.
* The type/tier of license this token represents.
*/
licenseType?: string;
/**
* Custom license metadata.
* Additional license-specific data that may be included in the token.
*/
metadata?: Record<string, unknown>;
/**
* Tenant identifier for multi-tenant licenses.
* Identifies which tenant this license belongs to.
*/
tenantId?: string | number;
}
/**
* License Client - License Payload Type
*
* Payload for license operations (activate, validate, deactivate)
*/
export declare interface TypeLicensePayload {
licenseKey: string;
domain?: string;
subdomain?: string;
ipAddress?: string;
}
/**
* Message interface for API responses
*/
export declare interface TypeMessage {
code: EnumMessageCode;
text: string;
}
/**
* Generic response interface for all API operations
* @template T - The type of data returned in the response (defaults to TypeDefaultResponseData)
*/
export declare interface TypeResponse<T = TypeDefaultResponseData> {
success: boolean;
messages?: TypeMessage[];
data?: T;
}
export { }