{"_id":"swimple","_rev":"21-409e3d5436eb9f92ebbce0da9fd2f580","name":"swimple","dist-tags":{"latest":"1.1.0"},"versions":{"0.1.0":{"name":"swimple","version":"0.1.0","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@0.1.0","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"7255236a6547b1ef6c3c70ae8b2c7210f6ed7924","tarball":"https://registry.npmjs.org/swimple/-/swimple-0.1.0.tgz","fileCount":6,"integrity":"sha512-hnQHYrD+ytFIKmtN8oISKc92dhiUe9dMecaPxZeeQqWsWQqKCYrhBEKLtrSuGrLPbk80Y1oJbLV0+HfllNAgSQ==","signatures":[{"sig":"MEUCIDwb5wRnRIVrTQtw2tCl43rD8QscqfwiR4jdbGC4X/i1AiEAshx1rKHuBTX8m/yq9CnSCJySgZ2fEA5kXz04eY1qNLo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":51931},"main":"index.js","type":"module","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":"./index.js"},"gitHead":"9b6f11b1b0c58e66c232b5dab3e5ed604a96af6a","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check ."},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_0.1.0_1767911114487_0.07570135071203943","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"swimple","version":"0.2.0","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@0.2.0","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"878fadffccfd0a141b8b8ab8bd0cd54b38b944a6","tarball":"https://registry.npmjs.org/swimple/-/swimple-0.2.0.tgz","fileCount":6,"integrity":"sha512-zGU9B8XKP2yHGFGfg9JTQ4e62Y6wA+5ZwOEdIRugT9upFEkWdCOTp0oZHsVWfsvyBn7FWwe8DYnQj87jJTydsw==","signatures":[{"sig":"MEUCIHEJpuB+0k+ruAhZ7DtHdu+gPgHGQvfAVUxLZIrm9OyfAiEAtqm9MJ/OI+F9RNxmolxZLGcMbi2qdwuu7RbnyfEJk/g=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":53922},"main":"index.js","type":"module","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":"./index.js"},"gitHead":"4cae706e2e72b926c66d596a9276059e37288c18","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check ."},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_0.2.0_1767930606277_0.30187811903424766","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"swimple","version":"0.3.0","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@0.3.0","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"2af4e3c9e12138009165d4ae3f1fb9f174b6fb5c","tarball":"https://registry.npmjs.org/swimple/-/swimple-0.3.0.tgz","fileCount":6,"integrity":"sha512-o/g4SfYhx4p7r18cjQJsNl5qDB/LZENlR3waWPa8CRiNk9M8GDQ/UCFvx06ncV357q1x0kcvflzSoxZal7ksNQ==","signatures":[{"sig":"MEYCIQCYBZ2gwg1RBiOaK/wtx8H/+bpQNahf/Ba9Hq0gvw/MAAIhAKXfEH+AdPZGu8+sFmojgaQSFG6KinpT7HWRNJZSlCTg","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":58170},"main":"index.js","type":"module","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":"./index.js"},"gitHead":"feeca88c2ccc01125989d04d2d0270edf2f1ca45","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check ."},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_0.3.0_1767971711329_0.44049293083181906","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"swimple","version":"0.4.0","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@0.4.0","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"e77d9243887b60be885222c3fc567cc22ca81b5d","tarball":"https://registry.npmjs.org/swimple/-/swimple-0.4.0.tgz","fileCount":6,"integrity":"sha512-uzjSBqdBXKpU1FnEvlKGjUQkZ0CAnXlrAcM8W7ZCSqbgvEQ6IrbYwjg8VTl1qWgjmZ2liH8jZmgCzGBc0bJ2Iw==","signatures":[{"sig":"MEQCIF//fgAmiCqxF7IToSoXiWIxdkTFB72jc1K7aBEw/mFsAiBQrVTEnX5mDlqIjChnhyfXwqtQo3DaiiCpFXIarP2hTg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":59425},"main":"index.js","type":"module","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":"./index.js"},"gitHead":"37c9a5a40b259b0d1fa2f289068680531ad5e642","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check ."},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_0.4.0_1767977739822_0.5245511888798311","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"swimple","version":"0.5.0","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@0.5.0","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"a3f6fc085d4b0c7beb392fe65ba532765af009bc","tarball":"https://registry.npmjs.org/swimple/-/swimple-0.5.0.tgz","fileCount":7,"integrity":"sha512-PsP/o0YWKC7MEeM3sUL/9uDpbgmvInz3idK+m4JJOdBSfkNH22904hYO4JqVwSORAa2VIJNNB78X3CgY9mf05Q==","signatures":[{"sig":"MEUCIH8nFGEXX7jxWfkfqxkEjPvggcZzyCalPN+HMzSbQ1zQAiEA7w1NK0zor4F5ZQ3N6ufpgKftmOIet8xvYct7GC4eoCA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":63015},"main":"index.js","type":"module","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":"./index.js","./headers":"./headers.js"},"gitHead":"7180e9f696337da82081a66efd8cab0dfd2202c3","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check ."},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_0.5.0_1767980835591_0.27325805931336733","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"swimple","version":"0.6.0","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@0.6.0","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"641db9d7db0e46aaf73499dc00572e1a7e3b4e2d","tarball":"https://registry.npmjs.org/swimple/-/swimple-0.6.0.tgz","fileCount":10,"integrity":"sha512-b/io36AsqAnAqleTym8rz8Mm2QSfdQtz516ceNj+bSmY7PY2cutNFt5bJBIeJhbu9aEXkDj3rdzrkF0ZfKxqiQ==","signatures":[{"sig":"MEUCIQDoWmBj9jX/2jwU1Vb0LhdpUs36nI9l5PfWt8pL+vEspwIgfENuxcDnsqNjpg87sdWVTvNtewQ39ktMqYvQ82Uc/K4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":71077},"main":"index.js","type":"module","types":"./index.d.ts","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":{"types":"./index.d.ts","default":"./index.js"},"./headers":{"types":"./headers.d.ts","default":"./headers.js"}},"gitHead":"7180e9f696337da82081a66efd8cab0dfd2202c3","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check .","prepublishOnly":"tsc --allowJs --declaration --emitDeclarationOnly --outDir ./ --skipLibCheck --target es2022 --module es2022 --moduleResolution node index.js headers.js helpers.js"},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","typescript":"^5.9.3","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_0.6.0_1767982428805_0.012363665014407443","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"swimple","version":"0.7.0","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@0.7.0","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"df3634f4360193733d0ac0cca1f37222ef1d6b4d","tarball":"https://registry.npmjs.org/swimple/-/swimple-0.7.0.tgz","fileCount":8,"integrity":"sha512-cMCpEjaW3MRdK6B/KKmZbTbDFtH1r5LTQfS3RUk7YGngIflGP0EdFVBgCmYzMgYo+MwdQoPy+P7KWlL9nfhbkQ==","signatures":[{"sig":"MEQCIFzuOQ3bQTDM0I8+uMUc+mMGbPVlj5wm2W2A8XMrglwFAiBOilXmOEaoSRHGzuwMsuiICs2TSX6swwNkgmgy2cGfCQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":74938},"main":"index.js","type":"module","types":"./index.d.ts","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":"./index.js","./headers":"./headers.js"},"gitHead":"8f68dca356a78504d94bea82dc770ddf4ac01c21","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check .","prepublishOnly":"tsc index.js headers.js helpers.js --declaration --allowJs --emitDeclarationOnly --outfile index.d.ts --target esnext"},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","typescript":"^5.9.3","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_0.7.0_1767994158529_0.41865793613894375","host":"s3://npm-registry-packages-npm-production"}},"0.8.0":{"name":"swimple","version":"0.8.0","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@0.8.0","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"f5984e662dc1e033a50e51408aa17d2e567dd79f","tarball":"https://registry.npmjs.org/swimple/-/swimple-0.8.0.tgz","fileCount":8,"integrity":"sha512-x5Drv2LX+K1hYWudw2qmjBnKeKFdPTO/7fWwFuMuUfAGighr/1yBdZCGDGbJS+014xD82r4BU13J0uhQRO348w==","signatures":[{"sig":"MEQCIGDp0kSRr8j2GDgTKZM6v/Ht9U8o4Mz9W1147z2Dc6K/AiBvDLbaAigwvVQlEiQYTbAO78itt2JVyR7cojNfOCOlZQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":75050},"main":"index.js","type":"module","types":"./index.d.ts","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":{"types":"./index.d.ts","default":"./index.js"},"./headers":{"types":"./index.d.ts","default":"./headers.js"}},"gitHead":"69dd9718c7fcdcb2b709124baab8313eef9a18de","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check .","prepublishOnly":"tsc index.js headers.js helpers.js --declaration --allowJs --emitDeclarationOnly --outfile index.d.ts --target esnext"},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","typescript":"^5.9.3","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_0.8.0_1767995756405_0.5024518587070637","host":"s3://npm-registry-packages-npm-production"}},"0.9.0":{"name":"swimple","version":"0.9.0","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@0.9.0","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"451c6cde1da4e36593022c1a0cc0dfaa7775683b","tarball":"https://registry.npmjs.org/swimple/-/swimple-0.9.0.tgz","fileCount":8,"integrity":"sha512-ZokrXgk7E58iyKhIplAOexSrdys2ebjwemkvEbN0BKLtp3X9YBzHxMptQ5fhdxoE3ymGj/qtihNVcoYJDlWZyg==","signatures":[{"sig":"MEUCIBXBHFuLcNilCDKOyy6TnIkvNxaD0ONU+hQFKdngvRwYAiEAmF62oXHlyv1Uk2jKNsaRLC4oLpdMHNyOU8PYKl2m/v8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":75056},"main":"index.js","type":"module","types":"./types.d.ts","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":{"types":"./types.d.ts","default":"./index.js"},"./headers":{"types":"./types.d.ts","default":"./headers.js"}},"gitHead":"e2c20d7a0676a8b3aaaf5926de8e857813efe891","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check .","prepublishOnly":"tsc index.js headers.js helpers.js --declaration --allowJs --emitDeclarationOnly --outfile types.d.ts --target esnext"},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","typescript":"^5.9.3","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_0.9.0_1767995920910_0.05689324843182475","host":"s3://npm-registry-packages-npm-production"}},"0.10.0":{"name":"swimple","version":"0.10.0","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@0.10.0","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"051a92060a32d9908130b63587da0bbc4a868e20","tarball":"https://registry.npmjs.org/swimple/-/swimple-0.10.0.tgz","fileCount":11,"integrity":"sha512-lIVhoIfmMpKC8efgzv42Lfa146Oz+Q2xfieaWAAeAd+kffcg2DKMgQxdEdYBrI8A4TrTnQMmoPo4Geozz9f5EQ==","signatures":[{"sig":"MEUCIQDQ3iFPqCwUb3zwcY5b4nCEFGYNZxbKrRi6VWyyJIyeawIgdv6060L+YbNMctUiRxawqBa52LUo+E4IU0ZDP9d1RUs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":74291},"main":"src/index.js","type":"module","types":"types/index.d.ts","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":{"types":"types/index.d.ts","default":"./src/index.js"},"./headers":{"types":"types/headers.d.ts","default":"./src/headers.js"}},"gitHead":"c8497d66594a66aab1a084ba0bf22dd839c20fe8","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check .","prepublishOnly":"tsc src/*.js --declaration --allowJs --emitDeclarationOnly --rootDir src --outDir types --target esnext"},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","typescript":"^5.9.3","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_0.10.0_1767996814185_0.6173017583776585","host":"s3://npm-registry-packages-npm-production"}},"0.11.0":{"name":"swimple","version":"0.11.0","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@0.11.0","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"b6a6f6596f8a6a41dfbf29f7a8104a1346a92f7b","tarball":"https://registry.npmjs.org/swimple/-/swimple-0.11.0.tgz","fileCount":11,"integrity":"sha512-hQ2jmG0i316bjlvTR5i6Zk7zRxVzQM+YaLr93n/L7UmZ6cjACuo87rAUBRLlebJn3rklh3/gRQuk+dxreVNi/g==","signatures":[{"sig":"MEUCIFl72pNKK4QV25233mOfPdMA0BvXjAcTT2HsM1EkFnGBAiEA5XFq7Rez7E/F4aOo0IJixZTnLrHaZ2dvIUDmhiNx/Og=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":74299},"main":"./src/index.js","type":"module","types":"./types/index.d.ts","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":{"types":"./types/index.d.ts","default":"./src/index.js"},"./headers":{"types":"./types/headers.d.ts","default":"./src/headers.js"}},"gitHead":"c8497d66594a66aab1a084ba0bf22dd839c20fe8","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check .","prepublishOnly":"tsc src/*.js --declaration --allowJs --emitDeclarationOnly --rootDir src --outDir types --target esnext"},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","typescript":"^5.9.3","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_0.11.0_1767996948635_0.03052010259048088","host":"s3://npm-registry-packages-npm-production"}},"0.12.0":{"name":"swimple","version":"0.12.0","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@0.12.0","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"1991f8d0cf6ede9e9205f4431f572f00ee108537","tarball":"https://registry.npmjs.org/swimple/-/swimple-0.12.0.tgz","fileCount":11,"integrity":"sha512-+qEVH/0bQI7Bi8wLhKoxo874za91L+RZl7B6taWSk77jXmQ29YzUmuBZnA5LzKEOFJvwght/OMpA/Z5cUBMxnA==","signatures":[{"sig":"MEQCIE1NWkROqkohW74Vi324m9ns7uKxeaVXyfmjggBmyWcSAiBuUlw7wT3uVhBA43ukOrBT0b8UjYZSE/n6AsePOeGVdA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":79700},"main":"./src/index.js","type":"module","types":"./types/index.d.ts","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":{"types":"./types/index.d.ts","default":"./src/index.js"},"./headers":{"types":"./types/headers.d.ts","default":"./src/headers.js"}},"gitHead":"51b9ee468fd0d4b56ee57296cc761cd520b35dd2","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check .","prepublishOnly":"tsc src/*.js --declaration --allowJs --emitDeclarationOnly --rootDir src --outDir types --target esnext"},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","typescript":"^5.9.3","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_0.12.0_1768192833369_0.26639157874614794","host":"s3://npm-registry-packages-npm-production"}},"0.12.1":{"name":"swimple","version":"0.12.1","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@0.12.1","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"e7b3aeb87db8719a23c186d7cdc2806816c1fc07","tarball":"https://registry.npmjs.org/swimple/-/swimple-0.12.1.tgz","fileCount":11,"integrity":"sha512-aja3aEoUqRzevBfMzw152zrQSHfuHhW0ixPiMGApBfaHtNO9ak3tKUI+sE/l2WZ7QPI5jCd7PYOT4VjIxLYv0w==","signatures":[{"sig":"MEUCIA+TVXAoqyI+KDWoJ0gGRcDtddaBDumjoDBITgFZiAI7AiEA8kA44Oq6WFWjtrBHwZNqJpPkgPG8NAd2zIHRT7GUk8M=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":79675},"main":"./src/index.js","type":"module","types":"./types/index.d.ts","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":{"types":"./types/index.d.ts","default":"./src/index.js"},"./headers":{"types":"./types/headers.d.ts","default":"./src/headers.js"}},"gitHead":"83457801f0d87f639f609500d9f45b3e868019aa","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check .","prepublishOnly":"tsc src/*.js --declaration --allowJs --emitDeclarationOnly --rootDir src --outDir types --target esnext"},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","typescript":"^5.9.3","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_0.12.1_1768193204048_0.18551470104991563","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"swimple","version":"1.0.0","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@1.0.0","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"64a36d627f9e2e13d0cae92dae10ae69ce61cd39","tarball":"https://registry.npmjs.org/swimple/-/swimple-1.0.0.tgz","fileCount":15,"integrity":"sha512-n71uuVku6A/wtLi7hqCBwV846g5uOLti8swf2tg8eYKq12eea+zMItFHacH3vt6lzpT+OcvQ+3NKv2gugfYrVA==","signatures":[{"sig":"MEQCIE2ZYar1EpVXCqR/mRsXuMUfdzCoSnXcVGbKfembdDVnAiA6FLJVmcYC7mAPvDpSAEGBHqNCVMi4C6G/XH9FiRT1kQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":110911},"main":"./src/index.js","type":"module","types":"./types/index.d.ts","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":{"types":"./types/index.d.ts","default":"./src/index.js"},"./headers":{"types":"./types/headers.d.ts","default":"./src/headers.js"}},"gitHead":"e3dae1fc046a36fb5d35e75946e0d87a7c262dc0","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check .","prepublishOnly":"tsc src/*.js --declaration --allowJs --emitDeclarationOnly --rootDir src --outDir types --target esnext"},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","typescript":"^5.9.3","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_1.0.0_1768324733210_0.646335878199108","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"swimple","version":"1.0.1","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@1.0.1","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"52571b02d7cc1b6aace9fe79e4c380383f1f1fc6","tarball":"https://registry.npmjs.org/swimple/-/swimple-1.0.1.tgz","fileCount":15,"integrity":"sha512-D+mfpPTKndGr5s7w3c3/MMwPzHwqbrJ9p/KFXa29uKG+NxOGlf0+51NZOkSpnRKpMSD1EBmoea4TXKwSY+P+MA==","signatures":[{"sig":"MEQCIHV+zsTXnnFpIqOgfkbgL0U6yfKoBNrN70viCqPghd6gAiBKdLyCYwGC2xN2sd31Y5bjfwJxCJhOsyUdV9QlPWtvwA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":114704},"main":"./src/index.js","type":"module","types":"./types/index.d.ts","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":{"types":"./types/index.d.ts","default":"./src/index.js"},"./headers":{"types":"./types/headers.d.ts","default":"./src/headers.js"}},"gitHead":"9cf3a0a65a4a0ca382c7aa293228a40e037afd70","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check .","prepublishOnly":"tsc src/*.js --declaration --allowJs --emitDeclarationOnly --rootDir src --outDir types --target esnext"},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","typescript":"^5.9.3","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_1.0.1_1768330815659_0.8697728197965207","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"swimple","version":"1.0.2","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@1.0.2","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"99a807a5ba16301246d59aa7b37c4d9e63cec0c6","tarball":"https://registry.npmjs.org/swimple/-/swimple-1.0.2.tgz","fileCount":17,"integrity":"sha512-VpmifqRm7kzIkI7MjeIar+N3dvddXuPzQJCydRHv484omv6C6crKYjerml1OQfA6NuJG+SAbYLaA3MvpeIWvIg==","signatures":[{"sig":"MEUCIQCJ8WO8aovu6UT7MnJr20etcVhboSozSnJOFDeeIHZ/PgIgb6WSd+lmTCYikHm4x/ZlmdN09cTRkidaOQ7T9uwl5sw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":134809},"main":"./src/index.js","type":"module","types":"./types/index.d.ts","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":{"types":"./types/index.d.ts","default":"./src/index.js"},"./headers":{"types":"./types/headers.d.ts","default":"./src/headers.js"}},"gitHead":"4e98d395a71953acef174a35a4357363ad9b2c5d","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check .","prepublishOnly":"tsc src/*.js --declaration --allowJs --emitDeclarationOnly --rootDir src --outDir types --target esnext"},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","typescript":"^5.9.3","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_1.0.2_1768495886216_0.2532657053551872","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"swimple","version":"1.0.3","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@1.0.3","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"e13ef1565da0127d0b0549b2418404cf8cd5f795","tarball":"https://registry.npmjs.org/swimple/-/swimple-1.0.3.tgz","fileCount":17,"integrity":"sha512-nAVgI2zcnhDIW7xHKxYncU3i7Ox0KEWMfIaTI/uXKIV39siR7rXEEz7If2PKY1jrg6NlRX8lHekitEzuYVt8BA==","signatures":[{"sig":"MEUCIAwBkEcD2LgzTSUr8QYQOQJsRiWd2dLfOdJX+eh/fBNsAiEAx4BWIS8Jdybcm4WSp2UHOPIufQAKkGNi8o8ivEjyNiw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":135441},"main":"./src/index.js","type":"module","types":"./types/index.d.ts","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":{"types":"./types/index.d.ts","default":"./src/index.js"},"./headers":{"types":"./types/headers.d.ts","default":"./src/headers.js"}},"gitHead":"b32cf274f05fb3339d831314007551d54a6fb362","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check .","prepublishOnly":"tsc src/*.js --declaration --allowJs --emitDeclarationOnly --rootDir src --outDir types --target esnext"},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","typescript":"^5.9.3","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_1.0.3_1770219894517_0.9258040989553349","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"swimple","version":"1.0.4","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@1.0.4","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"dist":{"shasum":"c959d28f2606547491e3fe8a726da88c10c41839","tarball":"https://registry.npmjs.org/swimple/-/swimple-1.0.4.tgz","fileCount":17,"integrity":"sha512-c0BlmcQvWZ/joePIWPOZQTz9RBPSWi3dmCwkCSLvHmVwqX2Ix/kvJlRmI/5OKyz9VsgKH7o+2OgQ6kabiz3zNQ==","signatures":[{"sig":"MEQCIFV7avmooPXsfLEYS//cz/g0SGZvksl1FkhzgJ/asqReAiAZlHAreekUWPgEinrctghvfHq8JXigt5attv739n9EBQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":135457},"main":"./src/index.js","type":"module","types":"./types/index.d.ts","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":{"types":"./types/index.d.ts","default":"./src/index.js"},"./headers":{"types":"./types/headers.d.ts","default":"./src/headers.js"}},"gitHead":"8d3bfefac53cfcb707df5d7d9619c481d07215d0","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check .","prepublishOnly":"tsc src/*.js --declaration --allowJs --emitDeclarationOnly --rootDir src --outDir types --target esnext"},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","typescript":"^5.9.3","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_1.0.4_1770237646324_0.8185077157907839","host":"s3://npm-registry-packages-npm-production"}},"1.0.5":{"name":"swimple","version":"1.0.5","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@1.0.5","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"homepage":"https://github.com/wes-goulet/swimple#readme","bugs":{"url":"https://github.com/wes-goulet/swimple/issues"},"dist":{"shasum":"46525b37bcfeb7376a273275306c2282eedc2686","tarball":"https://registry.npmjs.org/swimple/-/swimple-1.0.5.tgz","fileCount":17,"integrity":"sha512-wmkLP2vWzA0lCfe+JHkArptewTEUkCGoE+LowNYXzkFHduvGPFAgCAFz+bBiDnR8SNbmbvKmqcwoFP320HSNTA==","signatures":[{"sig":"MEYCIQCHZPKs7MD/QYvAJoHX66pw01RTM/6fxX0txmgi8D6GmQIhAOWu4lZ0X9EIwKLb0QuwvBsUn8eOa0BLBEGApEMwpUJT","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":135433},"main":"./src/index.js","type":"module","types":"./types/index.d.ts","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":{"types":"./types/index.d.ts","default":"./src/index.js"},"./headers":{"types":"./types/headers.d.ts","default":"./src/headers.js"}},"gitHead":"b281a2f01811f3bd72eacf681b7327295845782a","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check .","prepublishOnly":"tsc src/*.js --declaration --allowJs --emitDeclarationOnly --rootDir src --outDir types --target esnext"},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"repository":{"url":"git+https://github.com/wes-goulet/swimple.git","type":"git"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","typescript":"^5.9.3","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_1.0.5_1770309116475_0.11449639809713452","host":"s3://npm-registry-packages-npm-production"}},"1.0.6":{"name":"swimple","version":"1.0.6","keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","_id":"swimple@1.0.6","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"homepage":"https://github.com/wes-goulet/swimple#readme","bugs":{"url":"https://github.com/wes-goulet/swimple/issues"},"dist":{"shasum":"042c1fe7782dd463dc94c39ab3fb66f811fbf883","tarball":"https://registry.npmjs.org/swimple/-/swimple-1.0.6.tgz","fileCount":18,"integrity":"sha512-MaxXx5elgHF7/guPzq5KrN6X8cjUsbW7xhMpfuUnSG6dUDUXjwe8YwJxCByXh5RIAV0kkbAebPP1X+Jt6vc0Rw==","signatures":[{"sig":"MEQCIDC6CjkLxhj0Ndm4sU81UF0tqVGzSfDde/CNJ9FhMYtUAiANiA3gVKneCyFRxU2XfCBTKA8tYrBw46c6KdFcB4t7gw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":139890},"main":"./src/index.js","type":"module","types":"./types/index.d.ts","volta":{"node":"24.12.0"},"engines":{"node":">=24"},"exports":{".":{"types":"./types/index.d.ts","default":"./src/index.js"},"./headers":{"types":"./types/headers.d.ts","default":"./src/headers.js"}},"gitHead":"77f804cbf4edf2144b0905173d44f15b73163ded","scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:ui":"playwright test","test:e2e":"node --test tests/**/*.e2e.test.js","test:unit":"node --test tests/**/*.unit.test.js","format:fix":"prettier --write .","format:check":"prettier --check .","prepublishOnly":"tsc src/*.js --declaration --allowJs --emitDeclarationOnly --rootDir src --outDir types --target esnext"},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"repository":{"url":"git+https://github.com/wes-goulet/swimple.git","type":"git"},"_npmVersion":"11.6.2","description":"A simple service worker library for request caching","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.7.4","typescript":"^5.9.3","@playwright/test":"^1.57.0"},"_npmOperationalInternal":{"tmp":"tmp/swimple_1.0.6_1770310400222_0.37403219327488935","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"swimple","version":"1.1.0","description":"A simple service worker library for request caching","type":"module","main":"./src/index.js","types":"./types/index.d.ts","exports":{".":{"types":"./types/index.d.ts","default":"./src/index.js"},"./headers":{"types":"./types/headers.d.ts","default":"./src/headers.js"}},"scripts":{"test":"npm run test:unit && npm run test:e2e && npm run test:ui","test:unit":"node --test tests/**/*.unit.test.js","test:e2e":"node --test tests/**/*.e2e.test.js","test:ui":"playwright test","format:check":"prettier --check .","format:fix":"prettier --write .","prepublishOnly":"tsc src/*.js --declaration --allowJs --emitDeclarationOnly --rootDir src --outDir types --target esnext"},"keywords":["service-worker","cache","caching","sw","offline","pwa"],"author":{"name":"wes@goulet.dev"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/wes-goulet/swimple.git"},"devDependencies":{"@playwright/test":"^1.57.0","prettier":"^3.7.4","typescript":"^5.9.3"},"engines":{"node":">=24"},"volta":{"node":"24.12.0"},"gitHead":"6e289a8bd9844ab75a4018f852c347b63e2a3f8c","_id":"swimple@1.1.0","bugs":{"url":"https://github.com/wes-goulet/swimple/issues"},"homepage":"https://github.com/wes-goulet/swimple#readme","_nodeVersion":"24.12.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-PCM+0O2++KuSHE0ZfFV8Ob4Wh5NdvSCnWUmGLZ0Y9tgZqwYdu33WXrIMaWJR88PLP7GKMCMquCgHY+xz56ph2A==","shasum":"3fd12ac01713f0da7592fc139a842ef79f954195","tarball":"https://registry.npmjs.org/swimple/-/swimple-1.1.0.tgz","fileCount":18,"unpackedSize":146007,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCXhfHFdbdA11+0B+LK4w6zqKvSJatyHOkJJPSx1esv1gIhAIptP1VkHeVcWoWrz3JJmJmfa/rgFPFLCRiT93QYcJb1"}]},"_npmUser":{"name":"wes566","email":"wes@goulet.dev"},"directories":{},"maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/swimple_1.1.0_1771954293845_0.9728613691455785"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-08T22:25:14.486Z","modified":"2026-02-24T17:31:34.108Z","0.1.0":"2026-01-08T22:25:14.641Z","0.2.0":"2026-01-09T03:50:06.438Z","0.3.0":"2026-01-09T15:15:11.470Z","0.4.0":"2026-01-09T16:55:39.979Z","0.5.0":"2026-01-09T17:47:15.747Z","0.6.0":"2026-01-09T18:13:48.981Z","0.7.0":"2026-01-09T21:29:18.684Z","0.8.0":"2026-01-09T21:55:56.565Z","0.9.0":"2026-01-09T21:58:41.064Z","0.10.0":"2026-01-09T22:13:34.336Z","0.11.0":"2026-01-09T22:15:48.784Z","0.12.0":"2026-01-12T04:40:33.500Z","0.12.1":"2026-01-12T04:46:44.202Z","1.0.0":"2026-01-13T17:18:53.355Z","1.0.1":"2026-01-13T19:00:15.807Z","1.0.2":"2026-01-15T16:51:26.389Z","1.0.3":"2026-02-04T15:44:54.673Z","1.0.4":"2026-02-04T20:40:46.471Z","1.0.5":"2026-02-05T16:31:56.619Z","1.0.6":"2026-02-05T16:53:20.373Z","1.1.0":"2026-02-24T17:31:33.993Z"},"bugs":{"url":"https://github.com/wes-goulet/swimple/issues"},"author":{"name":"wes@goulet.dev"},"license":"MIT","homepage":"https://github.com/wes-goulet/swimple#readme","keywords":["service-worker","cache","caching","sw","offline","pwa"],"repository":{"type":"git","url":"git+https://github.com/wes-goulet/swimple.git"},"description":"A simple service worker library for request caching","maintainers":[{"name":"wes566","email":"wes@goulet.dev"}],"readme":"# swimple\n\nA simple service worker library for request caching.\n\n## Features\n\n- ⚡ **Low Configuration**: Request caching with automatic invalidation by default - minimal setup required\n- 🔄 **Smart Invalidation**: Automatically invalidate cache on mutations (POST/PATCH/PUT/DELETE)\n- 🎛️ **Flexible Strategies**: Support for cache-first, network-first, and stale-while-revalidate\n- 🪶 **Lightweight**: Single-purpose library with no dependencies\n- 🚀 **Modern**: Designed for ES module service workers (supported by all modern browsers as of January 2026)\n- 🔧 **Configurable**: Automatic caching by default, with per-request control\n\n## Installation\n\n### Direct CDN Import (Recommended)\n\n```javascript\n// sw.js\nimport { createHandleRequest } from \"https://cdn.jsdelivr.net/npm/swimple@1.1.0/src/index.js\";\n```\n\n### NPM Install\n\n```bash\nnpm install swimple\n```\n\n```javascript\n// sw.js\nimport { createHandleRequest } from \"swimple\";\n```\n\n## Quick Start\n\n> NOTE: This documentation focuses on modern browsers with module service workers support. If you aren't using module service workers, you can probably still use this with `importScripts` but I'll leave that to you to figure out.\n\n### 1. Register Your Service Worker\n\n```javascript\n// in javascript in index.html (or app.js or main.js or whatever frameworks use nowadays)\ntry {\n  await navigator.serviceWorker.register(\"/sw.js\", { type: \"module\" });\n} catch (error) {\n  console.error(\"Error registering module service worker:\", error);\n}\n```\n\n### 2. Set Up Request Handler in Service Worker\n\n```javascript\n// sw.js\nimport { createHandleRequest } from \"https://cdn.jsdelivr.net/npm/swimple@1.1.0/src/index.js\";\n\n// create the request handler\nconst handleRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  scope: [\"/api/\"] // this means only GET requests that start with /api/ will be cached\n});\n\nself.addEventListener(\"fetch\", (event) => {\n  const response = handleRequest(event);\n\n  if (response) {\n    event.respondWith(response);\n    return;\n  }\n\n  // fall through to other logic or just let the request go to network by doing nothing\n  return;\n});\n```\n\nThat's it! Your service worker will now cache GET requests that start with `/api/` using the default TTL of 300 seconds. Subsequent requests to the same path will return from the cache if the response is fresh (within the TTL). Any mutations (POST/PATCH/PUT/DELETE) will invalidate the cache. For example a PATCH request to `/api/users/123` will invalidate the cache for `/api/users/123` (ie: the details of that user) and `/api/users` (ie: the list of users that likely includes that user).\n\nAny requests outside the scope (ie: not starting with `/api/`) won't be processed by the cache handler (it will return null).\n\n## Configuring the request handler\n\nIf you want to use different defaults for all requests, you can pass in a config object to the `createHandleRequest` function.\n\n### Example 1: Network-First Strategy\n\n```javascript\nconst handleRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  scope: [\"/api/\"],\n  defaultStrategy: \"network-first\"\n});\n```\n\nWith network-first, requests always try the network first (even if cached and fresh). If the network fails and you're offline, it will return a cached response (if available and within the fresh or stale TTL). The cache is updated in the background when the network succeeds. This is useful when you want the latest data from the network when online, but still work offline with cached data.\n\n### Example 2: Stale-While-Revalidate Strategy\n\n```javascript\nconst handleRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  scope: [\"/api/\"],\n  defaultStrategy: \"stale-while-revalidate\"\n});\n```\n\nWith stale-while-revalidate, requests return from cache immediately if available. If the cache is fresh (within 300 seconds), it's returned without updating. If the cache is stale (past the fresh TTL but within the stale TTL of 3600 seconds), the stale response is returned immediately and the cache is updated in the background. If the cache is too stale (past the stale TTL) or missing, it fetches from network. This provides instant responses while keeping data fresh in the background.\n\n### Example 3: Skip Inferring Invalidations\n\n```javascript\nconst handleRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  scope: [\"/api/\"],\n  inferInvalidation: false\n});\n```\n\nWith inferInvalidation set to false, the library will not automatically invalidate the cache on mutation requests. You will need to manually invalidate the cache on mutation requests using the `X-SW-Cache-Invalidate` header.\n\n```javascript\nfetch(\"/api/users/123\", {\n  method: \"PATCH\",\n  headers: {\n    \"X-SW-Cache-Invalidate\": \"/api/users/123\"\n  }\n});\n```\n\nIf you need to invalidate multiple paths at once, you can set the `X-SW-Cache-Invalidate` header multiple times in a single request.\n\n```javascript\nconst headers = new Headers();\nheaders.append(\"X-SW-Cache-Invalidate\", \"/api/users\");\nheaders.append(\"X-SW-Cache-Invalidate\", \"/api/users/123\");\n\nfetch(\"/api/users/123\", {\n  method: \"PATCH\",\n  headers\n});\n```\n\n### Example 4: Custom Fetch Function\n\nYou can provide a custom fetch function to intercept and modify requests/responses. This is useful for handling authentication errors (e.g., 401/403 responses) or adding custom headers to all requests.\n\n```javascript\nconst handleRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  scope: [\"/api/\"],\n  customFetch: async (request) => {\n    const response = await fetch(request);\n\n    // Handle authentication errors\n    if (response.status === 401 || response.status === 403) {\n      // redirect to login page\n      // ...\n    }\n\n    return response;\n  }\n});\n```\n\nThe `customFetch` function has the same signature as the native `fetch` function. It will be used for all network requests made by the cache handler.\n\n### Example 5: Enable Logging\n\nYou can enable logging to debug cache behavior. The library supports three logging levels:\n\n- `\"none\"` (default): No logging\n- `\"minimal\"`: console.info logs cache hits and cache invalidation only\n- `\"verbose\"`: console.debug logs all events including cache misses, header usage, and cleanup\n\n```javascript\nconst handleRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  scope: [\"/api/\"],\n  loggingLevel: \"verbose\" // or \"minimal\" for less verbose output\n});\n```\n\nWith `loggingLevel: \"minimal\"`, you'll see:\n\n```\n[swimple] Cache hit: https://example.com/api/users\n[swimple] Cache invalidated: https://example.com/api/users/123\n```\n\nWith `loggingLevel: \"verbose\"`, you'll see all events:\n\n```\n[swimple] Cache hit: https://example.com/api/users\n[swimple] Cache miss: https://example.com/api/posts\n[swimple] X-SW-Cache-TTL-Seconds header set: 600 (https://example.com/api/users)\n[swimple] Cache invalidated: https://example.com/api/users/123\n[swimple] Cache entry cleaned up (maxAge): https://example.com/api/old-data\n```\n\nThis is useful for debugging cache behavior and understanding when requests are served from cache vs. network.\n\n## Clearing the cache on logout\n\nIt can be useful to clear the cache on logout or other events. You have two options:\n\n### Option 1: Header on each request\n\nSet the `X-SW-Cache-Clear` header on a request (any value will work—the header's presence triggers cache clearing).\n\n```javascript\nfetch(\"/api/logout\", {\n  method: \"POST\",\n  headers: {\n    \"X-SW-Cache-Clear\": \"true\" // Any value works - header presence triggers cache clear\n  }\n});\n```\n\n### Option 2: Configure in service worker (recommended for logout)\n\nUse `clearCacheRequests` to configure logout endpoints in one place. No need to modify each call site—just add the endpoint to your service worker config.\n\n```javascript\n// sw.js\nconst handleRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  scope: [\"/api/\"],\n  clearCacheRequests: [\n    { url: \"/api/logout\", method: \"POST\" },\n    { url: \"/api/logout\", method: \"GET\" },  // if your API uses GET for logout\n    { url: \"/api/session\", method: \"DELETE\" }\n  ]\n});\n```\n\nBoth options clear the entire cache for the cache name specified in the request handler configuration. Matching is by pathname (query params are ignored) and HTTP method.\n\n## Automatic Cache Cleanup\n\nThe library automatically cleans up cache entries that are older than `maxCacheAgeSeconds` (defaults to 7200 seconds). This prevents unbounded cache growth.\n\nCleanup happens in two ways:\n\n1. **Reactive cleanup**: When a cached entry is accessed and found to be older than `maxCacheAgeSeconds`, it's immediately deleted.\n2. **Periodic cleanup**: Every 100 fetches, the library scans the cache and removes all entries older than `maxCacheAgeSeconds`.\n\nIf the service worker restarts (which can happen at any time), cleanup runs again on the first fetch after restart, ensuring cleanup happens even if the service worker restarts frequently.\n\n### Manual Cleanup\n\nYou can also manually trigger cleanup in your service worker's `activate` handler:\n\n```javascript\n// sw.js\nimport { cleanupOldCacheEntries } from \"https://cdn.jsdelivr.net/npm/swimple@1.1.0/src/index.js\";\n\nself.addEventListener(\"activate\", (event) => {\n  event.waitUntil(\n    cleanupOldCacheEntries(\"api-cache-v1\", 7200) // cacheName, maxAgeSeconds\n  );\n});\n```\n\n## Understanding Fresh vs Stale TTL\n\n- **Fresh TTL** (`defaultTTLSeconds`): Responses within this time are considered \"fresh\". For `cache-first` and `stale-while-revalidate` strategies, fresh responses are returned from cache without background network updates.\n\n- **Stale TTL** (`defaultStaleTTLSeconds`): Responses past the fresh TTL but within the stale TTL are considered \"stale\". Stale responses can still be returned from cache:\n  - For `cache-first`: Used as a fallback when offline\n  - For `network-first`: Used as a fallback when offline\n  - For `stale-while-revalidate`: Returned immediately while updating in the background\n\nIf a response is past the stale TTL (or no stale TTL is set), it's too stale and must be fetched from the network.\n\n## API Reference\n\n### `createHandleRequest(config)`\n\nCreates a request handler function for your service worker fetch handler.\n\n#### Configuration Options\n\n| Option                   | Type       | Required | Default         | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |\n| ------------------------ | ---------- | -------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `cacheName`              | `string`   | Yes      | -               | Name of the cache, used when calling `Cache.open(cacheName)` internally. Changing this name effectively clears the previous cache entries.                                                                                                                                                                                                                                                                                                                                    |\n| `scope`                  | `string[]` | No       | `undefined`     | URL prefixes to cache by default (e.g., `['/api/']`). If not set and `defaultTTLSeconds` is set, all same-origin GET requests are cached automatically. If not set and `defaultTTLSeconds` is not set (or 0), no requests are cached by default. Individual requests outside the scope can still enable caching with `X-SW-Cache-TTL-Seconds` header. **Note:** Cross-origin requests are never cached, regardless of scope or TTL headers.                                   |\n| `defaultStrategy`        | `string`   | No       | `'cache-first'` | Default caching strategy: `'cache-first'`, `'network-first'`, or `'stale-while-revalidate'`.                                                                                                                                                                                                                                                                                                                                                                                  |\n| `defaultTTLSeconds`      | `number`   | No       | `300`           | Maximum age for fresh content. Fresh content will be returned from cache for cache-first and stale-while-revalidate strategies, and also from network-first when offline. Fresh content does not get updated from the network. Since this defaults to `300`, caching is automatic by default for GET requests matching the scope. Set to `0` or `undefined` to disable automatic caching (individual requests can still enable caching with `X-SW-Cache-TTL-Seconds` header). |\n| `defaultStaleTTLSeconds` | `number`   | No       | `3600`          | Maximum age for stale content. Stale content will be returned from cache for cache-first (when offline), network-first (when offline), and stale-while-revalidate strategies. That means responses past the fresh TTL but within stale TTL can still be returned from cache. Stale content does get updated from the network.                                                                                                                                                 |\n| `inferInvalidation`      | `boolean`  | No       | `true`          | Automatically invalidate cache on POST/PATCH/PUT/DELETE requests.                                                                                                                                                                                                                                                                                                                                                                                                             |\n| `customFetch`            | `function` | No       | `fetch`         | Custom fetch function to use for network requests. Receives a `Request` object and must return a `Promise<Response>`. Useful for handling authentication errors (401/403) or adding custom headers to all requests.                                                                                                                                                                                                                                                           |\n| `maxCacheAgeSeconds`     | `number`   | No       | `7200`          | Maximum age (in seconds) before cache entries are automatically cleaned up. Entries older than this age are deleted. Defaults to 7200 seconds (2 hours, which is 2x the default stale TTL). Cache entries are cleaned up reactively (when accessed) and periodically (every 100 fetches).                                                                                                                                                                                     |\n| `clearCacheRequests`    | `Array<{url: string, method: string}>` | No       | `[]`            | List of URLs and methods that trigger cache clearing when matched. Matches by pathname (ignores query params) and method. Useful for logout endpoints—configure once in the service worker instead of adding headers at each call site. Example: `[{ url: \"/api/logout\", method: \"POST\" }]`.                                                                                                                       |\n| `loggingLevel`           | `string`   | No       | `\"none\"`        | Logging level: `\"none\"` (no logging), `\"minimal\"` (cache hits and invalidation only), or `\"verbose\"` (all logging including misses, header usage, and cleanup). When enabled, logs are written to the console with the `[swimple]` prefix. Useful for debugging cache behavior.                                                                                                                                                                                               |\n\n#### Returns\n\nA request handler function `(event: FetchEvent) => Promise<Response> | null` that:\n\n- Returns a `Promise<Response>` if the request is handled by the cache handler\n- Returns `null` if the request should fall through to other handlers (e.g., when `X-SW-Cache-TTL-Seconds` is set to `0`, or when the request doesn't match the configured scope and has no TTL header)\n\n## HTTP Headers\n\nControl caching behavior on a per-request basis using these headers:\n\n### `X-SW-Cache-Strategy`\n\nOverride the default caching strategy for a specific request.\n\n**Values:**\n\n- `cache-first` - Return from cache if fresh (within TTL), otherwise fetch from network immediately. Stale cache is only used when offline (network request fails). No background updates.\n- `network-first` - Try network first, fall back to stale cache if offline (within stale TTL). Cache updated when network succeeds.\n- `stale-while-revalidate` - Return from cache immediately (fresh = no update, stale = update in background). Fetch from network if too stale or missing.\n\n**Example:**\n\n```javascript\nfetch(\"/api/users\", {\n  headers: {\n    \"X-SW-Cache-Strategy\": \"network-first\"\n  }\n});\n```\n\n### `X-SW-Cache-TTL-Seconds`\n\nSet the time-to-live (in seconds) used to validate a cached response when it's requested. The TTL is not stored with the cached response; only the timestamp of when it was cached is stored. Each request can specify a different TTL to use for validation.\n\n**Example:**\n\n```javascript\nfetch(\"/api/users\", {\n  headers: {\n    \"X-SW-Cache-TTL-Seconds\": \"600\" // Cache for 10 minutes\n  }\n});\n```\n\nTo completely opt out of caching for a specific request (the handler will return `null` and not process the request at all):\n\n```javascript\nfetch(\"/api/random\", {\n  headers: {\n    \"X-SW-Cache-TTL-Seconds\": \"0\" // Handler returns null\n  }\n});\n```\n\n**Important:** Setting TTL to `0` is a complete opt-out. The handler returns `null` immediately without checking cache, making network requests, or processing the request in any way.\n\n### `X-SW-Cache-Stale-TTL-Seconds`\n\nMaximum age before a cache entry is considered too stale to use. Used by `cache-first` (when offline), `network-first` (when offline) and `stale-while-revalidate` strategies.\n\n**How it works:**\n\n- **Fresh** (within TTL): Return from cache without background update\n- **Stale** (past TTL but within stale TTL): Return from cache and update in background (or use as offline fallback for cache-first and network-first)\n- **Too stale** (past stale TTL): Must fetch from network, not returned from cache\n\n**Example:**\n\n```javascript\nfetch(\"/api/users\", {\n  headers: {\n    \"X-SW-Cache-Strategy\": \"stale-while-revalidate\",\n    \"X-SW-Cache-TTL-Seconds\": \"300\", // Fresh for 5 minutes\n    \"X-SW-Cache-Stale-TTL-Seconds\": \"3600\" // Usable for 1 hour total\n  }\n});\n```\n\n**Timeline:**\n\n- 0-300s: Return from cache (fresh) - no background update\n- 300-3600s: Return from cache (stale) - update in background\n- 3600s+: Cache too stale - fetch from network\n\n### `X-SW-Cache-Invalidate`\n\nExplicitly invalidate specific cache entries. Can be set multiple times for multiple paths.\n\n**Important:** When `X-SW-Cache-Invalidate` headers are present, they **take precedence** over automatically inferred invalidation paths. If headers are provided, only the header-specified paths are invalidated - inferred paths are not added. This allows you to have fine-grained control over invalidation even when `inferInvalidation: true`.\n\n**Query Parameter Handling:** Invalidating a path (e.g., `/api/users`) will invalidate all cache entries with that pathname, regardless of query parameters. For example, invalidating `/api/users` will also invalidate `/api/users?org_id=123`, `/api/users?status=active`, and any other query parameter variants.\n\n**Example:**\n\n```javascript\nconst headers = new Headers();\nheaders.append(\"X-SW-Cache-Invalidate\", \"/api/users\");\nheaders.append(\"X-SW-Cache-Invalidate\", \"/api/users/123\");\nheaders.append(\"X-SW-Cache-Invalidate\", \"/api/teams\");\n\nfetch(\"/api/users/123\", {\n  method: \"PATCH\",\n  headers,\n  body: JSON.stringify(userData)\n});\n```\n\n**Example: Headers override inferred paths**\n\n```javascript\n// PATCH /api/users/123 with inferInvalidation: true\n// Without header, would invalidate: /api/users/123 AND /api/users\n// With header, only invalidates: /api/users (header takes precedence)\n\nfetch(\"/api/users/123\", {\n  method: \"PATCH\",\n  headers: {\n    \"X-SW-Cache-Invalidate\": \"/api/users\" // Only this path is invalidated\n  },\n  body: JSON.stringify(userData)\n});\n```\n\n### `X-SW-Cache-Clear`\n\nClear the entire cache. Typically used on logout to remove all user-specific cached data.\n\n**Important:** If this header is present (regardless of its value), the cache will be cleared.\n\n**Important behavior:**\n\n- When this header is present, the handler **always goes to network** - it does not check cache or return cached values\n- Stale responses are **never used**, even if offline\n- If the network request fails (e.g., offline), the error **bubbles up** to the caller\n- The cache is **always cleared** before making the network request, regardless of whether the network request succeeds or fails\n\n**Example:**\n\n```javascript\nfetch(\"/api/logout\", {\n  method: \"POST\",\n  headers: {\n    \"X-SW-Cache-Clear\": \"true\" // Any value works - header presence triggers cache clear\n  }\n});\n```\n\n**Note:** While this header is typically used on mutation requests (POST/PATCH/PUT/DELETE), if used on a GET request, it will still clear the cache and attempt to fetch from network. If the network fails, the error will propagate to the caller.\n\n## Header Constants\n\nFor convenience, swimple exports header name constants that you can use in your non-service-worker code (e.g., client-side JavaScript) to avoid hard-coding header names. This helps prevent typos and makes refactoring easier.\n\n### Importing Header Constants\n\n#### Node.js / npm Import\n\n```javascript\nimport {\n  CACHE_STRATEGY_HEADER,\n  CACHE_TTL_HEADER,\n  CACHE_STALE_TTL_HEADER,\n  CACHE_INVALIDATE_HEADER,\n  CACHE_CLEAR_HEADER\n} from \"swimple/headers\";\n\n// Use in your fetch calls\nfetch(\"/api/users\", {\n  headers: {\n    [CACHE_STRATEGY_HEADER]: \"network-first\",\n    [CACHE_TTL_HEADER]: \"600\"\n  }\n});\n```\n\n#### CDN Import\n\n```javascript\nimport {\n  CACHE_STRATEGY_HEADER,\n  CACHE_TTL_HEADER,\n  CACHE_STALE_TTL_HEADER,\n  CACHE_INVALIDATE_HEADER,\n  CACHE_CLEAR_HEADER\n} from \"https://cdn.jsdelivr.net/npm/swimple@1.1.0/src/headers.js\";\n\n// Use in your fetch calls\nconst headers = new Headers();\nheaders.set(CACHE_TTL_HEADER, \"300\");\nheaders.append(CACHE_INVALIDATE_HEADER, \"/api/users\");\nheaders.append(CACHE_INVALIDATE_HEADER, \"/api/posts\");\n\nfetch(\"/api/users/123\", {\n  method: \"PATCH\",\n  headers\n});\n```\n\n### Available Constants\n\n- `CACHE_STRATEGY_HEADER` - `\"X-SW-Cache-Strategy\"`\n- `CACHE_TTL_HEADER` - `\"X-SW-Cache-TTL-Seconds\"`\n- `CACHE_STALE_TTL_HEADER` - `\"X-SW-Cache-Stale-TTL-Seconds\"`\n- `CACHE_INVALIDATE_HEADER` - `\"X-SW-Cache-Invalidate\"`\n- `CACHE_CLEAR_HEADER` - `\"X-SW-Cache-Clear\"`\n\n**Note:** There is also an internal `CACHE_TIMESTAMP_HEADER` constant (`\"x-sw-cache-timestamp\"`), but this is used internally by the library and should not be set manually.\n\n### Detecting Cache Hits\n\n**Important:** Responses returned from cache will have the `x-sw-cache-timestamp` header set. Responses fetched from the network will **not** have this header (unless your server actually does set that header but that seems unlikely). The presence of this header is a reliable way to determine if a response came from cache or network.\n\n```javascript\nconst response = await fetch(\"/api/users\");\nconst isFromCache = response.headers.get(\"x-sw-cache-timestamp\") !== null;\n\nif (isFromCache) {\n  console.log(\"Response came from cache\");\n} else {\n  console.log(\"Response came from network\");\n}\n```\n\nThis works for all caching strategies:\n\n- **cache-first**: Cached responses (fresh or stale) will have the header\n- **network-first**: Cached responses returned as fallback will have the header\n- **stale-while-revalidate**: Cached responses (fresh or stale) will have the header\n\n## Caching Behavior\n\n### Automatic Caching (Default)\n\nSince `defaultTTLSeconds` defaults to `300`, caching is automatic by default. All GET requests matching the configured scope are cached automatically.\n\n```javascript\nconst handleRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  scope: [\"/api/\"]\n  // defaultTTLSeconds defaults to 300, so all /api/* GETs cached automatically\n});\n\n// Automatically cached with default TTL of 300 seconds\nfetch(\"/api/users\");\n\n// Completely opt out of caching for specific requests (handler returns null)\nfetch(\"/api/random\", {\n  headers: {\n    \"X-SW-Cache-TTL-Seconds\": \"0\"\n  }\n});\n```\n\n### Disabling Automatic Caching\n\nTo disable automatic caching, set `defaultTTLSeconds` to `0` or `undefined`. Individual requests can still enable caching with the `X-SW-Cache-TTL-Seconds` header.\n\n```javascript\nconst handleRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  scope: [\"/api/\"],\n  defaultTTLSeconds: 0 // Disable automatic caching\n});\n\n// Must explicitly enable caching per request\nfetch(\"/api/users\", {\n  headers: {\n    \"X-SW-Cache-TTL-Seconds\": \"300\"\n  }\n});\n```\n\n## Automatic Cache Invalidation\n\nWhen `inferInvalidation: true` (default), the library automatically invalidates relevant cache entries on mutation requests:\n\n| Request                 | Invalidates                               |\n| ----------------------- | ----------------------------------------- |\n| `POST /api/users`       | `GET /api/users`                          |\n| `PATCH /api/users/123`  | `GET /api/users/123` AND `GET /api/users` |\n| `PUT /api/users/123`    | `GET /api/users/123` AND `GET /api/users` |\n| `DELETE /api/users/123` | `GET /api/users/123` AND `GET /api/users` |\n\nThe library strips the last path segment to find the collection endpoint. This works for most REST API patterns, but may not handle all edge cases (e.g., nested resources like `/api/users/123/avatar`). For edge cases, you can manually specify invalidation paths using the `X-SW-Cache-Invalidate` header.\n\n**Query Parameter Handling:** Cache invalidation matches entries by pathname (ignoring query parameters). This means when you invalidate a path, all cache entries with that pathname are invalidated, regardless of their query parameters. For example, invalidating `/api/users` will also invalidate `/api/users?org_id=123`, `/api/users?status=active`, and any other query parameter variants. This ensures that when you update a resource (e.g., `PATCH /api/users/456`), all filtered views of the collection (e.g., `/api/users?org_id=123`) are also invalidated.\n\n**Note:** If you provide `X-SW-Cache-Invalidate` headers, they take precedence over inferred paths. Only the header-specified paths will be invalidated, not the inferred ones.\n\n**Example: Handling nested resources**\n\n```javascript\n// DELETE /api/users/123/avatar - inferred invalidation would only handle\n// /api/users/123/avatar and /api/users/123, but we also want to invalidate\n// /api/users since the user list might show avatar thumbnails\nconst headers = new Headers();\nheaders.append(\"X-SW-Cache-Invalidate\", \"/api/users/123/avatar\");\nheaders.append(\"X-SW-Cache-Invalidate\", \"/api/users/123\");\nheaders.append(\"X-SW-Cache-Invalidate\", \"/api/users\");\n\nfetch(\"/api/users/123/avatar\", {\n  method: \"DELETE\",\n  headers\n});\n```\n\n**Example: Query parameter invalidation**\n\n```javascript\n// Cache multiple filtered views of the users list\nfetch(\"/api/users\"); // Cached\nfetch(\"/api/users?org_id=123\"); // Cached separately\nfetch(\"/api/users?org_id=456&status=active\"); // Cached separately\n\n// PATCH /api/users/789 - automatically invalidates:\n// - /api/users/789 (exact item path)\n// - /api/users (collection, no query params)\n// - /api/users?org_id=123 (collection with query params)\n// - /api/users?org_id=456&status=active (collection with different query params)\n// All cache entries with pathname /api/users are invalidated\nfetch(\"/api/users/789\", {\n  method: \"PATCH\",\n  body: JSON.stringify({ name: \"Updated User\" })\n});\n```\n\nYou can disable automatic invalidation:\n\n```javascript\nconst handleRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  scope: [\"/api/\"],\n  inferInvalidation: false // Disable automatic invalidation\n});\n```\n\n## More Usage Examples\n\n### Example 1: Basic API Caching\n\n```javascript\n// sw.js\nimport { createHandleRequest } from \"swimple\";\n\nconst handleRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  scope: [\"/api/\"]\n});\n\nself.addEventListener(\"fetch\", (event) => {\n  const response = handleRequest(event);\n  if (response) {\n    event.respondWith(response);\n  }\n});\n\n// Client code\n// Cache user list for 10 minutes\nfetch(\"/api/users\", {\n  headers: {\n    \"X-SW-Cache-TTL-Seconds\": \"600\"\n  }\n});\n\n// Update user - automatically invalidates /api/users and /api/users/123\nfetch(\"/api/users/123\", {\n  method: \"PATCH\",\n  body: JSON.stringify({ name: \"Jane Doe\" })\n});\n```\n\n### Example 2: Automatic Caching with Custom TTL\n\n```javascript\n// sw.js\nconst handleRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  scope: [\"/api/\"],\n  defaultStrategy: \"cache-first\",\n  defaultTTLSeconds: 600 // Cache all API calls for 10 minutes\n});\n\nself.addEventListener(\"fetch\", (event) => {\n  const response = handleRequest(event);\n  if (response) {\n    event.respondWith(response);\n  }\n});\n\n// Client code\n// Automatically cached\nfetch(\"/api/users\");\n\n// Completely opt out of caching for specific request (handler returns null)\nfetch(\"/api/live-data\", {\n  headers: {\n    \"X-SW-Cache-TTL-Seconds\": \"0\"\n  }\n});\n```\n\n### Example 3: Stale-While-Revalidate\n\n```javascript\n// sw.js\nconst handleRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  scope: [\"/api/\"],\n  defaultStrategy: \"stale-while-revalidate\",\n  defaultTTLSeconds: 300, // Fresh for 5 minutes - return from cache without background update\n  defaultStaleTTLSeconds: 3600 // Stale for up to 1 hour - return from cache and update in background\n});\n\nself.addEventListener(\"fetch\", (event) => {\n  const response = handleRequest(event);\n  if (response) {\n    event.respondWith(response);\n  }\n});\n\n// Client code\n// Returns cached data immediately (fresh = no update, stale = update in background)\nfetch(\"/api/users\");\n```\n\n### Example 4: Multiple Scopes\n\n```javascript\n// sw.js\nconst handleRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  scope: [\"/api/\", \"/graphql/\", \"/data/\"],\n  defaultTTLSeconds: 300\n});\n\nself.addEventListener(\"fetch\", (event) => {\n  const response = handleRequest(event);\n  if (response) {\n    event.respondWith(response);\n  }\n});\n```\n\n### Example 5: Different Strategies for Different Scopes\n\nYou can compose multiple `handleRequest` methods to use different caching strategies for different scopes. For example, you might want `stale-while-revalidate` for static assets like fonts, and `cache-first` for API endpoints.\n\n```javascript\n// sw.js\nimport { createHandleRequest } from \"swimple\";\n\n// Handler for fonts - use stale-while-revalidate for instant loading\nconst handleFontsRequest = createHandleRequest({\n  cacheName: \"fonts-cache-v1\",\n  scope: [\"/fonts/\"],\n  defaultStrategy: \"stale-while-revalidate\",\n  defaultTTLSeconds: 86400, // Fresh for 24 hours\n  defaultStaleTTLSeconds: 604800 // Stale for up to 7 days\n});\n\n// Handler for API - use cache-first for fast responses\nconst handleApiRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  scope: [\"/api/\"],\n  defaultStrategy: \"cache-first\",\n  defaultTTLSeconds: 300 // Fresh for 5 minutes\n});\n\nself.addEventListener(\"fetch\", (event) => {\n  // Try fonts handler first\n  let response = handleFontsRequest(event);\n  if (response) {\n    event.respondWith(response);\n    return;\n  }\n\n  // Then try API handler\n  response = handleApiRequest(event);\n  if (response) {\n    event.respondWith(response);\n    return;\n  }\n\n  // Fall through to network for other requests\n});\n```\n\nWith this setup:\n\n- Requests to `/fonts/*` will use `stale-while-revalidate` - returning cached fonts immediately while updating in the background\n- Requests to `/api/*` will use `cache-first` - returning from cache if fresh, otherwise fetching from network\n- Each scope uses its own cache (`fonts-cache-v1` and `api-cache-v1`), so they can be managed independently\n\n### Example 6: Logout with Cache Clear\n\n```javascript\n// Client code - Option A: header on each request\nasync function logout() {\n  await fetch(\"/api/logout\", {\n    method: \"POST\",\n    headers: {\n      \"X-SW-Cache-Clear\": \"true\" // Clear all cached user data\n    }\n  });\n\n  window.location.href = \"/login\";\n}\n```\n\nAlternatively, configure `clearCacheRequests` in your service worker so you don't need the header at each call site:\n\n```javascript\n// sw.js - Option B: configure once\nconst handleRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  scope: [\"/api/\"],\n  clearCacheRequests: [{ url: \"/api/logout\", method: \"POST\" }]\n});\n```\n\n### Example 7: Custom Request Handler Chain\n\nYour service worker might have other \"handlers\" or \"middlewares\" that need to be called before the cache handler.\n\n```javascript\n// sw.js\nimport { createHandleRequest } from \"swimple\";\n\nconst handleRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  scope: [\"/api/\"],\n  defaultTTLSeconds: 300\n});\n\n// Custom handler for special handling\nconst customHandler = (event) => {\n  const url = new URL(event.request.url);\n\n  // Special handling for auth endpoints\n  if (url.pathname.startsWith(\"/api/auth\")) {\n    return fetch(event.request);\n  }\n\n  return null; // Fall through\n};\n\nself.addEventListener(\"fetch\", (event) => {\n  // Try custom handler first\n  let response = customHandler(event);\n  if (response) {\n    event.respondWith(response);\n    return;\n  }\n\n  // Then try cache handler\n  response = handleRequest(event);\n  if (response) {\n    event.respondWith(response);\n    return;\n  }\n\n  // Default fetch\n  event.respondWith(fetch(event.request));\n});\n```\n\n## How It Works\n\n1. **GET Requests**: The request handler checks if a GET request matches the configured scope and caching criteria\n2. **Cache Lookup**: For eligible requests, it checks the Cache API for a valid cached response\n3. **Strategy Execution**: Based on the strategy (cache-first, network-first, stale-while-revalidate), it either returns cached data or fetches from network\n4. **TTL Management**: Cached responses store only the timestamp of when they were cached. When a request is made, the TTL from the request (or default) is used to calculate if the cached response is fresh or stale by comparing the current time with the cached timestamp. Responses within the TTL are \"fresh\" (returned without background updates). Responses past the TTL but within the stale TTL are \"stale\" (returned with background updates or used as offline fallback)\n5. **Mutation Handling**: POST/PATCH/PUT/DELETE requests trigger cache invalidation based on inferred or explicit paths\n6. **Cache Clearing**: Requests with `X-SW-Cache-Clear` header wipe the entire cache\n\n## Important Notes\n\n- Only GET requests are cached\n- Only 2xx (OK) GET responses are cached. Non-OK responses (4xx, 5xx, etc.) are not cached\n- **Cross-origin requests are not cached** - Only requests to the same origin as the service worker are cached. Requests to different origins will return `null` and are not processed by the cache handler.\n- Non-GET and non-mutating requests (POST/PATCH/PUT/DELETE) are not processed by the cache handler - it will return null. Practically, this means HEAD requests are not handled by the cache handler.\n- Query strings are part of the cache key. Different query strings create different cache entries (e.g., `/api/users?page=1` and `/api/users?page=2` are separate cache entries). However, cache invalidation matches by pathname (ignoring query parameters), so invalidating `/api/users` will invalidate all query variants like `/api/users?page=1`, `/api/users?org_id=123`, etc.\n- Cache invalidation happens automatically for mutations when `inferInvalidation: true`\n- All headers are case-insensitive (per HTTP spec)\n- TTL of `0` completely opts out of caching for a request - the handler returns `null` immediately without checking cache, making network requests, or processing the request.\n- Cache entries store only the timestamp of when they were cached. The TTL is not stored; it's provided by each request (or set with a default via `createHandleRequest` config) and the freshness or staleness is calculated at request time. This means one request could use a longer TTL than another request and therefore allow a later expiration time.\n- **Cache detection**: Responses returned from cache will have the `x-sw-cache-timestamp` header set. Responses fetched from the network will **not** have this header. The presence of this header is a reliable way to determine if a response came from cache or network. See the [Detecting Cache Hits](#detecting-cache-hits) section for more details.\n\n## Error Handling\n\nThe library follows a straightforward error handling approach:\n\n### Configuration Validation Errors\n\nInvalid configuration values passed to `createHandleRequest` will throw errors immediately. This helps catch configuration mistakes early.\n\n```javascript\n// This will throw an error\nconst handleRequest = createHandleRequest({\n  cacheName: \"api-cache-v1\",\n  defaultStrategy: \"invalid-strategy\" // Error: invalid strategy\n});\n```\n\n### Exceptional Errors\n\nThe library does not catch or swallow exceptional errors. If an internal operation like `cache.delete()` throws an exception (which is truly exceptional since browsers don't throw in normal cases), that error will bubble up to your code.\n\nThis means you can wrap your `handleRequest` calls in try/catch if you want to handle errors:\n\n```javascript\nself.addEventListener(\"fetch\", (event) => {\n  try {\n    const response = handleRequest(event);\n    if (response) {\n      event.respondWith(response);\n    }\n  } catch (error) {\n    // Handle exceptional errors\n    console.error(\"Cache handler error:\", error);\n    // Fall back to network\n    event.respondWith(fetch(event.request));\n  }\n});\n```\n\nIf you don't wrap `handleRequest` in try/catch, any exceptional errors will propagate normally, which may cause the service worker fetch handler to fail. Whether you need error handling depends on your application's requirements.\n\n## License\n\nMIT\n\n## Contributing\n\nContributions are welcome! Please open an issue or PR on GitHub.\n\n## Links\n\n- [GitHub Repository](https://github.com/wes-goulet/swimple)\n- [NPM Package](https://www.npmjs.org/package/swimple)\n- [Report Issues](https://github.com/wes-goulet/swimple/issues)\n","readmeFilename":"README.md"}