Skip to content

Cache: port SWR tag revalidation from AWS #1122 / #1142 - #46

Open
conico974 wants to merge 43 commits into
mainfrom
conico/cache-4-swr-port
Open

conico974 wants to merge 43 commits into
mainfrom
conico/cache-4-swr-port

Conversation

@conico974

@conico974 conico974 commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Part 4 of 6 of the cache stack, split out of #31. Review only this PR's diff — it is based on the previous branch.

PR Base
#43 — core: dedicated cache handler function conico/share-build (#35)
#44 — cloudflare: OpenNextCache entrypoint #43
#45 — core: route all caching through the cache override ⚠️ breaking #44
👉 #46 — port SWR tag revalidation from AWS #45
#47 — core: honour Cache-Control on cache entries #46
#48 — cloudflare: per-entrypoint Workers caching #47

Ports opennextjs-aws#1122 and opennextjs-aws#1142 on top of the cache handler function.

  • Tags carry optional stale and expire durations: writeTags accepts a { tag, stale, expire } input as well as a plain name, OriginalTagCache entries gained the same fields, and both tag cache flavours gained an optional isStale.
  • Cache.revalidateTags takes the durations. The cache handler turns the expire delay into a timestamp, callers pass it through unchanged.
  • The composable cache handler implements updateTags, added in Next.js 16.
  • New per-request RequestCache on the OpenNext request context, so overrides can deduplicate work within a request without touching global state. globalThis.nextVersion is injected in the esbuild banner.
  • DynamoDB, fs-dev and the Cloudflare D1 / KV / sharded DO tag caches updated for the new signatures.

Supersedes #30, which was based on the pre-restructure layout (packages/open-next/).

…y into core adapter

feat: enhance build process with additional server bundle customization options

chore: update package.json scripts for improved build and testing workflow

test: add unit tests for adapter build process and server bundle generation

fix: ensure proper handling of external dependencies and edge configuration in server bundle
…udflare specific overrides"

This reverts commit 37c4d90.
…ad of throwing

- Extract ValidateConfigResult type with success/message/shouldThrow/level
- Convert validateFunctionOptions and validateSplittedFunctionOptions to return result objects
- Remove logger dependency from validateConfig.ts
- Preserve compatibilityMatrix, TODO comment, @ts-expect-error pragmas
- Add 5 characterization tests in validateConfig.spec.ts
- No caller impact: compileConfig.ts is the sole importer (updated in T3)
- Export OpenNextOutput interface (was internal)
- Extract buildOpenNextOutput(buildOpts) for construction-only (no fs write)
- Keep legacy generateOutput as thin wrapper (construction + file write)
- Preserve all construction logic verbatim, including @ts-expect-error
- Add 3 characterization tests in generateOutput.spec.ts
- Backward compatible: byte-equivalent output to today
- Replace bare validateConfig(config) call with result-handling block
- Throw on shouldThrow:true (bad routes — preserves existing behavior)
- Log at appropriate level on shouldThrow:false (level field from T1)
- All 3 export signatures and edge-runtime detection block unchanged
- Direct callers (aws/build.ts, cloudflare/utils.ts) unaffected
…OpenNextAdapterOptions

- Make OpenNextAdapterOptions<T = OpenNextOutput> and buildAdapter<T> generic
- Add validateConfig override hook (runs after callback in modifyConfig)
- Add generateOutput override hook (returns T, gated by skipGenerateOutput)
- buildAdapter serializes override return via fs.writeFileSync (override never touches fs)
- Default path uses buildOpenNextOutput (extracted in T2)
- Add 5 new tests covering override behaviors + default path + skipGenerateOutput
- All 16 existing adapter tests preserved; AWS/Cloudflare adapters compile with default T
When an adapter config specifies full package-specifier paths (e.g.,
@opennextjs/aws/overrides/wrappers/aws-lambda.js), esbuild cannot
resolve them during bundling. Use createRequire(args.path).resolve()
in the openNextResolvePlugin to convert package specifiers to
filesystem-relative paths at build time, falling back to the original
value if resolution fails.

