Skip to content

should prevent issues when loading website from cache#171

Merged
InfinityBowman merged 3 commits into
mainfrom
169-safari-unload-page-user-loses-access-to-projects-in-view
Dec 26, 2025
Merged

should prevent issues when loading website from cache#171
InfinityBowman merged 3 commits into
mainfrom
169-safari-unload-page-user-loses-access-to-projects-in-view

Conversation

@InfinityBowman
Copy link
Copy Markdown
Owner

@InfinityBowman InfinityBowman commented Dec 26, 2025

Summary by CodeRabbit

  • New Features

    • Added a manual session refresh API for callers.
    • Automatic session refresh on tab visibility change and bfcache restoration.
    • Added a project-list validation utility to ensure cache consistency.
  • Bug Fixes

    • Made session refresh and visibility handling asynchronous with improved error handling.
    • Prevented stale project data when switching users or restoring pages from bfcache.

✏️ Tip: You can customize this high-level summary in your review settings.

@InfinityBowman InfinityBowman linked an issue Dec 26, 2025 that may be closed by this pull request
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 26, 2025

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Async session refresh and project-cache validation were added for tab-visibility and bfcache restore events. A new bfcache handler initializes on startup; auth refresh logic became awaitable and a public forceRefreshSession() was exposed. Project list cache gained a validation utility.

Changes

Cohort / File(s) Summary
Session Management Enhancements
packages/web/src/api/better-auth-store.js
Made visibility-handler async: awaits session().refetch, waits 100ms, then validates or clears project list; added try/catch logging. Added internal forceRefreshSession() and exported it.
Back‑Forward Cache Restoration
packages/web/src/lib/bfcache-handler.js
New file: initBfcacheHandler() registers pageshow listener to detect bfcache restores, waits for auth loading (5s timeout), calls forceRefreshSession(), then validates/refreshes or clears project list; includes cleanup and safeguards.
App Startup Integration
packages/web/src/main.jsx
Imported and invoked initBfcacheHandler() during app initialization (after form-state cleanup); added explanatory comments.
Project Cache Validation Utility
packages/web/src/stores/projectStore.js
Added validateProjectListCache(currentUserId) to clear or reconcile cached project list and localStorage when user changes; exported as an action.

Sequence Diagrams

sequenceDiagram
    participant Browser as Browser (bfcache restore)
    participant Main as main.jsx (App Init)
    participant Handler as bfcacheHandler
    participant Auth as betterAuthStore
    participant Project as projectStore

    Note over Browser: Page restored from bfcache
    Browser->>Handler: pageshow (event, persisted=true)
    activate Handler
    Handler->>Auth: wait for auth loading (<=5s)
    activate Auth
    Auth-->>Handler: auth ready / timed out
    deactivate Auth
    Handler->>Auth: forceRefreshSession()
    activate Auth
    Auth->>Auth: session().refetch()
    Auth-->>Handler: session refreshed / error
    deactivate Auth
    Handler->>Project: validateProjectListCache(userId)
    activate Project
    alt user authenticated
        Project->>Project: refresh project list
    else unauthenticated
        Project->>Project: clear project list & localStorage
    end
    Project-->>Handler: complete
    deactivate Project
    Handler->>Handler: remove listener (cleanup)
    deactivate Handler
Loading
sequenceDiagram
    participant Tab as Browser Tab (visibility)
    participant Store as betterAuthStore
    participant Auth as session()
    participant Project as projectStore

    Note over Tab: Tab becomes visible
    Tab->>Store: visibilitychange (visible)
    activate Store
    Store->>Auth: await session().refetch()
    activate Auth
    Auth-->>Store: session data / error
    deactivate Auth
    Store->>Store: wait 100ms
    alt user authenticated
        Store->>Project: validateProjectListCache(userId)
        activate Project
        Project->>Project: refresh project list
        Project-->>Store: done
        deactivate Project
    else no user
        Store->>Project: clear project list
        activate Project
        Project-->>Store: cleared
        deactivate Project
    end
    deactivate Store
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

Poem

🐰 a quick nibble of code
Pages wake from bfcache, blinking bright,
I hop and refetch through the night.
Projects tidy, sessions true—
A rabbit's patch keeps states anew! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.56% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'should prevent issues when loading website from cache' accurately describes the main objective of the changes, which add bfcache restoration handling and session refresh mechanisms to prevent user access issues when pages are restored from the browser cache.

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bd87b2d and ebff60c.

