2 Commits

Author SHA1 Message Date
isra el
c1942a4ba3 fix: repair two cache invalidations that silently matched nothing
Both bugs were hand-written query keys. lib/api/query-keys.ts exists to
prevent exactly this and neither site used it.

1. /auth/who-am-i was cached under two keys. Four call sites used
   ['whoAmI'] and seven used ['currentUser'], including the typed
   useCurrentUser hook. So the endpoint was fetched twice on any page
   using both, and invalidating one never invalidated the other:
   edit-profile-form refreshed ['currentUser'] and left the email
   verification banner reading stale data under ['whoAmI'], while
   use-onboarding had the mirror-image bug.

   verify-email/page.tsx additionally cached the whole axios response
   where the others cached the unwrapped user, so unifying the key meant
   normalising that shape too. One key demands one shape.

2. generate-api-key invalidated ['apiKeys', 'stats'], which no query
   uses. react-query matches by prefix, so it matched neither the key
   list (['apiKeys', status]) nor the dashboard stats (['stats']).
   Generating an API key refreshed nothing at all. It is now three
   invalidations against queryKeys, using a new apiKeysAll prefix so
   every status filter refreshes rather than just 'active'.

Also added accountDeletionRequestedAt to the User type. It is a real
field on the user schema and the deletion banner already reads it; only
the type did not know about it.

Both bugs are invisible on inspection, which is how they shipped, so the
regression tests were each confirmed to fail against the pre-change code
before being trusted.

Verified: build clean, 0 lint errors (21 warnings, unchanged), 155 unit
tests (from 153), 78 e2e.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 04:02:30 +03:00
isra el
497a14074a refactor: centralize data fetching into typed react-query hooks
Introduce a typed data layer under lib/api (query-key factory, response
types, feature hooks) plus shared lib/format and lib/status helpers, and
migrate the canonical dashboard consumers (subscription-info, overview,
device-list, api-keys) onto it, deleting their duplicated inline queries,
mutations and formatters.

List hooks keep the raw { data: [] } envelope in the cache and unwrap
per-observer with react-query `select`, so shared keys like ['devices']
stay compatible with the not-yet-migrated components that still read the
raw shape (avoids a cache-shape collision surfaced by the dashboard e2e).

Adds unit tests for the formatters and the hooks (against MSW). Build,
19 unit tests, and 2 e2e all green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 01:36:16 +03:00