/** * LiteSpeed CDN Plugin for AlgorithmPress * Connects to LiteSpeed CDN services and provides caching capabilities * for the PHP-WASM environment, similar to the WordPress LiteSpeed plugin. */ const LiteSpeedPlugin = (function() { // Private variables const state = { initialized: false, connected: false, apiKey: '', siteId: '', enabled: true, cdnEnabled: false, cacheEnabled: true, imageOptEnabled: false, cssJsMinify: false, lazyLoadEnabled: false, criticalCSSEnabled: false, settings: {}, stats: { cacheHits: 0, cacheMisses: 0, cdnBandwidthSaved: 0, imageOptimizationSavings: 0 }, apiEndpoints: { connect: 'https://api.quic.cloud/connect', validate: 'https://api.quic.cloud/validate', cdn: 'https://api.quic.cloud/cdn', imageOptimize: 'https://api.quic.cloud/img_optm' } }; // Cache management const cacheManager = { cacheStorage: null, cacheName: 'litespeed-algorithpress-cache', // Initialize cache init: async function() { if ('caches' in window) { this.cacheStorage = await caches.open(this.cacheName); return true; } return false; }, // Store in cache async store(key, data, contentType = 'text/plain', ttl = 3600) { if (!this.cacheStorage) return false; try { const options = { headers: { 'Content-Type': contentType, 'Cache-Control': `max-age=${ttl}`, 'X-LiteSpeed-Cache': 'true', 'X-LiteSpeed-Cache-TTL': ttl, 'X-LiteSpeed-Cache-Timestamp': Date.now() } }; const blob = new Blob([data], { type: contentType }); const response = new Response(blob, options); await this.cacheStorage.put(key, response); return true; } catch (error) { console.error('LiteSpeed Cache: Failed to store in cache', error); return false; } }, // Retrieve from cache async retrieve(key) { if (!this.cacheStorage) return null; try { const response = await this.cacheStorage.match(key); if (!response) { state.stats.cacheMisses++; return null; } // Check if cache is still valid const timestamp = parseInt(response.headers.get('X-LiteSpeed-Cache-Timestamp') || '0'); const ttl = parseInt(response.headers.get('X-LiteSpeed-Cache-TTL') || '0'); const now = Date.now(); if (timestamp + (ttl * 1000) < now) { // Cache expired await this.cacheStorage.delete(key); state.stats.cacheMisses++; return null; } state.stats.cacheHits++; return await response.text(); } catch (error) { console.error('LiteSpeed Cache: Failed to retrieve from cache', error); state.stats.cacheMisses++; return null; } }, // Clear cache async clear() { if (!this.cacheStorage) return false; try { const keys = await this.cacheStorage.keys(); for (const request of keys) { await this.cacheStorage.delete(request); } return true; } catch (error) { console.error('LiteSpeed Cache: Failed to clear cache', error); return false; } }, // Purge specific cache entry async purge(key) { if (!this.cacheStorage) return false; try { return await this.cacheStorage.delete(key); } catch (error) { console.error('LiteSpeed Cache: Failed to purge cache entry', error); return false; } } }; // CDN Management const cdnManager = { cdnDomain: '', cdnEnabled: false, excludedFiles: [], // Initialize CDN init: function(cdnDomain) { this.cdnDomain = cdnDomain || ''; this.cdnEnabled = Boolean(cdnDomain); return this.cdnEnabled; }, // Generate CDN URL for a resource getCdnUrl: function(originalUrl) { if (!this.cdnEnabled || !this.cdnDomain) return originalUrl; try { // Check if file should be excluded from CDN const filename = originalUrl.split('/').pop(); if (this.excludedFiles.includes(filename)) { return originalUrl; } // Ensure it's a valid URL const url = new URL(originalUrl, window.location.origin); // Don't CDN external domains or special URLs if (url.hostname !== window.location.hostname && !originalUrl.startsWith('/')) { return originalUrl; } // Replace domain with CDN domain const cdnUrl = new URL(url.pathname + url.search, this.cdnDomain); return cdnUrl.toString(); } catch (error) { console.error('LiteSpeed CDN: Error generating CDN URL', error); return originalUrl; } }, // Set excluded files that shouldn't go through CDN setExcludedFiles: function(excludedFiles) { this.excludedFiles = Array.isArray(excludedFiles) ? excludedFiles : []; }, // Enable/disable CDN enable: function(enabled) { this.cdnEnabled = enabled && Boolean(this.cdnDomain); return this.cdnEnabled; } }; // Image Optimization const imageOptimizer = { enabled: false, quality: 85, webpEnabled: true, lazyLoadEnabled: false, excludedImages: [], // Initialize image optimizer init: function(config = {}) { this.enabled = config.enabled !== false; this.quality = config.quality || 85; this.webpEnabled = config.webpEnabled !== false; this.lazyLoadEnabled = config.lazyLoadEnabled || false; this.excludedImages = config.excludedImages || []; // Listen for image loading if using lazy load if (this.enabled && this.lazyLoadEnabled) { this.setupLazyLoading(); } return this.enabled; }, // Process an image URL through LiteSpeed image optimization processImageUrl: function(originalUrl) { if (!this.enabled) return originalUrl; try { // Check if image should be excluded const filename = originalUrl.split('/').pop(); if (this.excludedImages.includes(filename)) { return originalUrl; } // Validate URL const url = new URL(originalUrl, window.location.origin); // Don't process external images if (url.hostname !== window.location.hostname && !originalUrl.startsWith('/')) { return originalUrl; } // If CDN is enabled, use CDN URL as the base let baseUrl = originalUrl; if (cdnManager.cdnEnabled) { baseUrl = cdnManager.getCdnUrl(originalUrl); } // Append image optimization parameters const separator = baseUrl.includes('?') ? '&' : '?'; let optimizedUrl = `${baseUrl}${separator}ls-img=1&q=${this.quality}`; // Add WebP if supported and enabled if (this.webpEnabled && this.isWebpSupported()) { optimizedUrl += '&webp=1'; } return optimizedUrl; } catch (error) { console.error('LiteSpeed Image Optimizer: Error processing image URL', error); return originalUrl; } }, // Check if browser supports WebP isWebpSupported: function() { // Simple detection based on Safari support which was the last major browser to add WebP const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); const isSafari12OrNewer = isSafari && (parseInt(navigator.appVersion.match(/Version\/(\d+)/)?.[1] || 0) >= 12); // WebP is supported in Chrome, Firefox, Edge, and Safari 12+ return !isSafari || isSafari12OrNewer; }, // Set up lazy loading for images setupLazyLoading: function() { if (!('IntersectionObserver' in window)) return false; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; const lazySrc = img.getAttribute('data-ls-src'); if (lazySrc) { // Process and set the actual image source img.src = this.processImageUrl(lazySrc); // Remove the lazy attribute to prevent future observation img.removeAttribute('data-ls-src'); // Stop observing this image observer.unobserve(img); } } }); }, { rootMargin: '200px' // Load images when they're 200px away from viewport }); // Find all images with data-ls-src attribute and observe them document.querySelectorAll('img[data-ls-src]').forEach(img => { observer.observe(img); }); // Store the observer reference for future images this.lazyLoadObserver = observer; // Monitor for DOM changes to catch new images if ('MutationObserver' in window) { const mutationObserver = new MutationObserver((mutations) => { mutations.forEach(mutation => { if (mutation.type === 'childList') { mutation.addedNodes.forEach(node => { if (node.nodeType === 1) { // Element node // Check if this node is an image with data-ls-src if (node.nodeName === 'IMG' && node.hasAttribute('data-ls-src')) { observer.observe(node); } // Check child images node.querySelectorAll('img[data-ls-src]').forEach(img => { observer.observe(img); }); } }); } }); }); mutationObserver.observe(document.body, { childList: true, subtree: true }); this.mutationObserver = mutationObserver; } return true; }, // Add an image to lazy loading addToLazyLoad: function(imgElement, originalSrc) { if (!this.lazyLoadEnabled || !this.lazyLoadObserver) return false; try { // Set a placeholder image or low-quality version imgElement.src = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1"%3E%3C/svg%3E'; // Store the original source imgElement.setAttribute('data-ls-src', originalSrc); // Start observing this image this.lazyLoadObserver.observe(imgElement); return true; } catch (error) { console.error('LiteSpeed Image Optimizer: Error adding image to lazy load', error); return false; } } }; // CSS/JS Minification const minifier = { enabled: false, cssMinifyEnabled: false, jsMinifyEnabled: false, htmlMinifyEnabled: false, excludedFiles: [], // Initialize minifier init: function(config = {}) { this.enabled = config.enabled !== false; this.cssMinifyEnabled = config.cssMinifyEnabled !== false; this.jsMinifyEnabled = config.jsMinifyEnabled !== false; this.htmlMinifyEnabled = config.htmlMinifyEnabled || false; this.excludedFiles = config.excludedFiles || []; return this.enabled; }, // Process CSS content minifyCss: function(css) { if (!this.enabled || !this.cssMinifyEnabled) return css; try { // Basic CSS minification return css .replace(/\/\*[\s\S]*?\*\//g, '') // Remove comments .replace(/\s+/g, ' ') // Replace multiple spaces with single space .replace(/\s*(\{|\}|\:|\;|\,)\s*/g, '$1') // Remove spaces around {, }, :, ;, , .replace(/;\}/g, '}') // Remove unnecessary semicolons .trim(); } catch (error) { console.error('LiteSpeed Minifier: Error minifying CSS', error); return css; } }, // Process JavaScript content minifyJs: function(js) { if (!this.enabled || !this.jsMinifyEnabled) return js; try { // Basic JS minification - in a real implementation, use a proper minifier return js .replace(/\/\/.*$/gm, '') // Remove single-line comments .replace(/\/\*[\s\S]*?\*\//g, '') // Remove multi-line comments .replace(/^\s*\n/gm, '') // Remove empty lines .replace(/\s+/g, ' ') // Replace multiple spaces with single space .replace(/\s*(\(|\)|\{|\}|\[|\]|\:|\;|\,|\.|=|\+|-|\*|\/|>|<|&|\||\?)\s*/g, '$1') // Remove spaces around operators .trim(); } catch (error) { console.error('LiteSpeed Minifier: Error minifying JavaScript', error); return js; } }, // Process HTML content minifyHtml: function(html) { if (!this.enabled || !this.htmlMinifyEnabled) return html; try { // Basic HTML minification return html .replace(//g, '') // Remove HTML comments .replace(/\s+/g, ' ') // Replace multiple spaces with single space .replace(/>\s+<') // Remove spaces between tags .replace(/\s+>/g, '>') // Remove spaces before closing brackets .replace(/<\s+/g, '<') // Remove spaces after opening brackets .trim(); } catch (error) { console.error('LiteSpeed Minifier: Error minifying HTML', error); return html; } } }; // API integration const apiClient = { // Connect to LiteSpeed API connect: async function(apiKey, domain) { try { const response = await fetch(state.apiEndpoints.connect, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-LSCAPI-KEY': apiKey }, body: JSON.stringify({ domain: domain || window.location.hostname, source: 'algorithpress' }) }); if (!response.ok) { throw new Error(`API responded with status ${response.status}`); } const data = await response.json(); if (data.success) { state.connected = true; state.siteId = data.site_id || ''; return { success: true, siteId: data.site_id, message: data.message || 'Successfully connected to LiteSpeed CDN' }; } else { return { success: false, message: data.message || 'Failed to connect to LiteSpeed CDN' }; } } catch (error) { console.error('LiteSpeed API: Connection error', error); return { success: false, message: error.message || 'Connection error' }; } }, // Validate connection validateConnection: async function() { if (!state.apiKey || !state.siteId) { return { success: false, message: 'API key or Site ID not set' }; } try { const response = await fetch(state.apiEndpoints.validate, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-LSCAPI-KEY': state.apiKey }, body: JSON.stringify({ site_id: state.siteId }) }); if (!response.ok) { throw new Error(`API responded with status ${response.status}`); } const data = await response.json(); if (data.success) { state.connected = true; return { success: true, message: data.message || 'Connection validated' }; } else { state.connected = false; return { success: false, message: data.message || 'Connection validation failed' }; } } catch (error) { console.error('LiteSpeed API: Validation error', error); state.connected = false; return { success: false, message: error.message || 'Validation error' }; } }, // Get CDN configuration getCdnConfig: async function() { if (!state.apiKey || !state.siteId || !state.connected) { return { success: false, message: 'Not connected to LiteSpeed API' }; } try { const response = await fetch(`${state.apiEndpoints.cdn}/${state.siteId}/config`, { method: 'GET', headers: { 'Content-Type': 'application/json', 'X-LSCAPI-KEY': state.apiKey } }); if (!response.ok) { throw new Error(`API responded with status ${response.status}`); } const data = await response.json(); if (data.success) { return { success: true, config: data.config || {}, message: 'CDN configuration retrieved' }; } else { return { success: false, message: data.message || 'Failed to retrieve CDN configuration' }; } } catch (error) { console.error('LiteSpeed API: Error getting CDN config', error); return { success: false, message: error.message || 'Error retrieving CDN configuration' }; } }, // Purge CDN cache purgeCdnCache: async function(urls = []) { if (!state.apiKey || !state.siteId || !state.connected) { return { success: false, message: 'Not connected to LiteSpeed API' }; } try { const response = await fetch(`${state.apiEndpoints.cdn}/${state.siteId}/purge`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-LSCAPI-KEY': state.apiKey }, body: JSON.stringify({ urls: urls.length ? urls : ['*'] // Purge all if no URLs specified }) }); if (!response.ok) { throw new Error(`API responded with status ${response.status}`); } const data = await response.json(); if (data.success) { return { success: true, message: data.message || 'Cache purged successfully' }; } else { return { success: false, message: data.message || 'Failed to purge cache' }; } } catch (error) { console.error('LiteSpeed API: Error purging cache', error); return { success: false, message: error.message || 'Error purging cache' }; } } }; // Settings management const settingsManager = { defaultSettings: { apiKey: '', siteId: '', enabled: true, cdnEnabled: false, cdnDomain: '', cacheEnabled: true, cacheTTL: 3600, // 1 hour imageOptEnabled: false, imageQuality: 85, webpEnabled: true, lazyLoadEnabled: false, cssJsMinify: false, excludedFiles: [], excludedImages: [] }, // Load settings from storage loadSettings: function() { try { const savedSettings = localStorage.getItem('litespeed_settings'); if (savedSettings) { state.settings = JSON.parse(savedSettings); } else { state.settings = { ...this.defaultSettings }; } // Apply loaded settings to state this.applySettings(); return state.settings; } catch (error) { console.error('LiteSpeed Settings: Error loading settings', error); state.settings = { ...this.defaultSettings }; return state.settings; } }, // Save settings to storage saveSettings: function(settings = {}) { try { // Merge new settings with existing state.settings = { ...state.settings, ...settings }; // Save to localStorage localStorage.setItem('litespeed_settings', JSON.stringify(state.settings)); // Apply new settings this.applySettings(); return true; } catch (error) { console.error('LiteSpeed Settings: Error saving settings', error); return false; } }, // Apply settings to various components applySettings: function() { // Apply to state state.apiKey = state.settings.apiKey || ''; state.siteId = state.settings.siteId || ''; state.enabled = state.settings.enabled !== false; state.cdnEnabled = state.settings.cdnEnabled || false; state.cacheEnabled = state.settings.cacheEnabled !== false; state.imageOptEnabled = state.settings.imageOptEnabled || false; state.cssJsMinify = state.settings.cssJsMinify || false; state.lazyLoadEnabled = state.settings.lazyLoadEnabled || false; // Apply to CDN Manager cdnManager.init(state.settings.cdnDomain || ''); cdnManager.enable(state.cdnEnabled); cdnManager.setExcludedFiles(state.settings.excludedFiles || []); // Apply to Image Optimizer imageOptimizer.init({ enabled: state.imageOptEnabled, quality: state.settings.imageQuality || 85, webpEnabled: state.settings.webpEnabled !== false, lazyLoadEnabled: state.lazyLoadEnabled, excludedImages: state.settings.excludedImages || [] }); // Apply to Minifier minifier.init({ enabled: state.cssJsMinify, cssMinifyEnabled: state.cssJsMinify, jsMinifyEnabled: state.cssJsMinify, htmlMinifyEnabled: false, // HTML minification is more complex, disabled by default excludedFiles: state.settings.excludedFiles || [] }); }, // Reset settings to defaults resetSettings: function() { state.settings = { ...this.defaultSettings }; localStorage.setItem('litespeed_settings', JSON.stringify(state.settings)); this.applySettings(); return state.settings; } }; // UI Management const uiManager = { panelContainer: null, // Initialize UI init: function() { // Create panel container if it doesn't exist if (!this.panelContainer) { this.createPanelContainer(); } return true; }, // Create panel container createPanelContainer: function() { // Check if panel already exists if (document.getElementById('litespeed-panel')) { this.panelContainer = document.getElementById('litespeed-panel'); return this.panelContainer; } // Create panel container const container = document.createElement('div'); container.id = 'litespeed-panel'; container.className = 'litespeed-panel'; container.style.display = 'none'; // Add to document document.body.appendChild(container); this.panelContainer = container; return container; }, // Show settings panel showSettings: function() { if (!this.panelContainer) { this.createPanelContainer(); } // Create settings panel content this.panelContainer.innerHTML = `