This fixes the openbuild:local build error:
  ERROR: Could not resolve "@opennextjs/aws/overrides/wrappers/aws-lambda.js"
  ERROR: Could not resolve "@opennextjs/aws/overrides/tagCache/dynamodb.js"

Added test I verifying resolution of a mock package in node_modules.
@pkg-pr-new

pkg-pr-new Bot commented Aug 16, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/opennextjs/adapters-api/@opennextjs/aws@3f25aac
npm i https://pkg.pr.new/opennextjs/adapters-api/@opennextjs/cloudflare@3f25aac
npm i https://pkg.pr.new/opennextjs/adapters-api/@opennextjs/core@3f25aac

commit: 3f25aac

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

View 2 additional findings in Devin Review.

Open in Devin Review

Comment thread packages/core/src/adapters/cache-adapter.ts Outdated
Comment thread packages/aws/src/overrides/tagCache/dynamodb.ts Outdated
Comment thread packages/aws/src/overrides/tagCache/dynamodb-nextMode.ts
Add a standalone cache handler function that owns the incremental cache, the
tag cache and CDN invalidation, and a `cache` override that other functions use
to reach it.

- `adapters/cache-adapter.ts` exposes `GET/PUT/DELETE /cache/*` and
  `POST /cache/revalidate-tags` through `createGenericHandler`.
- `build/createCacheBundle.ts` bundles it to `.open-next/cache-function`, wired
  into `buildAdapter` behind the new `skipCache` option and reported as
  `cacheFunction` in the OpenNext output.
- New top level `cacheHandler` config option carries the incremental cache, tag
  cache and cdn invalidation overrides for that function.
- New `cache` override with `fetch`, `local` and `dummy` implementations, and a
  shared wire format in `utils/cache-get.ts` that splits the entry metadata into
  headers and the payload into the body.

Nothing is removed here: the existing in-process `incrementalCache` and
`tagCache` overrides keep working unchanged.
Build the OpenNext cache handler function as part of the worker and expose it
through a named entrypoint, so the cache can later run behind a service binding
- in this worker or in one of its own.

- `service-cache.ts` is a `cache` override that speaks the cache handler HTTP
  API over the `NEXT_CACHE_SERVICE` binding.
- `buildCacheFunction` emits the bundle from `beforeServerBundle`, because the
  worker imports the entrypoint; core's own cache step is skipped.
- `runWithCloudflareContext` initialises the Cloudflare context outside of a
  request, for entrypoints invoked over RPC. The origin is now populated
  separately, on the first call coming from the fetch handler.
- `withoutSelfEntrypointServices` strips the self referencing binding before
  handing the config to `getPlatformProxy`, which cannot resolve a named
  entrypoint of the worker it is configuring.
- Drop `compile-cache-assets-manifest.ts`, unreferenced.

`defineCloudflareConfig` is untouched: the entrypoint is built and exported but
nothing routes to it yet.
The incremental cache and the tag cache stop running inside the server
function. They only live in the cache handler function now, and the server, the
middleware and the composable cache reach them through the `cache` override.

- Remove `incrementalCache` and `tagCache` from `OverrideOptions`; they are only
  configured under `cacheHandler`. `resolveIncrementalCache` and
  `resolveTagCache` follow. The esbuild resolve plugin keeps its own fields, so
  adapter `defaultOverrides` are unaffected.
- Move tag revalidation - `hasBeenRevalidated`, `writeTags` and CDN
  invalidation - out of `adapters/cache.ts`, `composable-cache.ts` and
  `cacheInterceptor.ts` and into the cache handler, which now applies them in
  `get`, `set` and `revalidateTags`.
- `Cache.get` takes the additional tags to check, so the caller no longer needs
  the tag cache to resolve them.
- `defineCloudflareConfig` wires `cache` to the `OpenNextCache` entrypoint and
  moves the incremental cache, the tag cache and the cdn invalidation to
  `cacheHandler`; `ensureCloudflareConfig`, `populateCache` and
  `isPurgeCacheEnabled` read the new location.
- Examples move to `cache: "local"` with a `cacheHandler` block.

BREAKING CHANGE: `default.override.incrementalCache` and
`default.override.tagCache` are replaced by the top level `cacheHandler` option
and `default.override.cache`.
@conico974
conico974 force-pushed the conico/cache-4-swr-port branch from 18f4542 to 8672cf3 Compare August 16, 2026 13:47
Ports opennextjs-aws #1122 and #1142 on top of the cache handler function.

- Tags carry optional `stale` and `expire` durations: `writeTags` accepts a
  `{ tag, stale, expire }` input as well as a plain name, `OriginalTagCache`
  entries gained the same fields, and both tag cache flavours gained an optional
  `isStale`.
- `Cache.revalidateTags` takes the durations; the cache handler function turns
  the `expire` delay into a timestamp, callers pass it through unchanged.
- The composable cache handler implements `updateTags`, added in Next.js 16.
- New per-request `RequestCache` on the OpenNext request context, so overrides
  can deduplicate work within a request without touching global state, and
  `globalThis.nextVersion` is injected in the esbuild banner.
- DynamoDB, fs-dev and the Cloudflare D1 / KV / sharded DO tag caches are
  updated for the new signatures.
@vicb
vicb added this pull request to stack #52 September 21, 2026 07:15
Base automatically changed from conico/cache-3-consolidate to main September 23, 2026 17:28
Copilot AI lite review requested due to automatic review settings September 24, 2026 08:48
@vicb

vicb commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

@conico974 ChaptGPT helped rebased the PR and fix a few findings.

Could you please double check the additional commits

Report

  • Merged origin/main and resolved the conflicts while preserving the newer mainline cache-handler split.
  • Addressed all three PR review threads:
    • Preserved the revalidatedAt: 1 sentinel for newly associated cache tags.
    • Prevented original-mode DynamoDB SWR records from hard-invalidating before expiry.
    • Prevented next-mode DynamoDB and filesystem SWR records from hard-invalidating before expiry.
  • Restored SWR behavior dropped by the merge: composable-cache stale handling, cache-handler stale reads, duration transport, and Next.js 16 updateTags.
  • Fixed additional review findings in separate commits: filesystem original-mode SWR handling, request-local caching of missing DynamoDB tags, indefinite SWR handling, malformed duration validation, lightweight DynamoDB handling, and superseded expiry handling.
  • Added focused regression coverage for each corrected behavior.

Detailed Updates

a5bdec3a - Merge origin/main

  • Merged the current main branch into the PR branch before reviewing or modifying the feature.
  • Resolved the textual conflict in create-cloudflare/next/wrangler.jsonc consistently with main, where the obsolete generated example had been removed.
  • Retained the current mainline cache architecture, in which cache-service request handling lives in packages/core/src/adapters/cache-handler.ts rather than the older combined cache-adapter.ts implementation.
  • Audited the merge for semantic conflicts because Git could not detect behavior from the PR that had been implemented against the replaced cache architecture. The following commits restore that behavior explicitly.

f4c250a1 - Restore composable-cache stale handling

  • Restored the bridge between the cache service's stale marker and Next.js' composable cache API.
  • When the cache service returns lastModified: 1, ComposableCache.get now returns revalidate: -1, instructing Next.js to serve the cached value as stale and regenerate it rather than treating it as fresh.
  • This also preserves the revalidatedAt: 1 sentinel behavior discussed in the PR review: newly associated tags do not immediately hard-invalidate an entry, while stale entries still trigger background regeneration.
  • Added a unit test that supplies a stale cache-service response and verifies the resulting composable-cache entry has revalidate: -1.

e1b99d6d - Restore stale tag-cache reads

  • Reintroduced stale-state evaluation in the new cache handler after hard-revalidation checks complete.
  • Calls the configured tag cache's isStale implementation with the cache key and timestamp in original mode, or with the entry's tags and timestamp in next mode.
  • Marks a stale response with lastModified: 1 instead of returning a cache miss. This allows stale-while-revalidate to serve the existing entry while the composable cache requests regeneration.
  • Added tests for both original and next tag-cache modes, including extraction of next-mode tags from x-next-cache-tags metadata.

621c25b2 - Propagate tag revalidation durations

  • Extended the shared Cache.revalidateTags contract to accept optional { expire?: number } SWR durations.
  • Forwarded durations through all cache transports: local in-process events, the generic HTTP fetch transport, and the Cloudflare service binding transport.
  • Added ComposableCache.updateTags, which is used by newer Next.js versions for duration-aware tag updates, while retaining expireTags for immediate invalidation and compatibility.
  • Updated the core Cache.revalidateTag API to pass durations through when present without changing the payload shape of legacy calls that omit them.
  • Updated /cache/revalidate-tags to convert the relative expiry in seconds into absolute millisecond timestamps. Duration-aware writes set stale to the current time and optionally set expire; legacy writes remain immediate hard invalidations by setting expire to the current time.
  • Applied the same timestamp conversion in original mode, next mode, and propagated hard-tag invalidations caused by soft tags.
  • Generalized writeTags to accept the complete WriteTagInput union so duration-bearing tag records remain typed through the write path.
  • Added transport tests for local, fetch, and Cloudflare service caches, plus handler tests for timestamp conversion in original and next modes.

9c738196 - Preserve original-mode DynamoDB SWR entries before expiry

  • Replaced the original DynamoDB adapter's classification logic with a dedicated hasHardRevalidation helper.
  • A record now causes blocking regeneration only when it is newer than the cached entry and either represents an immediate hard revalidation or has reached an SWR expiry newer than that entry.
  • A duration-bearing record whose expiry is still in the future no longer produces -1; it remains available to the separate stale check and can be served stale.
  • Added unit coverage proving that a future expiry is not a hard invalidation and an elapsed expiry is.

f4c03c27 - Preserve next-mode SWR entries before expiry

  • Applied the same hard-versus-stale distinction to the next-mode DynamoDB adapter.
  • Updated the next-mode filesystem adapter so hasBeenRevalidated does not report a duration-bearing record as a hard invalidation until its expiry is reached.
  • Kept isStale responsible for identifying records inside the SWR window, separating stale serving from blocking regeneration.
  • Added DynamoDB and filesystem tests for both the active SWR window and the post-expiry hard-invalidation state.

7570c319 - Preserve original-mode filesystem SWR entries before expiry

  • Corrected the original-mode development filesystem adapter, which still treated every newer tag record as a hard invalidation regardless of its SWR expiry.
  • getLastModified now ignores duration-bearing records while their expiry is in the future and returns -1 after expiry.
  • Added tests showing that an entry is served stale before expiry and hard-invalidated after expiry.

08b80e10 - Cache missing next-mode DynamoDB tags per request

  • Changed the request-local DynamoDB item cache to store null for queried tags that do not exist, rather than caching only returned records.
  • Added cacheDynamoItems to map batch responses back to every requested tag and cache both hits and misses.
  • This prevents repeated BatchGetItem requests for the same absent tag when hasBeenRevalidated and isStale run during one request.
  • Preserved the positive-match behavior for returned records and shared the cached result between both checks.
  • Added a test that verifies an absent tag is explicitly represented by null in the request cache.

3becbc01 - Support SWR tags without expiry

  • Defined { durations: {} } as an indefinite stale-while-revalidate window rather than an immediate hard invalidation.
  • Updated original and next-mode DynamoDB classification so a newer record with a stale timestamp but no expire timestamp remains stale indefinitely.
  • Updated both filesystem tag-cache modes with the same behavior.
  • Preserved legacy hard invalidation for records that have neither stale nor expiry metadata.
  • Added regression tests for indefinite SWR in original DynamoDB, next-mode DynamoDB, original filesystem, and next-mode filesystem implementations.

82d483d3 - Validate tag revalidation durations

  • Changed request parsing so durations is treated as untrusted input rather than being accepted through a TypeScript assertion.
  • Rejects non-object values, arrays, non-numeric expiry values, non-finite numbers, and negative expiry values with HTTP 400 before writing tags.
  • Accepts an empty duration object as the intentional indefinite-SWR form and emits a stale timestamp without an expiry.
  • Added parameterized invalid-input tests and a successful no-expiry test.

07d8931d - Format cache review fixes

  • Applied the repository formatter to source and test files changed during the review.
  • This commit is formatting-only and contains no intended behavioral change.
  • Keeping it separate leaves the functional findings individually reviewable while making pnpm fmt pass.

1d60cf8d - Preserve lightweight DynamoDB SWR entries without expiry

  • Audited the separate dynamodb-lite implementation after fixing the primary DynamoDB adapters and found the same indefinite-SWR classification bug.
  • Added a typed hasHardRevalidation helper equivalent to the original-mode behavior: future and indefinite SWR records remain stale, elapsed SWR records block, and legacy revalidations block immediately.
  • Replaced the previous overlapping expired/non-expired filters with the helper, making the decision path explicit and consistent with the full adapter.
  • Added regression coverage for an indefinite SWR record in the lightweight adapter.

cfae0bf6 - Ignore superseded SWR expirations

  • Added an early revalidation-timestamp guard to next-mode DynamoDB hard-invalidation checks.
  • An old SWR record whose expiry has elapsed no longer invalidates a cache entry generated after that revalidation event.
  • Applied the equivalent ordering guard to next-mode filesystem records before evaluating expiry or legacy hard invalidation.
  • Added DynamoDB and filesystem tests where the SWR expiry is in the past but the cached entry is newer than the revalidation, confirming that the superseded record is ignored.

Deviations

  • Conflict resolution preferred main for overlapping cache architecture, then ported the PR's SWR delta onto cache-handler.ts; retaining the feature branch's obsolete combined cache-adapter.ts implementation would have regressed main.
  • Cloudflare D1, KV, and sharded Durable Object tag caches continue to document that duration metadata is unsupported. The SWR changeset is scoped to core and AWS, so persisted Cloudflare storage formats were not expanded in this PR.
  • A standalone formatting commit was required because repository formatting was checked after the finding-specific commits.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Unresolved critical staleness handling and multiple moderate AWS, Cloudflare, and release compatibility issues remain.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 High severity · 6 Medium severity

Open (7)
What changed in this PR

Ports SWR tag revalidation into the cache-handler stack across core, AWS, and Cloudflare adapters.

Changes:

  • Adds stale/expiry metadata and Next.js 16 updateTags support.
  • Adds request-scoped cache deduplication and stale response handling.
  • Updates cache overrides, tag caches, transports, and tests.