📒 Files selected for processing (1)
  • packages/web/src/stores/projectStore.js

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Dec 26, 2025

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
⛔ Deployment terminated
View logs
corates ebff60c Commit Preview URL Dec 26 2025, 09:41 PM

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/web/src/lib/bfcache-handler.js (3)

21-76: Code duplication with visibility change handler.

This handler logic (lines 51-76) is nearly identical to handleVisibilityChange in better-auth-store.js (lines 198-226). Both:

  1. Force refresh the auth session
  2. Wait 100ms
  3. Call validateProjectListCache then refreshProjectList if authenticated
  4. Call clearProjectList if not authenticated

Consider extracting shared logic into a reusable helper to reduce duplication and ensure consistent behavior.

Proposed helper extraction
// In a shared utility, e.g., @lib/auth-refresh-utils.js
export async function refreshAuthAndProjectState(auth, projectStore) {
  try {
    await auth.forceRefreshSession();
  } catch (err) {
    console.warn('[auth] Failed to refresh session:', err);
  }

  await new Promise(resolve => setTimeout(resolve, 100));

  const currentUser = auth.user();
  if (currentUser?.id) {
    projectStore.validateProjectListCache(currentUser.id);
    try {
      await projectStore.refreshProjectList(currentUser.id);
    } catch (err) {
      console.warn('[auth] Failed to refresh project list:', err);
    }
  } else {
    projectStore.clearProjectList();
  }
}

58-59: Magic delay without clear justification.

The 100ms delay after forceRefreshSession lacks documentation explaining why it's needed. If the session signal updates synchronously after refetch() resolves, this delay may be unnecessary. If it's required for a specific reason (e.g., reactive propagation), consider adding a brief comment.


64-72: Potentially redundant cache validation before refresh.

validateProjectListCache clears the cache if user IDs don't match, but refreshProjectList immediately fetches fresh data and overwrites the cache anyway. The validation may still be useful to prevent a brief flash of stale data before the refresh completes, but consider whether calling both is necessary or if refreshProjectList could handle the user ID mismatch internally.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9fb7063 and bd87b2d.

📒 Files selected for processing (4)
  • packages/web/src/api/better-auth-store.js
  • packages/web/src/lib/bfcache-handler.js
  • packages/web/src/main.jsx
  • packages/web/src/stores/projectStore.js
🧰 Additional context used
📓 Path-based instructions (14)
**/*

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not use emojis in code, comments, documentation, or commit messages

NEVER use emojis anywhere in code, comments, documentation, plan files, or commit messages. This includes unicode symbols. For UI icons, use solid-icons library or SVGs only.

Files:

  • packages/web/src/lib/bfcache-handler.js
  • packages/web/src/main.jsx
  • packages/web/src/api/better-auth-store.js
  • packages/web/src/stores/projectStore.js
packages/web/src/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

packages/web/src/**/*.{js,jsx,ts,tsx}: For UI icons, use the solid-icons library or SVGs only. Do not use emojis
Ensure browser compatibility for all frontend code (Safari is usually problematic)
Keep files small, focused, and modular. If a file exceeds a high number of lines, consider refactoring by extracting sub-modules into a folder with index.jsx and helper components, moving complex logic into separate utility files or primitives, or splitting large forms into section components
Do NOT prop-drill application state. Shared or cross-feature state must live in external stores under packages/web/src/stores/ or relative to the component file
Use createMemo for derived values to ensure they update reactively

Use import aliases from jsconfig.json instead of relative paths

Files:

  • packages/web/src/lib/bfcache-handler.js
  • packages/web/src/main.jsx
  • packages/web/src/api/better-auth-store.js
  • packages/web/src/stores/projectStore.js
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,jsx,ts,tsx}: Prefer modern ES6+ syntax and features
Use aliases for imports when appropriate to improve readability

