feat(core): add preserve_ls_keys and skip_ls options to clear_all_storage; update Clear & Reload buttons

core__browser_reset:
- clear_all_storage now accepts options: { preserve_ls_keys?, skip_ls? }
  - preserve_ls_keys: saves named localStorage keys before clearing and restores them after
    (use ['ae_loc'] to keep the user signed in through a full reset)
  - skip_ls: skips localStorage and sessionStorage entirely
    (for SW+Cache+IDB-only resets that should not disturb auth state)

journals/+layout.svelte:
- Replaced 60-line inline onclick with core_func.clear_idb() + ae_loc preserve pattern
- Hardcoded indexedDB.deleteDatabase() name list replaced with core_func.clear_idb()
  (gets indexedDB.databases() enumeration + older-browser fallback automatically)
- Non-edit mode: IDB clear + reload; edit mode: IDB + localStorage (ae_loc preserved) + goto('/')

e_app_help_tech + +page.svelte Clear & Reload buttons:
- Replaced inline SW/Cache/IDB/localStorage logic with core_func.clear_all_storage()
- Non-edit: skip_ls=true (SW+Cache+IDB only; sign-in preserved naturally)
- Edit mode: preserve_ls_keys=['ae_loc'] (full clear; sign-in survives the wipe)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-06-24 14:30:53 -04:00
parent db382b796c
commit 1b8f6efc39
4 changed files with 67 additions and 113 deletions

View File

@@ -66,8 +66,17 @@ export async function clear_idb(log?: BrowserResetLogFn): Promise<void> {
* @param log Optional progress callback. Receives each step message and a severity level.
* Use this to surface step-by-step feedback to the user (e.g. the fix-sw page).
* Omit for silent operation (e.g. the sys bar reset buttons).
* @param options Optional behavior overrides.
* - preserve_ls_keys: localStorage keys to save before clearing and restore after.
* Use ['ae_loc'] to keep the user signed in through the reset.
* - skip_ls: if true, skip clearing localStorage and sessionStorage entirely.
* Use this for "Clear & Reload" style resets that only need SW+Cache+IDB
* cleared (non-destructive to auth state — no ae_loc preservation needed).
*/
export async function clear_all_storage(log?: BrowserResetLogFn): Promise<void> {
export async function clear_all_storage(
log?: BrowserResetLogFn,
options?: { preserve_ls_keys?: string[]; skip_ls?: boolean }
): Promise<void> {
if (!browser) return;
log?.('Starting full storage reset...', 'info');
@@ -110,13 +119,27 @@ export async function clear_all_storage(log?: BrowserResetLogFn): Promise<void>
// 3. Clear all IndexedDB databases (handles enumeration + fallback internally)
await clear_idb(log);
// 4. Clear localStorage
if (options?.skip_ls) {
log?.('Skipping localStorage and sessionStorage (skip_ls=true).', 'info');
} else {
// 4. Clear localStorage (saving and restoring any keys that should survive the reset)
try {
const local_count = localStorage.length;
const preserved: Record<string, string> = {};
for (const key of options?.preserve_ls_keys ?? []) {
const val = localStorage.getItem(key);
if (val !== null) preserved[key] = val;
}
localStorage.clear();
log?.(`Cleared localStorage (${local_count} item(s)).`, 'ok');
} catch (err: any) {
log?.(`ERROR clearing localStorage: ${err.message}`, 'error');
for (const [key, val] of Object.entries(preserved)) {
localStorage.setItem(key, val);
}
const preserved_note = Object.keys(preserved).length
? ` (preserved: ${Object.keys(preserved).join(', ')})`
: '';
log?.(`Cleared localStorage (${local_count} item(s))${preserved_note}.`, 'ok');
} catch (err) {
log?.(`ERROR clearing localStorage: ${(err as Error).message}`, 'error');
}
// 5. Clear sessionStorage
@@ -124,7 +147,8 @@ export async function clear_all_storage(log?: BrowserResetLogFn): Promise<void>
const session_count = sessionStorage.length;
sessionStorage.clear();
log?.(`Cleared sessionStorage (${session_count} item(s)).`, 'ok');
} catch (err: any) {
log?.(`ERROR clearing sessionStorage: ${err.message}`, 'error');
} catch (err) {
log?.(`ERROR clearing sessionStorage: ${(err as Error).message}`, 'error');
}
}
}

View File

@@ -465,28 +465,12 @@ class:to-90%={$ae_sess.show_help_tech} -->
if (!confirm(confirm_msg)) return;
if ('serviceWorker' in navigator) {
const registrations = await navigator.serviceWorker.getRegistrations();
for (const reg of registrations) await reg.unregister();
}
const cache_keys = await caches.keys();
for (const key of cache_keys) await caches.delete(key);
// Enumerate and delete every IDB database on this origin.
const db_list = await indexedDB.databases();
console.log('[clear_reload] IDB databases found:', db_list.map((d) => d.name));
for (const db of db_list) {
if (db.name) indexedDB.deleteDatabase(db.name);
}
if (edit_mode) {
// Preserve ae_loc (sign-in credentials + permissions) across the wipe.
const ae_loc_saved = localStorage.getItem('ae_loc');
localStorage.clear();
sessionStorage.clear();
if (ae_loc_saved) localStorage.setItem('ae_loc', ae_loc_saved);
}
// Non-edit: skip_ls=true — SW+Cache+IDB only, localStorage untouched (sign-in preserved naturally).
// Edit mode: preserve_ls_keys=['ae_loc'] — full clear but sign-in survives the wipe.
await core_func.clear_all_storage(
undefined,
edit_mode ? { preserve_ls_keys: ['ae_loc'] } : { skip_ls: true }
);
window.location.reload();
}}
class="

