# `caching-strategies/router.ts` ## Purpose `Router` evaluates incoming `Request`s against a list of registered routes in order and dispatches the first match to its strategy. The router is the glue between the SW `fetch` event and the package's caching strategies. It owns the default `Cache` and `fetcher` references so individual strategies stay free of global access — strategies receive their `StrategyContext` through the router and need not touch `caches`, `fetch`, or `Date.now`. ## Features - HTTP-method filtering (`GET`, `POST`, `PUT`, …) with case-insensitive comparison. - Three pattern types: `RegExp`, substring `string`, and predicate function (`(Request) => boolean`). - Per-route cache-name override so different routes can write to isolated caches without re-instantiating the router. - Fall-through to `fetcher(request)` for unmatched requests — the router is always safe to `respondWith()` because every request gets a response. - OTel `pwa_cache_strategy_ms` histogram recording strategy latency. ## Usage: Basic ```ts import { Router, cacheFirst, networkFirst, staleWhileRevalidate, } from "@suaveplan/pwa"; const router = new Router({ cacheName: "v1" }); router.registerRoute({ pattern: /\.(png|jpg|webp)$/, strategy: cacheFirst({ ttlMs: 86_400_000 }), }); router.registerRoute({ pattern: /\/api\/static\//, strategy: staleWhileRevalidate(), }); router.registerRoute({ method: "GET", pattern: /\/api\//, strategy: networkFirst({ ttlMs: 30_000 }), }); self.addEventListener("fetch", (event) => event.respondWith(router.handle(event.request)) ); ``` ## Usage: Advanced Per-route cache + predicate matching: ```ts import { Router, cacheOnly } from "@suaveplan/pwa"; const router = new Router(); router.registerRoute({ method: "GET", pattern: (req) => req.url.startsWith("/offline-fallback/"), strategy: cacheOnly(), cacheName: "offline-fallbacks", }); ``` ## API Reference - `new Router(options?: RouterOptions)`. - `registerRoute(route: Route): void`. - `handle(request: Request): Promise`. - `size: number`. - `Route` — `{ method?, pattern, strategy, cacheName? }`. - `RouterOptions` — `{ cacheStorage?, cacheName?, fetcher?, clock?, observability? }`. ## Implementation Notes The router opens caches lazily via `cacheStorage.open()` on every `handle()` call. The platform `CacheStorage.open()` is idempotent and returns the same underlying `Cache` instance for the same name, so the per-call open is a trivial pointer lookup rather than a heavy initialisation. The fall-through path bypasses both the cache open and the strategy invocation entirely, so unmatched requests pay no per-request cost beyond the linear route scan. For applications with hundreds of routes, the scan can be optimised by the caller via predicate matchers that group routes by URL prefix.