ea99106677
* fix(sync): never toast third-party cloud-sync errors; log to console only The reader's per-book auto-sync surfaced an "Cloud sync authentication failed. Reconnect in Settings." toast on any AUTH_FAILED (e.g. an expired web Google Drive token), interrupting reading. Background sync failures shouldn't pop a toast — drop it and console.warn every sync error instead (the AUTH_FAILED branch only chose toast-vs-console, so it collapses to a plain log). Removes the now-unused authFailedToast + useTranslation/FileSyncError imports. Manual "Sync now" (FileSyncForm) still reports its result — it's a deliberate, foreground action. Native cloud sync (useBooksSync) is unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(sync): surface an expired cloud-sync session in the reader + Settings With sync-error toasts silenced, an expired third-party session (e.g. the short-lived web Google Drive token) had no UI indicator. Surface it without the old per-failure error toast: - Reader: a single top-right `hint` ("Google Drive session expired. Reconnect in Settings.") — the same affordance as the native "Reading Progress Synced" hint. De-duplicated via a per-instance ref so it shows once, not on every page-turn sync; reset on a successful sync / provider switch (web reconnect reloads anyway). - Settings → Google Drive: Disconnect swaps to Reconnect when the session is expired, and "Sync now" is disabled (FileSyncForm gains a `syncNowDisabled` prop) so a sync that would just fail isn't offered. No hint text in Settings. - webTokenStore.hasValidWebDriveToken() backs the web detection (the token lives in sessionStorage; native auto-refreshes so it doesn't apply there). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>