Files
cloudflare__vinext/.opencode
James Anderson f0f6aa72e0 feat(cache): configure cache adapters from vite plugin config (#1733)
* feat(cache): configure cache adapters from vite plugin config

Add a `cache` option to the vinext() plugin so CDN and data cache
adapters can be declared in vite.config instead of calling
setDataCacheHandler() / setCdnCacheAdapter() from a worker entry:

  vinext({
    cache: {
      cdn:  { adapter: require.resolve('vinext/cloudflare/cache/cdn-adapter') },
      data: { adapter: require.resolve('vinext/cloudflare/cache/kv-data-adapter') },
    },
  })

Each slot points at an adapter module whose default export is a factory
(DataCacheAdapterFactory / CdnCacheAdapterFactory). The plugin generates
a virtual:vinext-cache-adapters module that the App Router worker entry
calls per request (self-guarded, once per isolate), passing the host env
so binding-backed adapters (e.g. KV) can read their namespace.

Ships ready-made Cloudflare adapter entry points:
  - vinext/cloudflare/cache/kv-data-adapter  (KVCacheHandler)
  - vinext/cloudflare/cache/cdn-adapter      (CloudflareCdnCacheAdapter)

* feat(cache): add typed adapter builders (kvDataAdapter/cdnAdapter)

Instead of `{ adapter: require.resolve(...) }`, each adapter module now
also exports a config-time builder from the same path:

  import { cdnAdapter } from 'vinext/cloudflare/cache/cdn-adapter';
  import { kvDataAdapter } from 'vinext/cloudflare/cache/kv-data-adapter';

  vinext({ cache: { cdn: cdnAdapter(), data: kvDataAdapter({ binding: 'MY_KV' }) } })

A builder returns a plain, serializable { adapter, options } descriptor —
it never touches the Workers runtime, so nothing throws at config / build
/ dev time when bindings aren't available. Descriptor `options` (e.g. the
KV binding name) are inlined into the generated registration module and
forwarded to the factory's { env, options } context, where the binding is
resolved lazily on the first request.

- shims/cache-adapter: descriptors + options-aware factory/context types
- kv-data-adapter: kvDataAdapter() builder + configurable binding/appPrefix/ttl
- cdn-adapter: cdnAdapter() builder
- raw { adapter, options } path form still supported

* test(cache): verify absolute (require.resolve) local adapter path bundles

Real Cloudflare build pointing cache.data at a local adapter file by
absolute path (what require.resolve('./adapter') yields). Proves the
generated registration module resolves the absolute import, bundles the
local adapter into the worker, and does not need any Workers context at
build time.

* refactor(cache): builder require.resolve + register across all routers/runtimes

Addresses review feedback:

* Move adapters into their own runtime modules instead of re-exporting.
  Each adapter is now a builder module (kv-data-adapter.ts / cdn-adapter.ts)
  plus a sibling *.runtime.ts holding the default-export factory. Type
  definitions have a single home in shims/cache-adapter.ts (dropped the
  re-export shim; index.ts imports the config type from there).

* The exposed builder utility resolves the relative runtime path internally
  via import.meta.resolve (the ESM require.resolve), so the descriptor carries
  an absolute path to the runtime factory rather than a bare specifier — the
  example is just kvDataAdapter({ binding }), no require.resolve at the call site.

* Register configured cache handlers EVERYWHERE, not just the App Router worker:
  - App Router: the generated RSC entry passes registerConfiguredCacheAdapters
    into createAppRscHandler, which calls it per request — covering Workers,
    the Node server, and dev through the one shared handler.
  - Pages Router: the generated server entry registers in renderPage and
    handleApiRoute (Node/dev), and the generated worker registers with env
    (Workers, for KV bindings).
  Registration self-guards (first call with real env wins) and is now resilient:
  a factory that throws on an incompatible runtime is logged and skipped, so the
  default handler stays in place instead of failing every request.

Tests: generator-level assertions that every router/runtime entry wires
registration, plus the existing builder/codegen/factory and full-build coverage.
vp check clean; app-router (339) and pages-router (272) suites pass.

* refactor(cache): keep all Cloudflare adapter code under cloudflare/

The adapter factory contract lived in shims/cache-adapter.ts (outside
cloudflare/), and the Cloudflare adapters reached out to it. Move the
contract into cloudflare/cache/adapter.ts so every Cloudflare-specific
cache adapter file is self-contained under cloudflare/ — importing only
cloudflare-local modules and the core CacheHandler/CdnCacheAdapter
interfaces it implements.

The plugin's config schema (CacheAdapterDescriptor / VinextCacheConfig)
is genuinely framework-level (it's the vinext() `cache` option), so it
moves into the codegen module the plugin already owns; index.ts imports
it from there. Builders return a structural { adapter, options } so they
don't import the descriptor type either. Deletes shims/cache-adapter.ts.

* refactor(cache): merge KV/CDN classes into the runtime adapter files

All Cloudflare cache code now lives in one directory, cloudflare/cache/,
and each runtime file holds both the implementation class and its
config-driven factory (no separate class module to reach for):

  - kv-cache-handler.ts        -> cache/kv-data-adapter.runtime.ts
    (KVCacheHandler + ENTRY_PREFIX + createKvDataCacheAdapter default export)
  - cloudflare-cdn-cache.ts    -> cache/cdn-adapter.runtime.ts
    (CloudflareCdnCacheAdapter + createCloudflareCdnCacheAdapter default export)

Updated importers: cloudflare/index.ts re-exports the classes from the
runtime files, tpr.ts pulls ENTRY_PREFIX from there, shims/cdn-cache.ts
imports the edge adapter from there, and the tests follow the moved paths.
git mv preserves history.

vp check clean; cache/kv/cdn/app-route/tpr/shims suites pass (1300+ tests).

* chore(cache): trim low-value comments added in this branch

Remove narrating/redundant comments that just restated the code; keep
the non-obvious why (registration ordering/resilience, import.meta.resolve
rationale, edge cache-control semantics). No code changes.

* review: address PR #1733 feedback

- Make registerCacheAdapters a required field on the RSC handler options
  (the generated entry already passes it; test factory updated).
- Remove the separate cloudflare/cache/adapter.ts contract file; inline the
  factory param types directly into the two runtime adapters.
- Drop the CloudflareCdnCacheAdapter re-export from cloudflare/index.ts.
- Fold the virtual:vinext-cache-adapters declaration into global.d.ts and
  delete the standalone .d.ts.
- Remove the ./cloudflare/cache/* package.json export for now; README uses a
  local-adapter require.resolve example with a note that the built-in adapter
  export paths are pending.
- Rename the config-driven KV default binding to VINEXT_KV_CACHE (imperative
  deploy/tpr path keeps VINEXT_CACHE — flagged on the thread).

* refactor(cache): align KV binding name to VINEXT_KV_CACHE everywhere

Rename the KV cache binding from VINEXT_CACHE to VINEXT_KV_CACHE across the
whole codebase so the config-driven adapter, the imperative deploy-generated
worker, TPR's wrangler detection, and the apps/web example all agree. The
unrelated X-Vinext-Cache response-header constant (VINEXT_CACHE_HEADER) is
untouched.

* tidy

* .

* .

* .

* .

* .

* Move apps/web cache to plugin config

Co-authored-by: james-elicx <james-elicx@users.noreply.github.com>

---------

Co-authored-by: ask-bonk[bot] <ask-bonk[bot]@users.noreply.github.com>
Co-authored-by: james-elicx <james-elicx@users.noreply.github.com>
2026-06-04 23:30:33 +00:00
..
2026-03-09 14:56:14 +00:00