**/*.{js,jsx,ts,tsx}: Prefer modern ES6+ syntax and features in JavaScript/TypeScript code
Comments should explain why something is being done, not narrate what the code does. Avoid comments that repeat variable names or describe obvious code behavior.

Files:

  • packages/web/src/lib/bfcache-handler.js
  • packages/web/src/main.jsx
  • packages/web/src/api/better-auth-store.js
  • packages/web/src/stores/projectStore.js
packages/web/src/**/*.{jsx,tsx,js,ts}

📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)

In SolidJS, use createMemo for derived values

Files:

  • packages/web/src/lib/bfcache-handler.js
  • packages/web/src/main.jsx
  • packages/web/src/api/better-auth-store.js
  • packages/web/src/stores/projectStore.js
packages/web/src/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

packages/web/src/**/*.{js,ts,jsx,tsx}: Always use handleFetchError from @/lib/error-utils.js for fetch calls in frontend code with options like { showToast: true } for error handling
Use createFormErrorSignals from @/lib/form-errors.js for form validation error handling with field-level and global error management

Files:

  • packages/web/src/lib/bfcache-handler.js
  • packages/web/src/main.jsx
  • packages/web/src/api/better-auth-store.js
  • packages/web/src/stores/projectStore.js
packages/{web,workers}/src/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

packages/{web,workers}/src/**/*.{js,ts,jsx,tsx}: Never throw string literals; always throw Error objects or return domain errors from API routes
Use error utility functions like isErrorCode from @corates/shared or @/lib/error-utils.js to check specific error types instead of manual string comparisons

Files:

  • packages/web/src/lib/bfcache-handler.js
  • packages/web/src/main.jsx
  • packages/web/src/api/better-auth-store.js
  • packages/web/src/stores/projectStore.js
{packages/web/**,packages/landing/**}/**/*.{jsx,tsx,js,ts}

📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)

