Repository navigation
Conversation
fehmer
force-pushed
the
clear-user-collections-signout
branch
3 times, most recently
from
November 12, 2026 21:04
a49ff94 to
7e17585
Compare
queryClient.resetQueries on sign out never cleared the queryCollectionOptions collections: their rows live in the collection's normalized state, which resetting/removing the query never touches (the sync only applies successful fetches), so the previous user's themes/presets/tags/etc. stayed visible to the next user.
Each user collection now registers { clear, refetch } in a new leaf registry (queries/user-scoped.ts):
- clear (sign out): sweep all rows in a transaction (the collections have no onDelete handler), then empty the backing query with setQueryData([]), which the sync applies, dropping query ownership and the cache copy.
- refetch (sign in): collection.utils.refetch(), replacing the per-module createRoot sign-in effects with one central effect in queries/index.ts (resetQueries stays for plain user queries like friendsList, which gains enabled: isAuthenticated to avoid refetching into a 401 after sign out).
Verified in the browser: fresh load downloads and shows the themes, sign out empties the collection (status stays ready), sign in re-downloads. No duplicate fetches; no circular imports; full suite, typecheck and build green.
fehmer
force-pushed
the
clear-user-collections-signout
branch
from
November 12, 2026 21:36
7e17585 to
fbea5fe
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TL;DR
Signing out reset the
["user", …]queries but never cleared thequeryCollectionOptionscollections, so the next signed-in user kept the previous user's rows in every user-bound collection (custom themes, presets, tags, results, inbox, connections, ape keys, result filter presets) until their own download happened to replace them.QueryClient.resetQueries/removeQueriescannot clear a collection: the collection keeps its rows in its own normalized state, and the query↔collection sync only applies successful fetch results — resetting or removing the query never touches the rows (reproduced in the regression spec below).What this does
collections/utils/session-collection.tswith the session collections registry and the sign in / sign out cleanup. It only imports libraries (queryClientis passed to the clear as a parameter, so it never imports the app'squeriesmodule — no import cycle), and:clearSessionCollectionssweeps every row of each registered collection — the keys come from the collection's owngetKeyFromItem, deletes run inside a no-op transaction (the collections have noonDeletehandler, and locally written rows the query does not own would survive the sync anyway) — then empties the backing query withsetQueryData(rootKey, []), which the sync applies, dropping the query's ownership and the cache copy;refetchSessionCollectionscallscollection.utils.refetch()for each registered collection. Collections keepenabled: isAuthenticated, so the refetch is a no-op for collections whose query never started;startSync'd collections need it because their query is created at module load, before the auth state resolves, and never re-evaluatesenabledon its own. A refetch never double-downloads: it joins the in-flight initial download.queries/index.tsdrives the registry: on sign out it runsresetQueries({ queryKey: ["user"] })(for the plain user queries, as before) first, then the collection clears, so the clears'setQueryData([])wins as each query's final state.friendsListgetsenabled: isAuthenticated— the friends page is auth-gated, so the sign-out reset must not refetch it into a 401.{ collection, queryKey }; no cleanup logic lives in the collection modules.Repro before the fix
customThemescollection.Testing
frontend/__tests__/collections/utils/session-collection.spec.tscovers the registry in isolation with a collection created in the test (none of the app's modules): the download lands,clearSessionCollectionsempties the collection and the query without calling the collection'sonDeletehandler (the ambient transaction bypasses it — the guarantee that clearing never syncs deletes to the backend), andrefetchSessionCollectionsrestarts the download.oxlint --type-aware --type-checkclean;madgereports no circular dependencies; production build passes.readywith zero rows, and the network log shows no user-endpoint writes or 401s; sign in again → themes re-download and render.