* test: cover revalidate = 0 route handler never-cache semantics
Route handlers with `export const revalidate = 0` currently emit no
Cache-Control header at all. Downstream gates treat the 0 value as
equivalent to "no revalidate configured" and skip the header write,
which lets CDNs and browsers apply heuristic caching to a response the
author explicitly opted out of.
The existing policy test asserted the buggy collapse (`toBeNull()` for
revalidate = 0), protecting the behaviour instead of verifying it.
Rewrite the policy test to assert the preserved 0 and add coverage for
the read/write/header gates for revalidate = 0. Add a response-level
test asserting the exact Cache-Control string Next.js emits for
revalidate = 0 (private, no-cache, no-store, max-age=0, must-revalidate).
These tests fail against the current implementation and will pass once
the policy helper preserves 0 and the header builder branches on 0.
* fix: emit no-store Cache-Control for revalidate = 0 route handlers
A route handler exporting `export const revalidate = 0` currently
sends no Cache-Control header at all. Downstream CDNs and browsers
fall back to heuristic caching, so a response the author explicitly
opted out of caching can still be cached and replayed.
getAppRouteHandlerRevalidateSeconds filtered on `> 0`, collapsing the
"never cache" signal (0) and the "no revalidate configured" signal
(null) into the same null return. The three gates downstream
(shouldReadAppRouteHandlerCache, shouldApplyAppRouteHandlerRevalidateHeader,
shouldWriteAppRouteHandlerCache) all short-circuit when revalidateSeconds
is null, so the header was never applied and no cache entry was written.
That second part was accidentally correct; the first part left the
response vulnerable.
Preserve 0 as a distinct value, using Number.isFinite to keep NaN and
Infinity out of the number branch along with negatives. Keep the ISR
read and write gates on `> 0` so a never-cache handler never serves or
persists ISR entries. Keep the header gate on `!== null` so 0 still
triggers a Cache-Control write, and branch buildRouteHandlerCacheControl
on 0 to emit Next.js's canonical no-store string (matches
packages/next/src/server/lib/cache-control.ts).