/** * 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: * * 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} 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} 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} 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} 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; }