Skip to content

Fix frontend settings persistence for API client - #30

Draft
cursor[bot] wants to merge 1 commit into
mainfrom
cursor/critical-bug-investigation-cfe6
Draft

Fix frontend settings persistence for API client#30
cursor[bot] wants to merge 1 commit into
mainfrom
cursor/critical-bug-investigation-cfe6

Conversation

@cursor

@cursor cursor Bot commented Jun 1, 2026

Copy link
Copy Markdown

Summary

  • Restore a shared frontend settings storage contract for backend base URLs.
  • Store auth tokens in session storage and have the API interceptor read from the same location.
  • Exclude Playwright E2E specs from Jest so frontend unit tests run through the intended runner.

Validation

  • pnpm --filter @agentnexus/frontend test -- settings-storage.test.js --runInBand
  • pnpm --filter @agentnexus/frontend test -- --runInBand
  • pnpm --filter @agentnexus/frontend type-check
  • pnpm --filter @agentnexus/frontend exec eslint src/lib/settings-storage.ts src/lib/settings-storage.test.js --no-eslintrc --parser @typescript-eslint/parser --plugin @typescript-eslint --env browser --env jest --rule no-unused-vars:off --rule @typescript-eslint/no-unused-vars:warn

Known pre-existing gate failures

  • pnpm --filter @agentnexus/frontend lint fails because next lint is not a valid Next 16 command in this setup.
  • pnpm --filter @agentnexus/frontend build fails on an existing wagmi/viem export mismatch (sendCallsSync / sendTransactionSync).
Open in Web View Automation 

Greptile Summary

This PR introduces a shared settings-storage module that unifies three previously inconsistent localStorage keys for the backend URL into one canonical key with a migration fallback list, moves auth tokens from localStorage to sessionStorage, and wires both the settings page and modal to use the new helpers.

  • persistBackendBaseUrl destructive empty-save: clearing the URL field and saving removes all legacy keys while writing '', permanently discarding the user's server URL — unlike persistSessionAuthToken which guards against empty values.
  • Auth token migration gap: getBackendBaseUrl handles three legacy keys gracefully, but getSessionAuthToken has no localStorage fallback or cleanup for the previously-used auth_token key.
  • No token-delete path: the empty-string no-op in persistSessionAuthToken means there is no UI action to remove a stored session token short of closing the tab.

Confidence Score: 3/5

The core key-unification logic is sound, but persistBackendBaseUrl has a destructive edge case when the URL field is saved empty: it removes all legacy keys while writing an empty string, permanently discarding the user's configured server URL.

The empty-URL path in persistBackendBaseUrl removes every legacy key and stores '' in their place — any user who clears the field and saves loses their server address irrecoverably. The auth token migration gap is a secondary concern that could silently drop authentication for users with a token stored by an earlier code path.

frontend/src/lib/settings-storage.ts — the empty-URL branch of persistBackendBaseUrl and the absence of a localStorage fallback/cleanup in getSessionAuthToken both need attention before merging.

Important Files Changed

Filename Overview
frontend/src/lib/settings-storage.ts New module centralising settings I/O. persistBackendBaseUrl('') stores an empty string and removes all legacy keys — diverges from the symmetrical guard in persistSessionAuthToken. Auth token migration path from localStorage is also missing.
frontend/src/lib/settings-storage.test.js Comprehensive unit tests covering canonical key, legacy fallback, migration clean-up, sessionStorage for tokens, and blank-token no-op; all cases match documented intent.
frontend/src/lib/api.ts Delegates base-URL and auth-token resolution to the new settings-storage module; SSR safety preserved via null-returning browser storage helpers. No logic issues.
frontend/src/components/layout/SettingsModal.tsx Migrates inline localStorage calls to settings-storage functions; placeholder changed from 8200 to 3001, consistent with other callers. No issues.
frontend/src/app/settings/page.tsx Replaces two ad-hoc localStorage helpers with the shared module; now shows the effective URL including env-var default on mount. No issues.
frontend/jest.config.js Adds testPathIgnorePatterns to exclude e2e/ so Playwright specs are not picked up by Jest.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[SettingsModal / SettingsPage handleSave] -->|url| B[persistBackendBaseUrl]
    A -->|token| C[persistSessionAuthToken]
    B --> D{url empty?}
    D -- No --> E[localStorage: set backend_base_url, remove legacy keys]
    D -- Yes --> F[localStorage: set backend_base_url=empty, remove legacy keys - URL lost]
    C --> G{token empty?}
    G -- No --> H[sessionStorage: set auth_token]
    G -- Yes --> I[no-op - existing token kept, no delete path]
    J[api.ts interceptors] -->|getBackendBaseUrl| K[localStorage: backend_base_url, api_url, agentnexus_backend_url, env var fallback]
    J -->|getSessionAuthToken| L[sessionStorage: auth_token - no localStorage fallback]
