Implement version 0.0.9 features

- 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>
This commit is contained in:
2026-01-21 21:23:21 +01:00
parent 6378063180
commit d3830e24b9
8 changed files with 1178 additions and 9 deletions

View File

@@ -0,0 +1,220 @@
/**
* 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;
}