fix(frontend): keep the /cell prefetch seeding the dated grade URL
All checks were successful
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / changes (pull_request) Successful in 6s
secrets-guard / encrypted (pull_request) Successful in 5s
PR build (required check) / build-backend (pull_request) Has been skipped
shell-lint / shellcheck (pull_request) Successful in 7s
PR build (required check) / build-frontend (pull_request) Successful in 29s
PR build (required check) / gate (pull_request) Successful in 3s
All checks were successful
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / changes (pull_request) Successful in 6s
secrets-guard / encrypted (pull_request) Successful in 5s
PR build (required check) / build-backend (pull_request) Has been skipped
shell-lint / shellcheck (pull_request) Successful in 7s
PR build (required check) / build-frontend (pull_request) Successful in 29s
PR build (required check) / gate (pull_request) Successful in 3s
This commit is contained in:
parent
44b02d985a
commit
ab4ba54575
1 changed files with 15 additions and 6 deletions
|
|
@ -207,7 +207,7 @@ function seedCache(url, data, etag) {
|
||||||
// lives here next to the bundle fetch — not knowledge of any one page.
|
// lives here next to the bundle fetch — not knowledge of any one page.
|
||||||
function viewFetches(q, today) {
|
function viewFetches(q, today) {
|
||||||
return {
|
return {
|
||||||
grade: [uv(`grade?${q}`), TTL.grade],
|
grade: [uv(`grade?${q}&date=${today}`), TTL.grade],
|
||||||
forecast: [uv(`forecast?${q}`), TTL.forecast],
|
forecast: [uv(`forecast?${q}`), TTL.forecast],
|
||||||
calendar: [uv(`calendar?${q}&months=24`), TTL.calendar],
|
calendar: [uv(`calendar?${q}&months=24`), TTL.calendar],
|
||||||
day: [uv(`day?${q}&date=${today}`), TTL.day],
|
day: [uv(`day?${q}&date=${today}`), TTL.day],
|
||||||
|
|
@ -232,6 +232,12 @@ export function prefetchViews(lat, lon, ownViews) {
|
||||||
if (_prefetched === tag) return;
|
if (_prefetched === tag) return;
|
||||||
_prefetched = tag;
|
_prefetched = tag;
|
||||||
const q = `lat=${lat}&lon=${lon}`;
|
const q = `lat=${lat}&lon=${lon}`;
|
||||||
|
// The client's local "today" — sent explicitly so the server never has to guess
|
||||||
|
// it from its own (UTC) clock. Getting this wrong is exactly what poisoned the
|
||||||
|
// Weekly view's cache for UTC+ visitors between their local midnight and UTC
|
||||||
|
// midnight: the bundle used to be built against the server's date while the
|
||||||
|
// per-view request stated the client's, so the two silently disagreed.
|
||||||
|
const today = localDay();
|
||||||
const own = new Set(ownViews);
|
const own = new Set(ownViews);
|
||||||
// Yield first so the landing view finishes rendering before we fetch the rest.
|
// Yield first so the landing view finishes rendering before we fetch the rest.
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
|
|
@ -239,17 +245,20 @@ export function prefetchViews(lat, lon, ownViews) {
|
||||||
const ek = "tg-cell-etag:" + q;
|
const ek = "tg-cell-etag:" + q;
|
||||||
let prev = null;
|
let prev = null;
|
||||||
try { prev = sessionStorage.getItem(ek); } catch (e) {}
|
try { prev = sessionStorage.getItem(ek); } catch (e) {}
|
||||||
const res = await fetch(uv(`cell?${q}&neighbors=1`),
|
const res = await fetch(uv(`cell?${q}&date=${today}&neighbors=1`),
|
||||||
{ credentials: "include", ...(prev ? { headers: { "If-None-Match": prev } } : {}) });
|
{ credentials: "include", ...(prev ? { headers: { "If-None-Match": prev } } : {}) });
|
||||||
if (res.ok && res.status !== 304) {
|
if (res.ok && res.status !== 304) {
|
||||||
const bundle = await res.json();
|
const bundle = await res.json();
|
||||||
try { sessionStorage.setItem(ek, res.headers.get("ETag") || ""); } catch (e) {}
|
try { sessionStorage.setItem(ek, res.headers.get("ETag") || ""); } catch (e) {}
|
||||||
const fetches = viewFetches(q, localDay());
|
// Seed under bundle.today (the date the server actually resolved — normally
|
||||||
|
// just an echo of the date= we sent) rather than our own `today`, so the
|
||||||
|
// seeded key stays byte-identical to what a per-view request for that same
|
||||||
|
// resolved date will use even in the rare case the two disagree (e.g. a
|
||||||
|
// request that straddles local midnight).
|
||||||
|
const fetches = viewFetches(q, bundle.today);
|
||||||
for (const [name, slice] of Object.entries(bundle.slices || {})) {
|
for (const [name, slice] of Object.entries(bundle.slices || {})) {
|
||||||
if (own.has(name) || !slice || !slice.data) continue;
|
if (own.has(name) || !slice || !slice.data) continue;
|
||||||
const url = name === "day"
|
const url = (fetches[name] || [])[0];
|
||||||
? uv(`day?${q}&date=${bundle.today}`) // the day slice targets today
|
|
||||||
: (fetches[name] || [])[0];
|
|
||||||
if (url) seedCache(url, slice.data, slice.etag);
|
if (url) seedCache(url, slice.data, slice.etag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue