service-worker-cache-strategy-review
Reviews service-worker route-matching and caching-strategy choices (precache vs. cache-first vs. network-first vs. stale-while-revalidate) against request type and security sensitivity, rejecting uniform blanket strategies and flagging authenticated/PII responses cached in the Ca
Install
npx skills add https://github.com/VincentChuWaiChow/vanguard-frontier-agentic/tree/master/skills/frontend/service-worker-cache-strategy-review
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install vincentchuwaichow-vanguard-frontier-agentic@llmmart
git clone https://github.com/VincentChuWaiChow/vanguard-frontier-agentic.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole vincentchuwaichow/vanguard-frontier-agentic collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Service Worker Cache Strategy Review
Purpose
A service worker is a persistent, cross-session, JS-controlled cache layer that sits in front of every network request the browser makes for a scope. Unlike HTTP caching, it is not opt-in per response — once a route is matched, the developer's strategy code decides freshness and disclosure, not Cache-Control. The common failure mode is copy-pasting one strategy (usually CacheFirst, straight from a tutorial) across navigation, API, and asset routes without differentiating by freshness need or security sensitivity. This skill performs the per-route-class review that catches both the stale-content incidents that uniform cache-first causes on navigation/API routes, and the security incidents that happen when authenticated or PII-bearing responses land in a persistent Cache API store that Workbox strategies do not automatically protect.
When to use
Use this skill when the user asks to:
- review a service-worker file or Workbox config (
generateSW/injectManifest) for caching-strategy correctness, - debug reports of stale content after deploy, broken offline pages, or unexpectedly cached dynamic/API data,
- choose or validate a caching strategy per route class (navigation, API, static asset) before shipping,
- audit
scope/Service-Worker-Allowedcoverage and cache-versioning/cleanup behavior.
When not to use
- Manifest/installability review with no caching-behavior question — use
pwa-offline-readiness-reviewinstead. - General HTTP
Cache-Control/ETagheader review with no service worker involved — that is standard HTTP caching, a narrower and materially different concern than programmatic Cache API control.
Context7 Documentation Protocol
Workbox strategy internals and Vite-PWA config surface change between major versions — never assert runtime semantics (what bypasses HTTP headers, what revalidates, what the default expiration behavior is) from memory.
- Call
ToolSearchwith query"context7"(or"select:mcp__Context7__resolve-library-id,mcp__Context7__query-docs") to load the Context7 tools if not already loaded in this session. - Resolve
/googlechrome/workboxfor the strategy implementation in question (PrecacheStrategy,CacheFirst,NetworkFirst,StaleWhileRevalidate,NetworkOnly,ExpirationPlugin,cleanupOutdatedCaches). - Resolve
/websites/vite-pwa-org_netlify_app(or the closest match) when the project uses Vite PWA'sgenerateSW/injectManifestconfig surface,runtimeCaching,skipWaiting/clientsClaim, or custominjectManifestservice-worker source. - Query for the exact behavior before ruling — e.g. "does PrecacheStrategy revalidate against Cache-Control", "NetworkFirst networkTimeoutSeconds fallback behavior", "ExpirationPlugin maxAgeSeconds vs maxEntries eviction order" — per review, not once from a prior session.
- A confirmed, version-specific fact from Context7 (e.g.
precacheAndRouteserves viaPrecacheStrategy, which reads from the Cache API and returns immediately on a hit, completely bypassing HTTPCache-Controlsince no network round-trip occurs) is materially different from the general folk claim "precache is cache-first" — cite the specific mechanism, not the folk version. - If Context7 is unavailable or has no relevant match, fall back to
official_docs/references/workbox-strategy-semantics.md, and mark the claimdocumentation-based (Context7 unavailable)rather than presenting it as freshly verified. - Never invent a Workbox option, plugin, or config key that no queried source confirms.
Lean operating rules
- Classify every matched route into navigation/HTML, API/data (split further: read vs. write, public vs. authenticated), and static asset before judging any single strategy — a strategy is only correct or incorrect relative to its route class.
- Treat
PrecacheStrategy/precache-and-route as a distinct mechanism from runtimeCacheFirst— precache serves from the Cache API with no revalidation and no HTTPCache-Controlinvolvement at all; do not describe the two interchangeably. - Cache API only stores GET responses by spec — if a review encounters a manual
cache.put()on a non-GET request or response, treat that as a code smell requiring explanation, not a strategy question. - Any response containing
Set-Cookie, an echoedAuthorizationvalue, or clearly PII/payment-bearing JSON is a hard block on caching, regardless of the performance justification offered — recommendNetworkOnlyor explicit route exclusion instead. - Never accept "it's cached, so it's fast, so it's fine" as sufficient for navigation/HTML routes — blind cache-first strands users on a stale app shell after every deploy; require
StaleWhileRevalidateorNetworkFirstthere instead. - Flag
cache.put()on an opaque, cross-originno-corsresponse — the caller cannot inspect status or headers on an opaque response, so a poisoned or error response can be cached and served indefinitely with no visibility. - Verify
scope(registration time) andService-Worker-Allowed(response header, only needed when the script itself sits outside the desired scope) match the intended route coverage exactly — broader-than-needed scope expands blast radius for every finding above. - Verify a versioned cache-name scheme plus an
activate-event cleanup step (or Workbox'scleanupOutdatedCaches) exists, and thatskipWaiting/clients.claim()or a deliberate user-prompted update flow gets fixes to users in bounded time — otherwise caches grow unbounded and rollbacks/forward-fixes never land. - Query current Workbox/Vite-PWA docs (see Context7 Documentation Protocol) for the specific strategy/option in question before ruling; runtime semantics are version-sensitive and have changed across Workbox major versions.
- Label every claim as
live evidence,spec-cited,documentation-based, orinferenceso the reviewer knows what has actually been verified vs. reasoned about.
References
Load these only when needed:
- Workbox strategy semantics — use when confirming the exact runtime behavior of a specific strategy (precache vs.
CacheFirstvs.NetworkFirstvs.StaleWhileRevalidatevs.NetworkOnly), expiration/cleanup mechanics, or Vite-PWAgenerateSW/injectManifestwiring. - Route classification and strategy matrix — use when mapping a concrete route inventory to a strategy per class and justifying the mapping.
- Cache security and scope audit — use before endorsing any strategy change, when reviewing authenticated/PII route handling, opaque-response caching, or
scope/Service-Worker-Allowed/cache-versioning coverage.
Response minimum
Return, at minimum:
- the route classification (navigation / API read-public / API read-authenticated / API write / static asset) for every matched route pattern in scope,
- per-class strategy verdict with the Workbox-version-confirmed runtime semantics behind it,
- security flags (blocker severity) for any authenticated/PII response cached, any opaque cross-origin
cache.put(), or any scope broader than required, - cache-versioning and
activate-cleanup audit result, including whetherskipWaiting/clients.claim()or an equivalent update path exists, - verification steps (DevTools Application > Cache Storage inspection of actual cached entries, offline-throttle test) and a rollback note (cache-name version bump plan).
Files (vanguard-frontier-agentic)
-
references
-
cache-security-and-scope-audit.md 6 KB
# Cache Security and Scope Audit Use this reference before endorsing any caching-strategy addition or change, when reviewing authenticated/PII route handling, opaque cross-origin response caching, or `scope`/`Service-Worker-Allowed`/cache-versioning coverage. This is the hard-gate section of the skill — findings here are blockers, not style notes. ## What people get wrong The common bad assumption is: > "It worked fine when I tested it, so the caching is safe." Wrong, and dangerously so for shared/multi-account devices. A service worker's Cache API store is per-origin and persists across navigations and sessions — it has no built-in concept of "which user" a cached response belongs to. If an authenticated route (`/api/user`, `/api/account`, `/api/orders/:id`) is cached with any strategy that reads before checking identity, a single-session manual test will look correct while silently setting up cross-user data disclosure the moment a second user logs in on the same device without a full cache purge. This is not a hypothetical: it is the single most severe class of finding this skill exists to catch, and it is invisible to functional QA that only ever tests with one account. ## Non-negotiables - Do not endorse caching a response containing `Set-Cookie`, an echoed `Authorization` header/token value, or clearly PII/payment-bearing JSON, under any performance justification. The correct strategy for such a route is `NetworkOnly` or explicit exclusion from every `registerRoute`/`urlPattern` matcher — not a "short TTL" compromise. - Do not endorse a `scope` broader than the routes the service worker is meant to control. `scope` is set at `register()` time (`navigator.serviceWorker.register(url, { scope })`) and defines the maximum set of URLs the worker can intercept; a worker registered at `/` when it only needs to control `/app/` unnecessarily expands the blast radius of every other finding in this file. - `Service-Worker-Allowed` is a response header needed only when the service-worker *script* itself is served from a path outside the desired scope (e.g., script at `/sw.js` needs to control `/app/`, requiring the server to send `Service-Worker-Allowed: /app/` on the script response). Confirm it is present and no broader than necessary whenever the script path and intended scope diverge. - Flag `cache.put()` on an opaque (`no-cors`, cross-origin) response as an unreviewable-content risk per OWASP cache-poisoning guidance applied to Cache API misuse: an opaque response's status and headers cannot be inspected by the calling JS, so a `404`, an error page, or a compromised/poisoned upstream response can be cached and served as if it were a valid `200` indefinitely, with zero visibility from the caching code. - Do not accept "we'll purge the cache manually if this becomes a problem" as a mitigation for authenticated-data caching. There is no reliable trigger for "manually" here — the fix is not caching it in the first place. ## Minimal safe audit flow 1. Enumerate every route matcher and cross-reference against `route-classification-matrix.md` to identify which, if any, are classified authenticated/PII. 2. For every authenticated/PII route, confirm the applied strategy is `NetworkOnly` or that the route is excluded from all matchers (i.e., falls through to the browser's normal network path with no service-worker interception at all). 3. Open DevTools → Application → Cache Storage (or run the equivalent inspection command in an automated check) and manually inspect actual cached entries — do not trust config intent alone. Look for any entry whose URL matches an authenticated/PII route class, and for any response body containing session tokens, emails, names, or account identifiers that shouldn't be persisted client-side. 4. Confirm `scope` at registration matches the intended coverage, and `Service-Worker-Allowed` (if applicable) is no broader. 5. Confirm a versioned cache-name scheme exists (e.g., `app-cache-v3`) and that `activate` either calls `cleanupOutdatedCaches()` (Workbox precaching) or manually deletes cache keys not in the current manifest/version — an unbounded, unversioned cache cannot be reliably rolled back or purged. 6. Confirm any `cache.put()` call on a cross-origin request is not operating on an opaque response, or is explicitly justified and reviewed if it must be (e.g., a trusted, pinned third-party origin with documented risk acceptance). ## Adversarial checklist Before signing off on any caching-strategy change, answer these: - Is every authenticated/PII route verified excluded by inspecting actual cached entries in DevTools, not just by reading the strategy config? - If this device is shared or a second user logs in without a full logout/cache-clear, can any previously cached response leak across accounts? - Does `scope` match only what this worker needs to control, verified against the actual `register()` call, not assumed from the script's file location? - Is there a versioned cache-name and `activate`-time cleanup path, verified by checking that an old-version cache key actually gets deleted after a version bump — not just present in code but unexercised? - Is every `cache.put()` on a cross-origin request either non-opaque (`cors` mode with an inspectable response) or explicitly justified? If any of these cannot be answered from direct evidence (config read, DevTools inspection, or explicit user-provided confirmation), the finding is a residual risk, not a pass. ## When to push back Push back if the user asks for: - caching an authenticated API response "just for this one screen" to make it feel faster — the risk is identical regardless of scope of use, - a broader `scope` than the app actually needs "in case we add more routes later" — expand scope when the need is real, not speculatively, - skipping the DevTools cache-entry inspection step because "the config looks right" — config intent and actual cached content diverge often enough (matcher bugs, stale test data, prior strategy still in a live cache) that this step is not optional. -
route-classification-matrix.md 5.2 KB
# Route Classification and Strategy Matrix Use this reference when mapping a concrete route inventory (the actual `registerRoute`/`urlPattern` matchers in the service worker or Workbox config) to a caching strategy per class, and when a review needs to justify why one class gets a different strategy than another. ## What people get wrong The common bad assumption is: > "We picked a caching strategy for the service worker" — as if one strategy applies to the whole app. Wrong. A service worker's `fetch` handler intercepts every request type in its scope — HTML navigations, API calls, images, fonts, scripts — and each has a different freshness contract and a different security profile. A single copy-pasted strategy (almost always `CacheFirst`, lifted from a tutorial about caching fonts) applied uniformly is the single most common defect this skill exists to catch. It is not "faster" across the board; it is wrong for at least two of the four classes below in nearly every real app. ## Non-negotiable design rule: classify before you judge Before ruling on any single `registerRoute`/`runtimeCaching` entry, classify every matched route into one of these buckets. A strategy is only correct or incorrect *relative to its class* — there is no universally "best" strategy. ## Route class → strategy matrix | Route class | Example | Correct default strategy | Why | |---|---|---|---| | Static asset, content-hashed filename | `/assets/app.a1b2c3.js`, webfonts | Precache (`precacheAndRoute`) or `CacheFirst` with long `maxAgeSeconds` | Immutable — a content change produces a new URL, so serving a stale cached copy under the old URL is impossible by construction. | | Static asset, NOT content-hashed | `/logo.png`, `/favicon.ico` | `StaleWhileRevalidate` with `ExpirationPlugin` | Can change without a URL change; needs periodic revalidation, but instant-from-cache is still safe since content is non-sensitive. | | Navigation / HTML (app shell, document requests) | `/`, `/dashboard` (document destination) | `StaleWhileRevalidate` or `NetworkFirst` (short `networkTimeoutSeconds`) — never blind `CacheFirst` | Blind cache-first strands users on a stale app shell after every deploy, since the HTML entry point is how new asset references reach the client at all. | | API GET, public/non-sensitive | `/api/public-catalog` | `StaleWhileRevalidate` or `NetworkFirst` with short TTL (`ExpirationPlugin.maxAgeSeconds`) | Needs freshness bounded by business tolerance for staleness; non-sensitive, so caching itself is not a security concern — only staleness is. | | API GET, authenticated/PII-bearing | `/api/user`, `/api/account`, `/api/orders/:id` | `NetworkOnly`, or explicit exclusion from any `registerRoute` match entirely | Hard security block — see `cache-security-and-scope-audit.md`. No performance justification overrides this. | | API mutation (POST/PUT/PATCH/DELETE) | any write endpoint | Not cacheable by Cache API spec (GET-only); verify no workaround exists | If a manual `cache.put()` appears on a mutation response, that is a code smell requiring explanation on its own, independent of strategy choice. | | Cross-origin, third-party, `no-cors` | third-party widgets, uncontrolled CDNs | Avoid `cache.put()` on the resulting opaque response, or scope tightly with clear justification | Opaque responses cannot be inspected for status/headers — see `cache-security-and-scope-audit.md`. | ## Verification targets - Enumerate every `registerRoute`/`urlPattern` matcher in the file/config under review and assign it exactly one row from the matrix above — an unassignable route (matches nothing cleanly) is itself a finding: the matcher is probably too broad. - For each matcher, confirm the *matcher itself* is scoped correctly — a regex like `/^\/api\//` bundling public and authenticated endpoints under one strategy is a classification bug even before the strategy choice is evaluated. - Confirm no single strategy declaration (e.g., one `CacheFirst` block) is reused across more than one route class without an explicit justification for why that class's freshness/security needs happen to coincide. ## High-risk assumptions to kill - "One strategy for the whole app is simpler to maintain" — simplicity here trades directly against both stale-deploy incidents and cross-user data leakage; the per-class matrix is the actual minimum safe design, not an optional refinement. - "It's a GET request, so it's safe to cache" — GET-only is a Cache API constraint, not a security guarantee; `/api/user` is a GET and is exactly the kind of route that must never be cache-first. - "The tutorial cached fonts with CacheFirst, so CacheFirst is the safe default" — `CacheFirst` is only safe for the specific class (immutable/rarely-changing, non-sensitive) the tutorial was written for. ## When to push back Push back if the user asks to: - apply one strategy across the whole `fetch` handler "to keep the config simple," - cache an authenticated or account-scoped API route with any strategy other than `NetworkOnly`/exclusion, regardless of the performance rationale offered, - skip per-route classification because "it's basically all API calls" — read/write and public/authenticated are not the same bucket even when the URL prefix is shared. -
workbox-strategy-semantics.md 6.3 KB
# Workbox Strategy Semantics Use this reference when a review needs to confirm the exact runtime behavior of a caching strategy — precache vs. `CacheFirst` vs. `NetworkFirst` vs. `StaleWhileRevalidate` vs. `NetworkOnly` — or the Vite-PWA `generateSW`/`injectManifest` config surface that produces it, before ruling on whether it matches a route's freshness/security needs. ## What people get wrong The common bad assumption is: > "Precaching is just cache-first for build assets." Incomplete, and dangerous when carried into a security review. Per Workbox v7 source (`workbox-precaching/src/PrecacheStrategy.ts`, confirmed via Context7 against `/googlechrome/workbox`), `precacheAndRoute()` registers a `PrecacheRoute` whose `_handle` calls `handler.cacheMatch(request)` and **returns immediately on a hit — no network request, no revalidation, no HTTP involvement at all**. That is not "cache-first that also checks freshness sometimes" — it is a pure Cache API read with zero interaction with `Cache-Control`, `ETag`, or `Vary`. A runtime `CacheFirst` strategy is a different, separate mechanism: it also serves from cache on a hit, but falls through to a real network fetch (and populates the cache) on a miss. Treating the two as interchangeable in a finding misattributes which HTTP headers matter and which don't. > Version note: Workbox internals are version-sensitive. Confirm exact behavior against the installed Workbox major version via Context7 (`/googlechrome/workbox`) or the live `https://developer.chrome.com/docs/workbox/` docs before ruling — do not cite this file's summaries as the final word for an unverified version. ## Officially grounded strategy shape Per Workbox docs/source (Context7-confirmed): - **Precache (`precacheAndRoute`)** — build-time-known, content-hashed assets. Served from Cache API with no revalidation, no HTTP cache-control involvement. Correct only for immutable, versioned assets where the precache manifest itself is the freshness mechanism (a new manifest = new cache entries). - **`CacheFirst` (recipe/strategy)** — checks cache; on hit, returns immediately (no revalidation on hit, same as precache once cached); on miss, fetches network and populates cache. Per the Workbox Recipes README, this is "ideal for assets that rarely change, such as fonts or images" — not for anything that can change without a URL change. - **`StaleWhileRevalidate`** — serves the cached response immediately if present, then makes a network request in the background to update the cache for the *next* request. Balances performance and freshness; the response returned to this request can still be stale by one cycle. - **`NetworkFirst`** — attempts network first (optionally bounded by `networkTimeoutSeconds`); falls back to cache only on network failure/timeout. Appropriate for content that must be fresh when possible but should still work offline/flaky-network. - **`NetworkOnly`** — never touches the cache for this route. Use for anything that must never be served stale or never be persisted client-side (mutations, authenticated reads that are hard-blocked from caching). - **`ExpirationPlugin`** (`maxEntries`, `maxAgeSeconds`) — bounds a runtime cache's size/age; without it, a runtime cache used with `CacheFirst`/`StaleWhileRevalidate`/`NetworkFirst` grows unbounded. This does not apply to precache, which is version-bounded by the manifest itself. - **`cleanupOutdatedCaches`** (`workbox-precaching`) — removes precache caches from prior manifest versions on activate. Confirm this (or equivalent manual `activate`-event cache deletion, as shown in Vite-PWA's `injectManifest` example querying `manifestURLs` and deleting non-listed keys) is present before endorsing any precache-based strategy. ## Vite-PWA config surface (when in use) - `generateSW` strategy: `runtimeCaching` array maps `urlPattern` → `handler` (`'CacheFirst'`, `'NetworkFirst'`, `'StaleWhileRevalidate'`, `'NetworkOnly'`, etc.) + `options` (`cacheName`, `expiration`, `cacheableResponse`). Confirm every `runtimeCaching` entry's `urlPattern` is scoped tightly enough that it does not accidentally net authenticated API routes into a `CacheFirst` bucket meant for fonts/static assets. - `injectManifest` strategy: a custom `sw.ts`/`sw.js` source, precache manifest injected via `self.__WB_MANIFEST`. Review the custom source directly — Vite-PWA does not add any safety net here; every strategy choice, `activate` cleanup, and `skipWaiting`/`clientsClaim()` call is entirely the author's responsibility. - `clientsClaim()` + `self.skipWaiting()` — needed so a newly activated service worker takes control of open clients immediately rather than waiting for a full reload; absence of these (or an equivalent deliberate "update available, reload?" UX) means users can be stuck on stale app-shell logic indefinitely even after a successful deploy. ## Verification targets - Confirm the strategy name in code/config against this file's semantics table, then confirm current behavior via Context7 before finalizing — do not rely on the strategy's *name* alone (e.g., "NetworkFirst" implementations have varied `networkTimeoutSeconds` defaults across versions). - For any runtime-cached route, confirm an `ExpirationPlugin` (or Vite-PWA `expiration` option) is present with a `maxAgeSeconds`/`maxEntries` bound appropriate to the route's sensitivity and volatility. - For precache, confirm `cleanupOutdatedCaches` or equivalent manual `activate` cleanup runs so superseded manifest versions are purged. ## High-risk assumptions to kill - "Precache is basically cache-first" — precache bypasses HTTP entirely; runtime `CacheFirst` still makes a real network request on a cache miss. - "`StaleWhileRevalidate` means the user always gets fresh data" — the response served to the *current* request can be a stale copy; freshness only improves for the *next* request. - "No `ExpirationPlugin` is fine, the cache will sort itself out" — Cache API storage does not auto-evict; unbounded runtime caches grow until storage quota pressure causes browser-driven eviction, which is unpredictable and not a substitute for a deliberate policy. - "We use `generateSW`, so Vite-PWA handles safety for us" — `generateSW` only wires the strategy the author picked in `runtimeCaching`; it does not choose a safe strategy per route automatically or exclude authenticated routes on its own.
-
-
metadata.json 1.6 KB
{ "id": "service-worker-cache-strategy-review", "name": "Service Worker Cache Strategy Review", "type": "skill", "provider": "frontend", "harnesses": [ "claude-code", "cursor", "codex", "gemini", "kiro", "other" ], "summary": "Reviews service-worker route-matching and caching-strategy choices (precache vs. cache-first vs. network-first vs. stale-while-revalidate) against request type and security sensitivity, rejecting uniform blanket strategies and flagging authenticated/PII responses cached in the Cache API.", "source_type": "original", "official_docs": [ "https://developer.chrome.com/docs/workbox/", "https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API", "https://developer.mozilla.org/en-US/docs/Web/API/Cache", "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary", "https://web.dev/articles/service-worker-caching-and-http-caching", "https://owasp.org/www-community/attacks/Cache_Poisoning" ], "security_notes": "Hard-block caching of any response carrying Set-Cookie, an echoed Authorization value, or clearly PII/payment-bearing JSON without explicit, reviewed justification. Hard-block a service-worker scope broader than the routes it is meant to control unless justified. Flag cache.put() calls on opaque (no-cors) cross-origin responses as an unreviewable-content risk per OWASP cache-poisoning concerns. Do not paste real user session data, cookies, or authenticated response bodies into review examples.", "last_verified": "2026-07-02", "path": "skills/frontend/service-worker-cache-strategy-review", "author": "github: VincentChuWaiChow", "version": "0.1.0" } -
SKILL.md 7.9 KB
--- name: service-worker-cache-strategy-review description: Reviews service-worker route-matching and caching-strategy choices (precache vs. cache-first vs. network-first vs. stale-while-revalidate) against request type and security sensitivity, rejecting uniform blanket strategies and flagging authenticated/PII responses cached in the Cache API. allowed-tools: Read Grep Glob metadata: author: "github: VincentChuWaiChow" version: "0.1.0" updated: "2026-07-02" category: security --- # Service Worker Cache Strategy Review ## Purpose A service worker is a persistent, cross-session, JS-controlled cache layer that sits in front of every network request the browser makes for a scope. Unlike HTTP caching, it is not opt-in per response — once a route is matched, the developer's strategy code decides freshness and disclosure, not `Cache-Control`. The common failure mode is copy-pasting one strategy (usually `CacheFirst`, straight from a tutorial) across navigation, API, and asset routes without differentiating by freshness need or security sensitivity. This skill performs the per-route-class review that catches both the stale-content incidents that uniform cache-first causes on navigation/API routes, and the security incidents that happen when authenticated or PII-bearing responses land in a persistent Cache API store that Workbox strategies do not automatically protect. ## When to use Use this skill when the user asks to: - review a service-worker file or Workbox config (`generateSW`/`injectManifest`) for caching-strategy correctness, - debug reports of stale content after deploy, broken offline pages, or unexpectedly cached dynamic/API data, - choose or validate a caching strategy per route class (navigation, API, static asset) before shipping, - audit `scope` / `Service-Worker-Allowed` coverage and cache-versioning/cleanup behavior. ## When not to use - Manifest/installability review with no caching-behavior question — use `pwa-offline-readiness-review` instead. - General HTTP `Cache-Control`/`ETag` header review with no service worker involved — that is standard HTTP caching, a narrower and materially different concern than programmatic Cache API control. ## Context7 Documentation Protocol Workbox strategy internals and Vite-PWA config surface change between major versions — never assert runtime semantics (what bypasses HTTP headers, what revalidates, what the default `expiration` behavior is) from memory. 1. Call `ToolSearch` with query `"context7"` (or `"select:mcp__Context7__resolve-library-id,mcp__Context7__query-docs"`) to load the Context7 tools if not already loaded in this session. 2. Resolve `/googlechrome/workbox` for the strategy implementation in question (`PrecacheStrategy`, `CacheFirst`, `NetworkFirst`, `StaleWhileRevalidate`, `NetworkOnly`, `ExpirationPlugin`, `cleanupOutdatedCaches`). 3. Resolve `/websites/vite-pwa-org_netlify_app` (or the closest match) when the project uses Vite PWA's `generateSW`/`injectManifest` config surface, `runtimeCaching`, `skipWaiting`/`clientsClaim`, or custom `injectManifest` service-worker source. 4. Query for the exact behavior before ruling — e.g. "does PrecacheStrategy revalidate against Cache-Control", "NetworkFirst networkTimeoutSeconds fallback behavior", "ExpirationPlugin maxAgeSeconds vs maxEntries eviction order" — per review, not once from a prior session. 5. A confirmed, version-specific fact from Context7 (e.g. `precacheAndRoute` serves via `PrecacheStrategy`, which reads from the Cache API and returns immediately on a hit, completely bypassing HTTP `Cache-Control` since no network round-trip occurs) is materially different from the general folk claim "precache is cache-first" — cite the specific mechanism, not the folk version. 6. If Context7 is unavailable or has no relevant match, fall back to `official_docs` / `references/workbox-strategy-semantics.md`, and mark the claim `documentation-based (Context7 unavailable)` rather than presenting it as freshly verified. 7. Never invent a Workbox option, plugin, or config key that no queried source confirms. ## Lean operating rules - Classify every matched route into navigation/HTML, API/data (split further: read vs. write, public vs. authenticated), and static asset before judging any single strategy — a strategy is only correct or incorrect relative to its route class. - Treat `PrecacheStrategy`/precache-and-route as a distinct mechanism from runtime `CacheFirst` — precache serves from the Cache API with no revalidation and no HTTP `Cache-Control` involvement at all; do not describe the two interchangeably. - Cache API only stores GET responses by spec — if a review encounters a manual `cache.put()` on a non-GET request or response, treat that as a code smell requiring explanation, not a strategy question. - Any response containing `Set-Cookie`, an echoed `Authorization` value, or clearly PII/payment-bearing JSON is a hard block on caching, regardless of the performance justification offered — recommend `NetworkOnly` or explicit route exclusion instead. - Never accept "it's cached, so it's fast, so it's fine" as sufficient for navigation/HTML routes — blind cache-first strands users on a stale app shell after every deploy; require `StaleWhileRevalidate` or `NetworkFirst` there instead. - Flag `cache.put()` on an opaque, cross-origin `no-cors` response — the caller cannot inspect status or headers on an opaque response, so a poisoned or error response can be cached and served indefinitely with no visibility. - Verify `scope` (registration time) and `Service-Worker-Allowed` (response header, only needed when the script itself sits outside the desired scope) match the intended route coverage exactly — broader-than-needed scope expands blast radius for every finding above. - Verify a versioned cache-name scheme plus an `activate`-event cleanup step (or Workbox's `cleanupOutdatedCaches`) exists, and that `skipWaiting`/`clients.claim()` or a deliberate user-prompted update flow gets fixes to users in bounded time — otherwise caches grow unbounded and rollbacks/forward-fixes never land. - Query current Workbox/Vite-PWA docs (see Context7 Documentation Protocol) for the specific strategy/option in question before ruling; runtime semantics are version-sensitive and have changed across Workbox major versions. - Label every claim as `live evidence`, `spec-cited`, `documentation-based`, or `inference` so the reviewer knows what has actually been verified vs. reasoned about. ## References Load these only when needed: - [Workbox strategy semantics](references/workbox-strategy-semantics.md) — use when confirming the exact runtime behavior of a specific strategy (precache vs. `CacheFirst` vs. `NetworkFirst` vs. `StaleWhileRevalidate` vs. `NetworkOnly`), expiration/cleanup mechanics, or Vite-PWA `generateSW`/`injectManifest` wiring. - [Route classification and strategy matrix](references/route-classification-matrix.md) — use when mapping a concrete route inventory to a strategy per class and justifying the mapping. - [Cache security and scope audit](references/cache-security-and-scope-audit.md) — use before endorsing any strategy change, when reviewing authenticated/PII route handling, opaque-response caching, or `scope`/`Service-Worker-Allowed`/cache-versioning coverage. ## Response minimum Return, at minimum: - the route classification (navigation / API read-public / API read-authenticated / API write / static asset) for every matched route pattern in scope, - per-class strategy verdict with the Workbox-version-confirmed runtime semantics behind it, - security flags (blocker severity) for any authenticated/PII response cached, any opaque cross-origin `cache.put()`, or any scope broader than required, - cache-versioning and `activate`-cleanup audit result, including whether `skipWaiting`/`clients.claim()` or an equivalent update path exists, - verification steps (DevTools Application > Cache Storage inspection of actual cached entries, offline-throttle test) and a rollback note (cache-name version bump plan).
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.