View File

@@ -97,25 +97,12 @@ onMount(() => {
if (!confirm(confirm_msg)) return;
if ('serviceWorker' in navigator) {
const registrations = await navigator.serviceWorker.getRegistrations();
for (const reg of registrations) await reg.unregister();
}
const cache_keys = await caches.keys();
for (const key of cache_keys) await caches.delete(key);
const db_list = await indexedDB.databases();
for (const db of db_list) {
if (db.name) indexedDB.deleteDatabase(db.name);
}
if (edit_mode) {
const ae_loc_saved = localStorage.getItem('ae_loc');
localStorage.clear();
sessionStorage.clear();
if (ae_loc_saved) localStorage.setItem('ae_loc', ae_loc_saved);
}
// Non-edit: skip_ls=true — SW+Cache+IDB only, localStorage untouched (sign-in preserved naturally).
// Edit mode: preserve_ls_keys=['ae_loc'] — full clear but sign-in survives the wipe.
await core_func.clear_all_storage(
undefined,
edit_mode ? { preserve_ls_keys: ['ae_loc'] } : { skip_ls: true }
);
window.location.reload();
}}
class="btn btn-sm

View File

@@ -18,6 +18,7 @@ import {
// *** Import Aether specific variables and functions
import { ae_loc, ae_sess, ae_api, slct } from '$lib/stores/ae_stores';
import { core_func } from '$lib/ae_core/ae_core_functions';
import {
journals_loc,
journals_slct,
@@ -155,68 +156,26 @@ function scroll_container() {
<!-- <a href="/settings" class="btn btn-sm">Settings</a> -->
<button
type="button"
onclick={() => {
if ($ae_loc.edit_mode) {
// Confirm before clearing
if (
!confirm(
'Are you sure you want to clear IndexedDB databases, localStorage, and sessionStorage? This will also reload the page.'
)
) {
return;
}
onclick={async () => {
const edit_mode = $ae_loc.edit_mode;
const confirm_msg = edit_mode
? 'Clear all IDB caches, localStorage, and sessionStorage? Your sign-in will be preserved. This will reload the page.'
: 'Clear all IDB caches? This will reload the page.';
console.log(
'Clearing IndexedDB, localStorage, sessionStorage, and reloading the page...'
);
if (!confirm(confirm_msg)) return;
// Clear Indexed DB
indexedDB.deleteDatabase('ae_archives_db'); // Archives module
indexedDB.deleteDatabase('ae_core_db');
indexedDB.deleteDatabase('ae_events_db'); // Events module
indexedDB.deleteDatabase('ae_journals_db'); // Journals module
indexedDB.deleteDatabase('ae_posts_db'); // Posts module
indexedDB.deleteDatabase('ae_sponsorships_db'); // Sponsorships module
await core_func.clear_idb();
// Clear localStorage and sessionStorage
// Clearing the localStorage will force it to be re-created.
if (edit_mode) {
// Preserve ae_loc so the user stays signed in at their current level.
const ae_loc_saved = localStorage.getItem('ae_loc');
localStorage.clear();
sessionStorage.clear();
if (ae_loc_saved) localStorage.setItem('ae_loc', ae_loc_saved);
goto('/', { invalidateAll: true });
// window.location.reload(true);
} else {
// Confirm before clearing
if (
!confirm(
'Are you sure you want to clear IndexedDB databases and some caches? This will also reload the page.'
)
) {
return;
}
console.log(
'Clearing IndexedDB, localStorage, sessionStorage, and reloading the page...'
);
// Clear Indexed DB
indexedDB.deleteDatabase('ae_archives_db'); // Archives module
indexedDB.deleteDatabase('ae_core_db');
indexedDB.deleteDatabase('ae_events_db'); // Events module
indexedDB.deleteDatabase('ae_journals_db'); // Journals module
indexedDB.deleteDatabase('ae_posts_db'); // Posts module
indexedDB.deleteDatabase('ae_sponsorships_db'); // Sponsorships module
window.location.reload();
}
// This does not seem to work fast enough or something?
// goto('/', {invalidateAll: true});
// The page does usually seem to reload correctly?
// window.location.reload(true); // true only works with Firefox
// alert('Local and Session Storage cleared and Indexed DBs deleted. You will probably want to refresh the page.');
}}
class="btn btn-sm preset-tonal-surface border-surface-500 hover:preset-filled-warning-500 border"
title="Clear App Data & Settings: Clear IndexedDB and reload. If in edit mode localStorage and sessionStorage will also be cleared.">