Skip to content

[pull] main from jsr-io:main - #129

Merged
pull[bot] merged 1 commit into
code:mainfrom
jsr-io:main
Aug 27, 2026
Merged

[pull] main from jsr-io:main#129
pull[bot] merged 1 commit into
code:mainfrom
jsr-io:main

Conversation

@pull

@pullpullBot commented Aug 27, 2026

Copy link
Copy Markdown

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 : )

Fixes#1455.
### The bug
The lb keys R2-backed responses under a namespace of their own, because
`/@scope/...` is served as *either* a module file (bucket) or an HTML
page (frontend) depending on request headers, and the two must not
cross-serve. That namespace was a synthetic host:
`https://bucket-cache.jsr.internal/<host><path>`.
Cloudflare's purge-by-URL API only accepts URLs inside the zone, so
every publish-time purge of `https://jsr.io/@scope/pkg/meta.json` missed
the key the manifest was actually cached under. The result is exactly
what was reported: R2 had the regenerated `meta.json`, a cache-busting
query string returned the correct `latest`, but the edge kept serving
the previous copy until its TTL lapsed. `_meta.json` and the version
page were live the whole time, while Deno's resolver — which reads
`meta.json` — could not see the new version, and further publishes did
not dislodge it. The npm version manifest on `npm.jsr.io` had the same
gap.
(#1456 capped how *long* that lasts by dropping SWR and shortening
`s-maxage`; this makes the purge itself land, so a publish is visible
immediately rather than after the TTL.)
### The fix
Namespace bucket entries under a reserved path on the **public** origin
— `https://jsr.io/__bucket-cache/@scope/pkg/meta.json` — instead of a
synthetic host. The host is still part of the key, so the module and npm
buckets stay distinct, and the purge now has a URL inside the zone that
it can target.
`route` rejects inbound requests for the reserved prefix before any
backend, cache read, or cache write, so the namespace cannot be reached
— or poisoned — from outside.
The API mirrors the prefix (`s3_paths::BUCKET_CACHE_PREFIX`, kept in
sync with `lb/proxy.ts`) and purges both the public and the namespaced
form of each mutable manifest. The public URL still matters there: a
browser navigation to the same URL is served, and cached, by the
frontend.
Changing the key also orphans the current entries, so deploying this
clears any manifest that is stuck right now.
### Tests
- `s3_paths`: both purge helpers return the public URL *and* the
namespaced key.
- `lb/proxy_test.ts`: bucket cache keys live on the public origin under
the prefix, and the module vs. npm buckets stay keyed apart.
- `lb/main_test.ts`: `route` 404s the reserved namespace on all three
hosts without touching a backend, while a merely similar-looking path
routes normally.
`cargo clippy --all-targets` clean; `deno test` in `lb/` passes (43
tests).
@pullpullBot locked and limited conversation to collaborators Aug 27, 2026
@pull
pullBot merged commit 19ad24d into code:mainAug 27, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@crowlKats