- Ship one hashed Tailwind stylesheet instead of two (one render-blocking)
- Compress responses in-app (brotli/gzip, streaming-safe) and precompress
the node build so local and CI measurements match production
- Validate the Supabase session once per request
- Render the homepage immediately and stream public stats
- Stream a Pokedex's entries with the page instead of fetching after
hydration, running the rows and count queries in parallel
- Shrink the avatar and offline placeholder images, fix layout shift,
contrast, link names and missing meta descriptions
- Add Lighthouse CI (mobile + desktop) with score and metric budgets,
bundle-size budgets in the build tests, and signed-in speed scenarios
Google answers a revoked or expired refresh token with invalid_grant.
Every save then retried the dead token, and reconnecting never cleared
the old error, so it kept showing on Backup Settings afterwards.
- The Google Drive and Dropbox OAuth callbacks clear lastError when a
provider is reconnected.
- An invalid_grant, or a missing refresh token, now pauses the
integration with a readable "reconnect" message instead of retrying
it on every catch update. Other failures still retry as before.
- A banner on every page and an alert on the Pokédex page point to
Backup Settings, which shows a "Reconnect needed" badge. The Pokédex
page re-checks backup status after each export, because saving a
catch record also exports on the server and may pause a provider
first.
- Offline sync status and the "Save all artwork" link move from every
page to a new /offline-guide page, linked from the user menu and the
home and welcome pages. Only the offline read-only banner stays
sitewide.
- Unit tests cover every export path and the backup status store. BDD
covers revocation and reconnecting for both providers, and the
offline guide. The mock provider can now reject token refreshes, and
mock control calls fail loudly if a stale mock is reused. Coverage
thresholds are raised to the new baseline.
`npm run check` reported 15 errors and `npm run lint` 20, all pre-existing, so
neither gate could pass. Fixing them turned up three real bugs:
- SignOut destructured `{ error }` off `.then(() => {})`, which resolves to
undefined, so every sign-out threw a TypeError - after the signed-out event had
already been emitted. Sign-out also left the user on the protected page they
were on, still showing its content; it now returns them to the home page and
re-runs the server loads.
- SignUp passed `redirectTo`, which is not a signUp option and was silently
ignored, so the confirmation link has always used Supabase's configured site
URL. Documented rather than changed, since pointing it elsewhere needs an
absolute allow-listed URL.
- The Pokédex page tracked totalRecordsCreated but never passed it to the box
view, so the "Processed N entries so far" progress message never rendered.
The rest is typing and dead code: cookie callback parameters in hooks.server.ts
and +layout.ts, the untyped supabase props, a query-builder type that made
PostgREST rows untyped downstream, an unused session destructure, and
`while (true)` paging loops rewritten as `for (;;)`.
It turns out that tailwind excludes styles it hasn't found in use, so it needs to be explicitly told where to find the component files. This also therefore fixes the styles in the SignUp component.