refactor: implement minimal PWA caching strategy

- Cache only essential PWA assets (manifest, icons, core scripts)
- Use Network First for all other requests
- Remove aggressive caching of UI components and styles
- Preserve PWA installation while minimizing cache footprint
This commit is contained in:
lockbitchat
2025-10-13 01:35:32 -04:00
parent d24d578321
commit 7af8f528ff
11 changed files with 406 additions and 542 deletions

View File

@@ -3,7 +3,6 @@ import { EnhancedSecureWebRTCManager } from '../network/EnhancedSecureWebRTCMana
import { EnhancedSecureFileTransfer } from '../transfer/EnhancedSecureFileTransfer.js';
// Import UI components (side-effect: they attach themselves to window.*)
import '../components/ui/SessionTimer.jsx';
import '../components/ui/Header.jsx';
import '../components/ui/DownloadApps.jsx';
import '../components/ui/UniqueFeatureSlider.jsx';

View File

@@ -3,10 +3,9 @@
(async () => {
try {
const timestamp = Date.now();
const [cryptoModule, webrtcModule, paymentModule, fileTransferModule] = await Promise.all([
const [cryptoModule, webrtcModule, fileTransferModule] = await Promise.all([
import(`../crypto/EnhancedSecureCryptoUtils.js?v=${timestamp}`),
import(`../network/EnhancedSecureWebRTCManager.js?v=${timestamp}`),
import(`../session/PayPerSessionManager.js?v=${timestamp}`),
import(`../transfer/EnhancedSecureFileTransfer.js?v=${timestamp}`),
]);
@@ -14,8 +13,6 @@
window.EnhancedSecureCryptoUtils = EnhancedSecureCryptoUtils;
const { EnhancedSecureWebRTCManager } = webrtcModule;
window.EnhancedSecureWebRTCManager = EnhancedSecureWebRTCManager;
const { PayPerSessionManager } = paymentModule;
window.PayPerSessionManager = PayPerSessionManager;
const { EnhancedSecureFileTransfer } = fileTransferModule;
window.EnhancedSecureFileTransfer = EnhancedSecureFileTransfer;
@@ -28,11 +25,7 @@
}
await Promise.all([
loadReactComponent('../components/ui/SessionTimer.jsx'),
loadReactComponent('../components/ui/Header.jsx'),
loadReactComponent('../components/ui/SessionTypeSelector.jsx'),
loadReactComponent('../components/ui/LightningPayment.jsx'),
loadReactComponent('../components/ui/PaymentModal.jsx'),
loadReactComponent('../components/ui/DownloadApps.jsx'),
loadReactComponent('../components/ui/ComparisonTable.jsx'),
loadReactComponent('../components/ui/UniqueFeatureSlider.jsx'),

View File

@@ -1,27 +1,13 @@
window.forceUpdateHeader = (timeLeft, sessionType) => {
window.forceUpdateHeader = () => {
const event = new CustomEvent('force-header-update', {
detail: { timeLeft, sessionType, timestamp: Date.now() },
detail: { timestamp: Date.now() },
});
document.dispatchEvent(event);
if (window.sessionManager && window.sessionManager.forceUpdateTimer) {
window.sessionManager.forceUpdateTimer();
}
};
window.updateSessionTimer = (timeLeft, sessionType) => {
document.dispatchEvent(
new CustomEvent('session-timer-update', {
detail: { timeLeft, sessionType },
}),
);
};
document.addEventListener('session-activated', (event) => {
if (window.updateSessionTimer) {
window.updateSessionTimer(event.detail.timeLeft, event.detail.sessionType);
}
if (window.forceUpdateHeader) {
window.forceUpdateHeader(event.detail.timeLeft, event.detail.sessionType);
window.forceUpdateHeader();
}
if (window.webrtcManager && window.webrtcManager.handleSessionActivation) {
if (window.DEBUG_MODE) {
@@ -29,9 +15,6 @@ document.addEventListener('session-activated', (event) => {
}
window.webrtcManager.handleSessionActivation({
sessionId: event.detail.sessionId,
sessionType: event.detail.sessionType,
timeLeft: event.detail.timeLeft,
isDemo: event.detail.isDemo,
sessionManager: window.sessionManager,
});
}

View File

@@ -0,0 +1,270 @@
// PWA Offline Test Script for SecureBit.chat
// Enhanced Security Edition v4.3.120
// Tests offline functionality and cache status
class PWAOfflineTester {
constructor() {
this.testResults = [];
this.isRunning = false;
}
async runTests() {
if (this.isRunning) {
console.warn('⚠️ Tests already running');
return;
}
this.isRunning = true;
this.testResults = [];
console.log('🧪 Starting PWA Offline Tests...');
try {
await this.testServiceWorkerRegistration();
await this.testCacheStatus();
await this.testOfflineResources();
await this.testOnlineResources();
this.showTestResults();
} catch (error) {
console.error('❌ Test failed:', error);
this.addTestResult('Test Suite', false, `Test suite failed: ${error.message}`);
} finally {
this.isRunning = false;
}
}
async testServiceWorkerRegistration() {
try {
if ('serviceWorker' in navigator) {
const registration = await navigator.serviceWorker.getRegistration();
if (registration) {
this.addTestResult('Service Worker Registration', true, 'Service worker is registered');
} else {
this.addTestResult('Service Worker Registration', false, 'No service worker found');
}
} else {
this.addTestResult('Service Worker Support', false, 'Service worker not supported');
}
} catch (error) {
this.addTestResult('Service Worker Registration', false, `Error: ${error.message}`);
}
}
async testCacheStatus() {
try {
if ('caches' in window) {
const cacheNames = await caches.keys();
const totalCached = 0;
for (const cacheName of cacheNames) {
const cache = await caches.open(cacheName);
const keys = await cache.keys();
totalCached += keys.length;
}
if (totalCached > 0) {
this.addTestResult('Cache Status', true, `${totalCached} resources cached`);
} else {
this.addTestResult('Cache Status', false, 'No resources cached');
}
} else {
this.addTestResult('Cache API Support', false, 'Cache API not supported');
}
} catch (error) {
this.addTestResult('Cache Status', false, `Error: ${error.message}`);
}
}
async testOfflineResources() {
const criticalResources = [
'/',
'/index.html',
'/manifest.json',
'/dist/app.js',
'/dist/app-boot.js',
'/libs/react/react.production.min.js',
'/libs/react-dom/react-dom.production.min.js',
'/assets/tailwind.css'
];
let cachedCount = 0;
for (const resource of criticalResources) {
try {
const cached = await caches.match(resource);
if (cached) {
cachedCount++;
}
} catch (error) {
console.warn(`⚠️ Failed to check cache for ${resource}:`, error);
}
}
const success = cachedCount >= criticalResources.length * 0.8; // 80% success rate
this.addTestResult('Critical Resources Cached', success,
`${cachedCount}/${criticalResources.length} critical resources cached`);
}
async testOnlineResources() {
try {
// Test if we can fetch a simple resource
const response = await fetch('/favicon.ico', {
method: 'HEAD',
cache: 'no-cache'
});
if (response.ok) {
this.addTestResult('Network Connectivity', true, 'Network is accessible');
} else {
this.addTestResult('Network Connectivity', false, `Network error: ${response.status}`);
}
} catch (error) {
this.addTestResult('Network Connectivity', false, `Network error: ${error.message}`);
}
}
addTestResult(testName, passed, message) {
this.testResults.push({
name: testName,
passed,
message,
timestamp: new Date().toISOString()
});
console.log(`${passed ? '✅' : '❌'} ${testName}: ${message}`);
}
showTestResults() {
const passedTests = this.testResults.filter(test => test.passed).length;
const totalTests = this.testResults.length;
const successRate = Math.round((passedTests / totalTests) * 100);
const modal = document.createElement('div');
modal.className = 'fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4 backdrop-blur-sm';
modal.innerHTML = `
<div class="bg-gray-800 rounded-xl p-6 max-w-2xl w-full max-h-[80vh] overflow-y-auto">
<div class="flex items-center mb-6">
<div class="w-12 h-12 bg-blue-500/10 rounded-full flex items-center justify-center mr-4">
<i class="fas fa-vial text-blue-400 text-xl"></i>
</div>
<h3 class="text-xl font-semibold text-white">PWA Offline Test Results</h3>
</div>
<div class="mb-6 p-4 rounded-lg ${successRate >= 80 ? 'bg-green-500/10 border border-green-500/20' : 'bg-red-500/10 border border-red-500/20'}">
<div class="flex items-center justify-between">
<div>
<div class="font-medium text-white">Overall Score</div>
<div class="text-sm text-gray-300">${passedTests}/${totalTests} tests passed</div>
</div>
<div class="text-2xl font-bold ${successRate >= 80 ? 'text-green-400' : 'text-red-400'}">
${successRate}%
</div>
</div>
</div>
<div class="space-y-3">
${this.testResults.map(test => `
<div class="flex items-center justify-between p-3 rounded-lg ${test.passed ? 'bg-green-500/10 border border-green-500/20' : 'bg-red-500/10 border border-red-500/20'}">
<div class="flex items-center space-x-3">
<i class="fas ${test.passed ? 'fa-check-circle text-green-400' : 'fa-times-circle text-red-400'}"></i>
<div>
<div class="font-medium text-white">${test.name}</div>
<div class="text-sm text-gray-300">${test.message}</div>
</div>
</div>
</div>
`).join('')}
</div>
<div class="mt-6 space-y-3">
<div class="bg-blue-500/10 border border-blue-500/20 rounded-lg p-4">
<h4 class="font-medium text-blue-300 mb-2">Recommendations:</h4>
<ul class="text-sm text-blue-200 space-y-1">
${this.getRecommendations().map(rec => `<li>• ${rec}</li>`).join('')}
</ul>
</div>
<div class="flex space-x-3">
<button onclick="window.pwaOfflineTester.runTests(); this.parentElement.parentElement.parentElement.remove();"
class="flex-1 bg-blue-500 hover:bg-blue-600 text-white py-3 px-4 rounded-lg font-medium transition-colors">
Run Tests Again
</button>
<button onclick="this.parentElement.parentElement.remove()"
class="flex-1 bg-gray-600 hover:bg-gray-500 text-white py-3 px-4 rounded-lg font-medium transition-colors">
Close
</button>
</div>
</div>
</div>
`;
document.body.appendChild(modal);
}
getRecommendations() {
const recommendations = [];
const failedTests = this.testResults.filter(test => !test.passed);
if (failedTests.some(test => test.name.includes('Service Worker'))) {
recommendations.push('Ensure service worker is properly registered and active');
}
if (failedTests.some(test => test.name.includes('Cache'))) {
recommendations.push('Check cache configuration and ensure resources are being cached');
}
if (failedTests.some(test => test.name.includes('Network'))) {
recommendations.push('Verify network connectivity and server availability');
}
if (recommendations.length === 0) {
recommendations.push('All tests passed! Your PWA offline functionality is working correctly.');
}
return recommendations;
}
// Public API
getTestResults() {
return this.testResults;
}
clearResults() {
this.testResults = [];
}
}
// Singleton pattern
let instance = null;
const PWAOfflineTesterAPI = {
getInstance() {
if (!instance) {
instance = new PWAOfflineTester();
}
return instance;
},
runTests() {
return this.getInstance().runTests();
}
};
// Export for module use
if (typeof module !== 'undefined' && module.exports) {
module.exports = PWAOfflineTesterAPI;
} else if (typeof window !== 'undefined' && !window.PWAOfflineTester) {
window.PWAOfflineTester = PWAOfflineTesterAPI;
}
// Auto-initialize
if (typeof window !== 'undefined' && !window.pwaOfflineTester) {
window.pwaOfflineTester = PWAOfflineTesterAPI.getInstance();
// Add global function for easy access
window.testPWAOffline = () => {
window.pwaOfflineTester.runTests();
};
}