Restore dev-mode cache-fill timeout for `'use cache'`
When `'use cache'` fills during `next dev`, there was no timeout, so a
stalled fill could hang the request indefinitely. This change restores a
dev-mode cache-fill timeout that fires 50 seconds after the fill starts,
matching the 50s timeout we already have during prerender. The timer
sets `workStore.invalidDynamicUsageError` to a `UseCacheTimeoutError`
and aborts the signal passed to React's `renderToReadableStream`, which
errors the cache stream. From there the existing handling of
`invalidDynamicUsageError` in app-render surfaces the error in the
Redbox and the CLI output without any additional plumbing.
Prior to PR #85747, `spawnDynamicValidationInDev` reused the prerender
store and inherited the prerender cache timeout as a side effect. After
that change the validation became staged-rendering based and the timeout
stopped applying to dev renders. This PR closes that gap.
The timeout is skipped when the render is already in the Dynamic stage,
which mirrors prerender, where caches past `await connection()` aren't
executed at all. The check is written as exact equality on
`RenderStage.Dynamic` rather than a numeric `< Dynamic` comparison
because `RenderStage.Abandoned` is numerically higher than Dynamic but
semantically represents an aborted initial prospective render whose
pending caches still need to be timed out while the outer flow awaits
`cacheSignal.cacheReady()`. The 50s duration is shared with the
prerender path via a new `USE_CACHE_FILL_TIMEOUT_MS` constant and
carries a TODO to derive it from the user-configurable
`staticPageGenerationTimeout`.
The tests model a realistic migration hazard: a module-scoped in-flight
fetch dedupe loader (the hand-rolled variant of the documented
`React.cache`-based preload pattern) joined by a `'use cache'` function.
That configuration deadlocks because the outer fetch is parked on the
Dynamic stage in dev, or returns an intentionally hanging promise during
prerender, and the cache never fills.