Skip to content

[pull] main from withastro:main#419

Merged
pull[bot] merged 3 commits intocode:mainfrom
withastro:main
Mar 4, 2026
Merged

[pull] main from withastro:main#419
pull[bot] merged 3 commits intocode:mainfrom
withastro:main

Conversation

@pull
Copy link

@pull pull bot commented Mar 4, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

ascorbic and others added 3 commits March 4, 2026 07:28
* feat: add route caching core types, config schema, and AstroCache runtime

Adds the foundational building blocks for the route caching feature (RFC #1245):

- CacheOptions, CacheProvider, CacheProviderFactory, InvalidateOptions types
- Zod config schema (CacheSchema) registered under experimental.cache
- AstroCache class with set() merge semantics, tags accumulation, invalidate(), _applyHeaders()
- NoopAstroCache for dev mode
- Utility functions: normalizeCacheDriverConfig, cacheConfigToManifest, defaultSetHeaders
- Public type exports from astro package

* feat: wire cache driver into SSR pipeline and render context

Integrates the cache system into the full request lifecycle:

- Virtual module vite-plugin for cache driver resolution (resolves from project root)
- SSRManifest: cacheDriver and cacheConfig fields
- BasePipeline: getCacheProvider() with lazy resolution
- RenderContext: creates AstroCache/NoopAstroCache per request, exposes on
  Astro.cache and context.cache (API routes, actions, middleware)
- App base: wraps onRequest for runtime providers, strips CDN headers after;
  applies _applyHeaders for CDN-based providers
- Serialized manifest: cache driver import + config serialization
- Throwing getter on Astro global for prerendered routes

* feat: add config-level cache route pattern matching

Compiles cache.routes patterns using Astro's existing route parsing
infrastructure (getParts, getPattern, routeComparator). Patterns use
the same [param]/[...rest] syntax as file-based routing. Most specific
route wins, computed once at startup via compileCacheRoutes().

* test: add cache unit tests, integration tests, and fixture

72 unit tests covering:
- AstroCache runtime: set() merge semantics, tags, invalidate, _applyHeaders, _isActive
- Utils: defaultSetHeaders, normalizeCacheDriverConfig, cacheConfigToManifest, isCacheHint, isLiveDataEntry
- NoopAstroCache: all methods callable and no-op
- Route matching: exact paths, dynamic params, rest params, priority ordering

6 integration tests with mock CDN provider:
- CDN-Cache-Control and Cache-Tag from context.cache.set()
- cache.set(false) opt-out, tags-only, config-level routes
- .astro page and API route support

* feat: add Node adapter in-memory LRU cache driver

Runtime cache provider for @astrojs/node with:
- In-memory LRU cache (custom Map-based, no external deps)
- SWR support via stale-while-revalidate with background revalidation
- Tag-based and path-based invalidation
- X-Astro-Cache response header (HIT/MISS/STALE) for observability
- Auto-set as default when experimental.cache is enabled without a driver
- Exported as @astrojs/node/cache subpath

* test: add Node adapter cache integration tests

8 tests covering the full runtime caching lifecycle:
- Default driver auto-configuration
- Cache hit/miss behavior with body verification
- CDN header stripping for runtime providers
- Tag-based and path-based invalidation
- cache.set(false) opt-out
- Uncached route passthrough

* docs: add route caching implementation plan

Full phased implementation plan for RFC #1245 covering:
- Phases 1-3: Core types, pipeline wiring, route matching (complete)
- Phase 4: Node adapter with in-memory LRU (complete)
- Phase 5: Cloudflare adapter with CacheW
- Phase 6: Vercel & Netlify adapters
- Phase 7: Documentation

* refactor: use symbols + helper functions for cache internals

Replace _applyHeaders() and _isActive underscore convention with
symbol-keyed methods behind applyCacheHeaders() and isCacheActive()
helper functions. The symbols are not exported from the astro package,
so users can't access them. Framework call sites import the helpers
from the module directly. NoopAstroCache no longer needs the internal
methods — the helpers handle the no-op case via 'in' checks.

* Correctly disable when not configured

* feat(cache): rename driver→provider, add routeRules config

Breaking: cache.routes moved to experimental.routeRules

This commit addresses RFC #1245 feedback:

1. Terminology: Rename 'driver' to 'provider' throughout the cache API.
   Providers have a richer interface (headers, middleware, invalidation)
   than the simpler driver pattern used by sessions/unstorage.

2. Configuration: Move cache route config from cache.routes to
   experimental.routeRules with Nitro-style shortcuts:
   - Flat cache options: { maxAge: 600, swr: 60 }
   - Nested form: { cache: { maxAge: 600 } }
   - Prerender control: { prerender: true }

3. API: Add cache.options getter for full cache state access,
   complementing the existing cache.tags getter.

Files renamed:
- cache-driver.ts → cache-provider.ts (both astro + node adapter)
- mock-cache-driver.mjs → mock-cache-provider.mjs (test fixture)

All 109 tests pass (95 unit + 7 core + 7 node adapter).

* fix: remove prerender from routeRules (out of scope)

routeRules is focused on cache configuration only. Prerender control
will be handled separately if/when it's added to the feature.

* chore: add exact-match comment on path invalidation

* chore: move implementation plan to memory repo

* Add slow page

* fix: resolve lint errors (unexport internal schemas, fix generic constructor, fix test import)

* fix: move cache runtime code to runtime/ dir, remove node: imports from SSR bundle

- Move runtime cache code (AstroCache, noop, route-matching, utils) into
  cache/runtime/ directory following Astro conventions
- Remove node:url and node:path imports that leaked into SSR bundle,
  breaking Cloudflare/edge deployments and verify-no-node-stuff test plugin
- Guard getCacheProvider() call in hot path to skip async overhead when
  no cache provider is configured (addresses CodSpeed benchmark regression)

* refactor: move memory cache to core, add type-safe config function

- Move in-memory LRU cache provider from @astrojs/node to astro core
  (it's runtime-agnostic, not Node-specific)
- Export memoryCache() from astro/config (follows sharpImageService pattern)
- Runtime entrypoint at astro/cache/memory (separate from config context)
- Remove bare string form for cache provider config (object-only)
- Export CacheProviderConfig from public types

* refactor: move memory cache tests from node adapter to astro core

The memory cache provider is now in core, so its tests belong here
too. Uses testAdapter() + app.render() instead of a live Node server.

* docs: mention routeRules in changeset intro

* perf: skip all cache code in render hot path when no provider configured

* Changes from review

* Tighten up memory cache

* Fix import

* Changes from review

* Remove waitUntil from CacheProvider interface

The built-in memory provider only runs on long-lived servers where
fire-and-forget promises complete naturally. Platform-specific providers
(Cloudflare, Vercel) have direct access to their own waitUntil APIs
and don't need it on the shared interface.

* Changes from review

* Add memory provider unit tests and fix existing tests

- New: 22 unit tests for memory-provider covering onRequest, LRU eviction,
  query parameter handling, Vary headers, SWR, invalidation, and response
  body/status/header preservation
- Fix noop.test.js: use DisabledAstroCache class instead of removed singleton
- Fix runtime.test.js: update frozen-object and error-message assertions to
  match review changes (Object.freeze removal, AstroError for invalidate)

* Fix test:types: import cache types from dist/ instead of src/

Importing from src/ in the type test file pulls the src type tree into
the same compilation as dist types from other imports, causing
structural incompatibilities due to @internal-stripped members
(e.g. fsPath on ImageMetadata, renderTemplateResultSym).

* Revert "Fix test:types: import cache types from dist/ instead of src/"

This reverts commit f323107.

* Fix test:types cache types import mix

Use cache schema from src but import cache types from dist so the
schemas test still validates the public types without pulling the
entire src type graph into the same compilation as dist.
@pull pull bot locked and limited conversation to collaborators Mar 4, 2026
@pull pull bot added the ⤵️ pull label Mar 4, 2026
@pull pull bot merged commit ca6894a into code:main Mar 4, 2026
3 of 9 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant