web: new attempt at fixing revalidation/caching per day
web / ci (push) Successful in 1m51s

This commit is contained in:
2026-09-05 18:09:04 +02:00
parent 4bd05880ac
commit 57743e6640
2 changed files with 37 additions and 4 deletions
+30 -1
View File
@@ -1,6 +1,9 @@
import { describe, expect, it } from "vitest";
import { secondsUntilOsloMidnight } from "./revalidation.ts";
import {
cachedUntilOsloMidnight,
secondsUntilOsloMidnight,
} from "./revalidation.ts";
describe("secondsUntilOsloMidnight", () => {
it("is 12h from midnight at 12:00 CEST on a normal day", () => {
@@ -23,3 +26,29 @@ describe("secondsUntilOsloMidnight", () => {
expect(secondsUntilOsloMidnight(now)).toBe(23 * 3600);
});
});
describe("cachedUntilOsloMidnight", () => {
// urql types fetchOptions as RequestInit | () => RequestInit; we always pass an object
function fetchOptionsAt(now: Date): RequestInit {
const { fetchOptions } = cachedUntilOsloMidnight(now);
return typeof fetchOptions === "function" ? fetchOptions() : fetchOptions ?? {};
}
it("keys the fetch cache on the Oslo date, not the UTC date", () => {
// 00:30 CEST on Sep 5 is still Sep 4 in UTC
const { headers } = fetchOptionsAt(new Date("2026-09-04T22:30:00Z"));
expect(headers).toEqual({ "x-oslo-day": "2026-09-05" });
});
it("changes the cache key at Oslo midnight", () => {
const before = fetchOptionsAt(new Date("2026-09-04T21:59:59Z"));
const after = fetchOptionsAt(new Date("2026-09-04T22:00:00Z"));
expect(before.headers).toEqual({ "x-oslo-day": "2026-09-04" });
expect(after.headers).toEqual({ "x-oslo-day": "2026-09-05" });
});
it("revalidates at Oslo midnight and tags the entry", () => {
const { next } = fetchOptionsAt(new Date("2026-09-05T10:00:00Z"));
expect(next).toEqual({ revalidate: 12 * 3600, tags: ["cms"] });
});
});
+7 -3
View File
@@ -1,5 +1,5 @@
import { addDays, startOfDay } from "date-fns";
import { fromZonedTime, toZonedTime } from "date-fns-tz";
import { formatInTimeZone, fromZonedTime, toZonedTime } from "date-fns-tz";
import type { OperationContext } from "@urql/core";
const timeZone = "Europe/Oslo";
@@ -29,10 +29,14 @@ export const uncached: Partial<OperationContext> = {
};
// For queries whose results depend on "today" (futureEvents, opening hours)
export function cachedUntilOsloMidnight(): Partial<OperationContext> {
export function cachedUntilOsloMidnight(
now: Date = new Date()
): Partial<OperationContext> {
return {
fetchOptions: {
next: { revalidate: secondsUntilOsloMidnight(), tags: [CMS_CACHE_TAG] },
// Part of the fetch cache key, so yesterday's entry is never reused
headers: { "x-oslo-day": formatInTimeZone(now, timeZone, "yyyy-MM-dd") },
next: { revalidate: secondsUntilOsloMidnight(now), tags: [CMS_CACHE_TAG] },
},
};
}