You've already forked wc-licensed-product
- Add API client examples for PHP, Python, JavaScript, curl, and C# - Create comprehensive REST API documentation in docs/client-examples/ - All examples include rate limit handling (HTTP 429) - Examples cover validate, status, and activate endpoints Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
221 lines
7.2 KiB
JavaScript
221 lines
7.2 KiB
JavaScript
/**
|
|
* WC Licensed Product API Client for JavaScript
|
|
*
|
|
* A JavaScript client for interacting with the WC Licensed Product REST API.
|
|
* Works in both browser and Node.js environments.
|
|
*
|
|
* Browser usage:
|
|
* <script src="javascript-client.js"></script>
|
|
* const client = new WcLicensedProductClient('https://your-site.com');
|
|
* const result = await client.validate('XXXX-XXXX-XXXX-XXXX', 'example.com');
|
|
*
|
|
* Node.js usage:
|
|
* const WcLicensedProductClient = require('./javascript-client');
|
|
* const client = new WcLicensedProductClient('https://your-site.com');
|
|
*/
|
|
|
|
class WcLicensedProductError extends Error {
|
|
constructor(message, errorCode = null, httpCode = null) {
|
|
super(message);
|
|
this.name = 'WcLicensedProductError';
|
|
this.errorCode = errorCode;
|
|
this.httpCode = httpCode;
|
|
}
|
|
}
|
|
|
|
class RateLimitError extends WcLicensedProductError {
|
|
constructor(retryAfter) {
|
|
super(`Rate limit exceeded. Retry after ${retryAfter} seconds.`);
|
|
this.name = 'RateLimitError';
|
|
this.retryAfter = retryAfter;
|
|
}
|
|
}
|
|
|
|
class WcLicensedProductClient {
|
|
/**
|
|
* Initialize the client
|
|
* @param {string} siteUrl - Your WordPress site URL (e.g., 'https://example.com')
|
|
* @param {Object} options - Optional configuration
|
|
* @param {number} options.timeout - Request timeout in milliseconds (default: 30000)
|
|
*/
|
|
constructor(siteUrl, options = {}) {
|
|
this.baseUrl = siteUrl.replace(/\/$/, '') + '/wp-json/wc-licensed-product/v1';
|
|
this.timeout = options.timeout || 30000;
|
|
}
|
|
|
|
/**
|
|
* Validate a license key for a specific domain
|
|
* @param {string} licenseKey - The license key to validate
|
|
* @param {string} domain - The domain to validate against
|
|
* @returns {Promise<Object>} Response data with 'valid' boolean and license info
|
|
*/
|
|
async validate(licenseKey, domain) {
|
|
return this._request('/validate', {
|
|
license_key: licenseKey,
|
|
domain: domain,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get the status of a license
|
|
* @param {string} licenseKey - The license key to check
|
|
* @returns {Promise<Object>} License status data
|
|
*/
|
|
async status(licenseKey) {
|
|
return this._request('/status', {
|
|
license_key: licenseKey,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Activate a license on a domain
|
|
* @param {string} licenseKey - The license key to activate
|
|
* @param {string} domain - The domain to activate on
|
|
* @returns {Promise<Object>} Response with 'success' boolean and message
|
|
*/
|
|
async activate(licenseKey, domain) {
|
|
return this._request('/activate', {
|
|
license_key: licenseKey,
|
|
domain: domain,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Make an API request
|
|
* @private
|
|
* @param {string} endpoint - API endpoint path
|
|
* @param {Object} data - Request data
|
|
* @returns {Promise<Object>} Decoded response data
|
|
*/
|
|
async _request(endpoint, data) {
|
|
const url = this.baseUrl + endpoint;
|
|
|
|
const controller = new AbortController();
|
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
|
|
try {
|
|
const response = await fetch(url, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json',
|
|
},
|
|
body: JSON.stringify(data),
|
|
signal: controller.signal,
|
|
});
|
|
|
|
clearTimeout(timeoutId);
|
|
|
|
// Handle rate limiting
|
|
if (response.status === 429) {
|
|
const retryAfter = parseInt(response.headers.get('Retry-After') || '60', 10);
|
|
throw new RateLimitError(retryAfter);
|
|
}
|
|
|
|
const result = await response.json();
|
|
|
|
// Check for API errors
|
|
if (response.status >= 400 && result.error) {
|
|
throw new WcLicensedProductError(
|
|
result.message || 'Unknown error',
|
|
result.error,
|
|
response.status
|
|
);
|
|
}
|
|
|
|
return result;
|
|
} catch (error) {
|
|
clearTimeout(timeoutId);
|
|
|
|
if (error instanceof WcLicensedProductError) {
|
|
throw error;
|
|
}
|
|
|
|
if (error.name === 'AbortError') {
|
|
throw new WcLicensedProductError('Request timeout');
|
|
}
|
|
|
|
throw new WcLicensedProductError(`Request failed: ${error.message}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Usage Examples
|
|
// =============================================================================
|
|
|
|
// Example usage (uncomment to run):
|
|
|
|
/*
|
|
(async () => {
|
|
const client = new WcLicensedProductClient('https://your-wordpress-site.com');
|
|
|
|
// Example 1: Validate a license
|
|
console.log('=== Validate License ===');
|
|
try {
|
|
const result = await client.validate('XXXX-XXXX-XXXX-XXXX', 'myapp.example.com');
|
|
|
|
if (result.valid) {
|
|
console.log('License is valid!');
|
|
console.log('Status:', result.license?.status || 'active');
|
|
console.log('Expires:', result.license?.expires_at || 'Never');
|
|
} else {
|
|
console.log('License is not valid:', result.message || 'Unknown error');
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof RateLimitError) {
|
|
console.log(`Rate limited. Retry after ${error.retryAfter} seconds.`);
|
|
} else {
|
|
console.log('Error:', error.message);
|
|
}
|
|
}
|
|
|
|
console.log();
|
|
|
|
// Example 2: Check license status
|
|
console.log('=== Check License Status ===');
|
|
try {
|
|
const status = await client.status('XXXX-XXXX-XXXX-XXXX');
|
|
|
|
console.log('Valid:', status.valid ? 'Yes' : 'No');
|
|
console.log('Status:', status.status || 'unknown');
|
|
console.log('Domain:', status.domain || 'None');
|
|
console.log('Expires:', status.expires_at || 'Never');
|
|
console.log('Activations:', `${status.activations_count || 0}/${status.max_activations || 1}`);
|
|
} catch (error) {
|
|
if (error instanceof RateLimitError) {
|
|
console.log(`Rate limited. Retry after ${error.retryAfter} seconds.`);
|
|
} else {
|
|
console.log('Error:', error.message);
|
|
}
|
|
}
|
|
|
|
console.log();
|
|
|
|
// Example 3: Activate license on a domain
|
|
console.log('=== Activate License ===');
|
|
try {
|
|
const result = await client.activate('XXXX-XXXX-XXXX-XXXX', 'newsite.example.com');
|
|
|
|
if (result.success) {
|
|
console.log('License activated successfully!');
|
|
} else {
|
|
console.log('Activation failed:', result.message || 'Unknown error');
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof RateLimitError) {
|
|
console.log(`Rate limited. Retry after ${error.retryAfter} seconds.`);
|
|
} else {
|
|
console.log(`Error (${error.errorCode}):`, error.message);
|
|
}
|
|
}
|
|
})();
|
|
*/
|
|
|
|
// Export for Node.js
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = WcLicensedProductClient;
|
|
module.exports.WcLicensedProductError = WcLicensedProductError;
|
|
module.exports.RateLimitError = RateLimitError;
|
|
}
|