feat: precache resilience — circuit breaker, forensic diag log, safe version check
- Circuit breaker: abort preload after 5 consecutive network failures (success or 404 resets streak) instead of grinding doomed retries - localStorage diag ring buffer (survives cache wipes): preload-start/ done/abort, manifest-unavailable, version events; shown in Settings - checkDataVersion: no longer wipes IDB on transient read errors (DataCache.has tri-state probe); logs old value on real migrations - loadManifest: null result no longer cached forever (per-session fallback lock-in)
This commit is contained in:
1 parent
ee5fb17c6b
commit
8c4f60d635
6 files changed
+140
-7
No files matched your search
+17
-4
@@ -5,6 +5,7 @@
|
||||
import { getTranslations, type LanguageCode } from '../core/i18n';
|
||||
import { OfflineManager } from '../core/offline-manager';
|
||||
import { DataCache } from '../core/data-cache';
|
||||
import { diagTail } from '../core/diag-log';
|
||||
|
||||
const LANGUAGES = [
|
||||
{ code: 'en', name: 'English', local: 'English' },
|
||||
@@ -303,6 +304,7 @@ export class SettingsView {
|
||||
</div>
|
||||
<p id="offline-progress-text" class="text-xs text-navy-light">0 / 0 ${t.settings.offlineDataTypes}</p>
|
||||
</div>
|
||||
<pre id="diag-log" class="text-[10px] font-mono text-navy-light whitespace-pre-wrap max-h-32 overflow-auto mt-1"></pre>
|
||||
</div>
|
||||
|
||||
<!-- About -->
|
||||
@@ -552,13 +554,17 @@ export class SettingsView {
|
||||
}).then((prog) => {
|
||||
if (progressBar) progressBar.style.width = '100%';
|
||||
if (progressText) {
|
||||
if (prog.failed > 0) {
|
||||
if (prog.aborted) {
|
||||
progressText.textContent = t.settings.offlineAborted;
|
||||
} else if (prog.failed > 0) {
|
||||
const failList = prog.failedFiles?.length ? `: ${prog.failedFiles.join(', ')}` : '';
|
||||
progressText.textContent = `${t.settings.offlineDone} ${prog.failed} ${t.settings.offlineFailed}${failList}`;
|
||||
} else {
|
||||
progressText.textContent = t.settings.offlineDone;
|
||||
}
|
||||
}
|
||||
const diagEl = document.getElementById('diag-log');
|
||||
if (diagEl) diagEl.textContent = diagTail();
|
||||
OfflineManager.getStats().then(stats => {
|
||||
const statsEl = document.getElementById('offline-stats');
|
||||
if (statsEl) {
|
||||
@@ -601,6 +607,9 @@ export class SettingsView {
|
||||
}
|
||||
});
|
||||
|
||||
const diagEl = document.getElementById('diag-log');
|
||||
if (diagEl) diagEl.textContent = diagTail();
|
||||
|
||||
// Check cache status for each data type and set checkbox states
|
||||
(async () => {
|
||||
const checkCache = async (key: string): Promise<boolean> => {
|
||||
@@ -678,10 +687,14 @@ export class SettingsView {
|
||||
if (progressBar) progressBar.style.width = '100%';
|
||||
if (progressText) {
|
||||
const failList = prog.failedFiles?.length ? `: ${prog.failedFiles.join(', ')}` : '';
|
||||
progressText.textContent = prog.failed > 0
|
||||
? `${t.settings.offlineDone} ${prog.failed} ${t.settings.offlineFailed}${failList}`
|
||||
: t.settings.offlineDone;
|
||||
progressText.textContent = prog.aborted
|
||||
? t.settings.offlineAborted
|
||||
: prog.failed > 0
|
||||
? `${t.settings.offlineDone} ${prog.failed} ${t.settings.offlineFailed}${failList}`
|
||||
: t.settings.offlineDone;
|
||||
}
|
||||
const diagEl = document.getElementById('diag-log');
|
||||
if (diagEl) diagEl.textContent = diagTail();
|
||||
OfflineManager.getStats().then(stats => {
|
||||
const statsEl = document.getElementById('offline-stats');
|
||||
if (statsEl) {
|
||||
|
||||
Reference in new issue
Block a user