feat(core): purge Workers Caching on content/chrome writes#1380
feat(core): purge Workers Caching on content/chrome writes#1380scottbuscemi wants to merge 1 commit into
Conversation
Cloudflare Workers Caching (cache: { enabled: true } in Wrangler) sits
in front of the Worker and serves HITs without running it, so a long
Cache-Control max-age on public pages would serve stale HTML after edits
until the TTL lapsed — EmDash had no hook into that platform cache.
Add an optional, opt-in edge-cache invalidator that purges Workers
Caching on writes, the HTML-layer analogue of the existing data-cache
invalidation. Off by default; enable with the `edgeCache` adapter:
import { workersCache } from "@emdash-cms/cloudflare";
emdash({ database: d1({ binding: "DB" }), edgeCache: workersCache() });
- Core: EdgeCacheInvalidator interface + descriptor + virtual:emdash/edge-cache
module + EmDashConfig.edgeCache. invalidateEdgeCache() is coalesced (one
purge per tick) and deferred via after() (never blocks the write), and
no-ops when unconfigured.
- Cloudflare: workersCache() config + a runtime backend that calls
cache.purge({ purgeEverything: true }) from cloudflare:workers, with
feature-detection so it's a safe no-op on Node/older runtimes. The purge
runs from the default entrypoint (where writes and public pages live), so
it hits the page cache.
- Wired at the write seams: content (ContentRepository), menus and bylines
(their repositories), and piggybacked onto the existing settings,
taxonomy, and redirect/slug invalidations.
v1 uses purgeEverything; tag-based purging is planned behind the same
config. Independent of cloudflareCache() (Astro route cache) and the
data/object cache.
Tests: purge is deferred and coalesced, fires on content create and on a
settings write, no-ops when unconfigured; the CF backend calls
cache.purge and no-ops when cache.purge is unavailable.
🦋 Changeset detectedLatest commit: 9cd41d1 The changes in this PR will be included in the next version bump. This PR includes changesets to release 14 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
emdash-playground | 9cd41d1 | Jun 08 2026, 05:13 AM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
docs | 9cd41d1 | Jun 08 2026, 05:10 AM |
Scope checkThis PR changes 631 lines across 20 files. Large PRs are harder to review and more likely to be closed without review. If this scope is intentional, no action needed. A maintainer will review it. If not, please consider splitting this into smaller PRs. See CONTRIBUTING.md for contribution guidelines. |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-demo-cache | 9cd41d1 | Jun 08 2026, 05:11 AM |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
PR template validation failedPlease fix the following issues by editing your PR description:
See CONTRIBUTING.md for the full contribution policy. |
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
|
Is this just the same as the Astro route cache? withastro/astro#16335 |
What does this PR do?
Adds optional purging of Cloudflare Workers Caching on content and chrome writes.
Workers Caching (the platform cache enabled with
cache: { enabled: true }in Wrangler) sits in front of the Worker and serves HITs without running it — so a longCache-Controlmax-age on public pages would otherwise serve stale HTML until the TTL lapses. When configured, EmDash now purges that cache on writes, so edits appear without waiting for TTL.Off by default. Enable with the
edgeCacheadapter:and enable the platform cache in
wrangler.jsonc("cache": { "enabled": true }) with a cacheableCache-Controlon public responses.v1 uses
purgeEverything: any content or chrome write (content create/update/delete/publish/unpublish/schedule, settings, taxonomies, menus, bylines, slug-change redirects) triggers a singlecache.purge({ purgeEverything: true }). Purges are deferred viaafter()(never block the write response) and coalesced (a bulk import collapses into one purge, respecting the zone purge rate limit). On non-Cloudflare runtimes or older runtimes withoutcache.purge, it's a safe no-op. Tag-based purging (purge only affected pages) is planned behind the same config.Independent of, and complementary to, the Astro route cache (
cloudflareCache()) and the data/object cache: Workers Caching (HTML, in front) → Worker → data cache → DB. Existing sites are unaffected until they opt in.Closes #
Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change) — core edge-cache + cloudflare edge-purge suites (10 passed)pnpm formathas been runAI-generated code disclosure
Screenshots / test output