Loading

Fix All in Codex Fix All in Cursor

Reviews (1): Last reviewed commit: "fix: keep frontend settings aligned with..." | Re-trigger Greptile

Greptile also left 3 inline comments on this PR.

Co-authored-by: up2itnow0822 <up2itnow0822@gmail.com>
Comment on lines +28 to +32
const normalizedUrl = url.trim();
storage.setItem(BACKEND_BASE_URL_KEY, normalizedUrl);
for (const legacyKey of LEGACY_BACKEND_BASE_URL_KEYS) {
storage.removeItem(legacyKey);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 persistBackendBaseUrl stores an empty string in backend_base_url when the user clears the URL field and saves. Combined with the removal of all legacy keys, a user who accidentally saves an empty value will have their previous server URL permanently erased. persistSessionAuthToken correctly guards against empty values with an early return — the same pattern should apply here.

Suggested change
const normalizedUrl = url.trim();
storage.setItem(BACKEND_BASE_URL_KEY, normalizedUrl);
for (const legacyKey of LEGACY_BACKEND_BASE_URL_KEYS) {
storage.removeItem(legacyKey);
}
const normalizedUrl = url.trim();
if (!normalizedUrl) {
storage.removeItem(BACKEND_BASE_URL_KEY);
return;
}
storage.setItem(BACKEND_BASE_URL_KEY, normalizedUrl);
for (const legacyKey of LEGACY_BACKEND_BASE_URL_KEYS) {
storage.removeItem(legacyKey);
}

Fix in Codex Fix in Cursor

Comment on lines +40 to +45
export function persistSessionAuthToken(token: string): void {
const normalizedToken = token.trim();
if (!normalizedToken) return;

browserSessionStorage()?.setItem(AUTH_TOKEN_KEY, normalizedToken);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 No mechanism to clear a stored session token

persistSessionAuthToken('') is a no-op (intentionally), but once a token is saved there is no UI path to delete it. If a user's API key is rotated or revoked, requests will keep sending a stale Authorization header until the tab is closed. Consider adding a clearSessionAuthToken() helper and a "clear" action in the UI.

Fix in Codex Fix in Cursor

Comment on lines +1 to +3
const BACKEND_BASE_URL_KEY = 'backend_base_url';
const LEGACY_BACKEND_BASE_URL_KEYS = ['api_url', 'agentnexus_backend_url'];
const AUTH_TOKEN_KEY = 'auth_token';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Stale auth_token entry not cleaned up from localStorage

getBackendBaseUrl has an explicit LEGACY_BACKEND_BASE_URL_KEYS list for migration. Auth tokens have no analogous cleanup: the old api.ts read localStorage.getItem('auth_token'), and AUTH_TOKEN_KEY reuses the same string but now targets sessionStorage. Any pre-existing auth_token in localStorage is silently abandoned — never read, never deleted.

Fix in Codex Fix in Cursor

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate draft — recommend close

This PR overlaps with #35 (most complete), #34, #33, #32, and #31. All six drafts target the same frontend settings/API-client persistence bug.

#35 includes apiConfig.ts, session-scoped auth tokens, legacy key migration, and unit tests (4/4 passing).

Action

Close this PR in favor of #35 after it is marked ready and merged.

Open in Web View Automation 

Sent by Cursor Automation: Untitled

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant