UNPKG

edge-master

Version:
113 lines (112 loc) 4.16 kB
import { InterceptorType } from '../types/interceptor'; /** * Creates a request interceptor that checks the cache */ export function cacheCheckInterceptor(options = {}) { const { cacheKey = (req) => req.url, cacheGetOnly = true, cacheName = 'default', } = options; return { type: InterceptorType.Request, async intercept(ctx) { const req = ctx.reqCtx.req; // Skip cache for non-GET requests if configured if (cacheGetOnly && req.method !== 'GET') { return req; } try { const cache = caches.default || await caches.open(cacheName); const cacheKeyStr = cacheKey(req); const cachedResponse = await cache.match(cacheKeyStr); if (cachedResponse) { // Found in cache, short-circuit with cached response ctx.responder(cachedResponse); } } catch (error) { // Cache API not available or error - continue without cache console.warn('Cache check failed:', error); } return req; }, }; } /** * Creates a response interceptor that stores responses in cache */ export function cacheStoreInterceptor(options = {}) { const { ttl = 3600, cacheKey = (req) => req.url, cacheControl, cacheGetOnly = true, shouldCache = (_req, res) => res.status === 200, cacheName = 'default', } = options; return { type: InterceptorType.Response, async intercept(ctx) { const req = ctx.reqCtx.req; const res = ctx.res; // Skip cache for non-GET requests if configured if (cacheGetOnly && req.method !== 'GET') { return res; } // Check if response should be cached if (!shouldCache(req, res)) { return res; } try { const cache = caches.default || await caches.open(cacheName); const cacheKeyStr = cacheKey(req); // Clone response for caching const responseToCache = res.clone(); // Add cache control headers const headers = new Headers(responseToCache.headers); if (cacheControl) { headers.set('Cache-Control', cacheControl); } else { headers.set('Cache-Control', `public, max-age=${ttl}`); } const cachedResponse = new Response(responseToCache.body, { status: responseToCache.status, statusText: responseToCache.statusText, headers, }); // Store in cache (fire and forget) ctx.reqCtx.exeCtx?.waitUntil(cache.put(cacheKeyStr, cachedResponse)); } catch (error) { // Cache API not available or error - continue without caching console.warn('Cache store failed:', error); } return res; }, }; } /** * Creates both cache check and store interceptors */ export function cacheInterceptor(options = {}) { return { check: cacheCheckInterceptor(options), store: cacheStoreInterceptor(options), }; } /** * Helper to generate cache keys based on URL and query parameters */ export function cacheKeyFromUrl(req, includeQuery = true) { const url = new URL(req.url); if (includeQuery) { return url.href; } return `${url.origin}${url.pathname}`; } /** * Helper to generate cache keys based on URL and specific query parameters */ export function cacheKeyWithParams(req, params) { const url = new URL(req.url); const searchParams = new URLSearchParams(); params.forEach(param => { const value = url.searchParams.get(param); if (value !== null) { searchParams.set(param, value); } }); const queryString = searchParams.toString(); return `${url.origin}${url.pathname}${queryString ? '?' + queryString : ''}`; }