Files
cloudflare__vinext/examples/workers-cache/README.md

55 lines
4.4 KiB
Markdown

# Workers Response Store adapter POC
This example uses one `responseStoreAdapter()` from `@vinext/cloudflare` in place of both `cdnAdapter()` and `kvDataAdapter()`. The application Worker keeps Workers Cache disabled. Its `RESPONSE_STORE` service binding calls a separately deployed cache Worker that owns Workers Cache, R2 response bodies, SQLite Durable Object metadata, tag indexes, and SWR regeneration.
The cache Worker is shared infrastructure, not a second deployment of the application. Each application version has one ordinary build and deploy. Cached entries retain a loopback to that application version's vinext response-stage entrypoint. Route and fetch-cache entries can replay that stage, while a transformed public `"use cache"` entry records its encrypted arguments and server-reference identity so regeneration invokes only that function. If its arguments cannot be safely recorded, the adapter falls back to replaying the cacheable route.
On a page or RSC miss, vinext streams the render to the visitor while an independent bounded branch runs completed-response admission. A clean, cacheable response is inserted into Response Store in the background; late dynamic usage, timeout, or size rejection prevents publication without delaying the foreground response, while a source stream failure terminates both branches. The initial `MISS` status describes the lookup result because final admission happens after its headers have been sent. Route Handlers retain their completion barrier so body-time cookie, draft-mode, and cache-tag changes are reflected before headers are finalized. Warmup and loopback regeneration still wait for admission and durable publication because those operations must not report success before the replacement exists. Cache headers never enable Workers Cache on the application Worker; they only carry the admitted response policy to the cache Worker.
During SWR, Workers Cache returns its stale response immediately and invokes the cache Worker in the background. The cache Worker cannot currently distinguish that update from an empty edge location reading stale R2 data, so it returns the stale R2 response immediately instead of risking a blocking read. It regenerates through the application loopback, replaces the R2 revision only after vinext completed-response admission confirms the result is cacheable, and allows a later Workers Cache request to promote it. This can produce one extra stale response until the invocation reason is available to the cache Worker.
Automatic loopback regeneration is attached only to replay-safe `GET` and `HEAD` renders. Data written during actions or other non-replayable requests remains available and can still be invalidated explicitly, but Response Store will not replay that request in the background.
## Wiring
`vite.config.ts` contains the complete vinext integration:
```ts
import { responseStoreAdapter } from "@vinext/cloudflare/cache/response-store-adapter";
vinext({ cache: responseStoreAdapter() });
```
`wrangler.jsonc` supplies only the `RESPONSE_STORE` service binding and `CF_VERSION_METADATA` metadata binding. It does not bind KV, R2, a Durable Object, or Workers Cache to the application Worker. The adapter-generated Worker entry runs vinext's request stage, performs Response Store lookups, admits completed non-dynamic renders, and exports the loopback revalidator entrypoint.
## Routes
- `/cached/[slug]` exercises App Router ISR and tag/path revalidation.
- `/use-cache` exercises a dynamic route whose cached function is regenerated by Response Store.
- `/use-cache-expired` verifies that hard-expired data blocks on loopback regeneration.
- `/api/now` exercises cached App Route responses.
- `/pages-prewarm` exercises Pages Router ISR.
- `/dynamic` and `/vary` verify that unsafe completed responses bypass shared storage.
Canonical App Router RSC requests use the same response-stage transport:
```sh
curl 'https://workers-cache.vinext.workers.dev/cached/intro.rsc?_rsc=' -H 'Accept: text/x-component' -H 'RSC: 1'
```
## Build and deploy
Deploy the shared cache Worker only when its implementation or bindings change:
```sh
pnpm --filter @vinext/workers-response-store run build
pnpm --filter workers-cache exec wrangler deploy --config ../../packages/workers-response-store/example/service-binding/wrangler.cache.jsonc
```
Then build and deploy the application once:
```sh
pnpm --filter workers-cache run build
pnpm --filter workers-cache exec wrangler deploy
```