dex/src/sw.js
chris 2e4572428a Dense-data pass: training/breeding facts, STAB coverage, filters, cries
- Detail About tab: EV yield, base EXP, catch rate + ~%, base friendship,
  growth rate + total EXP, held items; Breeding block with a gender-ratio
  bar, egg groups, egg cycles/steps
- Stats tab: 'STAB coverage (attacking)' — types the Pokemon's STAB hits
  hard / is walled by (data/type-chart.js offensiveSummary)
- Feed: Type and Generation filter dropdowns + a Random button; cards now
  resolve typings for the selected game's generation via snapshot pastTypes
- Recently-viewed strip on the feed (ui.recent, capped at 12)
- Play-cry button on the detail hero; service worker caches PokeAPI cries

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-28 10:06:36 -04:00

54 lines
1.6 KiB
JavaScript

/**
* Service worker (Workbox, injectManifest mode).
*
* - App shell + the PokéAPI snapshot are precached (offline launch, instant
* list / search / game switching).
* - Lazy detail JSON from pokeapi.co: stale-while-revalidate, 30-day TTL.
* - Sprites from the PokeAPI sprites repo: cache-first, capped LRU.
*/
import { precacheAndRoute } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { StaleWhileRevalidate, CacheFirst } from 'workbox-strategies';
import { ExpirationPlugin } from 'workbox-expiration';
import { CacheableResponsePlugin } from 'workbox-cacheable-response';
precacheAndRoute(self.__WB_MANIFEST || []);
const MONTH = 30 * 24 * 60 * 60;
registerRoute(
({ url }) => url.origin === 'https://pokeapi.co',
new StaleWhileRevalidate({
cacheName: 'pokeapi-json',
plugins: [
new CacheableResponsePlugin({ statuses: [0, 200] }),
new ExpirationPlugin({
maxEntries: 1500,
maxAgeSeconds: MONTH,
purgeOnQuotaError: true,
}),
],
}),
);
registerRoute(
({ url }) =>
url.origin === 'https://raw.githubusercontent.com' &&
(url.pathname.includes('/PokeAPI/sprites/') || url.pathname.includes('/PokeAPI/cries/')),
new CacheFirst({
cacheName: 'pokeapi-img',
plugins: [
new CacheableResponsePlugin({ statuses: [0, 200] }),
new ExpirationPlugin({
maxEntries: 600,
maxAgeSeconds: MONTH,
purgeOnQuotaError: true,
}),
],
}),
);
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') self.skipWaiting();
});