Skip to content

Hardening: fetch races, i18n locale authority, server-side lang, lint#9

Merged
GeiserX merged 7 commits intomainfrom
fix/hardening-patch
Mar 31, 2026
Merged

Hardening: fetch races, i18n locale authority, server-side lang, lint#9
GeiserX merged 7 commits intomainfrom
fix/hardening-patch

Conversation

@GeiserX
Copy link
Copy Markdown
Owner

@GeiserX GeiserX commented Mar 31, 2026

Summary

Multi-round hardening pass covering fetch race conditions, i18n consistency, and tooling.

Fetch safety (map-view)

  • Split shared abortRef into independent bboxAbortRef / corridorAbortRef — bbox and corridor fetches can no longer cancel each other
  • Clear bbox debounce timer on route activation; guard fetchStations() against route mode
  • Abort in-flight corridor fetch when route is cleared (prevents stale station leak)
  • Fix double corridor-fetch on route activation — debounce effect now only triggers on corridorKm changes
  • Abort stale route requests in handleClearRoute

Route-stations endpoint

  • Cap coordinates at 2000, results at 500
  • Replace start-biased LIMIT 500 with CTE + ROW_NUMBER uniform spatial sampling
  • Compute bbox from full-resolution coords before polyline downsampling

i18n / locale

  • URL locale is authoritative: setLocale() writes cookie + navigates to /{locale}
  • Middleware reads cookie before Accept-Language (user choice persists)
  • Middleware sets x-pumperly-locale request header → root layout renders <html lang> server-side
  • All locales (including default es) use /locale prefix in canonical URLs and hreflang
  • Logo always links to /{locale} (no bounce-back for fresh visitors)
  • Privacy policy documents the pumperly-locale cookie

Lint / tooling

  • ESLint restored: pin to v9 (v10 incompatible with eslint-plugin-import), drop FlatCompat, use eslint-config-next flat array directly
  • Fix react-hooks/exhaustive-deps in station-layer
  • CI lint step re-enabled

Test plan

  • npm run build passes
  • npm run lint passes (0 errors, 2 pre-existing scraper warnings)
  • Browser: pan map then calculate route within 100ms — corridor stations load without empty flash
  • Browser: clear route while corridor is loading — no stale stations leak to next route
  • Browser: change corridor slider — single debounced fetch, not double
  • Browser: switch language — cookie persists, server HTML has correct lang
  • Browser: view-source on /fr<html lang="fr"> in server response

GeiserX added 2 commits March 31, 2026 12:46
…utes, restore lint

- Cap route geometry to 2000 coordinates and LIMIT SQL results to 500 (route-stations)
- Downsample Valhalla polylines to 2000 points before sending to corridor API
- Make URL [locale] param authoritative for i18n instead of localStorage/browser
- Sync <html lang> with active locale, navigate on locale switch
- Add AbortController to route requests to prevent stale-response races
- Fix lint: drop FlatCompat, use eslint-config-next flat config, pin ESLint 9
- Re-enable lint step in CI workflow
…lint, bbox

- Middleware reads pumperly-locale cookie before Accept-Language, preventing
  default-locale bounce-back for users who explicitly chose a language
- setLocale persists choice in cookie alongside localStorage
- Navbar logo links to current locale path instead of hardcoded /
- handleClearRoute aborts in-flight route requests via routeAbortRef
- Route-stations SQL uses CTE + ROW_NUMBER uniform sampling instead of
  naive LIMIT 500, distributing stations evenly along the entire route
- Compute bbox from full-resolution coords before downsampling in valhalla.ts
- Fix react-hooks/exhaustive-deps in station-layer.tsx (setSelectedStationId)
- Ignore src/generated/ in eslint config; lint now passes with 0 errors
@GeiserX GeiserX changed the title fix: harden route-stations, i18n, race conditions, lint feat: harden route-stations, fix i18n, abort stale routes, restore lint Mar 31, 2026
GeiserX added 4 commits March 31, 2026 13:09
…y copy

- Fix stale corridor-fetch race: debounce effect now depends on routes
  and reads fuel/routes from refs so timer always uses current values
- Logo always links to /${locale} (including es) — no cookie dependency
  for fresh visitors who land on /es
- setLocale navigates to /${locale} consistently (no special-case for es)
- Set pumperly-locale cookie on initial render so middleware has it
  even before the user explicitly switches language
- Locale layout sets document.documentElement.lang via inline script
  before hydration — crawlers and a11y tools see it in initial HTML
- Update privacy policy: document the single functional locale cookie
…server-side html lang

- Corridor debounce effect now only triggers on corridorKm changes (not route changes),
  preventing duplicate station fetches on every route activation
- All locales including default (es) use /locale prefix in canonical URLs and hreflang,
  matching the navigation behavior
- Middleware passes detected locale via x-pumperly-locale request header + sets cookie;
  root layout reads header to render lang attribute in server HTML
- Remove redundant inline script from locale layout (no longer needed)
A pending bbox debounce timer could abort an in-flight corridor fetch
when routes activated within ~100ms of a map pan, leaving the station
list empty. Fix:

- Split shared abortRef into bboxAbortRef and corridorAbortRef so
  neither fetch path can cancel the other
- Clear bbox debounce timer on route activation
- Guard fetchStations() with routesRef check to bail if routes are active
Without this, a slow route-stations response could repopulate
corridorPerRoute after the route was cleared, leaking stale
stations into the next route activation.
@GeiserX GeiserX changed the title feat: harden route-stations, fix i18n, abort stale routes, restore lint Hardening: fetch races, i18n locale authority, server-side lang, lint Mar 31, 2026
@GeiserX GeiserX merged commit 1525bf5 into main Mar 31, 2026
4 checks passed
@GeiserX GeiserX deleted the fix/hardening-patch branch March 31, 2026 11:46
GeiserX added a commit that referenced this pull request Apr 3, 2026
Hardening: fetch races, i18n locale authority, server-side lang, lint
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