Offline retry queue for userscript writes #5

Merged
sulthan merged 8 commits from feat/offline-retry-queue into main 2026-07-27 17:52:17 +07:00
Showing only changes of commit 4b863d5d2e - Show all commits
+29
View File
@@ -440,6 +440,31 @@
saveQueue(queue); saveQueue(queue);
} }
let draining = false;
// Replays everything owed. Cheap in the normal case — it returns on the first
// line when the queue is empty, which is why it can hang off navigation. A
// 401 stops the whole pass: the token is wrong, so the next entry would fail
// the same way, and the queue is left intact so fixing the token fixes it.
async function drain() {
if (draining || queue.length === 0) return;
draining = true;
authFailed = false;
try {
for (const e of queue.slice()) {
if (e.op === "delete") await pushDelete(e.key);
else await pushBookmark(e.key, e.sendStatus);
if (authFailed) {
toast("Sync auth failed — check the token", true);
break;
}
}
} finally {
draining = false;
}
render();
}
// ============================================================ // ============================================================
// Mutations (optimistic: update UI/cache first, then sync) // Mutations (optimistic: update UI/cache first, then sync)
// ============================================================ // ============================================================
@@ -1018,6 +1043,9 @@
// Asura is client-routed, so full loads are rare — checking here too is // Asura is client-routed, so full loads are rare — checking here too is
// what keeps its bookmarks current. The throttle still caps the rate. // what keeps its bookmarks current. The throttle still caps the rate.
backgroundRefreshLatest(); backgroundRefreshLatest();
// Drain only, not a full refresh: Asura may go a long time without a
// reload, and an extra GET per client-side route change is not wanted.
drain();
} }
// Framework-agnostic URL-change watcher: patch history + poll as a fallback, // Framework-agnostic URL-change watcher: patch history + poll as a fallback,
@@ -1053,6 +1081,7 @@
state.page = detect(); state.page = detect();
render(); render();
installNavWatcher(); installNavWatcher();
window.addEventListener("online", drain); // signal returned while the page stayed open
// Sync first: both auto-record and the latest-chapter checks below need to // Sync first: both auto-record and the latest-chapter checks below need to
// know which series are bookmarked and how fresh they are. // know which series are bookmarked and how fresh they are.
refresh().then(() => { refresh().then(() => {