const EMPTY32BYTES = String('').padStart(64, '0'); self.addEventListener('install', (event) => { event.waitUntil(self.skipWaiting()); // Activate worker immediately }); self.addEventListener('activate', (event) => { event.waitUntil(self.clients.claim()); // Become available to all pages }); // Event listener for messages from clients self.addEventListener('message', async (event) => { const data = event.data; console.log(data); if (data.type === 'SCAN') { try { const myProcessesId = data.payload; if (myProcessesId && myProcessesId.length != 0) { const toDownload = await scanMissingData(myProcessesId); if (toDownload.length != 0) { console.log('Sending TO_DOWNLOAD message'); event.source.postMessage({ type: 'TO_DOWNLOAD', data: toDownload}); } } else { event.source.postMessage({ status: 'error', message: 'Empty lists' }); } } catch (error) { event.source.postMessage({ status: 'error', message: error.message }); } } }); // ============================================ // DATABASE COMMUNICATION // ============================================ async function requestFromMainThread(client, action, payload) { return new Promise((resolve, reject) => { const messageId = `sw_${Date.now()}_${Math.random()}`; const messageHandler = (event) => { if (event.data.id === messageId) { self.removeEventListener('message', messageHandler); if (event.data.type === 'DB_RESPONSE') { resolve(event.data.result); } else if (event.data.type === 'DB_ERROR') { reject(new Error(event.data.error)); } } }; self.addEventListener('message', messageHandler); client.postMessage({ type: 'DB_REQUEST', id: messageId, action, payload }); setTimeout(() => { self.removeEventListener('message', messageHandler); reject(new Error('Database request timeout')); }, 10000); }); } // ============================================ // SCAN LOGIC // ============================================ async function scanMissingData(processesToScan) { console.log('Scanning for missing data...'); const myProcesses = await getProcesses(processesToScan); let toDownload = new Set(); // Iterate on each process if (myProcesses && myProcesses.length != 0) { for (const process of myProcesses) { // Iterate on states const firstState = process.states[0]; const processId = firstState.commited_in; for (const state of process.states) { if (state.state_id === EMPTY32BYTES) continue; // iterate on pcd_commitment for (const [field, hash] of Object.entries(state.pcd_commitment)) { // Skip public fields if (state.public_data[field] !== undefined || field === 'roles') continue; // Check if we have the data in db const existingData = await getBlob(hash); if (!existingData) { toDownload.add(hash); // We also add an entry in diff, in case it doesn't already exist await addDiff(processId, state.state_id, hash, state.roles, field); } else { // We remove it if we have it in the set if (toDownload.delete(hash)) { console.log(`Removing ${hash} from the set`); } } } } } } console.log('[Service Worker] Scan complete:', { toDownload: toDownload.size, diffsToCreate: diffsToCreate.length }); return { toDownload: Array.from(toDownload), diffsToCreate: diffsToCreate }; }