{"_id":"@push.rocks/webrequest","_rev":"15-343dc45a746f14053afd0495dc99ec11","name":"@push.rocks/webrequest","dist-tags":{"latest":"4.3.1"},"versions":{"3.0.29":{"name":"@push.rocks/webrequest","version":"3.0.29","author":{"name":"Lossless GmbH"},"license":"MIT","_id":"@push.rocks/webrequest@3.0.29","maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"dist":{"shasum":"dc403430cb5579e00feae304b56bccc85b47c781","tarball":"https://registry.npmjs.org/@push.rocks/webrequest/-/webrequest-3.0.29.tgz","fileCount":15,"integrity":"sha512-IPhHSRvlQI9ghv0UQFonVf+ZE69Hf1NyIIkivDA9ctoqWU1NLEojknA3q0yi00POMEdBh+sSvIu4OFy6wtHM8g==","signatures":[{"sig":"MEQCIAT/CQMUWg98EkE8hi1ZcklsNZaAV4eojOgeaat8pdNZAiAVt6mTQTHgsdBeK6fd1i1MjNLKcsDUAor92Eur5o2tlA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":882823},"main":"dist_ts/index.js","type":"module","gitHead":"342d93e34de92d0dff295526a25e5d97445e8a79","private":false,"scripts":{"test":"(tstest test/ --web)","build":"(tsbuild --web --allowimplicitany && tsbundle npm)","buildDocs":"tsdoc"},"typings":"dist_ts/index.d.ts","_npmUser":{"name":"lossless","email":"hello@lossless.com"},"_npmVersion":"9.8.0","description":"securely request from browsers","directories":{},"_nodeVersion":"18.16.1","browserslist":["last 1 chrome versions"],"dependencies":{"@adobe/fetch":"^4.0.13","@pushrocks/smartenv":"^5.0.2","@pushrocks/webstore":"^2.0.8","@pushrocks/smartjson":"^5.0.6","@pushrocks/smartdelay":"^3.0.1","@apiglobal/typedserver":"^2.0.65","@pushrocks/smartpromise":"^4.0.2"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^20.3.3","@gitzone/tsrun":"^1.2.42","@gitzone/tstest":"^1.0.73","@gitzone/tsbuild":"^2.1.66","@gitzone/tsbundle":"^2.0.8","@pushrocks/tapbundle":"^5.0.8"},"_npmOperationalInternal":{"tmp":"tmp/webrequest_3.0.29_1689021358766_0.3823656841240113","host":"s3://npm-registry-packages"}},"3.0.32":{"name":"@push.rocks/webrequest","version":"3.0.32","author":{"name":"Lossless GmbH"},"license":"MIT","_id":"@push.rocks/webrequest@3.0.32","maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"dist":{"shasum":"054abc1fe24beccde62f7bd366a7587d95f23db9","tarball":"https://registry.npmjs.org/@push.rocks/webrequest/-/webrequest-3.0.32.tgz","fileCount":15,"integrity":"sha512-9DSzN0rKpu0M9jt+MoWuvba5NrlPngYC7FMcmb2bVCR9HFlQvKJMMxytCDUOrZP38OdnIfWsJmVaxUcnjTKEzA==","signatures":[{"sig":"MEQCIDNzR9fViIR7isZBkNDxdYJ7LbgsgbhfDdIuSwZNs6WjAiA3ncFvxl/kqPl253eMbkGAT1ZUJkBJoPmHzWi0kKrxPQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":894615},"main":"dist_ts/index.js","type":"module","gitHead":"763afa62cd03c0b5160a3eb75308c7b6ac0f2ec4","private":false,"scripts":{"test":"(tstest test/ --web)","build":"(tsbuild --web --allowimplicitany && tsbundle npm)","buildDocs":"tsdoc"},"typings":"dist_ts/index.d.ts","_npmUser":{"name":"lossless","email":"hello@lossless.com"},"_npmVersion":"9.8.1","description":"securely request from browsers","directories":{},"_nodeVersion":"18.17.0","browserslist":["last 1 chrome versions"],"dependencies":{"@push.rocks/smartenv":"^5.0.5","@push.rocks/webstore":"^2.0.8","@push.rocks/smartjson":"^5.0.6","@apiglobal/typedserver":"^2.0.65","@push.rocks/smartdelay":"^3.0.5","@push.rocks/smartpromise":"^4.0.3"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^20.4.5","@gitzone/tsrun":"^1.2.44","@gitzone/tstest":"^1.0.77","@gitzone/tsbuild":"^2.1.66","@gitzone/tsbundle":"^2.0.8","@push.rocks/tapbundle":"^5.0.12"},"_npmOperationalInternal":{"tmp":"tmp/webrequest_3.0.32_1690459486031_0.33966788633410205","host":"s3://npm-registry-packages"}},"3.0.33":{"name":"@push.rocks/webrequest","version":"3.0.33","author":{"name":"Lossless GmbH"},"license":"MIT","_id":"@push.rocks/webrequest@3.0.33","maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"dist":{"shasum":"512d2865b5973d9b94169d81a2f37273967be288","tarball":"https://registry.npmjs.org/@push.rocks/webrequest/-/webrequest-3.0.33.tgz","fileCount":15,"integrity":"sha512-wO2ibVdTMIE4hwsK9pZSNMl1OcFNbn0/ZUjZS18wzHKR4WMMaVUPmI4eHUzc7fWR6PWvkseNGn3JFxA9YK4p1Q==","signatures":[{"sig":"MEUCIQCrz9h4DUgE8NRIig+6mAbf04OwKlrGxfwNPAt6QZXDgwIgbr6Xj0FVZ+uZBZxbDW1PZ2u8xa72EUC7TEX+2AH+Nyw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":879018},"main":"dist_ts/index.js","type":"module","gitHead":"b43050ff0c7a0a1e9baac7ad08c333d042414c73","private":false,"scripts":{"test":"(tstest test/ --web)","build":"(tsbuild --web --allowimplicitany && tsbundle npm)","buildDocs":"tsdoc"},"typings":"dist_ts/index.d.ts","_npmUser":{"name":"lossless","email":"hello@lossless.com"},"_npmVersion":"9.8.1","description":"securely request from browsers","directories":{},"_nodeVersion":"18.17.1","browserslist":["last 1 chrome versions"],"dependencies":{"@push.rocks/smartenv":"^5.0.5","@push.rocks/webstore":"^2.0.9","@push.rocks/smartjson":"^5.0.10","@push.rocks/smartdelay":"^3.0.5","@push.rocks/smartpromise":"^4.0.3"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^20.5.6","@git.zone/tsrun":"^1.2.46","@git.zone/tstest":"^1.0.80","@git.zone/tsbuild":"^2.1.70","@git.zone/tsbundle":"^2.0.8","@push.rocks/tapbundle":"^5.0.15","@api.global/typedserver":"^3.0.4"},"_npmOperationalInternal":{"tmp":"tmp/webrequest_3.0.33_1693147118261_0.34554472456916874","host":"s3://npm-registry-packages"}},"3.0.34":{"name":"@push.rocks/webrequest","version":"3.0.34","author":{"name":"Lossless GmbH"},"license":"MIT","_id":"@push.rocks/webrequest@3.0.34","maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"dist":{"shasum":"af09deb652828c3051de7ee7595073a703000b1f","tarball":"https://registry.npmjs.org/@push.rocks/webrequest/-/webrequest-3.0.34.tgz","fileCount":15,"integrity":"sha512-3gqJb58ZukPsOcS26ya2M/nAEOP7lMYyc2Syh45ljgwdM3X8PwHquk5pdc1MMdDWAo1aiYrxReEw6BgMCJUlNQ==","signatures":[{"sig":"MEUCICVG4eDUIca3KYUuXFg+kJk2edfW92+uzs9ttfaR/JjpAiEAmRm2vBujEzGPO1bcDntTx92CmOryRj/wcbbvTKogcZg=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":874352},"main":"dist_ts/index.js","type":"module","gitHead":"ab880d704a3cde650ec997627c894f086632051e","private":false,"scripts":{"test":"(tstest test/ --web)","build":"(tsbuild --web --allowimplicitany && tsbundle npm)","buildDocs":"tsdoc"},"typings":"dist_ts/index.d.ts","_npmUser":{"name":"lossless","email":"hello@lossless.com"},"_npmVersion":"10.2.1","description":"securely request from browsers","directories":{},"_nodeVersion":"18.18.2","browserslist":["last 1 chrome versions"],"dependencies":{"@push.rocks/smartenv":"^5.0.10","@push.rocks/webstore":"^2.0.13","@push.rocks/smartjson":"^5.0.10","@push.rocks/smartdelay":"^3.0.5","@push.rocks/smartpromise":"^4.0.3"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^20.8.7","@git.zone/tsrun":"^1.2.46","@git.zone/tstest":"^1.0.81","@git.zone/tsbuild":"^2.1.70","@git.zone/tsbundle":"^2.0.10","@push.rocks/tapbundle":"^5.0.15","@api.global/typedserver":"^3.0.5"},"_npmOperationalInternal":{"tmp":"tmp/webrequest_3.0.34_1697818014012_0.11486711460098342","host":"s3://npm-registry-packages"}},"3.0.35":{"name":"@push.rocks/webrequest","version":"3.0.35","author":{"name":"Lossless GmbH"},"license":"MIT","_id":"@push.rocks/webrequest@3.0.35","maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"dist":{"shasum":"e4abe339737f98c8a7e36acc3e2c2f95ea4176eb","tarball":"https://registry.npmjs.org/@push.rocks/webrequest/-/webrequest-3.0.35.tgz","fileCount":15,"integrity":"sha512-8RZJ1lznDGo/94kQDvNCKAcOPfMLFzYkcU/5gnIwpKeN7uBs2gAiKxRr71HWL2VoR5XUP1XtODIB0rnb7f/pdQ==","signatures":[{"sig":"MEUCIEscXc9hvPURTyLqi8ejn3pyuZsiKgWW5LLXoA5kGcQAAiEA7H1xoYV7FKie+ONjbhD56LItL8w3ZSApcuaiRcHryjM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":704977},"main":"dist_ts/index.js","type":"module","_from":"file:push.rocks-webrequest-3.0.35.tgz","private":false,"scripts":{"test":"(tstest test/ --web)","build":"(tsbuild --web --allowimplicitany && tsbundle npm)","buildDocs":"tsdoc"},"typings":"dist_ts/index.d.ts","_npmUser":{"name":"lossless","email":"hello@lossless.com"},"_resolved":"/tmp/8bb95d92c9156071a496b444ef195935/push.rocks-webrequest-3.0.35.tgz","_integrity":"sha512-8RZJ1lznDGo/94kQDvNCKAcOPfMLFzYkcU/5gnIwpKeN7uBs2gAiKxRr71HWL2VoR5XUP1XtODIB0rnb7f/pdQ==","_npmVersion":"10.2.3","description":"securely request from browsers","directories":{},"_nodeVersion":"21.2.0","browserslist":["last 1 chrome versions"],"dependencies":{"@push.rocks/smartenv":"^5.0.12","@push.rocks/webstore":"^2.0.13","@push.rocks/smartjson":"^5.0.14","@push.rocks/smartdelay":"^3.0.5","@push.rocks/smartpromise":"^4.0.3"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^20.11.24","@git.zone/tsrun":"^1.2.46","@git.zone/tstest":"^1.0.86","@git.zone/tsbuild":"^2.1.72","@git.zone/tsbundle":"^2.0.15","@push.rocks/tapbundle":"^5.0.15","@api.global/typedserver":"^3.0.26"},"_npmOperationalInternal":{"tmp":"tmp/webrequest_3.0.35_1709458600454_0.1682016931020891","host":"s3://npm-registry-packages"}},"3.0.36":{"name":"@push.rocks/webrequest","version":"3.0.36","keywords":["webrequest","HTTP","secure","browsers","caching","fault tolerance","json","abort","timeout","multi-endpoint","fetch API"],"author":{"name":"Lossless GmbH"},"license":"MIT","_id":"@push.rocks/webrequest@3.0.36","maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"dist":{"shasum":"c44020fc04cffde17d405b32b04d2a579176af68","tarball":"https://registry.npmjs.org/@push.rocks/webrequest/-/webrequest-3.0.36.tgz","fileCount":16,"integrity":"sha512-S2gcu2nBNXj+eFsIzCqNdvUnelcWsY2NzdwJTtt+DSwNMOT0jS1YuNUebN0TYnP0VoI7Kcj2AUej3zyHwwi1Ig==","signatures":[{"sig":"MEUCIE59FMFWKX0or+T9q8JI1XEnX+18Hw5F6a4W2Ul1Yd3wAiEAvgXXQJkyojJEcfIQ0b2V6mVFAFk3YD3QXya6dRnYNv4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":710367},"main":"dist_ts/index.js","type":"module","_from":"file:push.rocks-webrequest-3.0.36.tgz","private":false,"scripts":{"test":"(tstest test/ --web)","build":"(tsbuild --web --allowimplicitany && tsbundle npm)","buildDocs":"tsdoc"},"typings":"dist_ts/index.d.ts","_npmUser":{"name":"lossless","email":"hello@lossless.com"},"_resolved":"/tmp/cdad40fd6f8d09dba02a52da0805e503/push.rocks-webrequest-3.0.36.tgz","_integrity":"sha512-S2gcu2nBNXj+eFsIzCqNdvUnelcWsY2NzdwJTtt+DSwNMOT0jS1YuNUebN0TYnP0VoI7Kcj2AUej3zyHwwi1Ig==","_npmVersion":"10.2.3","description":"A module for making secure web requests from browsers with support for caching and fault tolerance.","directories":{},"_nodeVersion":"21.2.0","browserslist":["last 1 chrome versions"],"dependencies":{"@push.rocks/smartenv":"^5.0.12","@push.rocks/webstore":"^2.0.13","@push.rocks/smartjson":"^5.0.18","@push.rocks/smartdelay":"^3.0.5","@push.rocks/smartpromise":"^4.0.3"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^20.12.7","@git.zone/tsrun":"^1.2.46","@git.zone/tstest":"^1.0.88","@git.zone/tsbuild":"^2.1.72","@git.zone/tsbundle":"^2.0.15","@push.rocks/tapbundle":"^5.0.23","@api.global/typedserver":"^3.0.27"},"_npmOperationalInternal":{"tmp":"tmp/webrequest_3.0.36_1713377764185_0.9377056374595303","host":"s3://npm-registry-packages"}},"3.0.37":{"name":"@push.rocks/webrequest","version":"3.0.37","keywords":["webrequest","HTTP","secure","browsers","caching","fault tolerance","json","abort","timeout","multi-endpoint","fetch API"],"author":{"name":"Lossless GmbH"},"license":"MIT","_id":"@push.rocks/webrequest@3.0.37","maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"dist":{"shasum":"d23db716ca9f4d637d7a878919eb0800004b7f4c","tarball":"https://registry.npmjs.org/@push.rocks/webrequest/-/webrequest-3.0.37.tgz","fileCount":16,"integrity":"sha512-fLN7kP6GeHFxE4UH4r9C9pjcQb0QkJxHeAMwXvbOqB9hh0MFNKhtGU7GoaTn8SVRGRMPc9UqZVNwo6u5l8Wn0A==","signatures":[{"sig":"MEUCIHGe1bmP3DUUdg150m/opESD2tyz6OAnq3dKqzOhclv1AiEArOMQ+WwmHReStzpPSM7U5n5jMndSQWTn63p5P6nxiFU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":740879},"main":"dist_ts/index.js","type":"module","_from":"file:push.rocks-webrequest-3.0.37.tgz","private":false,"scripts":{"test":"(tstest test/ --web)","build":"(tsbuild --web --allowimplicitany && tsbundle npm)","buildDocs":"tsdoc"},"typings":"dist_ts/index.d.ts","_npmUser":{"name":"lossless","email":"hello@lossless.com"},"_resolved":"/tmp/685e293e704bf95242c7a8bb837b0bcd/push.rocks-webrequest-3.0.37.tgz","_integrity":"sha512-fLN7kP6GeHFxE4UH4r9C9pjcQb0QkJxHeAMwXvbOqB9hh0MFNKhtGU7GoaTn8SVRGRMPc9UqZVNwo6u5l8Wn0A==","_npmVersion":"10.2.3","description":"A module for making secure web requests from browsers with support for caching and fault tolerance.","directories":{},"_nodeVersion":"21.2.0","browserslist":["last 1 chrome versions"],"dependencies":{"@push.rocks/smartenv":"^5.0.12","@push.rocks/webstore":"^2.0.13","@push.rocks/smartjson":"^5.0.19","@push.rocks/smartdelay":"^3.0.5","@push.rocks/smartpromise":"^4.0.3"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^20.12.7","@git.zone/tsrun":"^1.2.46","@git.zone/tstest":"^1.0.88","@git.zone/tsbuild":"^2.1.72","@git.zone/tsbundle":"^2.0.15","@push.rocks/tapbundle":"^5.0.23","@api.global/typedserver":"^3.0.27"},"_npmOperationalInternal":{"tmp":"tmp/webrequest_3.0.37_1713378005978_0.24605688447421037","host":"s3://npm-registry-packages"}},"4.0.1":{"name":"@push.rocks/webrequest","version":"4.0.1","keywords":["webrequest","HTTP","secure","browsers","caching","fault tolerance","json","abort","timeout","multi-endpoint","fetch API"],"author":{"name":"Lossless GmbH"},"license":"MIT","_id":"@push.rocks/webrequest@4.0.1","maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"homepage":"https://code.foss.global/push.rocks/webrequest#readme","bugs":{"url":"https://code.foss.global/push.rocks/webrequest/issues"},"dist":{"shasum":"4603b987a41d0399e9752ed7a8b3f5393a4ab723","tarball":"https://registry.npmjs.org/@push.rocks/webrequest/-/webrequest-4.0.1.tgz","fileCount":55,"integrity":"sha512-I60XZZLVf8W5I7YdmUVVu4G92teE3rg3/aKaV00BRg8vJ3VXx3wc59Qj4em7zxQ5o0HvL8m1Aezw3RFMDPyVgA==","signatures":[{"sig":"MEQCIHfIWbH0pV6NKMShVtbwuhK2Kdt5kq2NhwBnsgxNn+4uAiBFxYrXw0p7o3/vjdse8lgUhDtC/n96mlTyugPALGdr/Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2125491},"main":"dist_ts/index.js","type":"module","_from":"file:push.rocks-webrequest-4.0.1.tgz","private":false,"scripts":{"test":"(tstest test/ --verbose)","build":"(tsbuild --web --allowimplicitany && tsbundle npm)","buildDocs":"tsdoc"},"typings":"dist_ts/index.d.ts","_npmUser":{"name":"lossless","email":"hello@lossless.com"},"_resolved":"/tmp/c34f4f523b1884efdf7876316ac2bca9/push.rocks-webrequest-4.0.1.tgz","_integrity":"sha512-I60XZZLVf8W5I7YdmUVVu4G92teE3rg3/aKaV00BRg8vJ3VXx3wc59Qj4em7zxQ5o0HvL8m1Aezw3RFMDPyVgA==","repository":{"url":"https://code.foss.global/push.rocks/webrequest.git","type":"git"},"_npmVersion":"11.3.0","description":"Modern, fetch-compatible web request library with intelligent HTTP caching, retry strategies, and fault tolerance.","directories":{},"_nodeVersion":"23.8.0","browserslist":["last 1 chrome versions"],"dependencies":{"@push.rocks/smartenv":"^5.0.12","@push.rocks/webstore":"^2.0.13","@push.rocks/smartjson":"^5.2.0","@push.rocks/smartdelay":"^3.0.5","@push.rocks/smartpromise":"^4.0.3"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^20.12.7","@git.zone/tstest":"^2.6.2","@git.zone/tsbuild":"^2.6.8","@git.zone/tsbundle":"^2.0.15","@api.global/typedserver":"^3.0.27"},"_npmOperationalInternal":{"tmp":"tmp/webrequest_4.0.1_1760967676869_0.2370307118708117","host":"s3://npm-registry-packages-npm-production"}},"4.0.5":{"name":"@push.rocks/webrequest","version":"4.0.5","keywords":["webrequest","HTTP","secure","browsers","caching","fault tolerance","json","abort","timeout","multi-endpoint","fetch API"],"author":{"name":"Lossless GmbH"},"license":"MIT","_id":"@push.rocks/webrequest@4.0.5","maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"homepage":"https://code.foss.global/push.rocks/webrequest#readme","bugs":{"url":"https://code.foss.global/push.rocks/webrequest/issues"},"dist":{"shasum":"05ce534031cbeeddc43494c519453844e5a0d7ef","tarball":"https://registry.npmjs.org/@push.rocks/webrequest/-/webrequest-4.0.5.tgz","fileCount":55,"integrity":"sha512-wVSCaXqJ9Vh+rbwVz0wDl46dYz4rnwwSrm5vbVXKbuH6oKTPF0YRoujeJPqRltIn64RVGdLeY9/6ix+ZCrzhsg==","signatures":[{"sig":"MEYCIQC17ZcJICoOznAhtb/ETdbeoGniLlTgTrh+K3a7du3GaQIhAMIla6UH/LDzdjdd95PtQtaRzGA3NMKOJUr4U6C5agqU","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2123875},"main":"dist_ts/index.js","pnpm":{"overrides":{}},"type":"module","gitHead":"f1609e67b70093ea5cc597d643be0f52fb925813","private":false,"scripts":{"test":"(tstest test/ --verbose)","build":"(tsbuild && tsbundle npm)","buildDocs":"tsdoc"},"typings":"dist_ts/index.d.ts","_npmUser":{"name":"lossless","email":"hello@lossless.com"},"repository":{"url":"https://code.foss.global/push.rocks/webrequest.git","type":"git"},"_npmVersion":"11.7.0","description":"Modern, fetch-compatible web request library with intelligent HTTP caching, retry strategies, and fault tolerance.","directories":{},"_nodeVersion":"25.2.1","browserslist":["last 1 chrome versions"],"dependencies":{"@push.rocks/smartenv":"^6.0.0","@push.rocks/webstore":"^2.0.13","@push.rocks/smartjson":"^6.0.0","@push.rocks/smartdelay":"^3.0.5","@push.rocks/smartpromise":"^4.0.3"},"_hasShrinkwrap":false,"packageManager":"pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977","devDependencies":{"@types/node":"^25.3.3","@git.zone/tstest":"^3.1.8","@git.zone/tsbuild":"^4.1.2","@git.zone/tsbundle":"^2.9.0","@api.global/typedserver":"^8.4.0"},"_npmOperationalInternal":{"tmp":"tmp/webrequest_4.0.5_1772459505288_0.9890735549607501","host":"s3://npm-registry-packages-npm-production"}},"4.0.6":{"name":"@push.rocks/webrequest","version":"4.0.6","keywords":["webrequest","HTTP","secure","browsers","caching","fault tolerance","json","abort","timeout","multi-endpoint","fetch API"],"author":"Lossless GmbH","license":"MIT","_id":"@push.rocks/webrequest@4.0.6","maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"homepage":"https://code.foss.global/push.rocks/webrequest#readme","bugs":{"url":"https://code.foss.global/push.rocks/webrequest/issues"},"dist":{"shasum":"9ac17e1b654eb19c9f902629f462fe8e239980aa","tarball":"https://registry.npmjs.org/@push.rocks/webrequest/-/webrequest-4.0.6.tgz","fileCount":55,"integrity":"sha512-mV/0g184gzeY8eAQ/N6SfYeNEapvr2mJccl6/DFo+LJ6fsBc1TsPaCqwT1zzX/xsiTp27PEpzueIu+PF+EXXIA==","signatures":[{"sig":"MEQCICw7xEdi8rH3znsuwaU86o96FXgDx+wJ5PoWoCVikM/0AiBUNMXCy0Mp37WZENl6+083oCa3XxOZL3WknaCsEdlY/w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2185103},"main":"dist_ts/index.js","type":"module","private":false,"scripts":{"test":"(tstest test/ --verbose)","build":"(tsbuild && tsbundle npm)","buildDocs":"tsdoc"},"typings":"dist_ts/index.d.ts","_npmUser":{"name":"lossless","email":"hello@lossless.com"},"repository":{"url":"https://code.foss.global/push.rocks/webrequest.git","type":"git"},"description":"Modern, fetch-compatible web request library with intelligent HTTP caching, retry strategies, and fault tolerance.","directories":{},"_nodeVersion":"25.2.1","browserslist":["last 1 chrome versions"],"dependencies":{"@push.rocks/smartenv":"^6.1.0","@push.rocks/webstore":"^2.1.0","@push.rocks/smartjson":"^6.0.1","@push.rocks/smartdelay":"^3.1.0","@push.rocks/smartpromise":"^4.2.4"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^26.1.1","@git.zone/tstest":"^3.6.7","@git.zone/tsbuild":"^4.4.2","@git.zone/tsbundle":"^2.11.3","@api.global/typedserver":"^8.7.0"},"_npmOperationalInternal":{"tmp":"tmp/webrequest_4.0.6_1785320441869_0.22024493434187775","host":"s3://npm-registry-packages-npm-production"}},"4.1.0":{"name":"@push.rocks/webrequest","version":"4.1.0","keywords":["webrequest","HTTP","secure","browsers","caching","fault tolerance","json","abort","timeout","multi-endpoint","fetch API"],"author":"Lossless GmbH","license":"MIT","_id":"@push.rocks/webrequest@4.1.0","maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"homepage":"https://code.foss.global/push.rocks/webrequest#readme","bugs":{"url":"https://code.foss.global/push.rocks/webrequest/issues"},"dist":{"shasum":"f01763f3113ad9b86c15796bf4bd56ee99800589","tarball":"https://registry.npmjs.org/@push.rocks/webrequest/-/webrequest-4.1.0.tgz","fileCount":54,"integrity":"sha512-1KfZNi20jBMFYGNW7DqND6CX47VEdour3Pi7/P4vMW2oCPXLuoPFG6MOrRWBwcLwT4+QfM+0JFl6ZCMGfs5zUQ==","signatures":[{"sig":"MEYCIQCAcNERkSJhfJnDfsDjSbcI5ArrsCEE/3diUU6XSkiY+wIhAM2fF48qz3BEa8rhv4zTfS4iNzBCI1BI6NRaNEY/05Te","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":865242},"main":"dist_ts/index.js","type":"module","private":false,"scripts":{"test":"(tstest test/ --verbose)","build":"(tsbuild && tsbundle npm)","buildDocs":"tsdoc"},"typings":"dist_ts/index.d.ts","_npmUser":{"name":"lossless","email":"hello@lossless.com"},"repository":{"url":"https://code.foss.global/push.rocks/webrequest.git","type":"git"},"description":"Modern, fetch-compatible web request library with intelligent HTTP caching, retry strategies, and fault tolerance.","directories":{},"_nodeVersion":"25.2.1","browserslist":["last 1 chrome versions"],"dependencies":{"@push.rocks/smartenv":"^6.1.0","@push.rocks/webstore":"^2.2.0","@push.rocks/smartjson":"^6.0.1","@push.rocks/smartdelay":"^3.1.0","@push.rocks/smartpromise":"^4.2.4"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^26.1.1","@git.zone/tstest":"^3.6.7","@git.zone/tsbuild":"^4.4.2","@git.zone/tsbundle":"^2.11.3","@api.global/typedserver":"^8.7.0"},"_npmOperationalInternal":{"tmp":"tmp/webrequest_4.1.0_1785327467763_0.7160235939135913","host":"s3://npm-registry-packages-npm-production"}},"4.1.1":{"name":"@push.rocks/webrequest","version":"4.1.1","keywords":["webrequest","HTTP","secure","browsers","caching","fault tolerance","json","abort","timeout","multi-endpoint","fetch API"],"author":"Lossless GmbH","license":"MIT","_id":"@push.rocks/webrequest@4.1.1","maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"homepage":"https://code.foss.global/push.rocks/webrequest#readme","bugs":{"url":"https://code.foss.global/push.rocks/webrequest/issues"},"dist":{"shasum":"3a7aabd1898c5c7874866ca4e8a205c2c29eff69","tarball":"https://registry.npmjs.org/@push.rocks/webrequest/-/webrequest-4.1.1.tgz","fileCount":54,"integrity":"sha512-y//RW/6VBnki8VW0EOWjRa/SK7svRPRqZQB98HdGw1NkDdRxhHCRr7QEAbKsZYyM/xC0rYLPP8mmY0X4m858DA==","signatures":[{"sig":"MEUCIBLKzghW5ZAlGx9n0S6utOKwNoQ4cr7YydERnByZcB9dAiEAhM+6ofOToQsYA7S3w5NJZSwpaqcuVmGnU0SbJuVGQfE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":866016},"main":"dist_ts/index.js","type":"module","private":false,"scripts":{"test":"(tstest test/ --verbose)","build":"(tsbuild && tsbundle npm)","buildDocs":"tsdoc"},"typings":"dist_ts/index.d.ts","_npmUser":{"name":"lossless","email":"hello@lossless.com"},"repository":{"url":"https://code.foss.global/push.rocks/webrequest.git","type":"git"},"description":"Modern, fetch-compatible web request library with intelligent HTTP caching, retry strategies, and fault tolerance.","directories":{},"_nodeVersion":"25.2.1","browserslist":["last 1 chrome versions"],"dependencies":{"@push.rocks/smartenv":"^6.1.0","@push.rocks/webstore":"^2.2.0","@push.rocks/smartjson":"^6.0.1","@push.rocks/smartdelay":"^3.1.0","@push.rocks/smartpromise":"^4.2.4"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^26.1.1","@git.zone/tstest":"^3.6.7","@git.zone/tsbuild":"^4.4.2","@git.zone/tsbundle":"^2.11.3","@api.global/typedserver":"^8.7.0"},"_npmOperationalInternal":{"tmp":"tmp/webrequest_4.1.1_1785327977014_0.45338675260768113","host":"s3://npm-registry-packages-npm-production"}},"4.2.0":{"name":"@push.rocks/webrequest","version":"4.2.0","keywords":["webrequest","HTTP","secure","browsers","caching","fault tolerance","json","abort","timeout","multi-endpoint","fetch API"],"author":"Lossless GmbH","license":"MIT","_id":"@push.rocks/webrequest@4.2.0","maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"homepage":"https://code.foss.global/push.rocks/webrequest#readme","bugs":{"url":"https://code.foss.global/push.rocks/webrequest/issues"},"dist":{"shasum":"6cc021e4c4de73ae223566ee5d0064df330784e7","tarball":"https://registry.npmjs.org/@push.rocks/webrequest/-/webrequest-4.2.0.tgz","fileCount":54,"integrity":"sha512-q7Clu3MdW/7K7M512Bzj7A9DJZXX453NPEVqOFMKE+zeVP+FoltzIlooMxKe+eQx3U3LYW4qlYCI/Zfm4zykag==","signatures":[{"sig":"MEUCIQCgIMHxR7WeEypObBQOkUg6f9rkRzYuB1kAMubsOtgXJgIgYQ05ZluUfrxyzHqCb8WkP4CWxf9akro3oO91nJp/g4s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":867099},"main":"dist_ts/index.js","type":"module","private":false,"scripts":{"test":"(tstest test/ --verbose)","build":"(tsbuild && tsbundle npm)","buildDocs":"tsdoc"},"typings":"dist_ts/index.d.ts","_npmUser":{"name":"lossless","email":"hello@lossless.com"},"repository":{"url":"https://code.foss.global/push.rocks/webrequest.git","type":"git"},"description":"Modern, fetch-compatible web request library with intelligent HTTP caching, retry strategies, and fault tolerance.","directories":{},"_nodeVersion":"25.2.1","browserslist":["last 1 chrome versions"],"dependencies":{"@push.rocks/smartenv":"^6.1.0","@push.rocks/webstore":"^2.2.0","@push.rocks/smartjson":"^6.0.1","@push.rocks/smartdelay":"^3.1.0","@push.rocks/smartpromise":"^4.2.4"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^26.1.1","@git.zone/tstest":"^3.6.7","@git.zone/tsbuild":"^4.4.2","@git.zone/tsbundle":"^2.11.3","@api.global/typedserver":"^8.7.0"},"_npmOperationalInternal":{"tmp":"tmp/webrequest_4.2.0_1785329716570_0.793576433252905","host":"s3://npm-registry-packages-npm-production"}},"4.3.0":{"name":"@push.rocks/webrequest","version":"4.3.0","keywords":["webrequest","HTTP","secure","browsers","caching","fault tolerance","json","abort","timeout","multi-endpoint","fetch API"],"author":"Lossless GmbH","license":"MIT","_id":"@push.rocks/webrequest@4.3.0","maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"homepage":"https://code.foss.global/push.rocks/webrequest#readme","bugs":{"url":"https://code.foss.global/push.rocks/webrequest/issues"},"dist":{"shasum":"af72c10c228de11287e3ee996d226de08290653d","tarball":"https://registry.npmjs.org/@push.rocks/webrequest/-/webrequest-4.3.0.tgz","fileCount":55,"integrity":"sha512-2ujXmi5d5q9xUtVdX5/Q+SU1MCeVl1F5cT2hC8XeSF+V/RIzIteB4hYmapB1XXYKXwrzCg6TPa5DVnLNjotszg==","signatures":[{"sig":"MEYCIQCT7GEu22dl1fiVvm48wHW1AifkUIa08LsUbNBJGYnfCAIhALrOF4ftJQlao1E97LYU1QTgdEIEAmCBCql7ZGVPQVtX","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2300384},"main":"dist_ts/index.js","type":"module","private":false,"scripts":{"test":"(tstest test/ --verbose)","build":"(tsbuild && tsbundle npm)","buildDocs":"tsdoc"},"typings":"dist_ts/index.d.ts","_npmUser":{"name":"lossless","email":"hello@lossless.com"},"repository":{"url":"https://code.foss.global/push.rocks/webrequest.git","type":"git"},"description":"Modern, fetch-compatible web request library with intelligent HTTP caching, retry strategies, and fault tolerance.","directories":{},"_nodeVersion":"25.2.1","browserslist":["last 1 chrome versions"],"dependencies":{"@push.rocks/smartenv":"^6.1.0","@push.rocks/webstore":"^2.2.0","@push.rocks/smartjson":"^6.0.1","@push.rocks/smartdelay":"^3.1.0","@push.rocks/smartpromise":"^4.2.4"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^26.2.0","@git.zone/tstest":"^4.0.0","@git.zone/tsbuild":"^4.4.2","@git.zone/tsbundle":"^2.11.4","@api.global/typedserver":"^8.7.0"},"_npmOperationalInternal":{"tmp":"tmp/webrequest_4.3.0_1786785786899_0.4482490831586263","host":"s3://npm-registry-packages-npm-production"}},"4.3.1":{"name":"@push.rocks/webrequest","version":"4.3.1","private":false,"description":"Modern, fetch-compatible web request library with intelligent HTTP caching, retry strategies, and fault tolerance.","main":"dist_ts/index.js","typings":"dist_ts/index.d.ts","type":"module","author":"Lossless GmbH","license":"MIT","devDependencies":{"@api.global/typedserver":"^8.7.0","@git.zone/tsbuild":"^4.4.2","@git.zone/tsbundle":"^2.11.4","@git.zone/tstest":"^4.0.0","@types/node":"^26.2.0"},"dependencies":{"@push.rocks/smartdelay":"^3.1.0","@push.rocks/smartenv":"^6.1.0","@push.rocks/smartjson":"^6.0.1","@push.rocks/smartpromise":"^4.2.4","@push.rocks/webstore":"^2.2.0"},"browserslist":["last 1 chrome versions"],"keywords":["webrequest","HTTP","secure","browsers","caching","fault tolerance","json","abort","timeout","multi-endpoint","fetch API"],"homepage":"https://code.foss.global/push.rocks/webrequest#readme","repository":{"type":"git","url":"https://code.foss.global/push.rocks/webrequest.git"},"bugs":{"url":"https://code.foss.global/push.rocks/webrequest/issues"},"scripts":{"test":"(tstest test/ --verbose)","build":"(tsbuild && tsbundle npm)","buildDocs":"tsdoc"},"_nodeVersion":"25.2.1","_id":"@push.rocks/webrequest@4.3.1","dist":{"integrity":"sha512-Ir/QuMSwQqHCBsxqikb/y++dmftK5/1vJ1fe41w2MQFV5miePBqC0T8kNC8Vzf2KGJOWQuCmsmJriVFMrRsy/A==","shasum":"e5047b208db572a511611b24e74afeacca8a6a0f","tarball":"https://registry.npmjs.org/@push.rocks/webrequest/-/webrequest-4.3.1.tgz","fileCount":55,"unpackedSize":2300404,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHTT+9VB5fV0sJ+PO7NZiO5wx8RFRjDNghlkH27w3X7FAiAdobFaLpYxTfBjjp5WG7R9ce5DABFDCRKGxEJgyPSBYA=="}]},"_npmUser":{"name":"lossless","email":"hello@lossless.com"},"directories":{},"maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/webrequest_4.3.1_1787498933723_0.914407735059438"},"_hasShrinkwrap":false}},"time":{"created":"2023-07-10T20:35:58.668Z","modified":"2026-08-23T15:28:54.146Z","3.0.29":"2023-07-10T20:35:59.089Z","3.0.32":"2023-07-27T12:04:46.265Z","3.0.33":"2023-08-27T14:38:38.505Z","3.0.34":"2023-10-20T16:06:54.296Z","3.0.35":"2024-03-03T09:36:40.657Z","3.0.36":"2024-04-17T18:16:04.388Z","3.0.37":"2024-04-17T18:20:06.225Z","4.0.1":"2025-10-20T13:41:17.079Z","4.0.5":"2026-03-02T13:51:45.451Z","4.0.6":"2026-07-29T10:20:42.031Z","4.1.0":"2026-07-29T12:17:47.912Z","4.1.1":"2026-07-29T12:26:17.206Z","4.2.0":"2026-07-29T12:55:16.740Z","4.3.0":"2026-08-15T09:23:07.063Z","4.3.1":"2026-08-23T15:28:53.875Z"},"bugs":{"url":"https://code.foss.global/push.rocks/webrequest/issues"},"author":"Lossless GmbH","license":"MIT","homepage":"https://code.foss.global/push.rocks/webrequest#readme","keywords":["webrequest","HTTP","secure","browsers","caching","fault tolerance","json","abort","timeout","multi-endpoint","fetch API"],"repository":{"type":"git","url":"https://code.foss.global/push.rocks/webrequest.git"},"description":"Modern, fetch-compatible web request library with intelligent HTTP caching, retry strategies, and fault tolerance.","maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"readme":"# @push.rocks/webrequest\n\nModern, fetch-compatible web request library with intelligent HTTP caching, retry strategies, and advanced fault tolerance. Works seamlessly in browsers, Node.js, Deno, and Bun.\n\n## Issue Reporting and Security\n\nFor reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.\n\n## Features\n\n- 🌐 **Fetch-Compatible API** — Drop-in replacement for native `fetch()` with enhanced features\n- 💾 **Intelligent HTTP Caching** — Respects `Cache-Control`, `ETag`, `Last-Modified`, and `Expires` headers (RFC 7234)\n- 🔄 **Multiple Cache Strategies** — network-first, cache-first, stale-while-revalidate, network-only, cache-only\n- 🔁 **Advanced Retry System** — Configurable retry with exponential, linear, or constant backoff\n- 🎯 **Request/Response Interceptors** — Middleware pattern for transforming requests and responses\n- 🚫 **Request Deduplication** — Automatically deduplicate simultaneous identical requests\n- 📘 **TypeScript Generics** — Type-safe response parsing with `webrequest.getJson<T>()`\n- 🛡️ **Multi-Endpoint Fallback** — Fault tolerance via fallback URLs with retry strategies\n- ⏱️ **Timeout Support** — Configurable request timeouts with AbortController\n- 🌍 **Cross-Runtime** — Works in browsers, Node.js, Deno, and Bun\n\n## Installation\n\n```bash\npnpm install @push.rocks/webrequest\n# or\nnpm install @push.rocks/webrequest\n```\n\nThis package requires a modern JavaScript environment with ESM and TypeScript support.\n\n## Quick Start\n\n### Basic Fetch-Compatible Usage\n\n```typescript\nimport { webrequest } from '@push.rocks/webrequest';\n\n// Use exactly like fetch()\nconst response = await webrequest('https://api.example.com/data');\nconst data = await response.json();\n\n// With options (fetch-compatible + enhanced)\nconst response = await webrequest('https://api.example.com/data', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({ key: 'value' }),\n  timeout: 30000,\n  retry: true,\n});\n```\n\n### JSON Convenience Methods\n\n```typescript\nimport { webrequest } from '@push.rocks/webrequest';\n\n// GET JSON with type safety\ninterface User {\n  id: number;\n  name: string;\n  email: string;\n}\n\nconst user = await webrequest.getJson<User>('https://api.example.com/user/1');\n// user is typed as User\n\n// POST JSON\nconst result = await webrequest.postJson('https://api.example.com/users', {\n  name: 'John Doe',\n  email: 'john@example.com',\n});\n\n// PUT and DELETE\nawait webrequest.putJson(url, data);\nawait webrequest.deleteJson(url);\n```\n\n### Cache-Origin Response Metadata\n\nUse the metadata-returning methods when a caller must distinguish a current\nnetwork response from a payload supplied by Webrequest's HTTP cache:\n\n```typescript\nconst result = await webrequest.postJsonWithMetadata<ApiResponse>(\n  'https://api.example.com/typedrequest',\n  requestPayload,\n  {\n    cacheStrategy: 'cache-first',\n    cacheKey: 'typedrequest:example',\n  },\n);\n\nconsole.log(result.data);\nconsole.log(result.metadata.fromCache);\nconsole.log(result.metadata.revalidated);\n```\n\n`metadata` is frozen and returned separately from HTTP headers, so a server\ncannot spoof cache origin. `fromCache` means that the foreground response body\ncame from Webrequest's persistent cache. `revalidated` means that Webrequest\ncompleted a conditional revalidation for this response. When the origin answers\n`304 Not Modified`, Webrequest returns the cached response body and status while\nthe metadata reports both flags as `true`. A changed network response obtained\nduring revalidation reports `fromCache: false` and `revalidated: true`.\nNetwork-only and multi-endpoint fallback responses report both flags as\n`false`. Retried requests preserve the final cache strategy result, so a retry\nmay still finish from cache or through conditional revalidation.\n\nRaw response callers can use `webrequest.requestWithMetadata()` or\n`client.requestWithMetadata()`. JSON callers can use\n`getJsonWithMetadata()`, `postJsonWithMetadata()`, `putJsonWithMetadata()`, or\n`deleteJsonWithMetadata()`. JSON results also include the native `response` for\nstatus and header inspection; its body has already been consumed. Existing\n`webrequest()`, `request()`, and JSON methods keep their original return values\nand behavior.\n\n## Cache Strategies\n\n### Network-First (Default)\n\nAlways fetch from network, fall back to cache on failure. Respects HTTP caching headers.\n\n```typescript\nconst data = await webrequest.getJson('https://api.example.com/data', {\n  cacheStrategy: 'network-first',\n});\n```\n\n### Cache-First\n\nCheck cache first, only fetch from network if not cached or stale.\n\n```typescript\nconst data = await webrequest.getJson('https://api.example.com/data', {\n  cacheStrategy: 'cache-first',\n  cacheMaxAge: 60000, // 60 seconds; use 0 for immediate staleness\n  cacheMaxEntries: 256,\n});\n```\n\nPersistent caches are capped at 256 entries by default. Set\n`cacheMaxEntries` to another positive integer to change the cap. Webrequest\nremoves expired or malformed entries first, then evicts the oldest stored\nresponses by timestamp. Concurrent writes share one coalesced pruning loop;\nbrowser tabs sharing the same IndexedDB database converge on the same bound on\nsubsequent writes.\n\n### Stale-While-Revalidate\n\nReturn cached data immediately, update in background.\n\n```typescript\nconst data = await webrequest.getJson('https://api.example.com/data', {\n  cacheStrategy: 'stale-while-revalidate',\n});\n```\n\n### Network-Only and Cache-Only\n\n```typescript\n// Always fetch from network, never cache\nconst fresh = await webrequest.getJson(url, {\n  cacheStrategy: 'network-only',\n});\n\n// Only use cache, never fetch from network\nconst cached = await webrequest.getJson(url, {\n  cacheStrategy: 'cache-only',\n});\n```\n\n### HTTP Header-Based Caching\n\nThe library automatically respects HTTP caching headers:\n\n```typescript\n// Server returns: Cache-Control: max-age=0, no-cache; ETag: \"abc123\"\nconst response = await webrequest('https://api.example.com/data', {\n  cacheStrategy: 'cache-first',\n});\n\n// A stale cache entry with validators sends:\n// If-None-Match: \"abc123\"\n// Server returns 304 Not Modified; Webrequest returns the cached response\n```\n\n### Custom Cache Keys\n\n```typescript\nconst response = await webrequest('https://api.example.com/search?q=test', {\n  cacheStrategy: 'cache-first',\n  cacheKey: (request) => {\n    const url = new URL(request.url);\n    return `search:${url.searchParams.get('q')}`;\n  },\n});\n```\n\n## Retry Strategies\n\n### Basic Retry\n\n```typescript\nconst response = await webrequest('https://api.example.com/data', {\n  retry: true, // Uses defaults: 3 attempts, exponential backoff\n});\n```\n\n### Advanced Retry Configuration\n\n```typescript\nconst response = await webrequest('https://api.example.com/data', {\n  retry: {\n    maxAttempts: 5,\n    backoff: 'exponential', // or 'linear', 'constant'\n    initialDelay: 1000,     // 1 second\n    maxDelay: 30000,        // 30 seconds\n    retryOn: [408, 429, 500, 502, 503, 504],\n    onRetry: (attempt, error, nextDelay) => {\n      console.log(`Retry attempt ${attempt}, waiting ${nextDelay}ms`);\n    },\n  },\n});\n```\n\n### Multi-Endpoint Fallback\n\nWhen the primary endpoint fails, automatically try fallback URLs:\n\n```typescript\nconst response = await webrequest('https://api1.example.com/data', {\n  fallbackUrls: [\n    'https://api2.example.com/data',\n    'https://api3.example.com/data',\n  ],\n  retry: {\n    maxAttempts: 3,\n    backoff: 'exponential',\n  },\n});\n```\n\nEach URL is tried with the configured retry strategy. If all attempts for a URL fail with server errors, the next fallback URL is tried.\n\n## Timeouts and cancellation\n\nRaw `webrequest()` / `client.request()` calls return an unmodified native\n`Response`. Their timeout bounds each network attempt until response headers\narrive when persistent caching is bypassed. Cache-using calls apply the same\ntimeout to the foreground cache operation, including response-body\nserialization, before returning the caller-owned response. The caller retains\nnormal `Response` ownership for subsequent body streaming, cloning, and Cache\nAPI use.\n\nThe JSON convenience methods (`getJson`, `postJson`, `putJson`, and\n`deleteJson`) also bound response-body consumption. With retries disabled\n(the default), one deadline covers the complete request and JSON body. When\nWebrequest retries are enabled, the timeout remains per attempt and the final\nbody receives the same timeout budget.\n\nA caller-provided `AbortSignal` cancels the active fetch or body read and also\ninterrupts retry backoff, persistent-cache reads and writes, cache response\ncloning, and pruning. Discarded retry, fallback, and unsuccessful JSON\nresponses have their bodies canceled before the operation continues. Abort or\ndeadline failures never fall back to a stale cached response.\n\nUse the exported `isWebrequestTimeoutError(error)` predicate when a consumer\nneeds to distinguish Webrequest-owned deadline failures without depending on\nerror message text.\n\nStale-while-revalidate refreshes are coalesced per cache key and use the\nrequest's configured timeout as an independent whole-refresh deadline (60\nseconds by default), including response-body caching. Call `await\nclient.close()` for clients created with `webrequest.createClient()` when their\nlifecycle ends; this aborts owned background refreshes and closes IndexedDB.\n\nUse `cacheStrategy: 'network-only'` when a timed request must neither access\npersistent cache nor fall back to a cached response.\n\n## Request/Response Interceptors\n\n### Global Interceptors\n\n```typescript\nimport { webrequest } from '@push.rocks/webrequest';\n\n// Add authentication to all requests\nwebrequest.addRequestInterceptor((request) => {\n  const headers = new Headers(request.headers);\n  headers.set('Authorization', `Bearer ${getToken()}`);\n  return new Request(request, { headers });\n});\n\n// Log all responses\nwebrequest.addResponseInterceptor((response) => {\n  console.log(`${response.status} ${response.url}`);\n  return response;\n});\n\n// Handle errors globally\nwebrequest.addErrorInterceptor((error) => {\n  console.error('Request failed:', error);\n  return error;\n});\n\n// Clear all interceptors when needed\nwebrequest.clearInterceptors();\n```\n\n### Per-Request Interceptors\n\n```typescript\nconst response = await webrequest('https://api.example.com/data', {\n  interceptors: {\n    request: [(req) => {\n      console.log('Sending:', req.url);\n      return req;\n    }],\n    response: [(res) => {\n      console.log('Received:', res.status);\n      return res;\n    }],\n  },\n});\n```\n\n## Request Deduplication\n\nAutomatically prevent duplicate simultaneous requests:\n\n```typescript\n// Only one actual network request is made\nconst [res1, res2, res3] = await Promise.all([\n  webrequest('https://api.example.com/data', { deduplicate: true }),\n  webrequest('https://api.example.com/data', { deduplicate: true }),\n  webrequest('https://api.example.com/data', { deduplicate: true }),\n]);\n\n// All three get the same response (cloned)\n```\n\nDeduplication works for GET and HEAD requests by matching URL + method. Non-GET/HEAD requests are not deduplicated since they may have different bodies.\n\n## WebrequestClient\n\nFor more control, use `WebrequestClient` to set default options that apply to all requests made through that client:\n\n```typescript\nimport { WebrequestClient } from '@push.rocks/webrequest';\n\nconst apiClient = new WebrequestClient({\n  logging: true,\n  timeout: 30000,\n  cacheStrategy: 'network-first',\n  retry: {\n    maxAttempts: 3,\n    backoff: 'exponential',\n  },\n});\n\n// Add global interceptors to this client\napiClient.addRequestInterceptor((request) => {\n  const headers = new Headers(request.headers);\n  headers.set('X-API-Key', 'my-key');\n  return new Request(request, { headers });\n});\n\n// All requests through this client use the configured defaults\nconst data = await apiClient.getJson('https://api.example.com/data');\n\n// Standard fetch-compatible API\nconst response = await apiClient.request('https://api.example.com/data');\n\n// Create a client from the webrequest function\nconst client = webrequest.createClient({ timeout: 5000 });\n```\n\n## Advanced Features\n\n### Timeout\n\n```typescript\nconst response = await webrequest('https://api.example.com/data', {\n  timeout: 5000, // 5 seconds — throws Error on timeout\n});\n```\n\nFor this raw response API, the timeout covers the network attempt until\nresponse headers arrive when persistent caching is bypassed, and covers the\nforeground cache operation when caching is enabled. Use a JSON convenience\nmethod when the same option must also bound caller-owned body consumption.\nSelect `cacheStrategy: 'network-only'` when a request must fail on network\ntimeout instead of using a configured cache fallback.\n\n### Cache Management\n\n```typescript\n// Clear all cached responses\nawait webrequest.clearCache();\n\n// Delete one custom cache entry from an owned client\nconst client = webrequest.createClient();\nawait client.request('https://api.example.com/user', {\n  cacheStrategy: 'cache-first',\n  cacheKey: 'current-user',\n});\nawait client.deleteCache('current-user');\nawait client.close();\n```\n\n## API Reference\n\n### Main Function\n\n```typescript\nwebrequest(input: string | Request | URL, options?: IWebrequestOptions): Promise<Response>\nwebrequest.requestWithMetadata(input: string | Request | URL, options?: IWebrequestOptions): Promise<IWebrequestResponseResult>\n```\n\n### Convenience Methods\n\n```typescript\nwebrequest.getJson<T>(url: string, options?: IWebrequestOptions): Promise<T>\nwebrequest.postJson<T>(url: string, body: any, options?: IWebrequestOptions): Promise<T>\nwebrequest.putJson<T>(url: string, body: any, options?: IWebrequestOptions): Promise<T>\nwebrequest.deleteJson<T>(url: string, options?: IWebrequestOptions): Promise<T>\nwebrequest.getJsonWithMetadata<T>(url: string, options?: IWebrequestOptions): Promise<IWebrequestJsonResult<T>>\nwebrequest.postJsonWithMetadata<T>(url: string, body: any, options?: IWebrequestOptions): Promise<IWebrequestJsonResult<T>>\nwebrequest.putJsonWithMetadata<T>(url: string, body: any, options?: IWebrequestOptions): Promise<IWebrequestJsonResult<T>>\nwebrequest.deleteJsonWithMetadata<T>(url: string, options?: IWebrequestOptions): Promise<IWebrequestJsonResult<T>>\n```\n\n### Global Methods\n\n```typescript\nwebrequest.addRequestInterceptor(interceptor: TRequestInterceptor): void\nwebrequest.addResponseInterceptor(interceptor: TResponseInterceptor): void\nwebrequest.addErrorInterceptor(interceptor: TErrorInterceptor): void\nwebrequest.clearInterceptors(): void\nwebrequest.clearCache(): Promise<void>\nwebrequest.createClient(options?: Partial<IWebrequestOptions>): WebrequestClient\nwebrequest.getDefaultClient(): WebrequestClient\n```\n\nCreated `WebrequestClient` instances expose `close(): Promise<void>` for\ndeterministic cache-resource cleanup and\n`deleteCache(cacheKey: string): Promise<void>` for deleting one cache entry\nwithout clearing unrelated cached responses.\n\n### Options Interface\n\n```typescript\ninterface IWebrequestOptions extends Omit<RequestInit, 'cache'> {\n  // Standard fetch options\n  method?: string;\n  headers?: HeadersInit;\n  body?: BodyInit;\n\n  // Caching\n  cache?: 'default' | 'no-store' | 'reload' | 'no-cache' | 'force-cache' | 'only-if-cached';\n  cacheStrategy?: 'network-first' | 'cache-first' | 'stale-while-revalidate' | 'network-only' | 'cache-only';\n  cacheMaxAge?: number;\n  cacheMaxEntries?: number;\n  cacheKey?: string | ((request: Request) => string);\n  revalidate?: boolean;\n\n  // Retry & Fault Tolerance\n  retry?: boolean | IRetryOptions;\n  fallbackUrls?: string[];\n  timeout?: number;\n\n  // Interceptors\n  interceptors?: {\n    request?: TRequestInterceptor[];\n    response?: TResponseInterceptor[];\n  };\n\n  // Deduplication\n  deduplicate?: boolean;\n\n  // Logging\n  logging?: boolean;\n}\n```\n\n### Retry Options\n\n```typescript\ninterface IRetryOptions {\n  maxAttempts?: number;        // Default: 3\n  backoff?: 'exponential' | 'linear' | 'constant'; // Default: 'exponential'\n  initialDelay?: number;       // Default: 1000 (ms)\n  maxDelay?: number;           // Default: 30000 (ms)\n  retryOn?: number[] | ((response: Response, error?: Error) => boolean);\n  onRetry?: (attempt: number, error: Error, nextDelay: number) => void;\n}\n```\n\n## Examples\n\n### Complete Example with All Features\n\n```typescript\nimport { webrequest } from '@push.rocks/webrequest';\n\nasync function fetchUserData(userId: string) {\n  interface User {\n    id: string;\n    name: string;\n    email: string;\n  }\n\n  const user = await webrequest.getJson<User>(\n    `https://api.example.com/users/${userId}`,\n    {\n      cacheStrategy: 'stale-while-revalidate',\n      cacheMaxAge: 300000, // 5 minutes\n      retry: {\n        maxAttempts: 3,\n        backoff: 'exponential',\n        retryOn: [500, 502, 503, 504],\n      },\n      fallbackUrls: [\n        `https://api-backup.example.com/users/${userId}`,\n      ],\n      timeout: 10000,\n      deduplicate: true,\n      interceptors: {\n        request: [(req) => {\n          console.log(`Fetching user ${userId}`);\n          return req;\n        }],\n      },\n    }\n  );\n\n  return user;\n}\n```\n\n### Building a Typed API Client\n\n```typescript\nimport { WebrequestClient } from '@push.rocks/webrequest';\n\ninterface User {\n  id: string;\n  name: string;\n  email: string;\n}\n\ninterface CreateUserData {\n  name: string;\n  email: string;\n}\n\nclass ApiClient {\n  private client: WebrequestClient;\n\n  constructor(private baseUrl: string, private apiKey: string) {\n    this.client = new WebrequestClient({\n      timeout: 30000,\n      cacheStrategy: 'network-first',\n      retry: {\n        maxAttempts: 3,\n        backoff: 'exponential',\n      },\n    });\n\n    this.client.addRequestInterceptor((request) => {\n      const headers = new Headers(request.headers);\n      headers.set('Authorization', `Bearer ${this.apiKey}`);\n      headers.set('Content-Type', 'application/json');\n      return new Request(request, { headers });\n    });\n  }\n\n  async getUser(id: string): Promise<User> {\n    return this.client.getJson<User>(`${this.baseUrl}/users/${id}`);\n  }\n\n  async createUser(data: CreateUserData): Promise<User> {\n    return this.client.postJson<User>(`${this.baseUrl}/users`, data);\n  }\n\n  async updateUser(id: string, data: Partial<User>): Promise<User> {\n    return this.client.putJson<User>(`${this.baseUrl}/users/${id}`, data);\n  }\n\n  async deleteUser(id: string): Promise<void> {\n    await this.client.deleteJson(`${this.baseUrl}/users/${id}`);\n  }\n}\n\nconst api = new ApiClient('https://api.example.com', 'my-api-key');\nconst user = await api.getUser('123');\n```\n\n## Migration from v3\n\nVersion 4.0 is a **complete rewrite** of `@push.rocks/webrequest`. The v3 API has been removed entirely.\n\n### Key Changes\n\n| v3 | v4 |\n|---|---|\n| `new WebRequest()` | `webrequest()` function or `new WebrequestClient()` |\n| `client.getJson(url, true)` | `webrequest.getJson(url, { cacheStrategy: 'cache-first' })` |\n| `client.requestMultiEndpoint([...urls])` | `webrequest(url, { fallbackUrls: [...] })` |\n| `request(url, { timeoutMs: 30000 })` | `webrequest(url, { timeout: 30000 })` |\n\n### Migration Examples\n\n```typescript\n// v3 — Class-based\nimport { WebRequest } from '@push.rocks/webrequest';\nconst client = new WebRequest();\nconst response = await client.request('https://api.example.com/data', { method: 'GET' });\n\n// v4 — Function-based (fetch-compatible)\nimport { webrequest } from '@push.rocks/webrequest';\nconst response = await webrequest('https://api.example.com/data');\nconst data = await response.json();\n\n// v4 — Client-based (when you need defaults)\nimport { WebrequestClient } from '@push.rocks/webrequest';\nconst client = new WebrequestClient({ timeout: 30000 });\nconst data = await client.getJson('https://api.example.com/data');\n```\n\n## License and Legal Information\n\nThis repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [license.md](./license.md) file.\n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.\n\nUse of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.\n\n### Company Information\n\nTask Venture Capital GmbH\nRegistered at District Court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n","readmeFilename":""}