{packages/web/**,packages/landing/**}/**/*.{jsx,tsx,js,ts}: Never destructure props in SolidJS components - destructuring breaks reactivity. Access props directly (e.g., props.name) or wrap in a function (e.g., const name = () => props.name) to maintain reactivity.
Import stores directly in components rather than prop-drilling store data through component hierarchies.
Use separate read and write patterns for stores: import the store directly for reading data (e.g., projectStore.getProjectList()) and import action stores separately for writing (e.g., projectActionsStore.createProject()).
Use createSignal from solid-js for managing simple reactive values. Prefer derived state with signals or memo over effects when possible.
Use createStore from solid-js/store for managing complex objects and arrays that require granular reactivity, enabling fine-grained updates where only affected parts re-render.
Use createMemo from solid-js for derived values that depend on reactive state, ensuring computed values update only when their dependencies change.
Always clean up effects that create subscriptions or timers using the onCleanup function from solid-js. Use effects sparingly, only when derived values won't work well.
Keep components lean and focused on rendering. Move business logic to stores (for shared state and operations), primitives (for reusable hooks/logic), or utilities (for pure functions).
Use the Show component from solid-js for conditional rendering instead of JavaScript ternary operators or logical AND operators.
Use the For component from solid-js for rendering lists. It provides better performance and keying compared to JavaScript's map function in JSX.
When manipulating children in wrapper components, use the children helper from solid-js to ensure proper reactivity and handling of child elements.

Files:

  • packages/web/src/lib/bfcache-handler.js
  • packages/web/src/main.jsx
  • packages/web/src/api/better-auth-store.js
  • packages/web/src/stores/projectStore.js
packages/{web,ui}/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

packages/{web,ui}/**/*.{js,jsx,ts,tsx}: Import UI components from '@corates/ui' package instead of local component files. Do not import Ark UI components from local paths like '@/components/zag/' or 'packages/web/src/components/zag/'
Always use 'solid-icons' library for icons. Never use emoji characters or text as icon replacements. Import from specific icon sets like 'solid-icons/bi', 'solid-icons/fi', 'solid-icons/ai', etc.

Files:

  • packages/web/src/lib/bfcache-handler.js
  • packages/web/src/main.jsx
  • packages/web/src/api/better-auth-store.js
  • packages/web/src/stores/projectStore.js
packages/web/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

Use import aliases from 'packages/web/jsconfig.json' instead of relative paths. Aliases include: '@/' (src/), '@components/' (src/components/), '@auth-ui/' (src/components/auth-ui/), '@checklist-ui/' (src/components/checklist-ui/), '@project-ui/' (src/components/project-ui/), '@routes/' (src/routes/), '@primitives/' (src/primitives/), '@api/' (src/api/), '@config/' (src/config/), and '@lib/' (src/lib/)

Files:

  • packages/web/src/lib/bfcache-handler.js
  • packages/web/src/main.jsx
  • packages/web/src/api/better-auth-store.js
  • packages/web/src/stores/projectStore.js
packages/{web,ui}/src/**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)

Group related components in subdirectories with barrel exports

Files:

  • packages/web/src/main.jsx
packages/{web,landing}/src/**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)

packages/{web,landing}/src/**/*.{jsx,tsx}: Use Ark UI components from @corates/ui package, not local component implementations
Use solid-icons library (e.g., solid-icons/bi, solid-icons/fi) for icon imports

Files:

  • packages/web/src/main.jsx
packages/web/src/**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)

packages/web/src/**/*.{jsx,tsx}: In SolidJS, do NOT prop-drill application state. Import stores directly where needed instead.
In SolidJS, do NOT destructure props. Access props.field directly or wrap in a function: () => props.field
In SolidJS components, components should receive at most 1-5 props (local config only, not shared state)

Files:

  • packages/web/src/main.jsx
packages/{web,ui}/**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

Use Tailwind CSS classes for styling components

Files:

  • packages/web/src/main.jsx
packages/web/src/stores/**/*.{js,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use Solid's createStore for complex state or state objects for better performance and reactivity

packages/web/src/stores/**/*.{js,ts}: In SolidJS, shared state should live in external stores under packages/web/src/stores/
In SolidJS, use createStore for complex state objects

Files:

  • packages/web/src/stores/projectStore.js
🧠 Learnings (2)
📚 Learning: 2025-12-24T17:23:10.082Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-24T17:23:10.082Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx,js,ts} : Import stores directly in components rather than prop-drilling store data through component hierarchies.

Applied to files:

  • packages/web/src/main.jsx
📚 Learning: 2025-12-19T14:49:49.730Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-19T14:49:49.730Z
Learning: Applies to packages/workers/src/**/*.{js,ts} : Use Better-Auth for authentication and user management

Applied to files:

  • packages/web/src/api/better-auth-store.js
🧬 Code graph analysis (2)
packages/web/src/main.jsx (2)
packages/web/src/lib/formStatePersistence.js (1)
  • cleanupExpiredStates (232-272)
packages/web/src/lib/bfcache-handler.js (1)
  • initBfcacheHandler (15-85)
packages/web/src/stores/projectStore.js (1)
packages/web/src/components/sidebar/Sidebar.jsx (1)
  • currentUserId (23-23)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Workers Builds: corates
🔇 Additional comments (3)
packages/web/src/main.jsx (1)

13-16: LGTM!

The bfcache handler initialization is correctly placed after form state cleanup, and the comment clearly explains the purpose. Since this is a singleton handler that should persist for the app's lifetime, not capturing the cleanup function is acceptable.

packages/web/src/api/better-auth-store.js (2)

679-691: LGTM - forceRefreshSession is well-designed.

Clean implementation that wraps the session refetch and properly re-throws errors so callers can handle failures. The warning log before re-throwing aids debugging without swallowing the error.


198-226: Visibility change handler improvements look good.

The async handling with proper error catching for both session refresh and project list refresh is well-structured. The guards (!authLoading() && isOnline()) prevent unnecessary work. The duplication with bfcache-handler.js was noted in that file's review.

Comment thread packages/web/src/stores/projectStore.js
@InfinityBowman InfinityBowman merged commit 9987be2 into main Dec 26, 2025
1 of 3 checks passed
@InfinityBowman InfinityBowman deleted the 169-safari-unload-page-user-loses-access-to-projects-in-view branch December 26, 2025 21:20
@github-actions github-actions Bot restored the 169-safari-unload-page-user-loses-access-to-projects-in-view branch December 26, 2025 21:20
@InfinityBowman InfinityBowman deleted the 169-safari-unload-page-user-loses-access-to-projects-in-view branch December 29, 2025 18:25
@coderabbitai coderabbitai Bot mentioned this pull request Dec 29, 2025
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.

Safari unload page, user loses access to projects in view.

2 participants