Files
pnpm/pnpr
Juan Picado 6f11872579 feat(pnpr): revalidate stale packuments with conditional GET to upstream (#12239)
* feat(pnpr): revalidate stale packuments with conditional GET to upstream

When a cached upstream packument goes stale past its TTL, pnpr now
revalidates it with a conditional GET instead of unconditionally
re-downloading the body. The upstream's ETag / Last-Modified are stored
in a sidecar (.package.json.meta) next to the cached packument and
replayed as If-None-Match / If-Modified-Since on the next refresh. A
304 Not Modified serves the cached copy and bumps its mtime so the entry
is fresh again, saving the (often large) packument download — matching
verdaccio's uplink revalidation.

The per-request access log gains a `cache=` field
(hit / revalidated / miss / stale / hosted) so operators can see how each
packument read was served against the proxy cache.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(pnpr): cover packument cache storage and address review feedback

- Add storage-layer unit tests for the conditional-GET cache: validator
  sidecar round-trip, sidecar removal when validators are empty, malformed
  sidecar degrading to empty validators, and TTL freshness.
- Only treat an upstream 304 as NotModified when a conditional header was
  actually sent; an unconditional 304 (e.g. cold cache) now falls through
  to a status error instead of being mistaken for a usable cached copy.
- Move packument bytes out on the cache-hit path instead of cloning the
  (potentially multi-MB) document on every request.
- Un-ignore pnpr's `src/storage/` source dir: the monorepo-wide `storage`
  gitignore rule (for Verdaccio runtime data) was swallowing the new test
  file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(pnpr): cover packument cache storage and address review feedback

- Add storage-layer unit tests for the conditional-GET cache: validator
  sidecar round-trip, sidecar removal when validators are empty, malformed
  sidecar degrading to empty validators, and TTL freshness.
- Only treat an upstream 304 as NotModified when a conditional header was
  actually sent; an unconditional 304 (e.g. cold cache) now falls through
  to a status error instead of being mistaken for a usable cached copy.
- Move packument bytes out on the cache-hit path instead of cloning the
  (potentially multi-MB) document on every request.
- Un-ignore pnpr's `src/storage/` source dir: the monorepo-wide `storage`
  gitignore rule (for Verdaccio runtime data) was swallowing the new test
  file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(pnpr): defer stale packument body read; add `orphaned` cache status

- Read a stale cached packument's body lazily: `read_cached_packument_entry`
  now returns `Fresh(bytes)` or `Stale(validators)`, so the common
  stale->200 refresh no longer reads and allocates the (potentially
  multi-MB) old body. It's pulled on demand only on the 304 / upstream-error
  paths that actually need it.
- Record `cache=orphaned` (not `hit`) when serving a leftover mirror with no
  upstream left to revalidate against, since that path serves regardless of
  the TTL.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(pnpr): defer stale packument body read; add `orphaned` cache status

- Read a stale cached packument's body lazily: `read_cached_packument_entry`
  now returns `Fresh(bytes)` or `Stale(validators)`, so the common
  stale->200 refresh no longer reads and allocates the (potentially
  multi-MB) old body. It's pulled on demand only on the 304 / upstream-error
  paths that actually need it.
- Record `cache=orphaned` (not `hit`) when serving a leftover mirror with no
  upstream left to revalidate against, since that path serves regardless of
  the TTL.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(pnpr): defer stale packument body read; add `orphaned` cache status

- Read a stale cached packument's body lazily: `read_cached_packument_entry`
  now returns `Fresh(bytes)` or `Stale(validators)`, so the common
  stale->200 refresh no longer reads and allocates the (potentially
  multi-MB) old body. It's pulled on demand only on the 304 / upstream-error
  paths that actually need it.
- Record `cache=orphaned` (not `hit`) when serving a leftover mirror with no
  upstream left to revalidate against, since that path serves regardless of
  the TTL.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(pnpr): cover packument cache storage and address review feedback

- Add storage-layer unit tests for the conditional-GET cache: validator
  sidecar round-trip, sidecar removal when validators are empty, malformed
  sidecar degrading to empty validators, and TTL freshness.
- Only treat an upstream 304 as NotModified when a conditional header was
  actually sent; an unconditional 304 (e.g. cold cache) now falls through
  to a status error instead of being mistaken for a usable cached copy.
- Move packument bytes out on the cache-hit path instead of cloning the
  (potentially multi-MB) document on every request.
- Un-ignore pnpr's `src/storage/` source dir: the monorepo-wide `storage`
  gitignore rule (for Verdaccio runtime data) was swallowing the new test
  file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 00:38:11 +02:00
..