File Reviewed change
packages/​tests-unit/​tests/​overrides/​tag-cache/​next-mode.test.ts Tests next-mode SWR behavior.
packages/​tests-unit/​tests/​overrides/​tag-cache/​fs-dev.test.ts Tests filesystem SWR behavior.
packages/​tests-unit/​tests/​overrides/​tag-cache/​dynamodb.test.ts Tests DynamoDB expiry behavior.
packages/​tests-unit/​tests/​overrides/​cache/​local.test.ts Tests duration forwarding.
packages/​tests-unit/​tests/​overrides/​cache/​fetch.test.ts Tests HTTP duration forwarding.
packages/​tests-unit/​tests/​core/​routing/​cacheInterceptor.test.ts Tests stale response handling.
packages/​tests-unit/​tests/​adapters/​composable-cache.test.ts Tests stale entries and updateTags.
packages/​tests-unit/​tests/​adapters/​cache-adapter.test.ts Tests duration validation and conversion.
packages/​core/​src/​utils/​requestCache.ts Adds per-request cache storage.
packages/​core/​src/​utils/​promise.ts Initializes request cache context.
packages/​core/​src/​utils/​cache.ts Adds stale checks and duration-aware writes.
packages/​core/​src/​types/​overrides.ts Extends tag-cache and cache interfaces.
packages/​core/​src/​types/​global.ts Adds request cache context typing.
packages/​core/​src/​types/​cache.ts Adds updateTags.
packages/​core/​src/​overrides/​tagCache/​fs-dev.ts Adds filesystem SWR metadata handling.
packages/​core/​src/​overrides/​tagCache/​fs-dev-nextMode.ts Adds next-mode SWR handling.
packages/​core/​src/​overrides/​tagCache/​dummy.ts Adds dummy stale behavior.
packages/​core/​src/​overrides/​cache/​local.ts Forwards revalidation durations locally.
packages/​core/​src/​overrides/​cache/​fetch.ts Forwards revalidation durations remotely.
packages/​core/​src/​core/​routing/​cacheInterceptor.ts Serves stale entries and queues revalidation.
packages/​core/​src/​build/​helper.ts Injects Next.js version metadata.
packages/​core/​src/​build/​generateOutput.ts Updates override extraction commentary.
packages/​core/​src/​adapters/​composable-cache.ts Implements stale results and updateTags.
packages/​core/​src/​adapters/​cache.ts Accepts revalidation durations.
packages/​core/​src/​adapters/​cache-handler.ts Validates and applies SWR durations.
packages/​cloudflare/​src/​api/​overrides/​tag-cache/​tag-cache-filter.ts Updates tag filtering for structured inputs.
packages/​cloudflare/​src/​api/​overrides/​tag-cache/​kv-next-tag-cache.ts Updates KV tag writes.
packages/​cloudflare/​src/​api/​overrides/​tag-cache/​kv-next-tag-cache.spec.ts Adjusts KV mocks.
packages/​cloudflare/​src/​api/​overrides/​tag-cache/​do-sharded-tag-cache.ts Updates sharded DO tag writes.
packages/​cloudflare/​src/​api/​overrides/​tag-cache/​d1-next-tag-cache.ts Updates D1 tag writes.
packages/​cloudflare/​src/​api/​overrides/​tag-cache/​d1-next-tag-cache.spec.ts Adjusts D1 mocks.
packages/​cloudflare/​src/​api/​overrides/​internal.ts Normalizes structured tag inputs.
packages/​cloudflare/​src/​api/​overrides/​cache/​service-cache.ts Forwards revalidation durations.
packages/​cloudflare/​src/​api/​overrides/​cache/​service-cache.spec.ts Tests service duration forwarding.
packages/​aws/​src/​overrides/​tagCache/​dynamodb.ts Adds DynamoDB SWR logic and request caching.
packages/​aws/​src/​overrides/​tagCache/​dynamodb-nextMode.ts Adds next-mode DynamoDB SWR handling.
packages/​aws/​src/​overrides/​tagCache/​dynamodb-lite.ts Adds lightweight DynamoDB SWR handling.
.changeset/​swr-tag-revalidation.md Documents the feature release.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/core/src/core/routing/cacheInterceptor.ts Outdated
Comment thread .changeset/swr-tag-revalidation.md
Comment thread packages/aws/src/overrides/tagCache/dynamodb-lite.ts Outdated
Comment thread packages/aws/src/overrides/tagCache/dynamodb.ts Outdated
Comment thread packages/cloudflare/src/api/overrides/internal.ts
Comment thread packages/cloudflare/src/api/overrides/tag-cache/tag-cache-filter.ts Outdated
Comment thread packages/cloudflare/src/api/overrides/tag-cache/tag-cache-filter.ts Outdated
vicb added 11 commits September 28, 2026 11:31
Replace the lastModified=1 transport sentinel with explicit isStale metadata. Preserve generation times through Next cache adapters, request context, queue messages, and deduplication; retain revalidatedAt=1 for newly associated tags.

Patch Next incremental-cache results to consume the stale flag for fetches and routes, including revalidate:false, while preserving blocking invalidation. Test against installed Next source plus wire parsing, adapters, the interceptor, and Cloudflare queue timestamp comparisons.

Verification: pnpm fmt:fix, pnpm lint:fix, pnpm ts:check, pnpm test. Addresses Copilot discussion_r4091697951.
Require a newer stale timestamp and an unexpired or indefinite SWR window instead of treating every DynamoDB query result as stale. This excludes legacy hard invalidations, delayed writes for superseded events, and elapsed windows.

Share queried records between lightweight hard and stale checks, re-evaluating expiry rather than caching a time-dependent classification. Add 16 adapter-level cases across SDK and lightweight backends, asserting one query per request.

Verification: formatter, linter, workspace type checks and full tests passed. Addresses Copilot discussion_r4091698102 and discussion_r4091698162.
Keep filterFn string-based and normalize only the predicate argument. Forward accepted write objects unchanged so stale and expiry metadata reach the backend. This also fixes ordinary invalidation objects, not just SWR.

Add mixed-input runtime coverage and a TypeScript semantic check of the consumer test under strictFunctionTypes, since the package build excludes specs. All formatting, lint, type checks and full tests pass. Addresses discussion_r4091698333.
Delegate optional isStale calls through withFilter, preserving the backend receiver and entry timestamp. Do not call the backend for an empty filtered tag list or advertise support when the backend has no stale method.

Add regression coverage for positive delegation, excluded tags, receiver binding, and absent support. Formatting, lint, type checks and full tests pass. Addresses discussion_r4091698274.
Establish an OpenNext request context when a cache service invocation has no caller context. Preserve existing local contexts and waitUntil so GET hard/stale checks can share request-local DynamoDB records without leaking across invocations.

Cover concurrent standalone request isolation and local context reuse. Update the test context fixture with RequestCache. Formatting, lint, workspace type checks and full tests pass.
Distinguish DynamoDB UnprocessedKeys from confirmed missing records before populating the request cache. Retry only pending keys with bounded exponential backoff and throw after three retries rather than treating unread invalidation records as absent.

Retain processed hits and misses for reuse between hard and stale checks. Test mixed partial responses, retry payloads, shared results, and retry exhaustion without poisoned negative cache entries. Formatting, lint, type checks and full tests pass.
Mirror the existing original-mode owning-path hard-invalidation fallback when checking tag staleness. Fetch entries without explicit hard tags now inherit an active stale window from the owning path, retaining their generation timestamp.

Add paired tests proving the fallback applies without hard tags and stays disabled when an explicit hard tag is supplied. Formatting, lint, type checks and full tests pass.
Reject duration-aware tag invalidations before D1, KV, or sharded Durable Object mutations instead of discarding stale and expiry metadata and silently performing a hard invalidation. Continue accepting plain tags and structured hard invalidations.

Mark unsupported operations structurally so the cache handler can return HTTP 501 across bundle boundaries, expose the reason through the cache transport, and surface it from local, fetch, and Cloudflare service clients. Document the limitation and cover each backend and transport. Formatting, lint, type checks, full tests, and focused tests pass.
Apply the repository formatter to the installed-Next tag staleness regression added during review. This is formatting-only and fixes the remote fmt check; runtime behavior and assertions are unchanged.
Preserve the unsupported-operation marker when local, fetch, and Cloudflare service cache clients reconstruct cache-handler failures. Rethrow marked failures from the incremental and composable Next adapters while continuing to tolerate ordinary cache errors.

Update the core max-profile E2E to wait for background SWR regeneration and the Cloudflare E2E to verify unsupported SWR leaves cached content unchanged rather than silently hard-invalidating it. Add marker propagation tests. Code checks, full unit tests, selected builds, and focused core/Cloudflare E2E tests pass.
Treat an explicit expire duration of zero as immediate hard invalidation and omit stale metadata. This preserves the supported structured hard-write shape for Cloudflare tag caches while positive and indefinite durations remain SWR and are rejected there.

Cover both next and original tag-cache modes. Code checks, full unit tests, and the focused Cloudflare revalidateTag/after E2E tests pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants