fix(refresh): don't call a stored copy "nothing newer", and point an entry at its feature
When the network failed behind the service worker, it answered from its own store. Check for new data then said nothing newer was published when the server was never reached. The worker now marks that copy, and a fresh check treats it as unreachable; ordinary loads still use it offline. The built-in tasks entry linked to a follow-up fix instead of the feature, and the changelog spec's details now match what shipped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1fc47e2864
commit
ab3173adf0
5 files changed
+37
-8
No files matched your search
@@ -88,19 +88,17 @@ launch window rather than replaying everything.
|
||||
|
||||
**What's new card** — top of the main column, above the lists; never in the rail, which holds
|
||||
instructions. Eyebrow `What's new`, up to five entries (`New` / `Fixed` / `Games & sources` tag,
|
||||
title, date), `See all` (opens the changelog) and `Got it`. More than five shows `+ 3 more` inside
|
||||
See all. Dismissible, never modal, never shown on first run.
|
||||
title, date), `See all` (opens the changelog) and `Got it`. More than five reads `See all (3 more)`. Dismissible, never modal, never shown on first run.
|
||||
|
||||
**Changelog sheet** — a `What's new` link in the footer beside the existing credits opens a sheet
|
||||
**Changelog sheet** — a `Changelog` link in the footer beside *Source code* opens a sheet
|
||||
in the detail sheet's style. Release notes, newest first, each with title, date, summary
|
||||
paragraphs, `commits from…to` (compare link) and spec links; the short entries a note covers listed
|
||||
under it with commit links. Entries with no note are listed by month at the end.
|
||||
|
||||
## Conventions this adds
|
||||
|
||||
AGENTS.md § Conventions gains: **a change a reader can see adds a short entry in the same commit**,
|
||||
with the ref filled in by a follow-up `chore(changelog)` commit when the change's own hash cannot
|
||||
be known in advance (a commit cannot contain its own hash). A feature that spans several commits
|
||||
AGENTS.md § Conventions gains: **a change a reader can see adds a short entry**, in a follow-up
|
||||
`chore(changelog)` commit naming the change's commit — a commit cannot contain its own hash. A feature that spans several commits
|
||||
gets a release note when it lands, summarising its spec and range.
|
||||
|
||||
## Backfill
|
||||
|
||||
@@ -29,6 +29,11 @@ export async function fetchFeed(
|
||||
if (!res.ok) {
|
||||
throw new Error(`Feed request failed (${res.status}).`);
|
||||
}
|
||||
// Asked for the newest data, a copy the service worker served from its own
|
||||
// store is not an answer from the server: the network failed behind it.
|
||||
if (options.fresh === true && res.headers.get("x-served-from") === "sw-cache") {
|
||||
throw new Error("The server could not be reached; this is the stored copy.");
|
||||
}
|
||||
|
||||
const json: unknown = await res.json();
|
||||
const version = (json as { schemaVersion?: number }).schemaVersion;
|
||||
|
||||
+8
-1
@@ -146,7 +146,14 @@ async function feedFirst(request) {
|
||||
return response;
|
||||
} catch {
|
||||
const cached = await cache.match(request);
|
||||
if (cached !== undefined) return cached;
|
||||
// Marked as the stored copy, so a reader who asked for the newest data
|
||||
// ("Check for new data") is told the server was not reached rather than
|
||||
// that nothing newer was published. An ordinary load ignores the mark.
|
||||
if (cached !== undefined) {
|
||||
const headers = new Headers(cached.headers);
|
||||
headers.set("x-served-from", "sw-cache");
|
||||
return new Response(cached.body, { status: cached.status, headers });
|
||||
}
|
||||
// No network and nothing cached: say so in the feed's own shape, so the
|
||||
// client renders its error state rather than failing to parse.
|
||||
return new Response(
|
||||
|
||||
@@ -72,7 +72,7 @@ export const ENTRIES: Entry[] = [
|
||||
kind: "feature",
|
||||
title: "Built-in weekly tasks for Zenless Zone Zero and Arknights: Endfield",
|
||||
body: "Ridu Weekly (1,300 points) and the Weekly Routine (10 points), each dated by the page it comes from. You're asked once per game; Make it mine copies one into your own tasks to edit.",
|
||||
ref: "1c7df63",
|
||||
ref: "624c725",
|
||||
note: "weekly-and-monthly-tasks",
|
||||
},
|
||||
// 2026-10-13 — weekly and monthly tasks
|
||||
|
||||
@@ -107,3 +107,22 @@ describe("the age right after a refresh", () => {
|
||||
expect(html).not.toContain("ended ago");
|
||||
});
|
||||
});
|
||||
|
||||
describe("review fix: a stored copy is not an answer from the server", () => {
|
||||
const original = globalThis.fetch;
|
||||
afterEach(() => {
|
||||
globalThis.fetch = original;
|
||||
});
|
||||
|
||||
test("asked fresh, the service worker's fallback copy counts as not reaching the server", async () => {
|
||||
globalThis.fetch = (async () =>
|
||||
new Response(JSON.stringify(feed()), {
|
||||
status: 200,
|
||||
headers: { "x-served-from": "sw-cache" },
|
||||
})) as unknown as typeof fetch;
|
||||
(globalThis as { document?: unknown }).document ??= { baseURI: "https://example.test/" };
|
||||
await expect(fetchFeed(undefined, { fresh: true })).rejects.toThrow();
|
||||
// An ordinary load still takes it: offline, the stored copy is the point.
|
||||
await expect(fetchFeed()).resolves.toBeDefined();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user