Skip to content

fix: self-heal stale auth token on translate instead of failing#33

Merged
navidshad merged 1 commit into
devfrom
fix/translate-auth-self-heal
Jun 8, 2026
Merged

fix: self-heal stale auth token on translate instead of failing#33
navidshad merged 1 commit into
devfrom
fix/translate-auth-self-heal

Conversation

@navidshad

@navidshad navidshad commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

🏷️ PR Title:
fix: self-heal stale auth token on translate instead of failing

📋 Summary

This PR introduces a fix that enables the system to automatically recover from a stale authentication token during translation requests rather than failing immediately. This improves the robustness and user experience of the translation feature.

🔗 Related Tasks

#6ef3766 - fix: self-heal stale auth token on translate instead of failing

📝 Additional Details

The change ensures that when an expired or invalid auth token is detected during a translate operation, the token is refreshed internally and the translation is retried, minimizing errors and interruptions.

📜 Commit List

6ef3766 fix: self-heal stale auth token on translate instead of failing

A purged/invalid token in chrome.storage.sync made every translation
fail with "User not found" (and other token-dependent calls 412) until a
full reload. Requests now detect auth-shaped failures, recover the
session, and retry once.

- isAuthError: detect token failures from the response body (the client
  discards the HTTP status). Patterns are grounded in the actual
  modular-rest server output, including the swallowed "Precondition
  Failed" body for invalid/expired/wrong-signature tokens.
- withAuthRetry: reusable wrapper that recovers + retries once on an auth
  error; wired into TranslateService's three function/run calls.
- recoverSession: tears a dead registered session down system-wide via
  logout() (profile/isLogin/analytics reset + broadcast) then re-auths
  anonymous; anonymous sessions just re-auth (contained).
- single-flight recovery: concurrent failures share ONE loginAnonymous
  instead of each minting and stranding an anonymous user.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copy link
Copy Markdown
Collaborator Author

Automated PR Review

Primary Task: fix: self-heal stale auth token on translate instead of failing
(No ClickUp task ID found — the link in the PR body resolves to the commit SHA, not a task record.)


Task alignment

Core fixwithAuthRetry wraps all three functionProvider.run calls in translate.service.ts (fetchSimpleTranslation, fetchDetailedTranslation, and translationAdvice). The retried result is still cached correctly.

Anonymous-login refactorloginWithLastSession is cleanly consolidated to call the shared reauthAnonymously() primitive, eliminating the duplicated inline anonymous-login chain. The finally callback is now correctly async, fixing a subtle case where the previous promise chain was fire-and-forget.

Registered-user downgrade pathrecoverSession in modular-rest.ts tears down a dead registered session via logout() before re-establishing anonymous, so no phantom logged-in UI lingers. The check authentication.user?.type?.toLowerCase() === "user" correctly skips the teardown for anonymous sessions.

Thundering-herd prevention — Two single-flight guards are in place: inflightReauth inside reauthAnonymously (prevents multiple /user/loginAnonymous calls) and inflightRecovery inside recoverOnce (coalesces concurrent withAuthRetry recoveries). The double-layering is harmless and correct.

Circular-import avoidancesetSessionRecovery / late binding is the right solution: auth-recovery.ts stays side-effect-free so importing it from translate.service doesn't drag the plugin's content-script init chain into the test graph.

translateByDictionaryapi not wrapped — correct; it calls dictionaryapi.dev (a public API), not the modular-rest backend, so it doesn't need auth recovery.


Commit messages

fix: self-heal stale auth token on translate instead of failing — well-formed conventional commit, fix: type is accurate (bug fix for a reported user-facing failure), message is descriptive enough to understand the change without reading the diff.


Prior review follow-up

(No prior reviews.)


Convention check

✅ New file src/common/helper/auth-recovery.ts is in the right location for a shared, bundle-agnostic utility.

✅ Comments follow the project convention: multi-line JSDoc explaining the why (auth-error detection rationale, the Koa/modular-rest body format, the single-flight guarantee, the late-binding motivation) — exactly what CLAUDE.md encourages.

vi.resetModules() is used in auth-anon-flow.test.ts where modular-rest.ts side effects (the setSessionRecovery call at module load) must re-run per test. auth-recovery.test.ts omits it intentionally since all operations are awaited and the .finally() guard resets in-flight state.

✅ No new bundle entries, no CSS/DOM, no manifest changes required.

One minor observation (no change needed): AUTH_ERROR_PATTERNS includes catch-all strings like "forbidden" and "jwt" marked as "defensive nets." These are well-documented as guards against intermediary proxies, not the backend itself. The conservative extractMessage depth-limit (3) prevents runaway recursion on exotic error shapes. The false-positive risk is low given the business errors documented as deliberately non-matching.


Verdict

APPROVE — The implementation is well-designed, thoroughly tested (25+ new unit/integration tests across 3 files), and follows all project conventions. The refactoring of the existing anonymous-login flow is a meaningful correctness improvement, not just scope creep.


Generated by Claude Code

@navidshad navidshad removed the review label Jun 8, 2026 — with Claude
@navidshad navidshad merged commit 98472c1 into dev Jun 8, 2026
3 checks passed
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 1.14.1-dev.2 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 1.14.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant