(function (root, factory) { if (typeof module === 'object' && module.exports) module.exports = factory; else { root.createDeviceStorage = factory; root.createDeviceStorage.mount = document => factory({ summary:document.querySelector('#device-storage-summary'), detail:document.querySelector('#device-storage-detail'), clearCachesButton:document.querySelector('#clear-device-caches'), clearAllButton:document.querySelector('#clear-private-device-data'), localStorage:root.localStorage, sessionStorage:root.sessionStorage, caches:root.caches, storageManager:root.navigator?.storage, privateDatabases:root.stackchainPrivateDatabases, clearPrivateDeviceData:root.stackchainPrivateDeviceData, }); } })(typeof self !== 'undefined' ? self : this, function createDeviceStorage(options) { let privateItemCount = 0; let fullClearArmed = false; const ownedCaches = async () => (await options.caches?.keys?.() || []) .filter(name => name.startsWith('stackchain-dashboard-')); function ownedStorageCount(storage) { if (!storage) return 0; let count = 0; for (let index = 0; index < storage.length; index += 1) { if (storage.key(index)?.startsWith('stackchain.')) count += 1; } return count; } function megabytes(value) { return Math.round((Number(value) || 0) / (1024 * 1024)); } async function refresh() { let estimate = null; try { estimate = await options.storageManager?.estimate?.(); } catch (_error) { /* Storage estimates are optional. */ } options.summary.textContent = estimate?.quota ? `${megabytes(estimate.usage)} MB of ${megabytes(estimate.quota)} MB browser storage used.` : 'Browser storage usage is unavailable.'; const itemCount = ownedStorageCount(options.localStorage) + (options.sessionStorage === options.localStorage ? 0 : ownedStorageCount(options.sessionStorage)); privateItemCount = itemCount; const cacheCount = (await ownedCaches()).length; options.detail.textContent = `${itemCount} private browser item${itemCount === 1 ? '' : 's'} · ` + `${options.privateDatabases.length} private work stores · ` + `${cacheCount} cached app cop${cacheCount === 1 ? 'y' : 'ies'}`; return { itemCount, cacheCount }; } async function clearCaches() { options.clearCachesButton.disabled = true; try { await Promise.all((await ownedCaches()).map(name => options.caches.delete(name))); await refresh(); options.summary.textContent = 'Cached app copies cleared. Private work was kept.'; } catch (error) { options.summary.textContent = `Cached copies could not be cleared: ${error.message}`; } finally { options.clearCachesButton.disabled = false; } } async function clearAll() { if (privateItemCount > 0 && !fullClearArmed) { fullClearArmed = true; options.clearAllButton.textContent = 'Confirm: clear private work'; options.summary.textContent = 'Private drafts or queued work may not be synced. Press confirm to clear them from this device.'; return; } options.clearAllButton.disabled = true; try { await options.clearPrivateDeviceData(); privateItemCount = 0; fullClearArmed = false; options.clearAllButton.textContent = 'Clear all private data'; options.detail.textContent = '0 private browser items · 0 private work stores · 0 cached app copies'; options.summary.textContent = 'All Stackchain private data was cleared from this device.'; } catch (error) { options.summary.textContent = `Private data was not fully cleared: ${error.message}`; } finally { options.clearAllButton.disabled = false; } } async function start() { options.clearCachesButton.addEventListener('click', clearCaches); options.clearAllButton.addEventListener('click', clearAll); return refresh(); } return { refresh, start }; });