diff --git a/src/service-workers/database.worker.js b/src/service-workers/database.worker.ts similarity index 61% rename from src/service-workers/database.worker.js rename to src/service-workers/database.worker.ts index 903ed32..8e974b5 100755 --- a/src/service-workers/database.worker.js +++ b/src/service-workers/database.worker.ts @@ -1,24 +1,73 @@ -let processesToScan = new Set(); -let toDownload = new Set(); +declare var self: ServiceWorkerGlobalScope; -self.addEventListener('install', (event) => { - event.waitUntil(self.skipWaiting()); // Activate worker immediately +// Interfaces +interface Process { + states: State[]; + merkle_root: string; + key: string; +} + +interface State { + state_id: string; + commited_in: string; + merkle_root: string; + pcd_commitment?: { + [key: string]: string; + }; +} + +interface Diff { + process_id: string; + state_id: string; + value_commitment: string; + field: string; + description: string | null; + previous_value: any; + new_value: any; + notify_user: boolean; + need_validation: boolean; + validation_status: string; +} + +interface ProcessWithDiffs { + process: State[]; + processId: string; + diffs: Diff[][]; +} + +interface MessagePayload { + myProcessesId?: string[]; + storeName?: string; + object?: any; + key?: IDBValidKey; +} + +interface MessageEvent { + type: string; + payload?: MessagePayload; +} + +let processesToScan: Set = new Set(); +let toDownload: Set = new Set(); + +self.addEventListener('install', (event: ExtendableEvent) => { + event.waitUntil(self.skipWaiting()); }); -self.addEventListener('activate', (event) => { - event.waitUntil(self.clients.claim()); // Become available to all pages +self.addEventListener('activate', (event: ExtendableEvent) => { + event.waitUntil(self.clients.claim()); }); -// Event listener for messages from clients -self.addEventListener('message', async (event) => { - const data = event.data; +self.addEventListener('message', async (event: ExtendableMessageEvent) => { + const data = event.data as MessageEvent; + if (data.type === 'START') { - const fetchNotifications = async () => { + processesToScan.clear(); + const fetchNotifications = async (): Promise => { const itemsWithFlag = await getAllDiffsNeedValidation(); - // Process items with the specific flag itemsWithFlag?.forEach((item) => { - console.log(item); // Do something with each flagged item + console.log(item); }); event.ports[0].postMessage({ @@ -26,28 +75,23 @@ self.addEventListener('message', async (event) => { data: itemsWithFlag, }); }; - const scanMissingData = async () => { + + const scanMissingData = async (): Promise => { console.log('Scanning for missing data...'); const myProcesses = await getProcesses(processesToScan); - // Iterate on each process - if (myProcesses && myProcesses.length != 0) { + 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.pcd_commitment) continue; - // iterate on pcd_commitment for (const [field, hash] of Object.entries(state.pcd_commitment)) { - // 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, field) + await addDiff(processId, state.state_id, hash, field); } else { - // We remove it if we have it in the set if (toDownload.delete(hash)) { console.log(`Removing ${hash} from the set`); } @@ -57,13 +101,14 @@ self.addEventListener('message', async (event) => { } } - if (toDownload.size != 0) { + if (toDownload.size !== 0) { event.ports[0].postMessage({ type: 'TO_DOWNLOAD', data: Array.from(toDownload), }); } - } + }; + fetchNotifications(); setInterval(fetchNotifications, 2 * 60 * 1000); scanMissingData(); @@ -72,24 +117,26 @@ self.addEventListener('message', async (event) => { if (data.type === 'UPDATE_PROCESSES') { try { - const { myProcessesId } = data.payload; + const { myProcessesId } = data.payload || {}; console.log(myProcessesId); - if (myProcessesId && myProcessesId.length != 0) { + if (myProcessesId && myProcessesId.length !== 0) { for (const processId of myProcessesId) { processesToScan.add(processId); } - console.log(processesToScan); + console.log(processesToScan); } else { event.ports[0].postMessage({ status: 'error', message: 'Empty lists' }); } } catch (error) { - event.ports[0].postMessage({ status: 'error', message: error.message }); + event.ports[0].postMessage({ status: 'error', message: (error as Error).message }); } } if (data.type === 'ADD_OBJECT') { try { - const { storeName, object, key } = data.payload; + const { storeName, object, key } = data.payload || {}; + if (!storeName) throw new Error('Store name is required'); + const db = await openDatabase(); const tx = db.transaction(storeName, 'readwrite'); const store = tx.objectStore(storeName); @@ -102,22 +149,25 @@ self.addEventListener('message', async (event) => { event.ports[0].postMessage({ status: 'success', message: '' }); } catch (error) { - event.ports[0].postMessage({ status: 'error', message: error.message }); + event.ports[0].postMessage({ status: 'error', message: (error as Error).message }); } } }); -async function openDatabase() { +async function openDatabase(): Promise { return new Promise((resolve, reject) => { const request = indexedDB.open('4nk', 1); - request.onerror = (event) => { + + request.onerror = () => { reject(request.error); }; - request.onsuccess = (event) => { + + request.onsuccess = () => { resolve(request.result); }; - request.onupgradeneeded = (event) => { - const db = event.target.result; + + request.onupgradeneeded = (event: IDBVersionChangeEvent) => { + const db = (event.target as IDBOpenDBRequest).result; if (!db.objectStoreNames.contains('wallet')) { db.createObjectStore('wallet', { keyPath: 'pre_id' }); } @@ -125,8 +175,7 @@ async function openDatabase() { }); } -// Function to get all processes because it is asynchronous -async function getAllProcesses() { +async function getAllProcesses(): Promise { const db = await openDatabase(); return new Promise((resolve, reject) => { if (!db) { @@ -145,10 +194,10 @@ async function getAllProcesses() { reject(request.error); }; }); -}; +} -async function getProcesses(processIds) { - if (!processIds || processIds.length === 0) { +async function getProcesses(processIds: Set): Promise { + if (!processIds || processIds.size === 0) { return []; } @@ -161,34 +210,33 @@ async function getProcesses(processIds) { const store = tx.objectStore('processes'); const requests = Array.from(processIds).map((processId) => { - return new Promise((resolve) => { + return new Promise((resolve) => { const request = store.get(processId); request.onsuccess = () => resolve(request.result); request.onerror = () => { console.error(`Error fetching process ${processId}:`, request.error); - resolve(undefined); + resolve(undefined); }; }); }); const results = await Promise.all(requests); - return results.filter(result => result !== undefined); + return results.filter((result): result is Process => result !== undefined); } -async function getAllDiffsNeedValidation() { +async function getAllDiffsNeedValidation(): Promise { const db = await openDatabase(); - const allProcesses = await getAllProcesses(); const tx = db.transaction('diffs', 'readonly'); const store = tx.objectStore('diffs'); return new Promise((resolve, reject) => { const request = store.getAll(); - request.onsuccess = (event) => { - const allItems = event.target.result; + request.onsuccess = (event: Event) => { + const allItems = (event.target as IDBRequest).result as Diff[]; const itemsWithFlag = allItems.filter((item) => item.need_validation); - const processMap = {}; + const processMap: { [key: string]: { process: State[]; processId: string; diffs: Diff[]; } } = {}; for (const diff of itemsWithFlag) { const currentProcess = allProcesses.find((item) => { @@ -210,11 +258,11 @@ async function getAllDiffsNeedValidation() { } const results = Object.values(processMap).map((entry) => { - const diffs = [] + const diffs: Diff[][] = []; for(const state of entry.process) { const filteredDiff = entry.diffs.filter(diff => diff.new_state_merkle_root === state.merkle_root); if(filteredDiff && filteredDiff.length) { - diffs.push(filteredDiff) + diffs.push(filteredDiff); } } return { @@ -227,44 +275,43 @@ async function getAllDiffsNeedValidation() { resolve(results); }; - request.onerror = (event) => { - reject(event.target.error); + request.onerror = (event: Event) => { + reject((event.target as IDBRequest).error); }; }); } -async function getBlob(hash) { +async function getBlob(hash: string): Promise { const db = await openDatabase(); const storeName = 'data'; const tx = db.transaction(storeName, 'readonly'); const store = tx.objectStore(storeName); - const result = await new Promise((resolve, reject) => { + + return new Promise((resolve, reject) => { const getRequest = store.get(hash); getRequest.onsuccess = () => resolve(getRequest.result); getRequest.onerror = () => reject(getRequest.error); }); - return result; } -async function addDiff(processId, stateId, hash) { +async function addDiff(processId: string, stateId: string, hash: string, field: string): Promise { const db = await openDatabase(); const storeName = 'diffs'; const tx = db.transaction(storeName, 'readwrite'); const store = tx.objectStore(storeName); - // Check if the diff already exists - const existingDiff = await new Promise((resolve, reject) => { + const existingDiff = await new Promise((resolve, reject) => { const getRequest = store.get(hash); getRequest.onsuccess = () => resolve(getRequest.result); getRequest.onerror = () => reject(getRequest.error); }); - if (!existingDiff) { - const newDiff = { + if (!existingDiff) { + const newDiff: Diff = { process_id: processId, state_id: stateId, value_commitment: hash, - field: '', + field: field, description: null, previous_value: null, new_value: null, @@ -273,13 +320,11 @@ async function addDiff(processId, stateId, hash) { validation_status: 'None' }; - const insertResult = await new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const putRequest = store.put(newDiff); putRequest.onsuccess = () => resolve(putRequest.result); putRequest.onerror = () => reject(putRequest.error); }); - - return insertResult; } return existingDiff; diff --git a/src/services/database.service.ts b/src/services/database.service.ts index e99370f..c1f188e 100755 --- a/src/services/database.service.ts +++ b/src/services/database.service.ts @@ -119,7 +119,7 @@ export class Database { const registrations = await navigator.serviceWorker.getRegistrations(); if (registrations.length === 0) { // No existing workers: register a new one. - this.serviceWorkerRegistration = await navigator.serviceWorker.register('/src/service-workers/database.worker.js', { type: 'module' }); + this.serviceWorkerRegistration = await navigator.serviceWorker.register('/src/service-workers/database.worker.ts', { type: 'module' }); console.log('Service Worker registered with scope:', registration.scope); } else if (registrations.length === 1) { // One existing worker: update it (restart it) without unregistering. @@ -131,7 +131,7 @@ export class Database { console.log('Multiple Service Worker(s) detected. Unregistering all...'); await Promise.all(registrations.map(reg => reg.unregister())); console.log('All previous Service Workers unregistered.'); - this.serviceWorkerRegistration = await navigator.serviceWorker.register('/src/service-workers/database.worker.js', { type: 'module' }); + this.serviceWorkerRegistration = await navigator.serviceWorker.register('/src/service-workers/database.worker.ts', { type: 'module' }); console.log('Service Worker registered with scope:', registration.scope); }