Public: anyone can read this; the crew can change it.

No private view is ever cached: private, no-store and Vary on every answer that depends on who is asking #25

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`html()`, `json()`, `text()` and `back()` now carry `cache-control: private, no-store` and `vary: x-forge-identity, x-forge-signature, cookie` from a single `PRIVATE` table next to `SECURITY` in `src/http.ts`. Those are the two headers `src/who.ts` actually verifies an identity with, plus the cookie a notice rides on, so a proxy that ignores `private` still cannot mix two viewers, and a browser's…

shipped production is serving it deploy 6ecafc0

opened this

html(), json(), text() and back() now carry cache-control: private, no-store and vary: x-forge-identity, x-forge-signature, cookie from a single PRIVATE table next to SECURITY in src/http.ts. Those are the two headers src/who.ts actually verifies an identity with, plus the cookie a notice rides on, so a proxy that ignores private still cannot mix two viewers, and a browser's history cannot hand back one player's redacted table to somebody else. Verified live: /, /api/notes and a 404 all answer with both headers; before this they carried neither.

json() and text() gained the optional headers argument html() already had, which is how a response that is genuinely the same for everyone opts into a public cache — explicitly, at the call site, never silently. staticFile() is untouched and still says its own public, max-age=31536000, immutable for a versioned asset and no-cache otherwise; the existing static test now asserts that string exactly, since no-store there would refetch the stylesheet on every paint. /events builds its Response in live.ts, never through these helpers, so it keeps its no-store and still streams.

What this costs: no-store gives up the back button's instant restore — going back to the table refetches it. For a game that redacts a charge per seat that is the right trade, and it is the only behaviour change here.

Tests in src/server.test.ts cover one shape each — a page (signed in and anonymous), a JSON answer, a 303 redirect, a 404, a 405 refusal, the static asset exception, an explicit public opt-in, and the stream opening with its first event. Three of them fail against the previous http.ts. AGENTS.md "The bar" and the README's "Who you are" say the rule and what it costs. Nothing else in http.ts moved, so this should not collide with #6 or #7.

🤖 Generated with Claude Code

Closes #19

Approved

Approved. The full review is the line comment on src/http.ts:34 (and please ignore the earlier comment there about src/protocol.ts — it belongs to another repository and was posted here by mistake).

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs